##// END OF EJS Templates
bookmarks: use cmdutil.check_incompatible_arguments() for action+rev...
Martin von Zweigbergk -
r44353:5cde1648 default
parent child Browse files
Show More
@@ -1,7832 +1,7830 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 wdirhex,
22 wdirhex,
23 wdirrev,
23 wdirrev,
24 )
24 )
25 from .pycompat import open
25 from .pycompat import open
26 from . import (
26 from . import (
27 archival,
27 archival,
28 bookmarks,
28 bookmarks,
29 bundle2,
29 bundle2,
30 changegroup,
30 changegroup,
31 cmdutil,
31 cmdutil,
32 copies,
32 copies,
33 debugcommands as debugcommandsmod,
33 debugcommands as debugcommandsmod,
34 destutil,
34 destutil,
35 dirstateguard,
35 dirstateguard,
36 discovery,
36 discovery,
37 encoding,
37 encoding,
38 error,
38 error,
39 exchange,
39 exchange,
40 extensions,
40 extensions,
41 filemerge,
41 filemerge,
42 formatter,
42 formatter,
43 graphmod,
43 graphmod,
44 hbisect,
44 hbisect,
45 help,
45 help,
46 hg,
46 hg,
47 logcmdutil,
47 logcmdutil,
48 merge as mergemod,
48 merge as mergemod,
49 narrowspec,
49 narrowspec,
50 obsolete,
50 obsolete,
51 obsutil,
51 obsutil,
52 patch,
52 patch,
53 phases,
53 phases,
54 pycompat,
54 pycompat,
55 rcutil,
55 rcutil,
56 registrar,
56 registrar,
57 revsetlang,
57 revsetlang,
58 rewriteutil,
58 rewriteutil,
59 scmutil,
59 scmutil,
60 server,
60 server,
61 shelve as shelvemod,
61 shelve as shelvemod,
62 state as statemod,
62 state as statemod,
63 streamclone,
63 streamclone,
64 tags as tagsmod,
64 tags as tagsmod,
65 ui as uimod,
65 ui as uimod,
66 util,
66 util,
67 verify as verifymod,
67 verify as verifymod,
68 wireprotoserver,
68 wireprotoserver,
69 )
69 )
70 from .utils import (
70 from .utils import (
71 dateutil,
71 dateutil,
72 stringutil,
72 stringutil,
73 )
73 )
74
74
75 table = {}
75 table = {}
76 table.update(debugcommandsmod.command._table)
76 table.update(debugcommandsmod.command._table)
77
77
78 command = registrar.command(table)
78 command = registrar.command(table)
79 INTENT_READONLY = registrar.INTENT_READONLY
79 INTENT_READONLY = registrar.INTENT_READONLY
80
80
81 # common command options
81 # common command options
82
82
83 globalopts = [
83 globalopts = [
84 (
84 (
85 b'R',
85 b'R',
86 b'repository',
86 b'repository',
87 b'',
87 b'',
88 _(b'repository root directory or name of overlay bundle file'),
88 _(b'repository root directory or name of overlay bundle file'),
89 _(b'REPO'),
89 _(b'REPO'),
90 ),
90 ),
91 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
91 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
92 (
92 (
93 b'y',
93 b'y',
94 b'noninteractive',
94 b'noninteractive',
95 None,
95 None,
96 _(
96 _(
97 b'do not prompt, automatically pick the first choice for all prompts'
97 b'do not prompt, automatically pick the first choice for all prompts'
98 ),
98 ),
99 ),
99 ),
100 (b'q', b'quiet', None, _(b'suppress output')),
100 (b'q', b'quiet', None, _(b'suppress output')),
101 (b'v', b'verbose', None, _(b'enable additional output')),
101 (b'v', b'verbose', None, _(b'enable additional output')),
102 (
102 (
103 b'',
103 b'',
104 b'color',
104 b'color',
105 b'',
105 b'',
106 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
106 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
107 # and should not be translated
107 # and should not be translated
108 _(b"when to colorize (boolean, always, auto, never, or debug)"),
108 _(b"when to colorize (boolean, always, auto, never, or debug)"),
109 _(b'TYPE'),
109 _(b'TYPE'),
110 ),
110 ),
111 (
111 (
112 b'',
112 b'',
113 b'config',
113 b'config',
114 [],
114 [],
115 _(b'set/override config option (use \'section.name=value\')'),
115 _(b'set/override config option (use \'section.name=value\')'),
116 _(b'CONFIG'),
116 _(b'CONFIG'),
117 ),
117 ),
118 (b'', b'debug', None, _(b'enable debugging output')),
118 (b'', b'debug', None, _(b'enable debugging output')),
119 (b'', b'debugger', None, _(b'start debugger')),
119 (b'', b'debugger', None, _(b'start debugger')),
120 (
120 (
121 b'',
121 b'',
122 b'encoding',
122 b'encoding',
123 encoding.encoding,
123 encoding.encoding,
124 _(b'set the charset encoding'),
124 _(b'set the charset encoding'),
125 _(b'ENCODE'),
125 _(b'ENCODE'),
126 ),
126 ),
127 (
127 (
128 b'',
128 b'',
129 b'encodingmode',
129 b'encodingmode',
130 encoding.encodingmode,
130 encoding.encodingmode,
131 _(b'set the charset encoding mode'),
131 _(b'set the charset encoding mode'),
132 _(b'MODE'),
132 _(b'MODE'),
133 ),
133 ),
134 (b'', b'traceback', None, _(b'always print a traceback on exception')),
134 (b'', b'traceback', None, _(b'always print a traceback on exception')),
135 (b'', b'time', None, _(b'time how long the command takes')),
135 (b'', b'time', None, _(b'time how long the command takes')),
136 (b'', b'profile', None, _(b'print command execution profile')),
136 (b'', b'profile', None, _(b'print command execution profile')),
137 (b'', b'version', None, _(b'output version information and exit')),
137 (b'', b'version', None, _(b'output version information and exit')),
138 (b'h', b'help', None, _(b'display help and exit')),
138 (b'h', b'help', None, _(b'display help and exit')),
139 (b'', b'hidden', False, _(b'consider hidden changesets')),
139 (b'', b'hidden', False, _(b'consider hidden changesets')),
140 (
140 (
141 b'',
141 b'',
142 b'pager',
142 b'pager',
143 b'auto',
143 b'auto',
144 _(b"when to paginate (boolean, always, auto, or never)"),
144 _(b"when to paginate (boolean, always, auto, or never)"),
145 _(b'TYPE'),
145 _(b'TYPE'),
146 ),
146 ),
147 ]
147 ]
148
148
149 dryrunopts = cmdutil.dryrunopts
149 dryrunopts = cmdutil.dryrunopts
150 remoteopts = cmdutil.remoteopts
150 remoteopts = cmdutil.remoteopts
151 walkopts = cmdutil.walkopts
151 walkopts = cmdutil.walkopts
152 commitopts = cmdutil.commitopts
152 commitopts = cmdutil.commitopts
153 commitopts2 = cmdutil.commitopts2
153 commitopts2 = cmdutil.commitopts2
154 commitopts3 = cmdutil.commitopts3
154 commitopts3 = cmdutil.commitopts3
155 formatteropts = cmdutil.formatteropts
155 formatteropts = cmdutil.formatteropts
156 templateopts = cmdutil.templateopts
156 templateopts = cmdutil.templateopts
157 logopts = cmdutil.logopts
157 logopts = cmdutil.logopts
158 diffopts = cmdutil.diffopts
158 diffopts = cmdutil.diffopts
159 diffwsopts = cmdutil.diffwsopts
159 diffwsopts = cmdutil.diffwsopts
160 diffopts2 = cmdutil.diffopts2
160 diffopts2 = cmdutil.diffopts2
161 mergetoolopts = cmdutil.mergetoolopts
161 mergetoolopts = cmdutil.mergetoolopts
162 similarityopts = cmdutil.similarityopts
162 similarityopts = cmdutil.similarityopts
163 subrepoopts = cmdutil.subrepoopts
163 subrepoopts = cmdutil.subrepoopts
164 debugrevlogopts = cmdutil.debugrevlogopts
164 debugrevlogopts = cmdutil.debugrevlogopts
165
165
166 # Commands start here, listed alphabetically
166 # Commands start here, listed alphabetically
167
167
168
168
169 @command(
169 @command(
170 b'abort',
170 b'abort',
171 dryrunopts,
171 dryrunopts,
172 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
172 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
173 helpbasic=True,
173 helpbasic=True,
174 )
174 )
175 def abort(ui, repo, **opts):
175 def abort(ui, repo, **opts):
176 """abort an unfinished operation (EXPERIMENTAL)
176 """abort an unfinished operation (EXPERIMENTAL)
177
177
178 Aborts a multistep operation like graft, histedit, rebase, merge,
178 Aborts a multistep operation like graft, histedit, rebase, merge,
179 and unshelve if they are in an unfinished state.
179 and unshelve if they are in an unfinished state.
180
180
181 use --dry-run/-n to dry run the command.
181 use --dry-run/-n to dry run the command.
182 """
182 """
183 dryrun = opts.get('dry_run')
183 dryrun = opts.get('dry_run')
184 abortstate = cmdutil.getunfinishedstate(repo)
184 abortstate = cmdutil.getunfinishedstate(repo)
185 if not abortstate:
185 if not abortstate:
186 raise error.Abort(_(b'no operation in progress'))
186 raise error.Abort(_(b'no operation in progress'))
187 if not abortstate.abortfunc:
187 if not abortstate.abortfunc:
188 raise error.Abort(
188 raise error.Abort(
189 (
189 (
190 _(b"%s in progress but does not support 'hg abort'")
190 _(b"%s in progress but does not support 'hg abort'")
191 % (abortstate._opname)
191 % (abortstate._opname)
192 ),
192 ),
193 hint=abortstate.hint(),
193 hint=abortstate.hint(),
194 )
194 )
195 if dryrun:
195 if dryrun:
196 ui.status(
196 ui.status(
197 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
197 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
198 )
198 )
199 return
199 return
200 return abortstate.abortfunc(ui, repo)
200 return abortstate.abortfunc(ui, repo)
201
201
202
202
203 @command(
203 @command(
204 b'add',
204 b'add',
205 walkopts + subrepoopts + dryrunopts,
205 walkopts + subrepoopts + dryrunopts,
206 _(b'[OPTION]... [FILE]...'),
206 _(b'[OPTION]... [FILE]...'),
207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
208 helpbasic=True,
208 helpbasic=True,
209 inferrepo=True,
209 inferrepo=True,
210 )
210 )
211 def add(ui, repo, *pats, **opts):
211 def add(ui, repo, *pats, **opts):
212 """add the specified files on the next commit
212 """add the specified files on the next commit
213
213
214 Schedule files to be version controlled and added to the
214 Schedule files to be version controlled and added to the
215 repository.
215 repository.
216
216
217 The files will be added to the repository at the next commit. To
217 The files will be added to the repository at the next commit. To
218 undo an add before that, see :hg:`forget`.
218 undo an add before that, see :hg:`forget`.
219
219
220 If no names are given, add all files to the repository (except
220 If no names are given, add all files to the repository (except
221 files matching ``.hgignore``).
221 files matching ``.hgignore``).
222
222
223 .. container:: verbose
223 .. container:: verbose
224
224
225 Examples:
225 Examples:
226
226
227 - New (unknown) files are added
227 - New (unknown) files are added
228 automatically by :hg:`add`::
228 automatically by :hg:`add`::
229
229
230 $ ls
230 $ ls
231 foo.c
231 foo.c
232 $ hg status
232 $ hg status
233 ? foo.c
233 ? foo.c
234 $ hg add
234 $ hg add
235 adding foo.c
235 adding foo.c
236 $ hg status
236 $ hg status
237 A foo.c
237 A foo.c
238
238
239 - Specific files to be added can be specified::
239 - Specific files to be added can be specified::
240
240
241 $ ls
241 $ ls
242 bar.c foo.c
242 bar.c foo.c
243 $ hg status
243 $ hg status
244 ? bar.c
244 ? bar.c
245 ? foo.c
245 ? foo.c
246 $ hg add bar.c
246 $ hg add bar.c
247 $ hg status
247 $ hg status
248 A bar.c
248 A bar.c
249 ? foo.c
249 ? foo.c
250
250
251 Returns 0 if all files are successfully added.
251 Returns 0 if all files are successfully added.
252 """
252 """
253
253
254 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
254 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
255 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
255 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
256 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
256 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
257 return rejected and 1 or 0
257 return rejected and 1 or 0
258
258
259
259
260 @command(
260 @command(
261 b'addremove',
261 b'addremove',
262 similarityopts + subrepoopts + walkopts + dryrunopts,
262 similarityopts + subrepoopts + walkopts + dryrunopts,
263 _(b'[OPTION]... [FILE]...'),
263 _(b'[OPTION]... [FILE]...'),
264 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
264 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
265 inferrepo=True,
265 inferrepo=True,
266 )
266 )
267 def addremove(ui, repo, *pats, **opts):
267 def addremove(ui, repo, *pats, **opts):
268 """add all new files, delete all missing files
268 """add all new files, delete all missing files
269
269
270 Add all new files and remove all missing files from the
270 Add all new files and remove all missing files from the
271 repository.
271 repository.
272
272
273 Unless names are given, new files are ignored if they match any of
273 Unless names are given, new files are ignored if they match any of
274 the patterns in ``.hgignore``. As with add, these changes take
274 the patterns in ``.hgignore``. As with add, these changes take
275 effect at the next commit.
275 effect at the next commit.
276
276
277 Use the -s/--similarity option to detect renamed files. This
277 Use the -s/--similarity option to detect renamed files. This
278 option takes a percentage between 0 (disabled) and 100 (files must
278 option takes a percentage between 0 (disabled) and 100 (files must
279 be identical) as its parameter. With a parameter greater than 0,
279 be identical) as its parameter. With a parameter greater than 0,
280 this compares every removed file with every added file and records
280 this compares every removed file with every added file and records
281 those similar enough as renames. Detecting renamed files this way
281 those similar enough as renames. Detecting renamed files this way
282 can be expensive. After using this option, :hg:`status -C` can be
282 can be expensive. After using this option, :hg:`status -C` can be
283 used to check which files were identified as moved or renamed. If
283 used to check which files were identified as moved or renamed. If
284 not specified, -s/--similarity defaults to 100 and only renames of
284 not specified, -s/--similarity defaults to 100 and only renames of
285 identical files are detected.
285 identical files are detected.
286
286
287 .. container:: verbose
287 .. container:: verbose
288
288
289 Examples:
289 Examples:
290
290
291 - A number of files (bar.c and foo.c) are new,
291 - A number of files (bar.c and foo.c) are new,
292 while foobar.c has been removed (without using :hg:`remove`)
292 while foobar.c has been removed (without using :hg:`remove`)
293 from the repository::
293 from the repository::
294
294
295 $ ls
295 $ ls
296 bar.c foo.c
296 bar.c foo.c
297 $ hg status
297 $ hg status
298 ! foobar.c
298 ! foobar.c
299 ? bar.c
299 ? bar.c
300 ? foo.c
300 ? foo.c
301 $ hg addremove
301 $ hg addremove
302 adding bar.c
302 adding bar.c
303 adding foo.c
303 adding foo.c
304 removing foobar.c
304 removing foobar.c
305 $ hg status
305 $ hg status
306 A bar.c
306 A bar.c
307 A foo.c
307 A foo.c
308 R foobar.c
308 R foobar.c
309
309
310 - A file foobar.c was moved to foo.c without using :hg:`rename`.
310 - A file foobar.c was moved to foo.c without using :hg:`rename`.
311 Afterwards, it was edited slightly::
311 Afterwards, it was edited slightly::
312
312
313 $ ls
313 $ ls
314 foo.c
314 foo.c
315 $ hg status
315 $ hg status
316 ! foobar.c
316 ! foobar.c
317 ? foo.c
317 ? foo.c
318 $ hg addremove --similarity 90
318 $ hg addremove --similarity 90
319 removing foobar.c
319 removing foobar.c
320 adding foo.c
320 adding foo.c
321 recording removal of foobar.c as rename to foo.c (94% similar)
321 recording removal of foobar.c as rename to foo.c (94% similar)
322 $ hg status -C
322 $ hg status -C
323 A foo.c
323 A foo.c
324 foobar.c
324 foobar.c
325 R foobar.c
325 R foobar.c
326
326
327 Returns 0 if all files are successfully added.
327 Returns 0 if all files are successfully added.
328 """
328 """
329 opts = pycompat.byteskwargs(opts)
329 opts = pycompat.byteskwargs(opts)
330 if not opts.get(b'similarity'):
330 if not opts.get(b'similarity'):
331 opts[b'similarity'] = b'100'
331 opts[b'similarity'] = b'100'
332 matcher = scmutil.match(repo[None], pats, opts)
332 matcher = scmutil.match(repo[None], pats, opts)
333 relative = scmutil.anypats(pats, opts)
333 relative = scmutil.anypats(pats, opts)
334 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
334 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
335 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
335 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
336
336
337
337
338 @command(
338 @command(
339 b'annotate|blame',
339 b'annotate|blame',
340 [
340 [
341 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
341 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
342 (
342 (
343 b'',
343 b'',
344 b'follow',
344 b'follow',
345 None,
345 None,
346 _(b'follow copies/renames and list the filename (DEPRECATED)'),
346 _(b'follow copies/renames and list the filename (DEPRECATED)'),
347 ),
347 ),
348 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
348 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
349 (b'a', b'text', None, _(b'treat all files as text')),
349 (b'a', b'text', None, _(b'treat all files as text')),
350 (b'u', b'user', None, _(b'list the author (long with -v)')),
350 (b'u', b'user', None, _(b'list the author (long with -v)')),
351 (b'f', b'file', None, _(b'list the filename')),
351 (b'f', b'file', None, _(b'list the filename')),
352 (b'd', b'date', None, _(b'list the date (short with -q)')),
352 (b'd', b'date', None, _(b'list the date (short with -q)')),
353 (b'n', b'number', None, _(b'list the revision number (default)')),
353 (b'n', b'number', None, _(b'list the revision number (default)')),
354 (b'c', b'changeset', None, _(b'list the changeset')),
354 (b'c', b'changeset', None, _(b'list the changeset')),
355 (
355 (
356 b'l',
356 b'l',
357 b'line-number',
357 b'line-number',
358 None,
358 None,
359 _(b'show line number at the first appearance'),
359 _(b'show line number at the first appearance'),
360 ),
360 ),
361 (
361 (
362 b'',
362 b'',
363 b'skip',
363 b'skip',
364 [],
364 [],
365 _(b'revset to not display (EXPERIMENTAL)'),
365 _(b'revset to not display (EXPERIMENTAL)'),
366 _(b'REV'),
366 _(b'REV'),
367 ),
367 ),
368 ]
368 ]
369 + diffwsopts
369 + diffwsopts
370 + walkopts
370 + walkopts
371 + formatteropts,
371 + formatteropts,
372 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
372 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
373 helpcategory=command.CATEGORY_FILE_CONTENTS,
373 helpcategory=command.CATEGORY_FILE_CONTENTS,
374 helpbasic=True,
374 helpbasic=True,
375 inferrepo=True,
375 inferrepo=True,
376 )
376 )
377 def annotate(ui, repo, *pats, **opts):
377 def annotate(ui, repo, *pats, **opts):
378 """show changeset information by line for each file
378 """show changeset information by line for each file
379
379
380 List changes in files, showing the revision id responsible for
380 List changes in files, showing the revision id responsible for
381 each line.
381 each line.
382
382
383 This command is useful for discovering when a change was made and
383 This command is useful for discovering when a change was made and
384 by whom.
384 by whom.
385
385
386 If you include --file, --user, or --date, the revision number is
386 If you include --file, --user, or --date, the revision number is
387 suppressed unless you also include --number.
387 suppressed unless you also include --number.
388
388
389 Without the -a/--text option, annotate will avoid processing files
389 Without the -a/--text option, annotate will avoid processing files
390 it detects as binary. With -a, annotate will annotate the file
390 it detects as binary. With -a, annotate will annotate the file
391 anyway, although the results will probably be neither useful
391 anyway, although the results will probably be neither useful
392 nor desirable.
392 nor desirable.
393
393
394 .. container:: verbose
394 .. container:: verbose
395
395
396 Template:
396 Template:
397
397
398 The following keywords are supported in addition to the common template
398 The following keywords are supported in addition to the common template
399 keywords and functions. See also :hg:`help templates`.
399 keywords and functions. See also :hg:`help templates`.
400
400
401 :lines: List of lines with annotation data.
401 :lines: List of lines with annotation data.
402 :path: String. Repository-absolute path of the specified file.
402 :path: String. Repository-absolute path of the specified file.
403
403
404 And each entry of ``{lines}`` provides the following sub-keywords in
404 And each entry of ``{lines}`` provides the following sub-keywords in
405 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
405 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
406
406
407 :line: String. Line content.
407 :line: String. Line content.
408 :lineno: Integer. Line number at that revision.
408 :lineno: Integer. Line number at that revision.
409 :path: String. Repository-absolute path of the file at that revision.
409 :path: String. Repository-absolute path of the file at that revision.
410
410
411 See :hg:`help templates.operators` for the list expansion syntax.
411 See :hg:`help templates.operators` for the list expansion syntax.
412
412
413 Returns 0 on success.
413 Returns 0 on success.
414 """
414 """
415 opts = pycompat.byteskwargs(opts)
415 opts = pycompat.byteskwargs(opts)
416 if not pats:
416 if not pats:
417 raise error.Abort(_(b'at least one filename or pattern is required'))
417 raise error.Abort(_(b'at least one filename or pattern is required'))
418
418
419 if opts.get(b'follow'):
419 if opts.get(b'follow'):
420 # --follow is deprecated and now just an alias for -f/--file
420 # --follow is deprecated and now just an alias for -f/--file
421 # to mimic the behavior of Mercurial before version 1.5
421 # to mimic the behavior of Mercurial before version 1.5
422 opts[b'file'] = True
422 opts[b'file'] = True
423
423
424 if (
424 if (
425 not opts.get(b'user')
425 not opts.get(b'user')
426 and not opts.get(b'changeset')
426 and not opts.get(b'changeset')
427 and not opts.get(b'date')
427 and not opts.get(b'date')
428 and not opts.get(b'file')
428 and not opts.get(b'file')
429 ):
429 ):
430 opts[b'number'] = True
430 opts[b'number'] = True
431
431
432 linenumber = opts.get(b'line_number') is not None
432 linenumber = opts.get(b'line_number') is not None
433 if (
433 if (
434 linenumber
434 linenumber
435 and (not opts.get(b'changeset'))
435 and (not opts.get(b'changeset'))
436 and (not opts.get(b'number'))
436 and (not opts.get(b'number'))
437 ):
437 ):
438 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
438 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
439
439
440 rev = opts.get(b'rev')
440 rev = opts.get(b'rev')
441 if rev:
441 if rev:
442 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
442 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
443 ctx = scmutil.revsingle(repo, rev)
443 ctx = scmutil.revsingle(repo, rev)
444
444
445 ui.pager(b'annotate')
445 ui.pager(b'annotate')
446 rootfm = ui.formatter(b'annotate', opts)
446 rootfm = ui.formatter(b'annotate', opts)
447 if ui.debugflag:
447 if ui.debugflag:
448 shorthex = pycompat.identity
448 shorthex = pycompat.identity
449 else:
449 else:
450
450
451 def shorthex(h):
451 def shorthex(h):
452 return h[:12]
452 return h[:12]
453
453
454 if ui.quiet:
454 if ui.quiet:
455 datefunc = dateutil.shortdate
455 datefunc = dateutil.shortdate
456 else:
456 else:
457 datefunc = dateutil.datestr
457 datefunc = dateutil.datestr
458 if ctx.rev() is None:
458 if ctx.rev() is None:
459 if opts.get(b'changeset'):
459 if opts.get(b'changeset'):
460 # omit "+" suffix which is appended to node hex
460 # omit "+" suffix which is appended to node hex
461 def formatrev(rev):
461 def formatrev(rev):
462 if rev == wdirrev:
462 if rev == wdirrev:
463 return b'%d' % ctx.p1().rev()
463 return b'%d' % ctx.p1().rev()
464 else:
464 else:
465 return b'%d' % rev
465 return b'%d' % rev
466
466
467 else:
467 else:
468
468
469 def formatrev(rev):
469 def formatrev(rev):
470 if rev == wdirrev:
470 if rev == wdirrev:
471 return b'%d+' % ctx.p1().rev()
471 return b'%d+' % ctx.p1().rev()
472 else:
472 else:
473 return b'%d ' % rev
473 return b'%d ' % rev
474
474
475 def formathex(h):
475 def formathex(h):
476 if h == wdirhex:
476 if h == wdirhex:
477 return b'%s+' % shorthex(hex(ctx.p1().node()))
477 return b'%s+' % shorthex(hex(ctx.p1().node()))
478 else:
478 else:
479 return b'%s ' % shorthex(h)
479 return b'%s ' % shorthex(h)
480
480
481 else:
481 else:
482 formatrev = b'%d'.__mod__
482 formatrev = b'%d'.__mod__
483 formathex = shorthex
483 formathex = shorthex
484
484
485 opmap = [
485 opmap = [
486 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
486 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
487 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
487 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
488 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
488 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
489 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
489 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
490 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
490 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
491 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
491 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
492 ]
492 ]
493 opnamemap = {
493 opnamemap = {
494 b'rev': b'number',
494 b'rev': b'number',
495 b'node': b'changeset',
495 b'node': b'changeset',
496 b'path': b'file',
496 b'path': b'file',
497 b'lineno': b'line_number',
497 b'lineno': b'line_number',
498 }
498 }
499
499
500 if rootfm.isplain():
500 if rootfm.isplain():
501
501
502 def makefunc(get, fmt):
502 def makefunc(get, fmt):
503 return lambda x: fmt(get(x))
503 return lambda x: fmt(get(x))
504
504
505 else:
505 else:
506
506
507 def makefunc(get, fmt):
507 def makefunc(get, fmt):
508 return get
508 return get
509
509
510 datahint = rootfm.datahint()
510 datahint = rootfm.datahint()
511 funcmap = [
511 funcmap = [
512 (makefunc(get, fmt), sep)
512 (makefunc(get, fmt), sep)
513 for fn, sep, get, fmt in opmap
513 for fn, sep, get, fmt in opmap
514 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
514 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
515 ]
515 ]
516 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
516 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
517 fields = b' '.join(
517 fields = b' '.join(
518 fn
518 fn
519 for fn, sep, get, fmt in opmap
519 for fn, sep, get, fmt in opmap
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
521 )
521 )
522
522
523 def bad(x, y):
523 def bad(x, y):
524 raise error.Abort(b"%s: %s" % (x, y))
524 raise error.Abort(b"%s: %s" % (x, y))
525
525
526 m = scmutil.match(ctx, pats, opts, badfn=bad)
526 m = scmutil.match(ctx, pats, opts, badfn=bad)
527
527
528 follow = not opts.get(b'no_follow')
528 follow = not opts.get(b'no_follow')
529 diffopts = patch.difffeatureopts(
529 diffopts = patch.difffeatureopts(
530 ui, opts, section=b'annotate', whitespace=True
530 ui, opts, section=b'annotate', whitespace=True
531 )
531 )
532 skiprevs = opts.get(b'skip')
532 skiprevs = opts.get(b'skip')
533 if skiprevs:
533 if skiprevs:
534 skiprevs = scmutil.revrange(repo, skiprevs)
534 skiprevs = scmutil.revrange(repo, skiprevs)
535
535
536 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
536 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
537 for abs in ctx.walk(m):
537 for abs in ctx.walk(m):
538 fctx = ctx[abs]
538 fctx = ctx[abs]
539 rootfm.startitem()
539 rootfm.startitem()
540 rootfm.data(path=abs)
540 rootfm.data(path=abs)
541 if not opts.get(b'text') and fctx.isbinary():
541 if not opts.get(b'text') and fctx.isbinary():
542 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
542 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
543 continue
543 continue
544
544
545 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
545 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
546 lines = fctx.annotate(
546 lines = fctx.annotate(
547 follow=follow, skiprevs=skiprevs, diffopts=diffopts
547 follow=follow, skiprevs=skiprevs, diffopts=diffopts
548 )
548 )
549 if not lines:
549 if not lines:
550 fm.end()
550 fm.end()
551 continue
551 continue
552 formats = []
552 formats = []
553 pieces = []
553 pieces = []
554
554
555 for f, sep in funcmap:
555 for f, sep in funcmap:
556 l = [f(n) for n in lines]
556 l = [f(n) for n in lines]
557 if fm.isplain():
557 if fm.isplain():
558 sizes = [encoding.colwidth(x) for x in l]
558 sizes = [encoding.colwidth(x) for x in l]
559 ml = max(sizes)
559 ml = max(sizes)
560 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
560 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
561 else:
561 else:
562 formats.append([b'%s' for x in l])
562 formats.append([b'%s' for x in l])
563 pieces.append(l)
563 pieces.append(l)
564
564
565 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
565 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
566 fm.startitem()
566 fm.startitem()
567 fm.context(fctx=n.fctx)
567 fm.context(fctx=n.fctx)
568 fm.write(fields, b"".join(f), *p)
568 fm.write(fields, b"".join(f), *p)
569 if n.skip:
569 if n.skip:
570 fmt = b"* %s"
570 fmt = b"* %s"
571 else:
571 else:
572 fmt = b": %s"
572 fmt = b": %s"
573 fm.write(b'line', fmt, n.text)
573 fm.write(b'line', fmt, n.text)
574
574
575 if not lines[-1].text.endswith(b'\n'):
575 if not lines[-1].text.endswith(b'\n'):
576 fm.plain(b'\n')
576 fm.plain(b'\n')
577 fm.end()
577 fm.end()
578
578
579 rootfm.end()
579 rootfm.end()
580
580
581
581
582 @command(
582 @command(
583 b'archive',
583 b'archive',
584 [
584 [
585 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
585 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
586 (
586 (
587 b'p',
587 b'p',
588 b'prefix',
588 b'prefix',
589 b'',
589 b'',
590 _(b'directory prefix for files in archive'),
590 _(b'directory prefix for files in archive'),
591 _(b'PREFIX'),
591 _(b'PREFIX'),
592 ),
592 ),
593 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
593 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
594 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
594 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
595 ]
595 ]
596 + subrepoopts
596 + subrepoopts
597 + walkopts,
597 + walkopts,
598 _(b'[OPTION]... DEST'),
598 _(b'[OPTION]... DEST'),
599 helpcategory=command.CATEGORY_IMPORT_EXPORT,
599 helpcategory=command.CATEGORY_IMPORT_EXPORT,
600 )
600 )
601 def archive(ui, repo, dest, **opts):
601 def archive(ui, repo, dest, **opts):
602 '''create an unversioned archive of a repository revision
602 '''create an unversioned archive of a repository revision
603
603
604 By default, the revision used is the parent of the working
604 By default, the revision used is the parent of the working
605 directory; use -r/--rev to specify a different revision.
605 directory; use -r/--rev to specify a different revision.
606
606
607 The archive type is automatically detected based on file
607 The archive type is automatically detected based on file
608 extension (to override, use -t/--type).
608 extension (to override, use -t/--type).
609
609
610 .. container:: verbose
610 .. container:: verbose
611
611
612 Examples:
612 Examples:
613
613
614 - create a zip file containing the 1.0 release::
614 - create a zip file containing the 1.0 release::
615
615
616 hg archive -r 1.0 project-1.0.zip
616 hg archive -r 1.0 project-1.0.zip
617
617
618 - create a tarball excluding .hg files::
618 - create a tarball excluding .hg files::
619
619
620 hg archive project.tar.gz -X ".hg*"
620 hg archive project.tar.gz -X ".hg*"
621
621
622 Valid types are:
622 Valid types are:
623
623
624 :``files``: a directory full of files (default)
624 :``files``: a directory full of files (default)
625 :``tar``: tar archive, uncompressed
625 :``tar``: tar archive, uncompressed
626 :``tbz2``: tar archive, compressed using bzip2
626 :``tbz2``: tar archive, compressed using bzip2
627 :``tgz``: tar archive, compressed using gzip
627 :``tgz``: tar archive, compressed using gzip
628 :``txz``: tar archive, compressed using lzma (only in Python 3)
628 :``txz``: tar archive, compressed using lzma (only in Python 3)
629 :``uzip``: zip archive, uncompressed
629 :``uzip``: zip archive, uncompressed
630 :``zip``: zip archive, compressed using deflate
630 :``zip``: zip archive, compressed using deflate
631
631
632 The exact name of the destination archive or directory is given
632 The exact name of the destination archive or directory is given
633 using a format string; see :hg:`help export` for details.
633 using a format string; see :hg:`help export` for details.
634
634
635 Each member added to an archive file has a directory prefix
635 Each member added to an archive file has a directory prefix
636 prepended. Use -p/--prefix to specify a format string for the
636 prepended. Use -p/--prefix to specify a format string for the
637 prefix. The default is the basename of the archive, with suffixes
637 prefix. The default is the basename of the archive, with suffixes
638 removed.
638 removed.
639
639
640 Returns 0 on success.
640 Returns 0 on success.
641 '''
641 '''
642
642
643 opts = pycompat.byteskwargs(opts)
643 opts = pycompat.byteskwargs(opts)
644 rev = opts.get(b'rev')
644 rev = opts.get(b'rev')
645 if rev:
645 if rev:
646 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
646 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
647 ctx = scmutil.revsingle(repo, rev)
647 ctx = scmutil.revsingle(repo, rev)
648 if not ctx:
648 if not ctx:
649 raise error.Abort(_(b'no working directory: please specify a revision'))
649 raise error.Abort(_(b'no working directory: please specify a revision'))
650 node = ctx.node()
650 node = ctx.node()
651 dest = cmdutil.makefilename(ctx, dest)
651 dest = cmdutil.makefilename(ctx, dest)
652 if os.path.realpath(dest) == repo.root:
652 if os.path.realpath(dest) == repo.root:
653 raise error.Abort(_(b'repository root cannot be destination'))
653 raise error.Abort(_(b'repository root cannot be destination'))
654
654
655 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
655 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
656 prefix = opts.get(b'prefix')
656 prefix = opts.get(b'prefix')
657
657
658 if dest == b'-':
658 if dest == b'-':
659 if kind == b'files':
659 if kind == b'files':
660 raise error.Abort(_(b'cannot archive plain files to stdout'))
660 raise error.Abort(_(b'cannot archive plain files to stdout'))
661 dest = cmdutil.makefileobj(ctx, dest)
661 dest = cmdutil.makefileobj(ctx, dest)
662 if not prefix:
662 if not prefix:
663 prefix = os.path.basename(repo.root) + b'-%h'
663 prefix = os.path.basename(repo.root) + b'-%h'
664
664
665 prefix = cmdutil.makefilename(ctx, prefix)
665 prefix = cmdutil.makefilename(ctx, prefix)
666 match = scmutil.match(ctx, [], opts)
666 match = scmutil.match(ctx, [], opts)
667 archival.archive(
667 archival.archive(
668 repo,
668 repo,
669 dest,
669 dest,
670 node,
670 node,
671 kind,
671 kind,
672 not opts.get(b'no_decode'),
672 not opts.get(b'no_decode'),
673 match,
673 match,
674 prefix,
674 prefix,
675 subrepos=opts.get(b'subrepos'),
675 subrepos=opts.get(b'subrepos'),
676 )
676 )
677
677
678
678
679 @command(
679 @command(
680 b'backout',
680 b'backout',
681 [
681 [
682 (
682 (
683 b'',
683 b'',
684 b'merge',
684 b'merge',
685 None,
685 None,
686 _(b'merge with old dirstate parent after backout'),
686 _(b'merge with old dirstate parent after backout'),
687 ),
687 ),
688 (
688 (
689 b'',
689 b'',
690 b'commit',
690 b'commit',
691 None,
691 None,
692 _(b'commit if no conflicts were encountered (DEPRECATED)'),
692 _(b'commit if no conflicts were encountered (DEPRECATED)'),
693 ),
693 ),
694 (b'', b'no-commit', None, _(b'do not commit')),
694 (b'', b'no-commit', None, _(b'do not commit')),
695 (
695 (
696 b'',
696 b'',
697 b'parent',
697 b'parent',
698 b'',
698 b'',
699 _(b'parent to choose when backing out merge (DEPRECATED)'),
699 _(b'parent to choose when backing out merge (DEPRECATED)'),
700 _(b'REV'),
700 _(b'REV'),
701 ),
701 ),
702 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
702 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
703 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
703 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
704 ]
704 ]
705 + mergetoolopts
705 + mergetoolopts
706 + walkopts
706 + walkopts
707 + commitopts
707 + commitopts
708 + commitopts2,
708 + commitopts2,
709 _(b'[OPTION]... [-r] REV'),
709 _(b'[OPTION]... [-r] REV'),
710 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
710 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
711 )
711 )
712 def backout(ui, repo, node=None, rev=None, **opts):
712 def backout(ui, repo, node=None, rev=None, **opts):
713 '''reverse effect of earlier changeset
713 '''reverse effect of earlier changeset
714
714
715 Prepare a new changeset with the effect of REV undone in the
715 Prepare a new changeset with the effect of REV undone in the
716 current working directory. If no conflicts were encountered,
716 current working directory. If no conflicts were encountered,
717 it will be committed immediately.
717 it will be committed immediately.
718
718
719 If REV is the parent of the working directory, then this new changeset
719 If REV is the parent of the working directory, then this new changeset
720 is committed automatically (unless --no-commit is specified).
720 is committed automatically (unless --no-commit is specified).
721
721
722 .. note::
722 .. note::
723
723
724 :hg:`backout` cannot be used to fix either an unwanted or
724 :hg:`backout` cannot be used to fix either an unwanted or
725 incorrect merge.
725 incorrect merge.
726
726
727 .. container:: verbose
727 .. container:: verbose
728
728
729 Examples:
729 Examples:
730
730
731 - Reverse the effect of the parent of the working directory.
731 - Reverse the effect of the parent of the working directory.
732 This backout will be committed immediately::
732 This backout will be committed immediately::
733
733
734 hg backout -r .
734 hg backout -r .
735
735
736 - Reverse the effect of previous bad revision 23::
736 - Reverse the effect of previous bad revision 23::
737
737
738 hg backout -r 23
738 hg backout -r 23
739
739
740 - Reverse the effect of previous bad revision 23 and
740 - Reverse the effect of previous bad revision 23 and
741 leave changes uncommitted::
741 leave changes uncommitted::
742
742
743 hg backout -r 23 --no-commit
743 hg backout -r 23 --no-commit
744 hg commit -m "Backout revision 23"
744 hg commit -m "Backout revision 23"
745
745
746 By default, the pending changeset will have one parent,
746 By default, the pending changeset will have one parent,
747 maintaining a linear history. With --merge, the pending
747 maintaining a linear history. With --merge, the pending
748 changeset will instead have two parents: the old parent of the
748 changeset will instead have two parents: the old parent of the
749 working directory and a new child of REV that simply undoes REV.
749 working directory and a new child of REV that simply undoes REV.
750
750
751 Before version 1.7, the behavior without --merge was equivalent
751 Before version 1.7, the behavior without --merge was equivalent
752 to specifying --merge followed by :hg:`update --clean .` to
752 to specifying --merge followed by :hg:`update --clean .` to
753 cancel the merge and leave the child of REV as a head to be
753 cancel the merge and leave the child of REV as a head to be
754 merged separately.
754 merged separately.
755
755
756 See :hg:`help dates` for a list of formats valid for -d/--date.
756 See :hg:`help dates` for a list of formats valid for -d/--date.
757
757
758 See :hg:`help revert` for a way to restore files to the state
758 See :hg:`help revert` for a way to restore files to the state
759 of another revision.
759 of another revision.
760
760
761 Returns 0 on success, 1 if nothing to backout or there are unresolved
761 Returns 0 on success, 1 if nothing to backout or there are unresolved
762 files.
762 files.
763 '''
763 '''
764 with repo.wlock(), repo.lock():
764 with repo.wlock(), repo.lock():
765 return _dobackout(ui, repo, node, rev, **opts)
765 return _dobackout(ui, repo, node, rev, **opts)
766
766
767
767
768 def _dobackout(ui, repo, node=None, rev=None, **opts):
768 def _dobackout(ui, repo, node=None, rev=None, **opts):
769 opts = pycompat.byteskwargs(opts)
769 opts = pycompat.byteskwargs(opts)
770 if opts.get(b'commit') and opts.get(b'no_commit'):
770 if opts.get(b'commit') and opts.get(b'no_commit'):
771 raise error.Abort(_(b"cannot use --commit with --no-commit"))
771 raise error.Abort(_(b"cannot use --commit with --no-commit"))
772 if opts.get(b'merge') and opts.get(b'no_commit'):
772 if opts.get(b'merge') and opts.get(b'no_commit'):
773 raise error.Abort(_(b"cannot use --merge with --no-commit"))
773 raise error.Abort(_(b"cannot use --merge with --no-commit"))
774
774
775 if rev and node:
775 if rev and node:
776 raise error.Abort(_(b"please specify just one revision"))
776 raise error.Abort(_(b"please specify just one revision"))
777
777
778 if not rev:
778 if not rev:
779 rev = node
779 rev = node
780
780
781 if not rev:
781 if not rev:
782 raise error.Abort(_(b"please specify a revision to backout"))
782 raise error.Abort(_(b"please specify a revision to backout"))
783
783
784 date = opts.get(b'date')
784 date = opts.get(b'date')
785 if date:
785 if date:
786 opts[b'date'] = dateutil.parsedate(date)
786 opts[b'date'] = dateutil.parsedate(date)
787
787
788 cmdutil.checkunfinished(repo)
788 cmdutil.checkunfinished(repo)
789 cmdutil.bailifchanged(repo)
789 cmdutil.bailifchanged(repo)
790 node = scmutil.revsingle(repo, rev).node()
790 node = scmutil.revsingle(repo, rev).node()
791
791
792 op1, op2 = repo.dirstate.parents()
792 op1, op2 = repo.dirstate.parents()
793 if not repo.changelog.isancestor(node, op1):
793 if not repo.changelog.isancestor(node, op1):
794 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
794 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
795
795
796 p1, p2 = repo.changelog.parents(node)
796 p1, p2 = repo.changelog.parents(node)
797 if p1 == nullid:
797 if p1 == nullid:
798 raise error.Abort(_(b'cannot backout a change with no parents'))
798 raise error.Abort(_(b'cannot backout a change with no parents'))
799 if p2 != nullid:
799 if p2 != nullid:
800 if not opts.get(b'parent'):
800 if not opts.get(b'parent'):
801 raise error.Abort(_(b'cannot backout a merge changeset'))
801 raise error.Abort(_(b'cannot backout a merge changeset'))
802 p = repo.lookup(opts[b'parent'])
802 p = repo.lookup(opts[b'parent'])
803 if p not in (p1, p2):
803 if p not in (p1, p2):
804 raise error.Abort(
804 raise error.Abort(
805 _(b'%s is not a parent of %s') % (short(p), short(node))
805 _(b'%s is not a parent of %s') % (short(p), short(node))
806 )
806 )
807 parent = p
807 parent = p
808 else:
808 else:
809 if opts.get(b'parent'):
809 if opts.get(b'parent'):
810 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
810 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
811 parent = p1
811 parent = p1
812
812
813 # the backout should appear on the same branch
813 # the backout should appear on the same branch
814 branch = repo.dirstate.branch()
814 branch = repo.dirstate.branch()
815 bheads = repo.branchheads(branch)
815 bheads = repo.branchheads(branch)
816 rctx = scmutil.revsingle(repo, hex(parent))
816 rctx = scmutil.revsingle(repo, hex(parent))
817 if not opts.get(b'merge') and op1 != node:
817 if not opts.get(b'merge') and op1 != node:
818 with dirstateguard.dirstateguard(repo, b'backout'):
818 with dirstateguard.dirstateguard(repo, b'backout'):
819 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
819 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
820 with ui.configoverride(overrides, b'backout'):
820 with ui.configoverride(overrides, b'backout'):
821 stats = mergemod.update(
821 stats = mergemod.update(
822 repo,
822 repo,
823 parent,
823 parent,
824 branchmerge=True,
824 branchmerge=True,
825 force=True,
825 force=True,
826 ancestor=node,
826 ancestor=node,
827 mergeancestor=False,
827 mergeancestor=False,
828 )
828 )
829 repo.setparents(op1, op2)
829 repo.setparents(op1, op2)
830 hg._showstats(repo, stats)
830 hg._showstats(repo, stats)
831 if stats.unresolvedcount:
831 if stats.unresolvedcount:
832 repo.ui.status(
832 repo.ui.status(
833 _(b"use 'hg resolve' to retry unresolved file merges\n")
833 _(b"use 'hg resolve' to retry unresolved file merges\n")
834 )
834 )
835 return 1
835 return 1
836 else:
836 else:
837 hg.clean(repo, node, show_stats=False)
837 hg.clean(repo, node, show_stats=False)
838 repo.dirstate.setbranch(branch)
838 repo.dirstate.setbranch(branch)
839 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
839 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
840
840
841 if opts.get(b'no_commit'):
841 if opts.get(b'no_commit'):
842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
842 msg = _(b"changeset %s backed out, don't forget to commit.\n")
843 ui.status(msg % short(node))
843 ui.status(msg % short(node))
844 return 0
844 return 0
845
845
846 def commitfunc(ui, repo, message, match, opts):
846 def commitfunc(ui, repo, message, match, opts):
847 editform = b'backout'
847 editform = b'backout'
848 e = cmdutil.getcommiteditor(
848 e = cmdutil.getcommiteditor(
849 editform=editform, **pycompat.strkwargs(opts)
849 editform=editform, **pycompat.strkwargs(opts)
850 )
850 )
851 if not message:
851 if not message:
852 # we don't translate commit messages
852 # we don't translate commit messages
853 message = b"Backed out changeset %s" % short(node)
853 message = b"Backed out changeset %s" % short(node)
854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
854 e = cmdutil.getcommiteditor(edit=True, editform=editform)
855 return repo.commit(
855 return repo.commit(
856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
856 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
857 )
857 )
858
858
859 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
859 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
860 if not newnode:
860 if not newnode:
861 ui.status(_(b"nothing changed\n"))
861 ui.status(_(b"nothing changed\n"))
862 return 1
862 return 1
863 cmdutil.commitstatus(repo, newnode, branch, bheads)
863 cmdutil.commitstatus(repo, newnode, branch, bheads)
864
864
865 def nice(node):
865 def nice(node):
866 return b'%d:%s' % (repo.changelog.rev(node), short(node))
866 return b'%d:%s' % (repo.changelog.rev(node), short(node))
867
867
868 ui.status(
868 ui.status(
869 _(b'changeset %s backs out changeset %s\n')
869 _(b'changeset %s backs out changeset %s\n')
870 % (nice(repo.changelog.tip()), nice(node))
870 % (nice(repo.changelog.tip()), nice(node))
871 )
871 )
872 if opts.get(b'merge') and op1 != node:
872 if opts.get(b'merge') and op1 != node:
873 hg.clean(repo, op1, show_stats=False)
873 hg.clean(repo, op1, show_stats=False)
874 ui.status(
874 ui.status(
875 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
875 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
876 )
876 )
877 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
877 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
878 with ui.configoverride(overrides, b'backout'):
878 with ui.configoverride(overrides, b'backout'):
879 return hg.merge(repo, hex(repo.changelog.tip()))
879 return hg.merge(repo, hex(repo.changelog.tip()))
880 return 0
880 return 0
881
881
882
882
883 @command(
883 @command(
884 b'bisect',
884 b'bisect',
885 [
885 [
886 (b'r', b'reset', False, _(b'reset bisect state')),
886 (b'r', b'reset', False, _(b'reset bisect state')),
887 (b'g', b'good', False, _(b'mark changeset good')),
887 (b'g', b'good', False, _(b'mark changeset good')),
888 (b'b', b'bad', False, _(b'mark changeset bad')),
888 (b'b', b'bad', False, _(b'mark changeset bad')),
889 (b's', b'skip', False, _(b'skip testing changeset')),
889 (b's', b'skip', False, _(b'skip testing changeset')),
890 (b'e', b'extend', False, _(b'extend the bisect range')),
890 (b'e', b'extend', False, _(b'extend the bisect range')),
891 (
891 (
892 b'c',
892 b'c',
893 b'command',
893 b'command',
894 b'',
894 b'',
895 _(b'use command to check changeset state'),
895 _(b'use command to check changeset state'),
896 _(b'CMD'),
896 _(b'CMD'),
897 ),
897 ),
898 (b'U', b'noupdate', False, _(b'do not update to target')),
898 (b'U', b'noupdate', False, _(b'do not update to target')),
899 ],
899 ],
900 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
900 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
901 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
901 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
902 )
902 )
903 def bisect(
903 def bisect(
904 ui,
904 ui,
905 repo,
905 repo,
906 rev=None,
906 rev=None,
907 extra=None,
907 extra=None,
908 command=None,
908 command=None,
909 reset=None,
909 reset=None,
910 good=None,
910 good=None,
911 bad=None,
911 bad=None,
912 skip=None,
912 skip=None,
913 extend=None,
913 extend=None,
914 noupdate=None,
914 noupdate=None,
915 ):
915 ):
916 """subdivision search of changesets
916 """subdivision search of changesets
917
917
918 This command helps to find changesets which introduce problems. To
918 This command helps to find changesets which introduce problems. To
919 use, mark the earliest changeset you know exhibits the problem as
919 use, mark the earliest changeset you know exhibits the problem as
920 bad, then mark the latest changeset which is free from the problem
920 bad, then mark the latest changeset which is free from the problem
921 as good. Bisect will update your working directory to a revision
921 as good. Bisect will update your working directory to a revision
922 for testing (unless the -U/--noupdate option is specified). Once
922 for testing (unless the -U/--noupdate option is specified). Once
923 you have performed tests, mark the working directory as good or
923 you have performed tests, mark the working directory as good or
924 bad, and bisect will either update to another candidate changeset
924 bad, and bisect will either update to another candidate changeset
925 or announce that it has found the bad revision.
925 or announce that it has found the bad revision.
926
926
927 As a shortcut, you can also use the revision argument to mark a
927 As a shortcut, you can also use the revision argument to mark a
928 revision as good or bad without checking it out first.
928 revision as good or bad without checking it out first.
929
929
930 If you supply a command, it will be used for automatic bisection.
930 If you supply a command, it will be used for automatic bisection.
931 The environment variable HG_NODE will contain the ID of the
931 The environment variable HG_NODE will contain the ID of the
932 changeset being tested. The exit status of the command will be
932 changeset being tested. The exit status of the command will be
933 used to mark revisions as good or bad: status 0 means good, 125
933 used to mark revisions as good or bad: status 0 means good, 125
934 means to skip the revision, 127 (command not found) will abort the
934 means to skip the revision, 127 (command not found) will abort the
935 bisection, and any other non-zero exit status means the revision
935 bisection, and any other non-zero exit status means the revision
936 is bad.
936 is bad.
937
937
938 .. container:: verbose
938 .. container:: verbose
939
939
940 Some examples:
940 Some examples:
941
941
942 - start a bisection with known bad revision 34, and good revision 12::
942 - start a bisection with known bad revision 34, and good revision 12::
943
943
944 hg bisect --bad 34
944 hg bisect --bad 34
945 hg bisect --good 12
945 hg bisect --good 12
946
946
947 - advance the current bisection by marking current revision as good or
947 - advance the current bisection by marking current revision as good or
948 bad::
948 bad::
949
949
950 hg bisect --good
950 hg bisect --good
951 hg bisect --bad
951 hg bisect --bad
952
952
953 - mark the current revision, or a known revision, to be skipped (e.g. if
953 - mark the current revision, or a known revision, to be skipped (e.g. if
954 that revision is not usable because of another issue)::
954 that revision is not usable because of another issue)::
955
955
956 hg bisect --skip
956 hg bisect --skip
957 hg bisect --skip 23
957 hg bisect --skip 23
958
958
959 - skip all revisions that do not touch directories ``foo`` or ``bar``::
959 - skip all revisions that do not touch directories ``foo`` or ``bar``::
960
960
961 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
961 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
962
962
963 - forget the current bisection::
963 - forget the current bisection::
964
964
965 hg bisect --reset
965 hg bisect --reset
966
966
967 - use 'make && make tests' to automatically find the first broken
967 - use 'make && make tests' to automatically find the first broken
968 revision::
968 revision::
969
969
970 hg bisect --reset
970 hg bisect --reset
971 hg bisect --bad 34
971 hg bisect --bad 34
972 hg bisect --good 12
972 hg bisect --good 12
973 hg bisect --command "make && make tests"
973 hg bisect --command "make && make tests"
974
974
975 - see all changesets whose states are already known in the current
975 - see all changesets whose states are already known in the current
976 bisection::
976 bisection::
977
977
978 hg log -r "bisect(pruned)"
978 hg log -r "bisect(pruned)"
979
979
980 - see the changeset currently being bisected (especially useful
980 - see the changeset currently being bisected (especially useful
981 if running with -U/--noupdate)::
981 if running with -U/--noupdate)::
982
982
983 hg log -r "bisect(current)"
983 hg log -r "bisect(current)"
984
984
985 - see all changesets that took part in the current bisection::
985 - see all changesets that took part in the current bisection::
986
986
987 hg log -r "bisect(range)"
987 hg log -r "bisect(range)"
988
988
989 - you can even get a nice graph::
989 - you can even get a nice graph::
990
990
991 hg log --graph -r "bisect(range)"
991 hg log --graph -r "bisect(range)"
992
992
993 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
993 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
994
994
995 Returns 0 on success.
995 Returns 0 on success.
996 """
996 """
997 # backward compatibility
997 # backward compatibility
998 if rev in b"good bad reset init".split():
998 if rev in b"good bad reset init".split():
999 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
999 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1000 cmd, rev, extra = rev, extra, None
1000 cmd, rev, extra = rev, extra, None
1001 if cmd == b"good":
1001 if cmd == b"good":
1002 good = True
1002 good = True
1003 elif cmd == b"bad":
1003 elif cmd == b"bad":
1004 bad = True
1004 bad = True
1005 else:
1005 else:
1006 reset = True
1006 reset = True
1007 elif extra:
1007 elif extra:
1008 raise error.Abort(_(b'incompatible arguments'))
1008 raise error.Abort(_(b'incompatible arguments'))
1009
1009
1010 incompatibles = {
1010 incompatibles = {
1011 b'--bad': bad,
1011 b'--bad': bad,
1012 b'--command': bool(command),
1012 b'--command': bool(command),
1013 b'--extend': extend,
1013 b'--extend': extend,
1014 b'--good': good,
1014 b'--good': good,
1015 b'--reset': reset,
1015 b'--reset': reset,
1016 b'--skip': skip,
1016 b'--skip': skip,
1017 }
1017 }
1018
1018
1019 enabled = [x for x in incompatibles if incompatibles[x]]
1019 enabled = [x for x in incompatibles if incompatibles[x]]
1020
1020
1021 if len(enabled) > 1:
1021 if len(enabled) > 1:
1022 raise error.Abort(
1022 raise error.Abort(
1023 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1023 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1024 )
1024 )
1025
1025
1026 if reset:
1026 if reset:
1027 hbisect.resetstate(repo)
1027 hbisect.resetstate(repo)
1028 return
1028 return
1029
1029
1030 state = hbisect.load_state(repo)
1030 state = hbisect.load_state(repo)
1031
1031
1032 # update state
1032 # update state
1033 if good or bad or skip:
1033 if good or bad or skip:
1034 if rev:
1034 if rev:
1035 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1035 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1036 else:
1036 else:
1037 nodes = [repo.lookup(b'.')]
1037 nodes = [repo.lookup(b'.')]
1038 if good:
1038 if good:
1039 state[b'good'] += nodes
1039 state[b'good'] += nodes
1040 elif bad:
1040 elif bad:
1041 state[b'bad'] += nodes
1041 state[b'bad'] += nodes
1042 elif skip:
1042 elif skip:
1043 state[b'skip'] += nodes
1043 state[b'skip'] += nodes
1044 hbisect.save_state(repo, state)
1044 hbisect.save_state(repo, state)
1045 if not (state[b'good'] and state[b'bad']):
1045 if not (state[b'good'] and state[b'bad']):
1046 return
1046 return
1047
1047
1048 def mayupdate(repo, node, show_stats=True):
1048 def mayupdate(repo, node, show_stats=True):
1049 """common used update sequence"""
1049 """common used update sequence"""
1050 if noupdate:
1050 if noupdate:
1051 return
1051 return
1052 cmdutil.checkunfinished(repo)
1052 cmdutil.checkunfinished(repo)
1053 cmdutil.bailifchanged(repo)
1053 cmdutil.bailifchanged(repo)
1054 return hg.clean(repo, node, show_stats=show_stats)
1054 return hg.clean(repo, node, show_stats=show_stats)
1055
1055
1056 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1056 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1057
1057
1058 if command:
1058 if command:
1059 changesets = 1
1059 changesets = 1
1060 if noupdate:
1060 if noupdate:
1061 try:
1061 try:
1062 node = state[b'current'][0]
1062 node = state[b'current'][0]
1063 except LookupError:
1063 except LookupError:
1064 raise error.Abort(
1064 raise error.Abort(
1065 _(
1065 _(
1066 b'current bisect revision is unknown - '
1066 b'current bisect revision is unknown - '
1067 b'start a new bisect to fix'
1067 b'start a new bisect to fix'
1068 )
1068 )
1069 )
1069 )
1070 else:
1070 else:
1071 node, p2 = repo.dirstate.parents()
1071 node, p2 = repo.dirstate.parents()
1072 if p2 != nullid:
1072 if p2 != nullid:
1073 raise error.Abort(_(b'current bisect revision is a merge'))
1073 raise error.Abort(_(b'current bisect revision is a merge'))
1074 if rev:
1074 if rev:
1075 node = repo[scmutil.revsingle(repo, rev, node)].node()
1075 node = repo[scmutil.revsingle(repo, rev, node)].node()
1076 with hbisect.restore_state(repo, state, node):
1076 with hbisect.restore_state(repo, state, node):
1077 while changesets:
1077 while changesets:
1078 # update state
1078 # update state
1079 state[b'current'] = [node]
1079 state[b'current'] = [node]
1080 hbisect.save_state(repo, state)
1080 hbisect.save_state(repo, state)
1081 status = ui.system(
1081 status = ui.system(
1082 command,
1082 command,
1083 environ={b'HG_NODE': hex(node)},
1083 environ={b'HG_NODE': hex(node)},
1084 blockedtag=b'bisect_check',
1084 blockedtag=b'bisect_check',
1085 )
1085 )
1086 if status == 125:
1086 if status == 125:
1087 transition = b"skip"
1087 transition = b"skip"
1088 elif status == 0:
1088 elif status == 0:
1089 transition = b"good"
1089 transition = b"good"
1090 # status < 0 means process was killed
1090 # status < 0 means process was killed
1091 elif status == 127:
1091 elif status == 127:
1092 raise error.Abort(_(b"failed to execute %s") % command)
1092 raise error.Abort(_(b"failed to execute %s") % command)
1093 elif status < 0:
1093 elif status < 0:
1094 raise error.Abort(_(b"%s killed") % command)
1094 raise error.Abort(_(b"%s killed") % command)
1095 else:
1095 else:
1096 transition = b"bad"
1096 transition = b"bad"
1097 state[transition].append(node)
1097 state[transition].append(node)
1098 ctx = repo[node]
1098 ctx = repo[node]
1099 ui.status(
1099 ui.status(
1100 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1100 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1101 )
1101 )
1102 hbisect.checkstate(state)
1102 hbisect.checkstate(state)
1103 # bisect
1103 # bisect
1104 nodes, changesets, bgood = hbisect.bisect(repo, state)
1104 nodes, changesets, bgood = hbisect.bisect(repo, state)
1105 # update to next check
1105 # update to next check
1106 node = nodes[0]
1106 node = nodes[0]
1107 mayupdate(repo, node, show_stats=False)
1107 mayupdate(repo, node, show_stats=False)
1108 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1108 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1109 return
1109 return
1110
1110
1111 hbisect.checkstate(state)
1111 hbisect.checkstate(state)
1112
1112
1113 # actually bisect
1113 # actually bisect
1114 nodes, changesets, good = hbisect.bisect(repo, state)
1114 nodes, changesets, good = hbisect.bisect(repo, state)
1115 if extend:
1115 if extend:
1116 if not changesets:
1116 if not changesets:
1117 extendnode = hbisect.extendrange(repo, state, nodes, good)
1117 extendnode = hbisect.extendrange(repo, state, nodes, good)
1118 if extendnode is not None:
1118 if extendnode is not None:
1119 ui.write(
1119 ui.write(
1120 _(b"Extending search to changeset %d:%s\n")
1120 _(b"Extending search to changeset %d:%s\n")
1121 % (extendnode.rev(), extendnode)
1121 % (extendnode.rev(), extendnode)
1122 )
1122 )
1123 state[b'current'] = [extendnode.node()]
1123 state[b'current'] = [extendnode.node()]
1124 hbisect.save_state(repo, state)
1124 hbisect.save_state(repo, state)
1125 return mayupdate(repo, extendnode.node())
1125 return mayupdate(repo, extendnode.node())
1126 raise error.Abort(_(b"nothing to extend"))
1126 raise error.Abort(_(b"nothing to extend"))
1127
1127
1128 if changesets == 0:
1128 if changesets == 0:
1129 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1129 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1130 else:
1130 else:
1131 assert len(nodes) == 1 # only a single node can be tested next
1131 assert len(nodes) == 1 # only a single node can be tested next
1132 node = nodes[0]
1132 node = nodes[0]
1133 # compute the approximate number of remaining tests
1133 # compute the approximate number of remaining tests
1134 tests, size = 0, 2
1134 tests, size = 0, 2
1135 while size <= changesets:
1135 while size <= changesets:
1136 tests, size = tests + 1, size * 2
1136 tests, size = tests + 1, size * 2
1137 rev = repo.changelog.rev(node)
1137 rev = repo.changelog.rev(node)
1138 ui.write(
1138 ui.write(
1139 _(
1139 _(
1140 b"Testing changeset %d:%s "
1140 b"Testing changeset %d:%s "
1141 b"(%d changesets remaining, ~%d tests)\n"
1141 b"(%d changesets remaining, ~%d tests)\n"
1142 )
1142 )
1143 % (rev, short(node), changesets, tests)
1143 % (rev, short(node), changesets, tests)
1144 )
1144 )
1145 state[b'current'] = [node]
1145 state[b'current'] = [node]
1146 hbisect.save_state(repo, state)
1146 hbisect.save_state(repo, state)
1147 return mayupdate(repo, node)
1147 return mayupdate(repo, node)
1148
1148
1149
1149
1150 @command(
1150 @command(
1151 b'bookmarks|bookmark',
1151 b'bookmarks|bookmark',
1152 [
1152 [
1153 (b'f', b'force', False, _(b'force')),
1153 (b'f', b'force', False, _(b'force')),
1154 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1154 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1155 (b'd', b'delete', False, _(b'delete a given bookmark')),
1155 (b'd', b'delete', False, _(b'delete a given bookmark')),
1156 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1156 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1157 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1157 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1158 (b'l', b'list', False, _(b'list existing bookmarks')),
1158 (b'l', b'list', False, _(b'list existing bookmarks')),
1159 ]
1159 ]
1160 + formatteropts,
1160 + formatteropts,
1161 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1161 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1162 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1162 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1163 )
1163 )
1164 def bookmark(ui, repo, *names, **opts):
1164 def bookmark(ui, repo, *names, **opts):
1165 '''create a new bookmark or list existing bookmarks
1165 '''create a new bookmark or list existing bookmarks
1166
1166
1167 Bookmarks are labels on changesets to help track lines of development.
1167 Bookmarks are labels on changesets to help track lines of development.
1168 Bookmarks are unversioned and can be moved, renamed and deleted.
1168 Bookmarks are unversioned and can be moved, renamed and deleted.
1169 Deleting or moving a bookmark has no effect on the associated changesets.
1169 Deleting or moving a bookmark has no effect on the associated changesets.
1170
1170
1171 Creating or updating to a bookmark causes it to be marked as 'active'.
1171 Creating or updating to a bookmark causes it to be marked as 'active'.
1172 The active bookmark is indicated with a '*'.
1172 The active bookmark is indicated with a '*'.
1173 When a commit is made, the active bookmark will advance to the new commit.
1173 When a commit is made, the active bookmark will advance to the new commit.
1174 A plain :hg:`update` will also advance an active bookmark, if possible.
1174 A plain :hg:`update` will also advance an active bookmark, if possible.
1175 Updating away from a bookmark will cause it to be deactivated.
1175 Updating away from a bookmark will cause it to be deactivated.
1176
1176
1177 Bookmarks can be pushed and pulled between repositories (see
1177 Bookmarks can be pushed and pulled between repositories (see
1178 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1178 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1179 diverged, a new 'divergent bookmark' of the form 'name@path' will
1179 diverged, a new 'divergent bookmark' of the form 'name@path' will
1180 be created. Using :hg:`merge` will resolve the divergence.
1180 be created. Using :hg:`merge` will resolve the divergence.
1181
1181
1182 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1182 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1183 the active bookmark's name.
1183 the active bookmark's name.
1184
1184
1185 A bookmark named '@' has the special property that :hg:`clone` will
1185 A bookmark named '@' has the special property that :hg:`clone` will
1186 check it out by default if it exists.
1186 check it out by default if it exists.
1187
1187
1188 .. container:: verbose
1188 .. container:: verbose
1189
1189
1190 Template:
1190 Template:
1191
1191
1192 The following keywords are supported in addition to the common template
1192 The following keywords are supported in addition to the common template
1193 keywords and functions such as ``{bookmark}``. See also
1193 keywords and functions such as ``{bookmark}``. See also
1194 :hg:`help templates`.
1194 :hg:`help templates`.
1195
1195
1196 :active: Boolean. True if the bookmark is active.
1196 :active: Boolean. True if the bookmark is active.
1197
1197
1198 Examples:
1198 Examples:
1199
1199
1200 - create an active bookmark for a new line of development::
1200 - create an active bookmark for a new line of development::
1201
1201
1202 hg book new-feature
1202 hg book new-feature
1203
1203
1204 - create an inactive bookmark as a place marker::
1204 - create an inactive bookmark as a place marker::
1205
1205
1206 hg book -i reviewed
1206 hg book -i reviewed
1207
1207
1208 - create an inactive bookmark on another changeset::
1208 - create an inactive bookmark on another changeset::
1209
1209
1210 hg book -r .^ tested
1210 hg book -r .^ tested
1211
1211
1212 - rename bookmark turkey to dinner::
1212 - rename bookmark turkey to dinner::
1213
1213
1214 hg book -m turkey dinner
1214 hg book -m turkey dinner
1215
1215
1216 - move the '@' bookmark from another branch::
1216 - move the '@' bookmark from another branch::
1217
1217
1218 hg book -f @
1218 hg book -f @
1219
1219
1220 - print only the active bookmark name::
1220 - print only the active bookmark name::
1221
1221
1222 hg book -ql .
1222 hg book -ql .
1223 '''
1223 '''
1224 opts = pycompat.byteskwargs(opts)
1224 opts = pycompat.byteskwargs(opts)
1225 force = opts.get(b'force')
1225 force = opts.get(b'force')
1226 rev = opts.get(b'rev')
1226 rev = opts.get(b'rev')
1227 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1227 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1228
1228
1229 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1229 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1230 if action:
1230 if action:
1231 pass
1231 cmdutil.check_incompatible_arguments(opts, action, b'rev')
1232 elif names or rev:
1232 elif names or rev:
1233 action = b'add'
1233 action = b'add'
1234 elif inactive:
1234 elif inactive:
1235 action = b'inactive' # meaning deactivate
1235 action = b'inactive' # meaning deactivate
1236 else:
1236 else:
1237 action = b'list'
1237 action = b'list'
1238
1238
1239 if rev and action in {b'delete', b'rename', b'list'}:
1240 raise error.Abort(_(b"--rev is incompatible with --%s") % action)
1241 if inactive and action in {b'delete', b'list'}:
1239 if inactive and action in {b'delete', b'list'}:
1242 raise error.Abort(_(b"--inactive is incompatible with --%s") % action)
1240 raise error.Abort(_(b"--inactive is incompatible with --%s") % action)
1243 if not names and action in {b'add', b'delete'}:
1241 if not names and action in {b'add', b'delete'}:
1244 raise error.Abort(_(b"bookmark name required"))
1242 raise error.Abort(_(b"bookmark name required"))
1245
1243
1246 if action in {b'add', b'delete', b'rename', b'inactive'}:
1244 if action in {b'add', b'delete', b'rename', b'inactive'}:
1247 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1245 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1248 if action == b'delete':
1246 if action == b'delete':
1249 names = pycompat.maplist(repo._bookmarks.expandname, names)
1247 names = pycompat.maplist(repo._bookmarks.expandname, names)
1250 bookmarks.delete(repo, tr, names)
1248 bookmarks.delete(repo, tr, names)
1251 elif action == b'rename':
1249 elif action == b'rename':
1252 if not names:
1250 if not names:
1253 raise error.Abort(_(b"new bookmark name required"))
1251 raise error.Abort(_(b"new bookmark name required"))
1254 elif len(names) > 1:
1252 elif len(names) > 1:
1255 raise error.Abort(_(b"only one new bookmark name allowed"))
1253 raise error.Abort(_(b"only one new bookmark name allowed"))
1256 oldname = repo._bookmarks.expandname(opts[b'rename'])
1254 oldname = repo._bookmarks.expandname(opts[b'rename'])
1257 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1255 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1258 elif action == b'add':
1256 elif action == b'add':
1259 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1257 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1260 elif action == b'inactive':
1258 elif action == b'inactive':
1261 if len(repo._bookmarks) == 0:
1259 if len(repo._bookmarks) == 0:
1262 ui.status(_(b"no bookmarks set\n"))
1260 ui.status(_(b"no bookmarks set\n"))
1263 elif not repo._activebookmark:
1261 elif not repo._activebookmark:
1264 ui.status(_(b"no active bookmark\n"))
1262 ui.status(_(b"no active bookmark\n"))
1265 else:
1263 else:
1266 bookmarks.deactivate(repo)
1264 bookmarks.deactivate(repo)
1267 elif action == b'list':
1265 elif action == b'list':
1268 names = pycompat.maplist(repo._bookmarks.expandname, names)
1266 names = pycompat.maplist(repo._bookmarks.expandname, names)
1269 with ui.formatter(b'bookmarks', opts) as fm:
1267 with ui.formatter(b'bookmarks', opts) as fm:
1270 bookmarks.printbookmarks(ui, repo, fm, names)
1268 bookmarks.printbookmarks(ui, repo, fm, names)
1271 else:
1269 else:
1272 raise error.ProgrammingError(b'invalid action: %s' % action)
1270 raise error.ProgrammingError(b'invalid action: %s' % action)
1273
1271
1274
1272
1275 @command(
1273 @command(
1276 b'branch',
1274 b'branch',
1277 [
1275 [
1278 (
1276 (
1279 b'f',
1277 b'f',
1280 b'force',
1278 b'force',
1281 None,
1279 None,
1282 _(b'set branch name even if it shadows an existing branch'),
1280 _(b'set branch name even if it shadows an existing branch'),
1283 ),
1281 ),
1284 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1282 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1285 (
1283 (
1286 b'r',
1284 b'r',
1287 b'rev',
1285 b'rev',
1288 [],
1286 [],
1289 _(b'change branches of the given revs (EXPERIMENTAL)'),
1287 _(b'change branches of the given revs (EXPERIMENTAL)'),
1290 ),
1288 ),
1291 ],
1289 ],
1292 _(b'[-fC] [NAME]'),
1290 _(b'[-fC] [NAME]'),
1293 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1291 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1294 )
1292 )
1295 def branch(ui, repo, label=None, **opts):
1293 def branch(ui, repo, label=None, **opts):
1296 """set or show the current branch name
1294 """set or show the current branch name
1297
1295
1298 .. note::
1296 .. note::
1299
1297
1300 Branch names are permanent and global. Use :hg:`bookmark` to create a
1298 Branch names are permanent and global. Use :hg:`bookmark` to create a
1301 light-weight bookmark instead. See :hg:`help glossary` for more
1299 light-weight bookmark instead. See :hg:`help glossary` for more
1302 information about named branches and bookmarks.
1300 information about named branches and bookmarks.
1303
1301
1304 With no argument, show the current branch name. With one argument,
1302 With no argument, show the current branch name. With one argument,
1305 set the working directory branch name (the branch will not exist
1303 set the working directory branch name (the branch will not exist
1306 in the repository until the next commit). Standard practice
1304 in the repository until the next commit). Standard practice
1307 recommends that primary development take place on the 'default'
1305 recommends that primary development take place on the 'default'
1308 branch.
1306 branch.
1309
1307
1310 Unless -f/--force is specified, branch will not let you set a
1308 Unless -f/--force is specified, branch will not let you set a
1311 branch name that already exists.
1309 branch name that already exists.
1312
1310
1313 Use -C/--clean to reset the working directory branch to that of
1311 Use -C/--clean to reset the working directory branch to that of
1314 the parent of the working directory, negating a previous branch
1312 the parent of the working directory, negating a previous branch
1315 change.
1313 change.
1316
1314
1317 Use the command :hg:`update` to switch to an existing branch. Use
1315 Use the command :hg:`update` to switch to an existing branch. Use
1318 :hg:`commit --close-branch` to mark this branch head as closed.
1316 :hg:`commit --close-branch` to mark this branch head as closed.
1319 When all heads of a branch are closed, the branch will be
1317 When all heads of a branch are closed, the branch will be
1320 considered closed.
1318 considered closed.
1321
1319
1322 Returns 0 on success.
1320 Returns 0 on success.
1323 """
1321 """
1324 opts = pycompat.byteskwargs(opts)
1322 opts = pycompat.byteskwargs(opts)
1325 revs = opts.get(b'rev')
1323 revs = opts.get(b'rev')
1326 if label:
1324 if label:
1327 label = label.strip()
1325 label = label.strip()
1328
1326
1329 if not opts.get(b'clean') and not label:
1327 if not opts.get(b'clean') and not label:
1330 if revs:
1328 if revs:
1331 raise error.Abort(_(b"no branch name specified for the revisions"))
1329 raise error.Abort(_(b"no branch name specified for the revisions"))
1332 ui.write(b"%s\n" % repo.dirstate.branch())
1330 ui.write(b"%s\n" % repo.dirstate.branch())
1333 return
1331 return
1334
1332
1335 with repo.wlock():
1333 with repo.wlock():
1336 if opts.get(b'clean'):
1334 if opts.get(b'clean'):
1337 label = repo[b'.'].branch()
1335 label = repo[b'.'].branch()
1338 repo.dirstate.setbranch(label)
1336 repo.dirstate.setbranch(label)
1339 ui.status(_(b'reset working directory to branch %s\n') % label)
1337 ui.status(_(b'reset working directory to branch %s\n') % label)
1340 elif label:
1338 elif label:
1341
1339
1342 scmutil.checknewlabel(repo, label, b'branch')
1340 scmutil.checknewlabel(repo, label, b'branch')
1343 if revs:
1341 if revs:
1344 return cmdutil.changebranch(ui, repo, revs, label)
1342 return cmdutil.changebranch(ui, repo, revs, label)
1345
1343
1346 if not opts.get(b'force') and label in repo.branchmap():
1344 if not opts.get(b'force') and label in repo.branchmap():
1347 if label not in [p.branch() for p in repo[None].parents()]:
1345 if label not in [p.branch() for p in repo[None].parents()]:
1348 raise error.Abort(
1346 raise error.Abort(
1349 _(b'a branch of the same name already exists'),
1347 _(b'a branch of the same name already exists'),
1350 # i18n: "it" refers to an existing branch
1348 # i18n: "it" refers to an existing branch
1351 hint=_(b"use 'hg update' to switch to it"),
1349 hint=_(b"use 'hg update' to switch to it"),
1352 )
1350 )
1353
1351
1354 repo.dirstate.setbranch(label)
1352 repo.dirstate.setbranch(label)
1355 ui.status(_(b'marked working directory as branch %s\n') % label)
1353 ui.status(_(b'marked working directory as branch %s\n') % label)
1356
1354
1357 # find any open named branches aside from default
1355 # find any open named branches aside from default
1358 for n, h, t, c in repo.branchmap().iterbranches():
1356 for n, h, t, c in repo.branchmap().iterbranches():
1359 if n != b"default" and not c:
1357 if n != b"default" and not c:
1360 return 0
1358 return 0
1361 ui.status(
1359 ui.status(
1362 _(
1360 _(
1363 b'(branches are permanent and global, '
1361 b'(branches are permanent and global, '
1364 b'did you want a bookmark?)\n'
1362 b'did you want a bookmark?)\n'
1365 )
1363 )
1366 )
1364 )
1367
1365
1368
1366
1369 @command(
1367 @command(
1370 b'branches',
1368 b'branches',
1371 [
1369 [
1372 (
1370 (
1373 b'a',
1371 b'a',
1374 b'active',
1372 b'active',
1375 False,
1373 False,
1376 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1374 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1377 ),
1375 ),
1378 (b'c', b'closed', False, _(b'show normal and closed branches')),
1376 (b'c', b'closed', False, _(b'show normal and closed branches')),
1379 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1377 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1380 ]
1378 ]
1381 + formatteropts,
1379 + formatteropts,
1382 _(b'[-c]'),
1380 _(b'[-c]'),
1383 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1381 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1384 intents={INTENT_READONLY},
1382 intents={INTENT_READONLY},
1385 )
1383 )
1386 def branches(ui, repo, active=False, closed=False, **opts):
1384 def branches(ui, repo, active=False, closed=False, **opts):
1387 """list repository named branches
1385 """list repository named branches
1388
1386
1389 List the repository's named branches, indicating which ones are
1387 List the repository's named branches, indicating which ones are
1390 inactive. If -c/--closed is specified, also list branches which have
1388 inactive. If -c/--closed is specified, also list branches which have
1391 been marked closed (see :hg:`commit --close-branch`).
1389 been marked closed (see :hg:`commit --close-branch`).
1392
1390
1393 Use the command :hg:`update` to switch to an existing branch.
1391 Use the command :hg:`update` to switch to an existing branch.
1394
1392
1395 .. container:: verbose
1393 .. container:: verbose
1396
1394
1397 Template:
1395 Template:
1398
1396
1399 The following keywords are supported in addition to the common template
1397 The following keywords are supported in addition to the common template
1400 keywords and functions such as ``{branch}``. See also
1398 keywords and functions such as ``{branch}``. See also
1401 :hg:`help templates`.
1399 :hg:`help templates`.
1402
1400
1403 :active: Boolean. True if the branch is active.
1401 :active: Boolean. True if the branch is active.
1404 :closed: Boolean. True if the branch is closed.
1402 :closed: Boolean. True if the branch is closed.
1405 :current: Boolean. True if it is the current branch.
1403 :current: Boolean. True if it is the current branch.
1406
1404
1407 Returns 0.
1405 Returns 0.
1408 """
1406 """
1409
1407
1410 opts = pycompat.byteskwargs(opts)
1408 opts = pycompat.byteskwargs(opts)
1411 revs = opts.get(b'rev')
1409 revs = opts.get(b'rev')
1412 selectedbranches = None
1410 selectedbranches = None
1413 if revs:
1411 if revs:
1414 revs = scmutil.revrange(repo, revs)
1412 revs = scmutil.revrange(repo, revs)
1415 getbi = repo.revbranchcache().branchinfo
1413 getbi = repo.revbranchcache().branchinfo
1416 selectedbranches = {getbi(r)[0] for r in revs}
1414 selectedbranches = {getbi(r)[0] for r in revs}
1417
1415
1418 ui.pager(b'branches')
1416 ui.pager(b'branches')
1419 fm = ui.formatter(b'branches', opts)
1417 fm = ui.formatter(b'branches', opts)
1420 hexfunc = fm.hexfunc
1418 hexfunc = fm.hexfunc
1421
1419
1422 allheads = set(repo.heads())
1420 allheads = set(repo.heads())
1423 branches = []
1421 branches = []
1424 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1422 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1425 if selectedbranches is not None and tag not in selectedbranches:
1423 if selectedbranches is not None and tag not in selectedbranches:
1426 continue
1424 continue
1427 isactive = False
1425 isactive = False
1428 if not isclosed:
1426 if not isclosed:
1429 openheads = set(repo.branchmap().iteropen(heads))
1427 openheads = set(repo.branchmap().iteropen(heads))
1430 isactive = bool(openheads & allheads)
1428 isactive = bool(openheads & allheads)
1431 branches.append((tag, repo[tip], isactive, not isclosed))
1429 branches.append((tag, repo[tip], isactive, not isclosed))
1432 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1430 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1433
1431
1434 for tag, ctx, isactive, isopen in branches:
1432 for tag, ctx, isactive, isopen in branches:
1435 if active and not isactive:
1433 if active and not isactive:
1436 continue
1434 continue
1437 if isactive:
1435 if isactive:
1438 label = b'branches.active'
1436 label = b'branches.active'
1439 notice = b''
1437 notice = b''
1440 elif not isopen:
1438 elif not isopen:
1441 if not closed:
1439 if not closed:
1442 continue
1440 continue
1443 label = b'branches.closed'
1441 label = b'branches.closed'
1444 notice = _(b' (closed)')
1442 notice = _(b' (closed)')
1445 else:
1443 else:
1446 label = b'branches.inactive'
1444 label = b'branches.inactive'
1447 notice = _(b' (inactive)')
1445 notice = _(b' (inactive)')
1448 current = tag == repo.dirstate.branch()
1446 current = tag == repo.dirstate.branch()
1449 if current:
1447 if current:
1450 label = b'branches.current'
1448 label = b'branches.current'
1451
1449
1452 fm.startitem()
1450 fm.startitem()
1453 fm.write(b'branch', b'%s', tag, label=label)
1451 fm.write(b'branch', b'%s', tag, label=label)
1454 rev = ctx.rev()
1452 rev = ctx.rev()
1455 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1453 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1456 fmt = b' ' * padsize + b' %d:%s'
1454 fmt = b' ' * padsize + b' %d:%s'
1457 fm.condwrite(
1455 fm.condwrite(
1458 not ui.quiet,
1456 not ui.quiet,
1459 b'rev node',
1457 b'rev node',
1460 fmt,
1458 fmt,
1461 rev,
1459 rev,
1462 hexfunc(ctx.node()),
1460 hexfunc(ctx.node()),
1463 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1461 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1464 )
1462 )
1465 fm.context(ctx=ctx)
1463 fm.context(ctx=ctx)
1466 fm.data(active=isactive, closed=not isopen, current=current)
1464 fm.data(active=isactive, closed=not isopen, current=current)
1467 if not ui.quiet:
1465 if not ui.quiet:
1468 fm.plain(notice)
1466 fm.plain(notice)
1469 fm.plain(b'\n')
1467 fm.plain(b'\n')
1470 fm.end()
1468 fm.end()
1471
1469
1472
1470
1473 @command(
1471 @command(
1474 b'bundle',
1472 b'bundle',
1475 [
1473 [
1476 (
1474 (
1477 b'f',
1475 b'f',
1478 b'force',
1476 b'force',
1479 None,
1477 None,
1480 _(b'run even when the destination is unrelated'),
1478 _(b'run even when the destination is unrelated'),
1481 ),
1479 ),
1482 (
1480 (
1483 b'r',
1481 b'r',
1484 b'rev',
1482 b'rev',
1485 [],
1483 [],
1486 _(b'a changeset intended to be added to the destination'),
1484 _(b'a changeset intended to be added to the destination'),
1487 _(b'REV'),
1485 _(b'REV'),
1488 ),
1486 ),
1489 (
1487 (
1490 b'b',
1488 b'b',
1491 b'branch',
1489 b'branch',
1492 [],
1490 [],
1493 _(b'a specific branch you would like to bundle'),
1491 _(b'a specific branch you would like to bundle'),
1494 _(b'BRANCH'),
1492 _(b'BRANCH'),
1495 ),
1493 ),
1496 (
1494 (
1497 b'',
1495 b'',
1498 b'base',
1496 b'base',
1499 [],
1497 [],
1500 _(b'a base changeset assumed to be available at the destination'),
1498 _(b'a base changeset assumed to be available at the destination'),
1501 _(b'REV'),
1499 _(b'REV'),
1502 ),
1500 ),
1503 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1501 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1504 (
1502 (
1505 b't',
1503 b't',
1506 b'type',
1504 b'type',
1507 b'bzip2',
1505 b'bzip2',
1508 _(b'bundle compression type to use'),
1506 _(b'bundle compression type to use'),
1509 _(b'TYPE'),
1507 _(b'TYPE'),
1510 ),
1508 ),
1511 ]
1509 ]
1512 + remoteopts,
1510 + remoteopts,
1513 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1511 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1514 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1512 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1515 )
1513 )
1516 def bundle(ui, repo, fname, dest=None, **opts):
1514 def bundle(ui, repo, fname, dest=None, **opts):
1517 """create a bundle file
1515 """create a bundle file
1518
1516
1519 Generate a bundle file containing data to be transferred to another
1517 Generate a bundle file containing data to be transferred to another
1520 repository.
1518 repository.
1521
1519
1522 To create a bundle containing all changesets, use -a/--all
1520 To create a bundle containing all changesets, use -a/--all
1523 (or --base null). Otherwise, hg assumes the destination will have
1521 (or --base null). Otherwise, hg assumes the destination will have
1524 all the nodes you specify with --base parameters. Otherwise, hg
1522 all the nodes you specify with --base parameters. Otherwise, hg
1525 will assume the repository has all the nodes in destination, or
1523 will assume the repository has all the nodes in destination, or
1526 default-push/default if no destination is specified, where destination
1524 default-push/default if no destination is specified, where destination
1527 is the repository you provide through DEST option.
1525 is the repository you provide through DEST option.
1528
1526
1529 You can change bundle format with the -t/--type option. See
1527 You can change bundle format with the -t/--type option. See
1530 :hg:`help bundlespec` for documentation on this format. By default,
1528 :hg:`help bundlespec` for documentation on this format. By default,
1531 the most appropriate format is used and compression defaults to
1529 the most appropriate format is used and compression defaults to
1532 bzip2.
1530 bzip2.
1533
1531
1534 The bundle file can then be transferred using conventional means
1532 The bundle file can then be transferred using conventional means
1535 and applied to another repository with the unbundle or pull
1533 and applied to another repository with the unbundle or pull
1536 command. This is useful when direct push and pull are not
1534 command. This is useful when direct push and pull are not
1537 available or when exporting an entire repository is undesirable.
1535 available or when exporting an entire repository is undesirable.
1538
1536
1539 Applying bundles preserves all changeset contents including
1537 Applying bundles preserves all changeset contents including
1540 permissions, copy/rename information, and revision history.
1538 permissions, copy/rename information, and revision history.
1541
1539
1542 Returns 0 on success, 1 if no changes found.
1540 Returns 0 on success, 1 if no changes found.
1543 """
1541 """
1544 opts = pycompat.byteskwargs(opts)
1542 opts = pycompat.byteskwargs(opts)
1545 revs = None
1543 revs = None
1546 if b'rev' in opts:
1544 if b'rev' in opts:
1547 revstrings = opts[b'rev']
1545 revstrings = opts[b'rev']
1548 revs = scmutil.revrange(repo, revstrings)
1546 revs = scmutil.revrange(repo, revstrings)
1549 if revstrings and not revs:
1547 if revstrings and not revs:
1550 raise error.Abort(_(b'no commits to bundle'))
1548 raise error.Abort(_(b'no commits to bundle'))
1551
1549
1552 bundletype = opts.get(b'type', b'bzip2').lower()
1550 bundletype = opts.get(b'type', b'bzip2').lower()
1553 try:
1551 try:
1554 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1552 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1555 except error.UnsupportedBundleSpecification as e:
1553 except error.UnsupportedBundleSpecification as e:
1556 raise error.Abort(
1554 raise error.Abort(
1557 pycompat.bytestr(e),
1555 pycompat.bytestr(e),
1558 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1556 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1559 )
1557 )
1560 cgversion = bundlespec.contentopts[b"cg.version"]
1558 cgversion = bundlespec.contentopts[b"cg.version"]
1561
1559
1562 # Packed bundles are a pseudo bundle format for now.
1560 # Packed bundles are a pseudo bundle format for now.
1563 if cgversion == b's1':
1561 if cgversion == b's1':
1564 raise error.Abort(
1562 raise error.Abort(
1565 _(b'packed bundles cannot be produced by "hg bundle"'),
1563 _(b'packed bundles cannot be produced by "hg bundle"'),
1566 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1564 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1567 )
1565 )
1568
1566
1569 if opts.get(b'all'):
1567 if opts.get(b'all'):
1570 if dest:
1568 if dest:
1571 raise error.Abort(
1569 raise error.Abort(
1572 _(b"--all is incompatible with specifying a destination")
1570 _(b"--all is incompatible with specifying a destination")
1573 )
1571 )
1574 if opts.get(b'base'):
1572 if opts.get(b'base'):
1575 ui.warn(_(b"ignoring --base because --all was specified\n"))
1573 ui.warn(_(b"ignoring --base because --all was specified\n"))
1576 base = [nullrev]
1574 base = [nullrev]
1577 else:
1575 else:
1578 base = scmutil.revrange(repo, opts.get(b'base'))
1576 base = scmutil.revrange(repo, opts.get(b'base'))
1579 if cgversion not in changegroup.supportedoutgoingversions(repo):
1577 if cgversion not in changegroup.supportedoutgoingversions(repo):
1580 raise error.Abort(
1578 raise error.Abort(
1581 _(b"repository does not support bundle version %s") % cgversion
1579 _(b"repository does not support bundle version %s") % cgversion
1582 )
1580 )
1583
1581
1584 if base:
1582 if base:
1585 if dest:
1583 if dest:
1586 raise error.Abort(
1584 raise error.Abort(
1587 _(b"--base is incompatible with specifying a destination")
1585 _(b"--base is incompatible with specifying a destination")
1588 )
1586 )
1589 common = [repo[rev].node() for rev in base]
1587 common = [repo[rev].node() for rev in base]
1590 heads = [repo[r].node() for r in revs] if revs else None
1588 heads = [repo[r].node() for r in revs] if revs else None
1591 outgoing = discovery.outgoing(repo, common, heads)
1589 outgoing = discovery.outgoing(repo, common, heads)
1592 else:
1590 else:
1593 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1591 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1594 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1592 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1595 other = hg.peer(repo, opts, dest)
1593 other = hg.peer(repo, opts, dest)
1596 revs = [repo[r].hex() for r in revs]
1594 revs = [repo[r].hex() for r in revs]
1597 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1595 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1598 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1596 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1599 outgoing = discovery.findcommonoutgoing(
1597 outgoing = discovery.findcommonoutgoing(
1600 repo,
1598 repo,
1601 other,
1599 other,
1602 onlyheads=heads,
1600 onlyheads=heads,
1603 force=opts.get(b'force'),
1601 force=opts.get(b'force'),
1604 portable=True,
1602 portable=True,
1605 )
1603 )
1606
1604
1607 if not outgoing.missing:
1605 if not outgoing.missing:
1608 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1606 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1609 return 1
1607 return 1
1610
1608
1611 if cgversion == b'01': # bundle1
1609 if cgversion == b'01': # bundle1
1612 bversion = b'HG10' + bundlespec.wirecompression
1610 bversion = b'HG10' + bundlespec.wirecompression
1613 bcompression = None
1611 bcompression = None
1614 elif cgversion in (b'02', b'03'):
1612 elif cgversion in (b'02', b'03'):
1615 bversion = b'HG20'
1613 bversion = b'HG20'
1616 bcompression = bundlespec.wirecompression
1614 bcompression = bundlespec.wirecompression
1617 else:
1615 else:
1618 raise error.ProgrammingError(
1616 raise error.ProgrammingError(
1619 b'bundle: unexpected changegroup version %s' % cgversion
1617 b'bundle: unexpected changegroup version %s' % cgversion
1620 )
1618 )
1621
1619
1622 # TODO compression options should be derived from bundlespec parsing.
1620 # TODO compression options should be derived from bundlespec parsing.
1623 # This is a temporary hack to allow adjusting bundle compression
1621 # This is a temporary hack to allow adjusting bundle compression
1624 # level without a) formalizing the bundlespec changes to declare it
1622 # level without a) formalizing the bundlespec changes to declare it
1625 # b) introducing a command flag.
1623 # b) introducing a command flag.
1626 compopts = {}
1624 compopts = {}
1627 complevel = ui.configint(
1625 complevel = ui.configint(
1628 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1626 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1629 )
1627 )
1630 if complevel is None:
1628 if complevel is None:
1631 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1629 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1632 if complevel is not None:
1630 if complevel is not None:
1633 compopts[b'level'] = complevel
1631 compopts[b'level'] = complevel
1634
1632
1635 # Allow overriding the bundling of obsmarker in phases through
1633 # Allow overriding the bundling of obsmarker in phases through
1636 # configuration while we don't have a bundle version that include them
1634 # configuration while we don't have a bundle version that include them
1637 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1635 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1638 bundlespec.contentopts[b'obsolescence'] = True
1636 bundlespec.contentopts[b'obsolescence'] = True
1639 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1637 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1640 bundlespec.contentopts[b'phases'] = True
1638 bundlespec.contentopts[b'phases'] = True
1641
1639
1642 bundle2.writenewbundle(
1640 bundle2.writenewbundle(
1643 ui,
1641 ui,
1644 repo,
1642 repo,
1645 b'bundle',
1643 b'bundle',
1646 fname,
1644 fname,
1647 bversion,
1645 bversion,
1648 outgoing,
1646 outgoing,
1649 bundlespec.contentopts,
1647 bundlespec.contentopts,
1650 compression=bcompression,
1648 compression=bcompression,
1651 compopts=compopts,
1649 compopts=compopts,
1652 )
1650 )
1653
1651
1654
1652
1655 @command(
1653 @command(
1656 b'cat',
1654 b'cat',
1657 [
1655 [
1658 (
1656 (
1659 b'o',
1657 b'o',
1660 b'output',
1658 b'output',
1661 b'',
1659 b'',
1662 _(b'print output to file with formatted name'),
1660 _(b'print output to file with formatted name'),
1663 _(b'FORMAT'),
1661 _(b'FORMAT'),
1664 ),
1662 ),
1665 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1663 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1666 (b'', b'decode', None, _(b'apply any matching decode filter')),
1664 (b'', b'decode', None, _(b'apply any matching decode filter')),
1667 ]
1665 ]
1668 + walkopts
1666 + walkopts
1669 + formatteropts,
1667 + formatteropts,
1670 _(b'[OPTION]... FILE...'),
1668 _(b'[OPTION]... FILE...'),
1671 helpcategory=command.CATEGORY_FILE_CONTENTS,
1669 helpcategory=command.CATEGORY_FILE_CONTENTS,
1672 inferrepo=True,
1670 inferrepo=True,
1673 intents={INTENT_READONLY},
1671 intents={INTENT_READONLY},
1674 )
1672 )
1675 def cat(ui, repo, file1, *pats, **opts):
1673 def cat(ui, repo, file1, *pats, **opts):
1676 """output the current or given revision of files
1674 """output the current or given revision of files
1677
1675
1678 Print the specified files as they were at the given revision. If
1676 Print the specified files as they were at the given revision. If
1679 no revision is given, the parent of the working directory is used.
1677 no revision is given, the parent of the working directory is used.
1680
1678
1681 Output may be to a file, in which case the name of the file is
1679 Output may be to a file, in which case the name of the file is
1682 given using a template string. See :hg:`help templates`. In addition
1680 given using a template string. See :hg:`help templates`. In addition
1683 to the common template keywords, the following formatting rules are
1681 to the common template keywords, the following formatting rules are
1684 supported:
1682 supported:
1685
1683
1686 :``%%``: literal "%" character
1684 :``%%``: literal "%" character
1687 :``%s``: basename of file being printed
1685 :``%s``: basename of file being printed
1688 :``%d``: dirname of file being printed, or '.' if in repository root
1686 :``%d``: dirname of file being printed, or '.' if in repository root
1689 :``%p``: root-relative path name of file being printed
1687 :``%p``: root-relative path name of file being printed
1690 :``%H``: changeset hash (40 hexadecimal digits)
1688 :``%H``: changeset hash (40 hexadecimal digits)
1691 :``%R``: changeset revision number
1689 :``%R``: changeset revision number
1692 :``%h``: short-form changeset hash (12 hexadecimal digits)
1690 :``%h``: short-form changeset hash (12 hexadecimal digits)
1693 :``%r``: zero-padded changeset revision number
1691 :``%r``: zero-padded changeset revision number
1694 :``%b``: basename of the exporting repository
1692 :``%b``: basename of the exporting repository
1695 :``\\``: literal "\\" character
1693 :``\\``: literal "\\" character
1696
1694
1697 .. container:: verbose
1695 .. container:: verbose
1698
1696
1699 Template:
1697 Template:
1700
1698
1701 The following keywords are supported in addition to the common template
1699 The following keywords are supported in addition to the common template
1702 keywords and functions. See also :hg:`help templates`.
1700 keywords and functions. See also :hg:`help templates`.
1703
1701
1704 :data: String. File content.
1702 :data: String. File content.
1705 :path: String. Repository-absolute path of the file.
1703 :path: String. Repository-absolute path of the file.
1706
1704
1707 Returns 0 on success.
1705 Returns 0 on success.
1708 """
1706 """
1709 opts = pycompat.byteskwargs(opts)
1707 opts = pycompat.byteskwargs(opts)
1710 rev = opts.get(b'rev')
1708 rev = opts.get(b'rev')
1711 if rev:
1709 if rev:
1712 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1710 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1713 ctx = scmutil.revsingle(repo, rev)
1711 ctx = scmutil.revsingle(repo, rev)
1714 m = scmutil.match(ctx, (file1,) + pats, opts)
1712 m = scmutil.match(ctx, (file1,) + pats, opts)
1715 fntemplate = opts.pop(b'output', b'')
1713 fntemplate = opts.pop(b'output', b'')
1716 if cmdutil.isstdiofilename(fntemplate):
1714 if cmdutil.isstdiofilename(fntemplate):
1717 fntemplate = b''
1715 fntemplate = b''
1718
1716
1719 if fntemplate:
1717 if fntemplate:
1720 fm = formatter.nullformatter(ui, b'cat', opts)
1718 fm = formatter.nullformatter(ui, b'cat', opts)
1721 else:
1719 else:
1722 ui.pager(b'cat')
1720 ui.pager(b'cat')
1723 fm = ui.formatter(b'cat', opts)
1721 fm = ui.formatter(b'cat', opts)
1724 with fm:
1722 with fm:
1725 return cmdutil.cat(
1723 return cmdutil.cat(
1726 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1724 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1727 )
1725 )
1728
1726
1729
1727
1730 @command(
1728 @command(
1731 b'clone',
1729 b'clone',
1732 [
1730 [
1733 (
1731 (
1734 b'U',
1732 b'U',
1735 b'noupdate',
1733 b'noupdate',
1736 None,
1734 None,
1737 _(
1735 _(
1738 b'the clone will include an empty working '
1736 b'the clone will include an empty working '
1739 b'directory (only a repository)'
1737 b'directory (only a repository)'
1740 ),
1738 ),
1741 ),
1739 ),
1742 (
1740 (
1743 b'u',
1741 b'u',
1744 b'updaterev',
1742 b'updaterev',
1745 b'',
1743 b'',
1746 _(b'revision, tag, or branch to check out'),
1744 _(b'revision, tag, or branch to check out'),
1747 _(b'REV'),
1745 _(b'REV'),
1748 ),
1746 ),
1749 (
1747 (
1750 b'r',
1748 b'r',
1751 b'rev',
1749 b'rev',
1752 [],
1750 [],
1753 _(
1751 _(
1754 b'do not clone everything, but include this changeset'
1752 b'do not clone everything, but include this changeset'
1755 b' and its ancestors'
1753 b' and its ancestors'
1756 ),
1754 ),
1757 _(b'REV'),
1755 _(b'REV'),
1758 ),
1756 ),
1759 (
1757 (
1760 b'b',
1758 b'b',
1761 b'branch',
1759 b'branch',
1762 [],
1760 [],
1763 _(
1761 _(
1764 b'do not clone everything, but include this branch\'s'
1762 b'do not clone everything, but include this branch\'s'
1765 b' changesets and their ancestors'
1763 b' changesets and their ancestors'
1766 ),
1764 ),
1767 _(b'BRANCH'),
1765 _(b'BRANCH'),
1768 ),
1766 ),
1769 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1767 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1770 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1768 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1771 (b'', b'stream', None, _(b'clone with minimal data processing')),
1769 (b'', b'stream', None, _(b'clone with minimal data processing')),
1772 ]
1770 ]
1773 + remoteopts,
1771 + remoteopts,
1774 _(b'[OPTION]... SOURCE [DEST]'),
1772 _(b'[OPTION]... SOURCE [DEST]'),
1775 helpcategory=command.CATEGORY_REPO_CREATION,
1773 helpcategory=command.CATEGORY_REPO_CREATION,
1776 helpbasic=True,
1774 helpbasic=True,
1777 norepo=True,
1775 norepo=True,
1778 )
1776 )
1779 def clone(ui, source, dest=None, **opts):
1777 def clone(ui, source, dest=None, **opts):
1780 """make a copy of an existing repository
1778 """make a copy of an existing repository
1781
1779
1782 Create a copy of an existing repository in a new directory.
1780 Create a copy of an existing repository in a new directory.
1783
1781
1784 If no destination directory name is specified, it defaults to the
1782 If no destination directory name is specified, it defaults to the
1785 basename of the source.
1783 basename of the source.
1786
1784
1787 The location of the source is added to the new repository's
1785 The location of the source is added to the new repository's
1788 ``.hg/hgrc`` file, as the default to be used for future pulls.
1786 ``.hg/hgrc`` file, as the default to be used for future pulls.
1789
1787
1790 Only local paths and ``ssh://`` URLs are supported as
1788 Only local paths and ``ssh://`` URLs are supported as
1791 destinations. For ``ssh://`` destinations, no working directory or
1789 destinations. For ``ssh://`` destinations, no working directory or
1792 ``.hg/hgrc`` will be created on the remote side.
1790 ``.hg/hgrc`` will be created on the remote side.
1793
1791
1794 If the source repository has a bookmark called '@' set, that
1792 If the source repository has a bookmark called '@' set, that
1795 revision will be checked out in the new repository by default.
1793 revision will be checked out in the new repository by default.
1796
1794
1797 To check out a particular version, use -u/--update, or
1795 To check out a particular version, use -u/--update, or
1798 -U/--noupdate to create a clone with no working directory.
1796 -U/--noupdate to create a clone with no working directory.
1799
1797
1800 To pull only a subset of changesets, specify one or more revisions
1798 To pull only a subset of changesets, specify one or more revisions
1801 identifiers with -r/--rev or branches with -b/--branch. The
1799 identifiers with -r/--rev or branches with -b/--branch. The
1802 resulting clone will contain only the specified changesets and
1800 resulting clone will contain only the specified changesets and
1803 their ancestors. These options (or 'clone src#rev dest') imply
1801 their ancestors. These options (or 'clone src#rev dest') imply
1804 --pull, even for local source repositories.
1802 --pull, even for local source repositories.
1805
1803
1806 In normal clone mode, the remote normalizes repository data into a common
1804 In normal clone mode, the remote normalizes repository data into a common
1807 exchange format and the receiving end translates this data into its local
1805 exchange format and the receiving end translates this data into its local
1808 storage format. --stream activates a different clone mode that essentially
1806 storage format. --stream activates a different clone mode that essentially
1809 copies repository files from the remote with minimal data processing. This
1807 copies repository files from the remote with minimal data processing. This
1810 significantly reduces the CPU cost of a clone both remotely and locally.
1808 significantly reduces the CPU cost of a clone both remotely and locally.
1811 However, it often increases the transferred data size by 30-40%. This can
1809 However, it often increases the transferred data size by 30-40%. This can
1812 result in substantially faster clones where I/O throughput is plentiful,
1810 result in substantially faster clones where I/O throughput is plentiful,
1813 especially for larger repositories. A side-effect of --stream clones is
1811 especially for larger repositories. A side-effect of --stream clones is
1814 that storage settings and requirements on the remote are applied locally:
1812 that storage settings and requirements on the remote are applied locally:
1815 a modern client may inherit legacy or inefficient storage used by the
1813 a modern client may inherit legacy or inefficient storage used by the
1816 remote or a legacy Mercurial client may not be able to clone from a
1814 remote or a legacy Mercurial client may not be able to clone from a
1817 modern Mercurial remote.
1815 modern Mercurial remote.
1818
1816
1819 .. note::
1817 .. note::
1820
1818
1821 Specifying a tag will include the tagged changeset but not the
1819 Specifying a tag will include the tagged changeset but not the
1822 changeset containing the tag.
1820 changeset containing the tag.
1823
1821
1824 .. container:: verbose
1822 .. container:: verbose
1825
1823
1826 For efficiency, hardlinks are used for cloning whenever the
1824 For efficiency, hardlinks are used for cloning whenever the
1827 source and destination are on the same filesystem (note this
1825 source and destination are on the same filesystem (note this
1828 applies only to the repository data, not to the working
1826 applies only to the repository data, not to the working
1829 directory). Some filesystems, such as AFS, implement hardlinking
1827 directory). Some filesystems, such as AFS, implement hardlinking
1830 incorrectly, but do not report errors. In these cases, use the
1828 incorrectly, but do not report errors. In these cases, use the
1831 --pull option to avoid hardlinking.
1829 --pull option to avoid hardlinking.
1832
1830
1833 Mercurial will update the working directory to the first applicable
1831 Mercurial will update the working directory to the first applicable
1834 revision from this list:
1832 revision from this list:
1835
1833
1836 a) null if -U or the source repository has no changesets
1834 a) null if -U or the source repository has no changesets
1837 b) if -u . and the source repository is local, the first parent of
1835 b) if -u . and the source repository is local, the first parent of
1838 the source repository's working directory
1836 the source repository's working directory
1839 c) the changeset specified with -u (if a branch name, this means the
1837 c) the changeset specified with -u (if a branch name, this means the
1840 latest head of that branch)
1838 latest head of that branch)
1841 d) the changeset specified with -r
1839 d) the changeset specified with -r
1842 e) the tipmost head specified with -b
1840 e) the tipmost head specified with -b
1843 f) the tipmost head specified with the url#branch source syntax
1841 f) the tipmost head specified with the url#branch source syntax
1844 g) the revision marked with the '@' bookmark, if present
1842 g) the revision marked with the '@' bookmark, if present
1845 h) the tipmost head of the default branch
1843 h) the tipmost head of the default branch
1846 i) tip
1844 i) tip
1847
1845
1848 When cloning from servers that support it, Mercurial may fetch
1846 When cloning from servers that support it, Mercurial may fetch
1849 pre-generated data from a server-advertised URL or inline from the
1847 pre-generated data from a server-advertised URL or inline from the
1850 same stream. When this is done, hooks operating on incoming changesets
1848 same stream. When this is done, hooks operating on incoming changesets
1851 and changegroups may fire more than once, once for each pre-generated
1849 and changegroups may fire more than once, once for each pre-generated
1852 bundle and as well as for any additional remaining data. In addition,
1850 bundle and as well as for any additional remaining data. In addition,
1853 if an error occurs, the repository may be rolled back to a partial
1851 if an error occurs, the repository may be rolled back to a partial
1854 clone. This behavior may change in future releases.
1852 clone. This behavior may change in future releases.
1855 See :hg:`help -e clonebundles` for more.
1853 See :hg:`help -e clonebundles` for more.
1856
1854
1857 Examples:
1855 Examples:
1858
1856
1859 - clone a remote repository to a new directory named hg/::
1857 - clone a remote repository to a new directory named hg/::
1860
1858
1861 hg clone https://www.mercurial-scm.org/repo/hg/
1859 hg clone https://www.mercurial-scm.org/repo/hg/
1862
1860
1863 - create a lightweight local clone::
1861 - create a lightweight local clone::
1864
1862
1865 hg clone project/ project-feature/
1863 hg clone project/ project-feature/
1866
1864
1867 - clone from an absolute path on an ssh server (note double-slash)::
1865 - clone from an absolute path on an ssh server (note double-slash)::
1868
1866
1869 hg clone ssh://user@server//home/projects/alpha/
1867 hg clone ssh://user@server//home/projects/alpha/
1870
1868
1871 - do a streaming clone while checking out a specified version::
1869 - do a streaming clone while checking out a specified version::
1872
1870
1873 hg clone --stream http://server/repo -u 1.5
1871 hg clone --stream http://server/repo -u 1.5
1874
1872
1875 - create a repository without changesets after a particular revision::
1873 - create a repository without changesets after a particular revision::
1876
1874
1877 hg clone -r 04e544 experimental/ good/
1875 hg clone -r 04e544 experimental/ good/
1878
1876
1879 - clone (and track) a particular named branch::
1877 - clone (and track) a particular named branch::
1880
1878
1881 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1879 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1882
1880
1883 See :hg:`help urls` for details on specifying URLs.
1881 See :hg:`help urls` for details on specifying URLs.
1884
1882
1885 Returns 0 on success.
1883 Returns 0 on success.
1886 """
1884 """
1887 opts = pycompat.byteskwargs(opts)
1885 opts = pycompat.byteskwargs(opts)
1888 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1886 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1889
1887
1890 # --include/--exclude can come from narrow or sparse.
1888 # --include/--exclude can come from narrow or sparse.
1891 includepats, excludepats = None, None
1889 includepats, excludepats = None, None
1892
1890
1893 # hg.clone() differentiates between None and an empty set. So make sure
1891 # hg.clone() differentiates between None and an empty set. So make sure
1894 # patterns are sets if narrow is requested without patterns.
1892 # patterns are sets if narrow is requested without patterns.
1895 if opts.get(b'narrow'):
1893 if opts.get(b'narrow'):
1896 includepats = set()
1894 includepats = set()
1897 excludepats = set()
1895 excludepats = set()
1898
1896
1899 if opts.get(b'include'):
1897 if opts.get(b'include'):
1900 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1898 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1901 if opts.get(b'exclude'):
1899 if opts.get(b'exclude'):
1902 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1900 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1903
1901
1904 r = hg.clone(
1902 r = hg.clone(
1905 ui,
1903 ui,
1906 opts,
1904 opts,
1907 source,
1905 source,
1908 dest,
1906 dest,
1909 pull=opts.get(b'pull'),
1907 pull=opts.get(b'pull'),
1910 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1908 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1911 revs=opts.get(b'rev'),
1909 revs=opts.get(b'rev'),
1912 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1910 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1913 branch=opts.get(b'branch'),
1911 branch=opts.get(b'branch'),
1914 shareopts=opts.get(b'shareopts'),
1912 shareopts=opts.get(b'shareopts'),
1915 storeincludepats=includepats,
1913 storeincludepats=includepats,
1916 storeexcludepats=excludepats,
1914 storeexcludepats=excludepats,
1917 depth=opts.get(b'depth') or None,
1915 depth=opts.get(b'depth') or None,
1918 )
1916 )
1919
1917
1920 return r is None
1918 return r is None
1921
1919
1922
1920
1923 @command(
1921 @command(
1924 b'commit|ci',
1922 b'commit|ci',
1925 [
1923 [
1926 (
1924 (
1927 b'A',
1925 b'A',
1928 b'addremove',
1926 b'addremove',
1929 None,
1927 None,
1930 _(b'mark new/missing files as added/removed before committing'),
1928 _(b'mark new/missing files as added/removed before committing'),
1931 ),
1929 ),
1932 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1930 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1933 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1931 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1934 (b's', b'secret', None, _(b'use the secret phase for committing')),
1932 (b's', b'secret', None, _(b'use the secret phase for committing')),
1935 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1933 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1936 (
1934 (
1937 b'',
1935 b'',
1938 b'force-close-branch',
1936 b'force-close-branch',
1939 None,
1937 None,
1940 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1938 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1941 ),
1939 ),
1942 (b'i', b'interactive', None, _(b'use interactive mode')),
1940 (b'i', b'interactive', None, _(b'use interactive mode')),
1943 ]
1941 ]
1944 + walkopts
1942 + walkopts
1945 + commitopts
1943 + commitopts
1946 + commitopts2
1944 + commitopts2
1947 + subrepoopts,
1945 + subrepoopts,
1948 _(b'[OPTION]... [FILE]...'),
1946 _(b'[OPTION]... [FILE]...'),
1949 helpcategory=command.CATEGORY_COMMITTING,
1947 helpcategory=command.CATEGORY_COMMITTING,
1950 helpbasic=True,
1948 helpbasic=True,
1951 inferrepo=True,
1949 inferrepo=True,
1952 )
1950 )
1953 def commit(ui, repo, *pats, **opts):
1951 def commit(ui, repo, *pats, **opts):
1954 """commit the specified files or all outstanding changes
1952 """commit the specified files or all outstanding changes
1955
1953
1956 Commit changes to the given files into the repository. Unlike a
1954 Commit changes to the given files into the repository. Unlike a
1957 centralized SCM, this operation is a local operation. See
1955 centralized SCM, this operation is a local operation. See
1958 :hg:`push` for a way to actively distribute your changes.
1956 :hg:`push` for a way to actively distribute your changes.
1959
1957
1960 If a list of files is omitted, all changes reported by :hg:`status`
1958 If a list of files is omitted, all changes reported by :hg:`status`
1961 will be committed.
1959 will be committed.
1962
1960
1963 If you are committing the result of a merge, do not provide any
1961 If you are committing the result of a merge, do not provide any
1964 filenames or -I/-X filters.
1962 filenames or -I/-X filters.
1965
1963
1966 If no commit message is specified, Mercurial starts your
1964 If no commit message is specified, Mercurial starts your
1967 configured editor where you can enter a message. In case your
1965 configured editor where you can enter a message. In case your
1968 commit fails, you will find a backup of your message in
1966 commit fails, you will find a backup of your message in
1969 ``.hg/last-message.txt``.
1967 ``.hg/last-message.txt``.
1970
1968
1971 The --close-branch flag can be used to mark the current branch
1969 The --close-branch flag can be used to mark the current branch
1972 head closed. When all heads of a branch are closed, the branch
1970 head closed. When all heads of a branch are closed, the branch
1973 will be considered closed and no longer listed.
1971 will be considered closed and no longer listed.
1974
1972
1975 The --amend flag can be used to amend the parent of the
1973 The --amend flag can be used to amend the parent of the
1976 working directory with a new commit that contains the changes
1974 working directory with a new commit that contains the changes
1977 in the parent in addition to those currently reported by :hg:`status`,
1975 in the parent in addition to those currently reported by :hg:`status`,
1978 if there are any. The old commit is stored in a backup bundle in
1976 if there are any. The old commit is stored in a backup bundle in
1979 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1977 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1980 on how to restore it).
1978 on how to restore it).
1981
1979
1982 Message, user and date are taken from the amended commit unless
1980 Message, user and date are taken from the amended commit unless
1983 specified. When a message isn't specified on the command line,
1981 specified. When a message isn't specified on the command line,
1984 the editor will open with the message of the amended commit.
1982 the editor will open with the message of the amended commit.
1985
1983
1986 It is not possible to amend public changesets (see :hg:`help phases`)
1984 It is not possible to amend public changesets (see :hg:`help phases`)
1987 or changesets that have children.
1985 or changesets that have children.
1988
1986
1989 See :hg:`help dates` for a list of formats valid for -d/--date.
1987 See :hg:`help dates` for a list of formats valid for -d/--date.
1990
1988
1991 Returns 0 on success, 1 if nothing changed.
1989 Returns 0 on success, 1 if nothing changed.
1992
1990
1993 .. container:: verbose
1991 .. container:: verbose
1994
1992
1995 Examples:
1993 Examples:
1996
1994
1997 - commit all files ending in .py::
1995 - commit all files ending in .py::
1998
1996
1999 hg commit --include "set:**.py"
1997 hg commit --include "set:**.py"
2000
1998
2001 - commit all non-binary files::
1999 - commit all non-binary files::
2002
2000
2003 hg commit --exclude "set:binary()"
2001 hg commit --exclude "set:binary()"
2004
2002
2005 - amend the current commit and set the date to now::
2003 - amend the current commit and set the date to now::
2006
2004
2007 hg commit --amend --date now
2005 hg commit --amend --date now
2008 """
2006 """
2009 with repo.wlock(), repo.lock():
2007 with repo.wlock(), repo.lock():
2010 return _docommit(ui, repo, *pats, **opts)
2008 return _docommit(ui, repo, *pats, **opts)
2011
2009
2012
2010
2013 def _docommit(ui, repo, *pats, **opts):
2011 def _docommit(ui, repo, *pats, **opts):
2014 if opts.get('interactive'):
2012 if opts.get('interactive'):
2015 opts.pop('interactive')
2013 opts.pop('interactive')
2016 ret = cmdutil.dorecord(
2014 ret = cmdutil.dorecord(
2017 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2015 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2018 )
2016 )
2019 # ret can be 0 (no changes to record) or the value returned by
2017 # ret can be 0 (no changes to record) or the value returned by
2020 # commit(), 1 if nothing changed or None on success.
2018 # commit(), 1 if nothing changed or None on success.
2021 return 1 if ret == 0 else ret
2019 return 1 if ret == 0 else ret
2022
2020
2023 opts = pycompat.byteskwargs(opts)
2021 opts = pycompat.byteskwargs(opts)
2024 if opts.get(b'subrepos'):
2022 if opts.get(b'subrepos'):
2025 if opts.get(b'amend'):
2023 if opts.get(b'amend'):
2026 raise error.Abort(_(b'cannot amend with --subrepos'))
2024 raise error.Abort(_(b'cannot amend with --subrepos'))
2027 # Let --subrepos on the command line override config setting.
2025 # Let --subrepos on the command line override config setting.
2028 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2026 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2029
2027
2030 cmdutil.checkunfinished(repo, commit=True)
2028 cmdutil.checkunfinished(repo, commit=True)
2031
2029
2032 branch = repo[None].branch()
2030 branch = repo[None].branch()
2033 bheads = repo.branchheads(branch)
2031 bheads = repo.branchheads(branch)
2034
2032
2035 extra = {}
2033 extra = {}
2036 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2034 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2037 extra[b'close'] = b'1'
2035 extra[b'close'] = b'1'
2038
2036
2039 if repo[b'.'].closesbranch():
2037 if repo[b'.'].closesbranch():
2040 raise error.Abort(
2038 raise error.Abort(
2041 _(b'current revision is already a branch closing head')
2039 _(b'current revision is already a branch closing head')
2042 )
2040 )
2043 elif not bheads:
2041 elif not bheads:
2044 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2042 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2045 elif (
2043 elif (
2046 branch == repo[b'.'].branch()
2044 branch == repo[b'.'].branch()
2047 and repo[b'.'].node() not in bheads
2045 and repo[b'.'].node() not in bheads
2048 and not opts.get(b'force_close_branch')
2046 and not opts.get(b'force_close_branch')
2049 ):
2047 ):
2050 hint = _(
2048 hint = _(
2051 b'use --force-close-branch to close branch from a non-head'
2049 b'use --force-close-branch to close branch from a non-head'
2052 b' changeset'
2050 b' changeset'
2053 )
2051 )
2054 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2052 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2055 elif opts.get(b'amend'):
2053 elif opts.get(b'amend'):
2056 if (
2054 if (
2057 repo[b'.'].p1().branch() != branch
2055 repo[b'.'].p1().branch() != branch
2058 and repo[b'.'].p2().branch() != branch
2056 and repo[b'.'].p2().branch() != branch
2059 ):
2057 ):
2060 raise error.Abort(_(b'can only close branch heads'))
2058 raise error.Abort(_(b'can only close branch heads'))
2061
2059
2062 if opts.get(b'amend'):
2060 if opts.get(b'amend'):
2063 if ui.configbool(b'ui', b'commitsubrepos'):
2061 if ui.configbool(b'ui', b'commitsubrepos'):
2064 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2062 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2065
2063
2066 old = repo[b'.']
2064 old = repo[b'.']
2067 rewriteutil.precheck(repo, [old.rev()], b'amend')
2065 rewriteutil.precheck(repo, [old.rev()], b'amend')
2068
2066
2069 # Currently histedit gets confused if an amend happens while histedit
2067 # Currently histedit gets confused if an amend happens while histedit
2070 # is in progress. Since we have a checkunfinished command, we are
2068 # is in progress. Since we have a checkunfinished command, we are
2071 # temporarily honoring it.
2069 # temporarily honoring it.
2072 #
2070 #
2073 # Note: eventually this guard will be removed. Please do not expect
2071 # Note: eventually this guard will be removed. Please do not expect
2074 # this behavior to remain.
2072 # this behavior to remain.
2075 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2073 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2076 cmdutil.checkunfinished(repo)
2074 cmdutil.checkunfinished(repo)
2077
2075
2078 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2076 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2079 if node == old.node():
2077 if node == old.node():
2080 ui.status(_(b"nothing changed\n"))
2078 ui.status(_(b"nothing changed\n"))
2081 return 1
2079 return 1
2082 else:
2080 else:
2083
2081
2084 def commitfunc(ui, repo, message, match, opts):
2082 def commitfunc(ui, repo, message, match, opts):
2085 overrides = {}
2083 overrides = {}
2086 if opts.get(b'secret'):
2084 if opts.get(b'secret'):
2087 overrides[(b'phases', b'new-commit')] = b'secret'
2085 overrides[(b'phases', b'new-commit')] = b'secret'
2088
2086
2089 baseui = repo.baseui
2087 baseui = repo.baseui
2090 with baseui.configoverride(overrides, b'commit'):
2088 with baseui.configoverride(overrides, b'commit'):
2091 with ui.configoverride(overrides, b'commit'):
2089 with ui.configoverride(overrides, b'commit'):
2092 editform = cmdutil.mergeeditform(
2090 editform = cmdutil.mergeeditform(
2093 repo[None], b'commit.normal'
2091 repo[None], b'commit.normal'
2094 )
2092 )
2095 editor = cmdutil.getcommiteditor(
2093 editor = cmdutil.getcommiteditor(
2096 editform=editform, **pycompat.strkwargs(opts)
2094 editform=editform, **pycompat.strkwargs(opts)
2097 )
2095 )
2098 return repo.commit(
2096 return repo.commit(
2099 message,
2097 message,
2100 opts.get(b'user'),
2098 opts.get(b'user'),
2101 opts.get(b'date'),
2099 opts.get(b'date'),
2102 match,
2100 match,
2103 editor=editor,
2101 editor=editor,
2104 extra=extra,
2102 extra=extra,
2105 )
2103 )
2106
2104
2107 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2105 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2108
2106
2109 if not node:
2107 if not node:
2110 stat = cmdutil.postcommitstatus(repo, pats, opts)
2108 stat = cmdutil.postcommitstatus(repo, pats, opts)
2111 if stat.deleted:
2109 if stat.deleted:
2112 ui.status(
2110 ui.status(
2113 _(
2111 _(
2114 b"nothing changed (%d missing files, see "
2112 b"nothing changed (%d missing files, see "
2115 b"'hg status')\n"
2113 b"'hg status')\n"
2116 )
2114 )
2117 % len(stat.deleted)
2115 % len(stat.deleted)
2118 )
2116 )
2119 else:
2117 else:
2120 ui.status(_(b"nothing changed\n"))
2118 ui.status(_(b"nothing changed\n"))
2121 return 1
2119 return 1
2122
2120
2123 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2121 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2124
2122
2125 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2123 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2126 status(
2124 status(
2127 ui,
2125 ui,
2128 repo,
2126 repo,
2129 modified=True,
2127 modified=True,
2130 added=True,
2128 added=True,
2131 removed=True,
2129 removed=True,
2132 deleted=True,
2130 deleted=True,
2133 unknown=True,
2131 unknown=True,
2134 subrepos=opts.get(b'subrepos'),
2132 subrepos=opts.get(b'subrepos'),
2135 )
2133 )
2136
2134
2137
2135
2138 @command(
2136 @command(
2139 b'config|showconfig|debugconfig',
2137 b'config|showconfig|debugconfig',
2140 [
2138 [
2141 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2139 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2142 (b'e', b'edit', None, _(b'edit user config')),
2140 (b'e', b'edit', None, _(b'edit user config')),
2143 (b'l', b'local', None, _(b'edit repository config')),
2141 (b'l', b'local', None, _(b'edit repository config')),
2144 (b'g', b'global', None, _(b'edit global config')),
2142 (b'g', b'global', None, _(b'edit global config')),
2145 ]
2143 ]
2146 + formatteropts,
2144 + formatteropts,
2147 _(b'[-u] [NAME]...'),
2145 _(b'[-u] [NAME]...'),
2148 helpcategory=command.CATEGORY_HELP,
2146 helpcategory=command.CATEGORY_HELP,
2149 optionalrepo=True,
2147 optionalrepo=True,
2150 intents={INTENT_READONLY},
2148 intents={INTENT_READONLY},
2151 )
2149 )
2152 def config(ui, repo, *values, **opts):
2150 def config(ui, repo, *values, **opts):
2153 """show combined config settings from all hgrc files
2151 """show combined config settings from all hgrc files
2154
2152
2155 With no arguments, print names and values of all config items.
2153 With no arguments, print names and values of all config items.
2156
2154
2157 With one argument of the form section.name, print just the value
2155 With one argument of the form section.name, print just the value
2158 of that config item.
2156 of that config item.
2159
2157
2160 With multiple arguments, print names and values of all config
2158 With multiple arguments, print names and values of all config
2161 items with matching section names or section.names.
2159 items with matching section names or section.names.
2162
2160
2163 With --edit, start an editor on the user-level config file. With
2161 With --edit, start an editor on the user-level config file. With
2164 --global, edit the system-wide config file. With --local, edit the
2162 --global, edit the system-wide config file. With --local, edit the
2165 repository-level config file.
2163 repository-level config file.
2166
2164
2167 With --debug, the source (filename and line number) is printed
2165 With --debug, the source (filename and line number) is printed
2168 for each config item.
2166 for each config item.
2169
2167
2170 See :hg:`help config` for more information about config files.
2168 See :hg:`help config` for more information about config files.
2171
2169
2172 .. container:: verbose
2170 .. container:: verbose
2173
2171
2174 Template:
2172 Template:
2175
2173
2176 The following keywords are supported. See also :hg:`help templates`.
2174 The following keywords are supported. See also :hg:`help templates`.
2177
2175
2178 :name: String. Config name.
2176 :name: String. Config name.
2179 :source: String. Filename and line number where the item is defined.
2177 :source: String. Filename and line number where the item is defined.
2180 :value: String. Config value.
2178 :value: String. Config value.
2181
2179
2182 Returns 0 on success, 1 if NAME does not exist.
2180 Returns 0 on success, 1 if NAME does not exist.
2183
2181
2184 """
2182 """
2185
2183
2186 opts = pycompat.byteskwargs(opts)
2184 opts = pycompat.byteskwargs(opts)
2187 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2185 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2188 if opts.get(b'local') and opts.get(b'global'):
2186 if opts.get(b'local') and opts.get(b'global'):
2189 raise error.Abort(_(b"can't use --local and --global together"))
2187 raise error.Abort(_(b"can't use --local and --global together"))
2190
2188
2191 if opts.get(b'local'):
2189 if opts.get(b'local'):
2192 if not repo:
2190 if not repo:
2193 raise error.Abort(_(b"can't use --local outside a repository"))
2191 raise error.Abort(_(b"can't use --local outside a repository"))
2194 paths = [repo.vfs.join(b'hgrc')]
2192 paths = [repo.vfs.join(b'hgrc')]
2195 elif opts.get(b'global'):
2193 elif opts.get(b'global'):
2196 paths = rcutil.systemrcpath()
2194 paths = rcutil.systemrcpath()
2197 else:
2195 else:
2198 paths = rcutil.userrcpath()
2196 paths = rcutil.userrcpath()
2199
2197
2200 for f in paths:
2198 for f in paths:
2201 if os.path.exists(f):
2199 if os.path.exists(f):
2202 break
2200 break
2203 else:
2201 else:
2204 if opts.get(b'global'):
2202 if opts.get(b'global'):
2205 samplehgrc = uimod.samplehgrcs[b'global']
2203 samplehgrc = uimod.samplehgrcs[b'global']
2206 elif opts.get(b'local'):
2204 elif opts.get(b'local'):
2207 samplehgrc = uimod.samplehgrcs[b'local']
2205 samplehgrc = uimod.samplehgrcs[b'local']
2208 else:
2206 else:
2209 samplehgrc = uimod.samplehgrcs[b'user']
2207 samplehgrc = uimod.samplehgrcs[b'user']
2210
2208
2211 f = paths[0]
2209 f = paths[0]
2212 fp = open(f, b"wb")
2210 fp = open(f, b"wb")
2213 fp.write(util.tonativeeol(samplehgrc))
2211 fp.write(util.tonativeeol(samplehgrc))
2214 fp.close()
2212 fp.close()
2215
2213
2216 editor = ui.geteditor()
2214 editor = ui.geteditor()
2217 ui.system(
2215 ui.system(
2218 b"%s \"%s\"" % (editor, f),
2216 b"%s \"%s\"" % (editor, f),
2219 onerr=error.Abort,
2217 onerr=error.Abort,
2220 errprefix=_(b"edit failed"),
2218 errprefix=_(b"edit failed"),
2221 blockedtag=b'config_edit',
2219 blockedtag=b'config_edit',
2222 )
2220 )
2223 return
2221 return
2224 ui.pager(b'config')
2222 ui.pager(b'config')
2225 fm = ui.formatter(b'config', opts)
2223 fm = ui.formatter(b'config', opts)
2226 for t, f in rcutil.rccomponents():
2224 for t, f in rcutil.rccomponents():
2227 if t == b'path':
2225 if t == b'path':
2228 ui.debug(b'read config from: %s\n' % f)
2226 ui.debug(b'read config from: %s\n' % f)
2229 elif t == b'items':
2227 elif t == b'items':
2230 for section, name, value, source in f:
2228 for section, name, value, source in f:
2231 ui.debug(b'set config by: %s\n' % source)
2229 ui.debug(b'set config by: %s\n' % source)
2232 else:
2230 else:
2233 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2231 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2234 untrusted = bool(opts.get(b'untrusted'))
2232 untrusted = bool(opts.get(b'untrusted'))
2235
2233
2236 selsections = selentries = []
2234 selsections = selentries = []
2237 if values:
2235 if values:
2238 selsections = [v for v in values if b'.' not in v]
2236 selsections = [v for v in values if b'.' not in v]
2239 selentries = [v for v in values if b'.' in v]
2237 selentries = [v for v in values if b'.' in v]
2240 uniquesel = len(selentries) == 1 and not selsections
2238 uniquesel = len(selentries) == 1 and not selsections
2241 selsections = set(selsections)
2239 selsections = set(selsections)
2242 selentries = set(selentries)
2240 selentries = set(selentries)
2243
2241
2244 matched = False
2242 matched = False
2245 for section, name, value in ui.walkconfig(untrusted=untrusted):
2243 for section, name, value in ui.walkconfig(untrusted=untrusted):
2246 source = ui.configsource(section, name, untrusted)
2244 source = ui.configsource(section, name, untrusted)
2247 value = pycompat.bytestr(value)
2245 value = pycompat.bytestr(value)
2248 defaultvalue = ui.configdefault(section, name)
2246 defaultvalue = ui.configdefault(section, name)
2249 if fm.isplain():
2247 if fm.isplain():
2250 source = source or b'none'
2248 source = source or b'none'
2251 value = value.replace(b'\n', b'\\n')
2249 value = value.replace(b'\n', b'\\n')
2252 entryname = section + b'.' + name
2250 entryname = section + b'.' + name
2253 if values and not (section in selsections or entryname in selentries):
2251 if values and not (section in selsections or entryname in selentries):
2254 continue
2252 continue
2255 fm.startitem()
2253 fm.startitem()
2256 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2254 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2257 if uniquesel:
2255 if uniquesel:
2258 fm.data(name=entryname)
2256 fm.data(name=entryname)
2259 fm.write(b'value', b'%s\n', value)
2257 fm.write(b'value', b'%s\n', value)
2260 else:
2258 else:
2261 fm.write(b'name value', b'%s=%s\n', entryname, value)
2259 fm.write(b'name value', b'%s=%s\n', entryname, value)
2262 if formatter.isprintable(defaultvalue):
2260 if formatter.isprintable(defaultvalue):
2263 fm.data(defaultvalue=defaultvalue)
2261 fm.data(defaultvalue=defaultvalue)
2264 elif isinstance(defaultvalue, list) and all(
2262 elif isinstance(defaultvalue, list) and all(
2265 formatter.isprintable(e) for e in defaultvalue
2263 formatter.isprintable(e) for e in defaultvalue
2266 ):
2264 ):
2267 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2265 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2268 # TODO: no idea how to process unsupported defaultvalue types
2266 # TODO: no idea how to process unsupported defaultvalue types
2269 matched = True
2267 matched = True
2270 fm.end()
2268 fm.end()
2271 if matched:
2269 if matched:
2272 return 0
2270 return 0
2273 return 1
2271 return 1
2274
2272
2275
2273
2276 @command(
2274 @command(
2277 b'continue',
2275 b'continue',
2278 dryrunopts,
2276 dryrunopts,
2279 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2277 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2280 helpbasic=True,
2278 helpbasic=True,
2281 )
2279 )
2282 def continuecmd(ui, repo, **opts):
2280 def continuecmd(ui, repo, **opts):
2283 """resumes an interrupted operation (EXPERIMENTAL)
2281 """resumes an interrupted operation (EXPERIMENTAL)
2284
2282
2285 Finishes a multistep operation like graft, histedit, rebase, merge,
2283 Finishes a multistep operation like graft, histedit, rebase, merge,
2286 and unshelve if they are in an interrupted state.
2284 and unshelve if they are in an interrupted state.
2287
2285
2288 use --dry-run/-n to dry run the command.
2286 use --dry-run/-n to dry run the command.
2289 """
2287 """
2290 dryrun = opts.get('dry_run')
2288 dryrun = opts.get('dry_run')
2291 contstate = cmdutil.getunfinishedstate(repo)
2289 contstate = cmdutil.getunfinishedstate(repo)
2292 if not contstate:
2290 if not contstate:
2293 raise error.Abort(_(b'no operation in progress'))
2291 raise error.Abort(_(b'no operation in progress'))
2294 if not contstate.continuefunc:
2292 if not contstate.continuefunc:
2295 raise error.Abort(
2293 raise error.Abort(
2296 (
2294 (
2297 _(b"%s in progress but does not support 'hg continue'")
2295 _(b"%s in progress but does not support 'hg continue'")
2298 % (contstate._opname)
2296 % (contstate._opname)
2299 ),
2297 ),
2300 hint=contstate.continuemsg(),
2298 hint=contstate.continuemsg(),
2301 )
2299 )
2302 if dryrun:
2300 if dryrun:
2303 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2301 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2304 return
2302 return
2305 return contstate.continuefunc(ui, repo)
2303 return contstate.continuefunc(ui, repo)
2306
2304
2307
2305
2308 @command(
2306 @command(
2309 b'copy|cp',
2307 b'copy|cp',
2310 [
2308 [
2311 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2309 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2312 (
2310 (
2313 b'f',
2311 b'f',
2314 b'force',
2312 b'force',
2315 None,
2313 None,
2316 _(b'forcibly copy over an existing managed file'),
2314 _(b'forcibly copy over an existing managed file'),
2317 ),
2315 ),
2318 ]
2316 ]
2319 + walkopts
2317 + walkopts
2320 + dryrunopts,
2318 + dryrunopts,
2321 _(b'[OPTION]... SOURCE... DEST'),
2319 _(b'[OPTION]... SOURCE... DEST'),
2322 helpcategory=command.CATEGORY_FILE_CONTENTS,
2320 helpcategory=command.CATEGORY_FILE_CONTENTS,
2323 )
2321 )
2324 def copy(ui, repo, *pats, **opts):
2322 def copy(ui, repo, *pats, **opts):
2325 """mark files as copied for the next commit
2323 """mark files as copied for the next commit
2326
2324
2327 Mark dest as having copies of source files. If dest is a
2325 Mark dest as having copies of source files. If dest is a
2328 directory, copies are put in that directory. If dest is a file,
2326 directory, copies are put in that directory. If dest is a file,
2329 the source must be a single file.
2327 the source must be a single file.
2330
2328
2331 By default, this command copies the contents of files as they
2329 By default, this command copies the contents of files as they
2332 exist in the working directory. If invoked with -A/--after, the
2330 exist in the working directory. If invoked with -A/--after, the
2333 operation is recorded, but no copying is performed.
2331 operation is recorded, but no copying is performed.
2334
2332
2335 This command takes effect with the next commit. To undo a copy
2333 This command takes effect with the next commit. To undo a copy
2336 before that, see :hg:`revert`.
2334 before that, see :hg:`revert`.
2337
2335
2338 Returns 0 on success, 1 if errors are encountered.
2336 Returns 0 on success, 1 if errors are encountered.
2339 """
2337 """
2340 opts = pycompat.byteskwargs(opts)
2338 opts = pycompat.byteskwargs(opts)
2341 with repo.wlock(False):
2339 with repo.wlock(False):
2342 return cmdutil.copy(ui, repo, pats, opts)
2340 return cmdutil.copy(ui, repo, pats, opts)
2343
2341
2344
2342
2345 @command(
2343 @command(
2346 b'debugcommands',
2344 b'debugcommands',
2347 [],
2345 [],
2348 _(b'[COMMAND]'),
2346 _(b'[COMMAND]'),
2349 helpcategory=command.CATEGORY_HELP,
2347 helpcategory=command.CATEGORY_HELP,
2350 norepo=True,
2348 norepo=True,
2351 )
2349 )
2352 def debugcommands(ui, cmd=b'', *args):
2350 def debugcommands(ui, cmd=b'', *args):
2353 """list all available commands and options"""
2351 """list all available commands and options"""
2354 for cmd, vals in sorted(pycompat.iteritems(table)):
2352 for cmd, vals in sorted(pycompat.iteritems(table)):
2355 cmd = cmd.split(b'|')[0]
2353 cmd = cmd.split(b'|')[0]
2356 opts = b', '.join([i[1] for i in vals[1]])
2354 opts = b', '.join([i[1] for i in vals[1]])
2357 ui.write(b'%s: %s\n' % (cmd, opts))
2355 ui.write(b'%s: %s\n' % (cmd, opts))
2358
2356
2359
2357
2360 @command(
2358 @command(
2361 b'debugcomplete',
2359 b'debugcomplete',
2362 [(b'o', b'options', None, _(b'show the command options'))],
2360 [(b'o', b'options', None, _(b'show the command options'))],
2363 _(b'[-o] CMD'),
2361 _(b'[-o] CMD'),
2364 helpcategory=command.CATEGORY_HELP,
2362 helpcategory=command.CATEGORY_HELP,
2365 norepo=True,
2363 norepo=True,
2366 )
2364 )
2367 def debugcomplete(ui, cmd=b'', **opts):
2365 def debugcomplete(ui, cmd=b'', **opts):
2368 """returns the completion list associated with the given command"""
2366 """returns the completion list associated with the given command"""
2369
2367
2370 if opts.get('options'):
2368 if opts.get('options'):
2371 options = []
2369 options = []
2372 otables = [globalopts]
2370 otables = [globalopts]
2373 if cmd:
2371 if cmd:
2374 aliases, entry = cmdutil.findcmd(cmd, table, False)
2372 aliases, entry = cmdutil.findcmd(cmd, table, False)
2375 otables.append(entry[1])
2373 otables.append(entry[1])
2376 for t in otables:
2374 for t in otables:
2377 for o in t:
2375 for o in t:
2378 if b"(DEPRECATED)" in o[3]:
2376 if b"(DEPRECATED)" in o[3]:
2379 continue
2377 continue
2380 if o[0]:
2378 if o[0]:
2381 options.append(b'-%s' % o[0])
2379 options.append(b'-%s' % o[0])
2382 options.append(b'--%s' % o[1])
2380 options.append(b'--%s' % o[1])
2383 ui.write(b"%s\n" % b"\n".join(options))
2381 ui.write(b"%s\n" % b"\n".join(options))
2384 return
2382 return
2385
2383
2386 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2384 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2387 if ui.verbose:
2385 if ui.verbose:
2388 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2386 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2389 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2387 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2390
2388
2391
2389
2392 @command(
2390 @command(
2393 b'diff',
2391 b'diff',
2394 [
2392 [
2395 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2393 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2396 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2394 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2397 ]
2395 ]
2398 + diffopts
2396 + diffopts
2399 + diffopts2
2397 + diffopts2
2400 + walkopts
2398 + walkopts
2401 + subrepoopts,
2399 + subrepoopts,
2402 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2400 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2403 helpcategory=command.CATEGORY_FILE_CONTENTS,
2401 helpcategory=command.CATEGORY_FILE_CONTENTS,
2404 helpbasic=True,
2402 helpbasic=True,
2405 inferrepo=True,
2403 inferrepo=True,
2406 intents={INTENT_READONLY},
2404 intents={INTENT_READONLY},
2407 )
2405 )
2408 def diff(ui, repo, *pats, **opts):
2406 def diff(ui, repo, *pats, **opts):
2409 """diff repository (or selected files)
2407 """diff repository (or selected files)
2410
2408
2411 Show differences between revisions for the specified files.
2409 Show differences between revisions for the specified files.
2412
2410
2413 Differences between files are shown using the unified diff format.
2411 Differences between files are shown using the unified diff format.
2414
2412
2415 .. note::
2413 .. note::
2416
2414
2417 :hg:`diff` may generate unexpected results for merges, as it will
2415 :hg:`diff` may generate unexpected results for merges, as it will
2418 default to comparing against the working directory's first
2416 default to comparing against the working directory's first
2419 parent changeset if no revisions are specified.
2417 parent changeset if no revisions are specified.
2420
2418
2421 When two revision arguments are given, then changes are shown
2419 When two revision arguments are given, then changes are shown
2422 between those revisions. If only one revision is specified then
2420 between those revisions. If only one revision is specified then
2423 that revision is compared to the working directory, and, when no
2421 that revision is compared to the working directory, and, when no
2424 revisions are specified, the working directory files are compared
2422 revisions are specified, the working directory files are compared
2425 to its first parent.
2423 to its first parent.
2426
2424
2427 Alternatively you can specify -c/--change with a revision to see
2425 Alternatively you can specify -c/--change with a revision to see
2428 the changes in that changeset relative to its first parent.
2426 the changes in that changeset relative to its first parent.
2429
2427
2430 Without the -a/--text option, diff will avoid generating diffs of
2428 Without the -a/--text option, diff will avoid generating diffs of
2431 files it detects as binary. With -a, diff will generate a diff
2429 files it detects as binary. With -a, diff will generate a diff
2432 anyway, probably with undesirable results.
2430 anyway, probably with undesirable results.
2433
2431
2434 Use the -g/--git option to generate diffs in the git extended diff
2432 Use the -g/--git option to generate diffs in the git extended diff
2435 format. For more information, read :hg:`help diffs`.
2433 format. For more information, read :hg:`help diffs`.
2436
2434
2437 .. container:: verbose
2435 .. container:: verbose
2438
2436
2439 Examples:
2437 Examples:
2440
2438
2441 - compare a file in the current working directory to its parent::
2439 - compare a file in the current working directory to its parent::
2442
2440
2443 hg diff foo.c
2441 hg diff foo.c
2444
2442
2445 - compare two historical versions of a directory, with rename info::
2443 - compare two historical versions of a directory, with rename info::
2446
2444
2447 hg diff --git -r 1.0:1.2 lib/
2445 hg diff --git -r 1.0:1.2 lib/
2448
2446
2449 - get change stats relative to the last change on some date::
2447 - get change stats relative to the last change on some date::
2450
2448
2451 hg diff --stat -r "date('may 2')"
2449 hg diff --stat -r "date('may 2')"
2452
2450
2453 - diff all newly-added files that contain a keyword::
2451 - diff all newly-added files that contain a keyword::
2454
2452
2455 hg diff "set:added() and grep(GNU)"
2453 hg diff "set:added() and grep(GNU)"
2456
2454
2457 - compare a revision and its parents::
2455 - compare a revision and its parents::
2458
2456
2459 hg diff -c 9353 # compare against first parent
2457 hg diff -c 9353 # compare against first parent
2460 hg diff -r 9353^:9353 # same using revset syntax
2458 hg diff -r 9353^:9353 # same using revset syntax
2461 hg diff -r 9353^2:9353 # compare against the second parent
2459 hg diff -r 9353^2:9353 # compare against the second parent
2462
2460
2463 Returns 0 on success.
2461 Returns 0 on success.
2464 """
2462 """
2465
2463
2466 opts = pycompat.byteskwargs(opts)
2464 opts = pycompat.byteskwargs(opts)
2467 revs = opts.get(b'rev')
2465 revs = opts.get(b'rev')
2468 change = opts.get(b'change')
2466 change = opts.get(b'change')
2469 stat = opts.get(b'stat')
2467 stat = opts.get(b'stat')
2470 reverse = opts.get(b'reverse')
2468 reverse = opts.get(b'reverse')
2471
2469
2472 if revs and change:
2470 if revs and change:
2473 msg = _(b'cannot specify --rev and --change at the same time')
2471 msg = _(b'cannot specify --rev and --change at the same time')
2474 raise error.Abort(msg)
2472 raise error.Abort(msg)
2475 elif change:
2473 elif change:
2476 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2474 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2477 ctx2 = scmutil.revsingle(repo, change, None)
2475 ctx2 = scmutil.revsingle(repo, change, None)
2478 ctx1 = ctx2.p1()
2476 ctx1 = ctx2.p1()
2479 else:
2477 else:
2480 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2478 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2481 ctx1, ctx2 = scmutil.revpair(repo, revs)
2479 ctx1, ctx2 = scmutil.revpair(repo, revs)
2482 node1, node2 = ctx1.node(), ctx2.node()
2480 node1, node2 = ctx1.node(), ctx2.node()
2483
2481
2484 if reverse:
2482 if reverse:
2485 node1, node2 = node2, node1
2483 node1, node2 = node2, node1
2486
2484
2487 diffopts = patch.diffallopts(ui, opts)
2485 diffopts = patch.diffallopts(ui, opts)
2488 m = scmutil.match(ctx2, pats, opts)
2486 m = scmutil.match(ctx2, pats, opts)
2489 m = repo.narrowmatch(m)
2487 m = repo.narrowmatch(m)
2490 ui.pager(b'diff')
2488 ui.pager(b'diff')
2491 logcmdutil.diffordiffstat(
2489 logcmdutil.diffordiffstat(
2492 ui,
2490 ui,
2493 repo,
2491 repo,
2494 diffopts,
2492 diffopts,
2495 node1,
2493 node1,
2496 node2,
2494 node2,
2497 m,
2495 m,
2498 stat=stat,
2496 stat=stat,
2499 listsubrepos=opts.get(b'subrepos'),
2497 listsubrepos=opts.get(b'subrepos'),
2500 root=opts.get(b'root'),
2498 root=opts.get(b'root'),
2501 )
2499 )
2502
2500
2503
2501
2504 @command(
2502 @command(
2505 b'export',
2503 b'export',
2506 [
2504 [
2507 (
2505 (
2508 b'B',
2506 b'B',
2509 b'bookmark',
2507 b'bookmark',
2510 b'',
2508 b'',
2511 _(b'export changes only reachable by given bookmark'),
2509 _(b'export changes only reachable by given bookmark'),
2512 _(b'BOOKMARK'),
2510 _(b'BOOKMARK'),
2513 ),
2511 ),
2514 (
2512 (
2515 b'o',
2513 b'o',
2516 b'output',
2514 b'output',
2517 b'',
2515 b'',
2518 _(b'print output to file with formatted name'),
2516 _(b'print output to file with formatted name'),
2519 _(b'FORMAT'),
2517 _(b'FORMAT'),
2520 ),
2518 ),
2521 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2519 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2522 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2520 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2523 ]
2521 ]
2524 + diffopts
2522 + diffopts
2525 + formatteropts,
2523 + formatteropts,
2526 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2524 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2527 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2525 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2528 helpbasic=True,
2526 helpbasic=True,
2529 intents={INTENT_READONLY},
2527 intents={INTENT_READONLY},
2530 )
2528 )
2531 def export(ui, repo, *changesets, **opts):
2529 def export(ui, repo, *changesets, **opts):
2532 """dump the header and diffs for one or more changesets
2530 """dump the header and diffs for one or more changesets
2533
2531
2534 Print the changeset header and diffs for one or more revisions.
2532 Print the changeset header and diffs for one or more revisions.
2535 If no revision is given, the parent of the working directory is used.
2533 If no revision is given, the parent of the working directory is used.
2536
2534
2537 The information shown in the changeset header is: author, date,
2535 The information shown in the changeset header is: author, date,
2538 branch name (if non-default), changeset hash, parent(s) and commit
2536 branch name (if non-default), changeset hash, parent(s) and commit
2539 comment.
2537 comment.
2540
2538
2541 .. note::
2539 .. note::
2542
2540
2543 :hg:`export` may generate unexpected diff output for merge
2541 :hg:`export` may generate unexpected diff output for merge
2544 changesets, as it will compare the merge changeset against its
2542 changesets, as it will compare the merge changeset against its
2545 first parent only.
2543 first parent only.
2546
2544
2547 Output may be to a file, in which case the name of the file is
2545 Output may be to a file, in which case the name of the file is
2548 given using a template string. See :hg:`help templates`. In addition
2546 given using a template string. See :hg:`help templates`. In addition
2549 to the common template keywords, the following formatting rules are
2547 to the common template keywords, the following formatting rules are
2550 supported:
2548 supported:
2551
2549
2552 :``%%``: literal "%" character
2550 :``%%``: literal "%" character
2553 :``%H``: changeset hash (40 hexadecimal digits)
2551 :``%H``: changeset hash (40 hexadecimal digits)
2554 :``%N``: number of patches being generated
2552 :``%N``: number of patches being generated
2555 :``%R``: changeset revision number
2553 :``%R``: changeset revision number
2556 :``%b``: basename of the exporting repository
2554 :``%b``: basename of the exporting repository
2557 :``%h``: short-form changeset hash (12 hexadecimal digits)
2555 :``%h``: short-form changeset hash (12 hexadecimal digits)
2558 :``%m``: first line of the commit message (only alphanumeric characters)
2556 :``%m``: first line of the commit message (only alphanumeric characters)
2559 :``%n``: zero-padded sequence number, starting at 1
2557 :``%n``: zero-padded sequence number, starting at 1
2560 :``%r``: zero-padded changeset revision number
2558 :``%r``: zero-padded changeset revision number
2561 :``\\``: literal "\\" character
2559 :``\\``: literal "\\" character
2562
2560
2563 Without the -a/--text option, export will avoid generating diffs
2561 Without the -a/--text option, export will avoid generating diffs
2564 of files it detects as binary. With -a, export will generate a
2562 of files it detects as binary. With -a, export will generate a
2565 diff anyway, probably with undesirable results.
2563 diff anyway, probably with undesirable results.
2566
2564
2567 With -B/--bookmark changesets reachable by the given bookmark are
2565 With -B/--bookmark changesets reachable by the given bookmark are
2568 selected.
2566 selected.
2569
2567
2570 Use the -g/--git option to generate diffs in the git extended diff
2568 Use the -g/--git option to generate diffs in the git extended diff
2571 format. See :hg:`help diffs` for more information.
2569 format. See :hg:`help diffs` for more information.
2572
2570
2573 With the --switch-parent option, the diff will be against the
2571 With the --switch-parent option, the diff will be against the
2574 second parent. It can be useful to review a merge.
2572 second parent. It can be useful to review a merge.
2575
2573
2576 .. container:: verbose
2574 .. container:: verbose
2577
2575
2578 Template:
2576 Template:
2579
2577
2580 The following keywords are supported in addition to the common template
2578 The following keywords are supported in addition to the common template
2581 keywords and functions. See also :hg:`help templates`.
2579 keywords and functions. See also :hg:`help templates`.
2582
2580
2583 :diff: String. Diff content.
2581 :diff: String. Diff content.
2584 :parents: List of strings. Parent nodes of the changeset.
2582 :parents: List of strings. Parent nodes of the changeset.
2585
2583
2586 Examples:
2584 Examples:
2587
2585
2588 - use export and import to transplant a bugfix to the current
2586 - use export and import to transplant a bugfix to the current
2589 branch::
2587 branch::
2590
2588
2591 hg export -r 9353 | hg import -
2589 hg export -r 9353 | hg import -
2592
2590
2593 - export all the changesets between two revisions to a file with
2591 - export all the changesets between two revisions to a file with
2594 rename information::
2592 rename information::
2595
2593
2596 hg export --git -r 123:150 > changes.txt
2594 hg export --git -r 123:150 > changes.txt
2597
2595
2598 - split outgoing changes into a series of patches with
2596 - split outgoing changes into a series of patches with
2599 descriptive names::
2597 descriptive names::
2600
2598
2601 hg export -r "outgoing()" -o "%n-%m.patch"
2599 hg export -r "outgoing()" -o "%n-%m.patch"
2602
2600
2603 Returns 0 on success.
2601 Returns 0 on success.
2604 """
2602 """
2605 opts = pycompat.byteskwargs(opts)
2603 opts = pycompat.byteskwargs(opts)
2606 bookmark = opts.get(b'bookmark')
2604 bookmark = opts.get(b'bookmark')
2607 changesets += tuple(opts.get(b'rev', []))
2605 changesets += tuple(opts.get(b'rev', []))
2608
2606
2609 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2607 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2610
2608
2611 if bookmark:
2609 if bookmark:
2612 if bookmark not in repo._bookmarks:
2610 if bookmark not in repo._bookmarks:
2613 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2611 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2614
2612
2615 revs = scmutil.bookmarkrevs(repo, bookmark)
2613 revs = scmutil.bookmarkrevs(repo, bookmark)
2616 else:
2614 else:
2617 if not changesets:
2615 if not changesets:
2618 changesets = [b'.']
2616 changesets = [b'.']
2619
2617
2620 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2618 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2621 revs = scmutil.revrange(repo, changesets)
2619 revs = scmutil.revrange(repo, changesets)
2622
2620
2623 if not revs:
2621 if not revs:
2624 raise error.Abort(_(b"export requires at least one changeset"))
2622 raise error.Abort(_(b"export requires at least one changeset"))
2625 if len(revs) > 1:
2623 if len(revs) > 1:
2626 ui.note(_(b'exporting patches:\n'))
2624 ui.note(_(b'exporting patches:\n'))
2627 else:
2625 else:
2628 ui.note(_(b'exporting patch:\n'))
2626 ui.note(_(b'exporting patch:\n'))
2629
2627
2630 fntemplate = opts.get(b'output')
2628 fntemplate = opts.get(b'output')
2631 if cmdutil.isstdiofilename(fntemplate):
2629 if cmdutil.isstdiofilename(fntemplate):
2632 fntemplate = b''
2630 fntemplate = b''
2633
2631
2634 if fntemplate:
2632 if fntemplate:
2635 fm = formatter.nullformatter(ui, b'export', opts)
2633 fm = formatter.nullformatter(ui, b'export', opts)
2636 else:
2634 else:
2637 ui.pager(b'export')
2635 ui.pager(b'export')
2638 fm = ui.formatter(b'export', opts)
2636 fm = ui.formatter(b'export', opts)
2639 with fm:
2637 with fm:
2640 cmdutil.export(
2638 cmdutil.export(
2641 repo,
2639 repo,
2642 revs,
2640 revs,
2643 fm,
2641 fm,
2644 fntemplate=fntemplate,
2642 fntemplate=fntemplate,
2645 switch_parent=opts.get(b'switch_parent'),
2643 switch_parent=opts.get(b'switch_parent'),
2646 opts=patch.diffallopts(ui, opts),
2644 opts=patch.diffallopts(ui, opts),
2647 )
2645 )
2648
2646
2649
2647
2650 @command(
2648 @command(
2651 b'files',
2649 b'files',
2652 [
2650 [
2653 (
2651 (
2654 b'r',
2652 b'r',
2655 b'rev',
2653 b'rev',
2656 b'',
2654 b'',
2657 _(b'search the repository as it is in REV'),
2655 _(b'search the repository as it is in REV'),
2658 _(b'REV'),
2656 _(b'REV'),
2659 ),
2657 ),
2660 (
2658 (
2661 b'0',
2659 b'0',
2662 b'print0',
2660 b'print0',
2663 None,
2661 None,
2664 _(b'end filenames with NUL, for use with xargs'),
2662 _(b'end filenames with NUL, for use with xargs'),
2665 ),
2663 ),
2666 ]
2664 ]
2667 + walkopts
2665 + walkopts
2668 + formatteropts
2666 + formatteropts
2669 + subrepoopts,
2667 + subrepoopts,
2670 _(b'[OPTION]... [FILE]...'),
2668 _(b'[OPTION]... [FILE]...'),
2671 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2669 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2672 intents={INTENT_READONLY},
2670 intents={INTENT_READONLY},
2673 )
2671 )
2674 def files(ui, repo, *pats, **opts):
2672 def files(ui, repo, *pats, **opts):
2675 """list tracked files
2673 """list tracked files
2676
2674
2677 Print files under Mercurial control in the working directory or
2675 Print files under Mercurial control in the working directory or
2678 specified revision for given files (excluding removed files).
2676 specified revision for given files (excluding removed files).
2679 Files can be specified as filenames or filesets.
2677 Files can be specified as filenames or filesets.
2680
2678
2681 If no files are given to match, this command prints the names
2679 If no files are given to match, this command prints the names
2682 of all files under Mercurial control.
2680 of all files under Mercurial control.
2683
2681
2684 .. container:: verbose
2682 .. container:: verbose
2685
2683
2686 Template:
2684 Template:
2687
2685
2688 The following keywords are supported in addition to the common template
2686 The following keywords are supported in addition to the common template
2689 keywords and functions. See also :hg:`help templates`.
2687 keywords and functions. See also :hg:`help templates`.
2690
2688
2691 :flags: String. Character denoting file's symlink and executable bits.
2689 :flags: String. Character denoting file's symlink and executable bits.
2692 :path: String. Repository-absolute path of the file.
2690 :path: String. Repository-absolute path of the file.
2693 :size: Integer. Size of the file in bytes.
2691 :size: Integer. Size of the file in bytes.
2694
2692
2695 Examples:
2693 Examples:
2696
2694
2697 - list all files under the current directory::
2695 - list all files under the current directory::
2698
2696
2699 hg files .
2697 hg files .
2700
2698
2701 - shows sizes and flags for current revision::
2699 - shows sizes and flags for current revision::
2702
2700
2703 hg files -vr .
2701 hg files -vr .
2704
2702
2705 - list all files named README::
2703 - list all files named README::
2706
2704
2707 hg files -I "**/README"
2705 hg files -I "**/README"
2708
2706
2709 - list all binary files::
2707 - list all binary files::
2710
2708
2711 hg files "set:binary()"
2709 hg files "set:binary()"
2712
2710
2713 - find files containing a regular expression::
2711 - find files containing a regular expression::
2714
2712
2715 hg files "set:grep('bob')"
2713 hg files "set:grep('bob')"
2716
2714
2717 - search tracked file contents with xargs and grep::
2715 - search tracked file contents with xargs and grep::
2718
2716
2719 hg files -0 | xargs -0 grep foo
2717 hg files -0 | xargs -0 grep foo
2720
2718
2721 See :hg:`help patterns` and :hg:`help filesets` for more information
2719 See :hg:`help patterns` and :hg:`help filesets` for more information
2722 on specifying file patterns.
2720 on specifying file patterns.
2723
2721
2724 Returns 0 if a match is found, 1 otherwise.
2722 Returns 0 if a match is found, 1 otherwise.
2725
2723
2726 """
2724 """
2727
2725
2728 opts = pycompat.byteskwargs(opts)
2726 opts = pycompat.byteskwargs(opts)
2729 rev = opts.get(b'rev')
2727 rev = opts.get(b'rev')
2730 if rev:
2728 if rev:
2731 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2729 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2732 ctx = scmutil.revsingle(repo, rev, None)
2730 ctx = scmutil.revsingle(repo, rev, None)
2733
2731
2734 end = b'\n'
2732 end = b'\n'
2735 if opts.get(b'print0'):
2733 if opts.get(b'print0'):
2736 end = b'\0'
2734 end = b'\0'
2737 fmt = b'%s' + end
2735 fmt = b'%s' + end
2738
2736
2739 m = scmutil.match(ctx, pats, opts)
2737 m = scmutil.match(ctx, pats, opts)
2740 ui.pager(b'files')
2738 ui.pager(b'files')
2741 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2739 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2742 with ui.formatter(b'files', opts) as fm:
2740 with ui.formatter(b'files', opts) as fm:
2743 return cmdutil.files(
2741 return cmdutil.files(
2744 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2742 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2745 )
2743 )
2746
2744
2747
2745
2748 @command(
2746 @command(
2749 b'forget',
2747 b'forget',
2750 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2748 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2751 + walkopts
2749 + walkopts
2752 + dryrunopts,
2750 + dryrunopts,
2753 _(b'[OPTION]... FILE...'),
2751 _(b'[OPTION]... FILE...'),
2754 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2752 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2755 helpbasic=True,
2753 helpbasic=True,
2756 inferrepo=True,
2754 inferrepo=True,
2757 )
2755 )
2758 def forget(ui, repo, *pats, **opts):
2756 def forget(ui, repo, *pats, **opts):
2759 """forget the specified files on the next commit
2757 """forget the specified files on the next commit
2760
2758
2761 Mark the specified files so they will no longer be tracked
2759 Mark the specified files so they will no longer be tracked
2762 after the next commit.
2760 after the next commit.
2763
2761
2764 This only removes files from the current branch, not from the
2762 This only removes files from the current branch, not from the
2765 entire project history, and it does not delete them from the
2763 entire project history, and it does not delete them from the
2766 working directory.
2764 working directory.
2767
2765
2768 To delete the file from the working directory, see :hg:`remove`.
2766 To delete the file from the working directory, see :hg:`remove`.
2769
2767
2770 To undo a forget before the next commit, see :hg:`add`.
2768 To undo a forget before the next commit, see :hg:`add`.
2771
2769
2772 .. container:: verbose
2770 .. container:: verbose
2773
2771
2774 Examples:
2772 Examples:
2775
2773
2776 - forget newly-added binary files::
2774 - forget newly-added binary files::
2777
2775
2778 hg forget "set:added() and binary()"
2776 hg forget "set:added() and binary()"
2779
2777
2780 - forget files that would be excluded by .hgignore::
2778 - forget files that would be excluded by .hgignore::
2781
2779
2782 hg forget "set:hgignore()"
2780 hg forget "set:hgignore()"
2783
2781
2784 Returns 0 on success.
2782 Returns 0 on success.
2785 """
2783 """
2786
2784
2787 opts = pycompat.byteskwargs(opts)
2785 opts = pycompat.byteskwargs(opts)
2788 if not pats:
2786 if not pats:
2789 raise error.Abort(_(b'no files specified'))
2787 raise error.Abort(_(b'no files specified'))
2790
2788
2791 m = scmutil.match(repo[None], pats, opts)
2789 m = scmutil.match(repo[None], pats, opts)
2792 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2790 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2793 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2791 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2794 rejected = cmdutil.forget(
2792 rejected = cmdutil.forget(
2795 ui,
2793 ui,
2796 repo,
2794 repo,
2797 m,
2795 m,
2798 prefix=b"",
2796 prefix=b"",
2799 uipathfn=uipathfn,
2797 uipathfn=uipathfn,
2800 explicitonly=False,
2798 explicitonly=False,
2801 dryrun=dryrun,
2799 dryrun=dryrun,
2802 interactive=interactive,
2800 interactive=interactive,
2803 )[0]
2801 )[0]
2804 return rejected and 1 or 0
2802 return rejected and 1 or 0
2805
2803
2806
2804
2807 @command(
2805 @command(
2808 b'graft',
2806 b'graft',
2809 [
2807 [
2810 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2808 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2811 (
2809 (
2812 b'',
2810 b'',
2813 b'base',
2811 b'base',
2814 b'',
2812 b'',
2815 _(b'base revision when doing the graft merge (ADVANCED)'),
2813 _(b'base revision when doing the graft merge (ADVANCED)'),
2816 _(b'REV'),
2814 _(b'REV'),
2817 ),
2815 ),
2818 (b'c', b'continue', False, _(b'resume interrupted graft')),
2816 (b'c', b'continue', False, _(b'resume interrupted graft')),
2819 (b'', b'stop', False, _(b'stop interrupted graft')),
2817 (b'', b'stop', False, _(b'stop interrupted graft')),
2820 (b'', b'abort', False, _(b'abort interrupted graft')),
2818 (b'', b'abort', False, _(b'abort interrupted graft')),
2821 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2819 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2822 (b'', b'log', None, _(b'append graft info to log message')),
2820 (b'', b'log', None, _(b'append graft info to log message')),
2823 (
2821 (
2824 b'',
2822 b'',
2825 b'no-commit',
2823 b'no-commit',
2826 None,
2824 None,
2827 _(b"don't commit, just apply the changes in working directory"),
2825 _(b"don't commit, just apply the changes in working directory"),
2828 ),
2826 ),
2829 (b'f', b'force', False, _(b'force graft')),
2827 (b'f', b'force', False, _(b'force graft')),
2830 (
2828 (
2831 b'D',
2829 b'D',
2832 b'currentdate',
2830 b'currentdate',
2833 False,
2831 False,
2834 _(b'record the current date as commit date'),
2832 _(b'record the current date as commit date'),
2835 ),
2833 ),
2836 (
2834 (
2837 b'U',
2835 b'U',
2838 b'currentuser',
2836 b'currentuser',
2839 False,
2837 False,
2840 _(b'record the current user as committer'),
2838 _(b'record the current user as committer'),
2841 ),
2839 ),
2842 ]
2840 ]
2843 + commitopts2
2841 + commitopts2
2844 + mergetoolopts
2842 + mergetoolopts
2845 + dryrunopts,
2843 + dryrunopts,
2846 _(b'[OPTION]... [-r REV]... REV...'),
2844 _(b'[OPTION]... [-r REV]... REV...'),
2847 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2845 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2848 )
2846 )
2849 def graft(ui, repo, *revs, **opts):
2847 def graft(ui, repo, *revs, **opts):
2850 '''copy changes from other branches onto the current branch
2848 '''copy changes from other branches onto the current branch
2851
2849
2852 This command uses Mercurial's merge logic to copy individual
2850 This command uses Mercurial's merge logic to copy individual
2853 changes from other branches without merging branches in the
2851 changes from other branches without merging branches in the
2854 history graph. This is sometimes known as 'backporting' or
2852 history graph. This is sometimes known as 'backporting' or
2855 'cherry-picking'. By default, graft will copy user, date, and
2853 'cherry-picking'. By default, graft will copy user, date, and
2856 description from the source changesets.
2854 description from the source changesets.
2857
2855
2858 Changesets that are ancestors of the current revision, that have
2856 Changesets that are ancestors of the current revision, that have
2859 already been grafted, or that are merges will be skipped.
2857 already been grafted, or that are merges will be skipped.
2860
2858
2861 If --log is specified, log messages will have a comment appended
2859 If --log is specified, log messages will have a comment appended
2862 of the form::
2860 of the form::
2863
2861
2864 (grafted from CHANGESETHASH)
2862 (grafted from CHANGESETHASH)
2865
2863
2866 If --force is specified, revisions will be grafted even if they
2864 If --force is specified, revisions will be grafted even if they
2867 are already ancestors of, or have been grafted to, the destination.
2865 are already ancestors of, or have been grafted to, the destination.
2868 This is useful when the revisions have since been backed out.
2866 This is useful when the revisions have since been backed out.
2869
2867
2870 If a graft merge results in conflicts, the graft process is
2868 If a graft merge results in conflicts, the graft process is
2871 interrupted so that the current merge can be manually resolved.
2869 interrupted so that the current merge can be manually resolved.
2872 Once all conflicts are addressed, the graft process can be
2870 Once all conflicts are addressed, the graft process can be
2873 continued with the -c/--continue option.
2871 continued with the -c/--continue option.
2874
2872
2875 The -c/--continue option reapplies all the earlier options.
2873 The -c/--continue option reapplies all the earlier options.
2876
2874
2877 .. container:: verbose
2875 .. container:: verbose
2878
2876
2879 The --base option exposes more of how graft internally uses merge with a
2877 The --base option exposes more of how graft internally uses merge with a
2880 custom base revision. --base can be used to specify another ancestor than
2878 custom base revision. --base can be used to specify another ancestor than
2881 the first and only parent.
2879 the first and only parent.
2882
2880
2883 The command::
2881 The command::
2884
2882
2885 hg graft -r 345 --base 234
2883 hg graft -r 345 --base 234
2886
2884
2887 is thus pretty much the same as::
2885 is thus pretty much the same as::
2888
2886
2889 hg diff -r 234 -r 345 | hg import
2887 hg diff -r 234 -r 345 | hg import
2890
2888
2891 but using merge to resolve conflicts and track moved files.
2889 but using merge to resolve conflicts and track moved files.
2892
2890
2893 The result of a merge can thus be backported as a single commit by
2891 The result of a merge can thus be backported as a single commit by
2894 specifying one of the merge parents as base, and thus effectively
2892 specifying one of the merge parents as base, and thus effectively
2895 grafting the changes from the other side.
2893 grafting the changes from the other side.
2896
2894
2897 It is also possible to collapse multiple changesets and clean up history
2895 It is also possible to collapse multiple changesets and clean up history
2898 by specifying another ancestor as base, much like rebase --collapse
2896 by specifying another ancestor as base, much like rebase --collapse
2899 --keep.
2897 --keep.
2900
2898
2901 The commit message can be tweaked after the fact using commit --amend .
2899 The commit message can be tweaked after the fact using commit --amend .
2902
2900
2903 For using non-ancestors as the base to backout changes, see the backout
2901 For using non-ancestors as the base to backout changes, see the backout
2904 command and the hidden --parent option.
2902 command and the hidden --parent option.
2905
2903
2906 .. container:: verbose
2904 .. container:: verbose
2907
2905
2908 Examples:
2906 Examples:
2909
2907
2910 - copy a single change to the stable branch and edit its description::
2908 - copy a single change to the stable branch and edit its description::
2911
2909
2912 hg update stable
2910 hg update stable
2913 hg graft --edit 9393
2911 hg graft --edit 9393
2914
2912
2915 - graft a range of changesets with one exception, updating dates::
2913 - graft a range of changesets with one exception, updating dates::
2916
2914
2917 hg graft -D "2085::2093 and not 2091"
2915 hg graft -D "2085::2093 and not 2091"
2918
2916
2919 - continue a graft after resolving conflicts::
2917 - continue a graft after resolving conflicts::
2920
2918
2921 hg graft -c
2919 hg graft -c
2922
2920
2923 - show the source of a grafted changeset::
2921 - show the source of a grafted changeset::
2924
2922
2925 hg log --debug -r .
2923 hg log --debug -r .
2926
2924
2927 - show revisions sorted by date::
2925 - show revisions sorted by date::
2928
2926
2929 hg log -r "sort(all(), date)"
2927 hg log -r "sort(all(), date)"
2930
2928
2931 - backport the result of a merge as a single commit::
2929 - backport the result of a merge as a single commit::
2932
2930
2933 hg graft -r 123 --base 123^
2931 hg graft -r 123 --base 123^
2934
2932
2935 - land a feature branch as one changeset::
2933 - land a feature branch as one changeset::
2936
2934
2937 hg up -cr default
2935 hg up -cr default
2938 hg graft -r featureX --base "ancestor('featureX', 'default')"
2936 hg graft -r featureX --base "ancestor('featureX', 'default')"
2939
2937
2940 See :hg:`help revisions` for more about specifying revisions.
2938 See :hg:`help revisions` for more about specifying revisions.
2941
2939
2942 Returns 0 on successful completion.
2940 Returns 0 on successful completion.
2943 '''
2941 '''
2944 with repo.wlock():
2942 with repo.wlock():
2945 return _dograft(ui, repo, *revs, **opts)
2943 return _dograft(ui, repo, *revs, **opts)
2946
2944
2947
2945
2948 def _dograft(ui, repo, *revs, **opts):
2946 def _dograft(ui, repo, *revs, **opts):
2949 opts = pycompat.byteskwargs(opts)
2947 opts = pycompat.byteskwargs(opts)
2950 if revs and opts.get(b'rev'):
2948 if revs and opts.get(b'rev'):
2951 ui.warn(
2949 ui.warn(
2952 _(
2950 _(
2953 b'warning: inconsistent use of --rev might give unexpected '
2951 b'warning: inconsistent use of --rev might give unexpected '
2954 b'revision ordering!\n'
2952 b'revision ordering!\n'
2955 )
2953 )
2956 )
2954 )
2957
2955
2958 revs = list(revs)
2956 revs = list(revs)
2959 revs.extend(opts.get(b'rev'))
2957 revs.extend(opts.get(b'rev'))
2960 basectx = None
2958 basectx = None
2961 if opts.get(b'base'):
2959 if opts.get(b'base'):
2962 basectx = scmutil.revsingle(repo, opts[b'base'], None)
2960 basectx = scmutil.revsingle(repo, opts[b'base'], None)
2963 # a dict of data to be stored in state file
2961 # a dict of data to be stored in state file
2964 statedata = {}
2962 statedata = {}
2965 # list of new nodes created by ongoing graft
2963 # list of new nodes created by ongoing graft
2966 statedata[b'newnodes'] = []
2964 statedata[b'newnodes'] = []
2967
2965
2968 cmdutil.resolvecommitoptions(ui, opts)
2966 cmdutil.resolvecommitoptions(ui, opts)
2969
2967
2970 editor = cmdutil.getcommiteditor(
2968 editor = cmdutil.getcommiteditor(
2971 editform=b'graft', **pycompat.strkwargs(opts)
2969 editform=b'graft', **pycompat.strkwargs(opts)
2972 )
2970 )
2973
2971
2974 cont = False
2972 cont = False
2975 if opts.get(b'no_commit'):
2973 if opts.get(b'no_commit'):
2976 if opts.get(b'edit'):
2974 if opts.get(b'edit'):
2977 raise error.Abort(
2975 raise error.Abort(
2978 _(b"cannot specify --no-commit and --edit together")
2976 _(b"cannot specify --no-commit and --edit together")
2979 )
2977 )
2980 if opts.get(b'currentuser'):
2978 if opts.get(b'currentuser'):
2981 raise error.Abort(
2979 raise error.Abort(
2982 _(b"cannot specify --no-commit and --currentuser together")
2980 _(b"cannot specify --no-commit and --currentuser together")
2983 )
2981 )
2984 if opts.get(b'currentdate'):
2982 if opts.get(b'currentdate'):
2985 raise error.Abort(
2983 raise error.Abort(
2986 _(b"cannot specify --no-commit and --currentdate together")
2984 _(b"cannot specify --no-commit and --currentdate together")
2987 )
2985 )
2988 if opts.get(b'log'):
2986 if opts.get(b'log'):
2989 raise error.Abort(
2987 raise error.Abort(
2990 _(b"cannot specify --no-commit and --log together")
2988 _(b"cannot specify --no-commit and --log together")
2991 )
2989 )
2992
2990
2993 graftstate = statemod.cmdstate(repo, b'graftstate')
2991 graftstate = statemod.cmdstate(repo, b'graftstate')
2994
2992
2995 if opts.get(b'stop'):
2993 if opts.get(b'stop'):
2996 if opts.get(b'continue'):
2994 if opts.get(b'continue'):
2997 raise error.Abort(
2995 raise error.Abort(
2998 _(b"cannot use '--continue' and '--stop' together")
2996 _(b"cannot use '--continue' and '--stop' together")
2999 )
2997 )
3000 if opts.get(b'abort'):
2998 if opts.get(b'abort'):
3001 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
2999 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
3002
3000
3003 if any(
3001 if any(
3004 (
3002 (
3005 opts.get(b'edit'),
3003 opts.get(b'edit'),
3006 opts.get(b'log'),
3004 opts.get(b'log'),
3007 opts.get(b'user'),
3005 opts.get(b'user'),
3008 opts.get(b'date'),
3006 opts.get(b'date'),
3009 opts.get(b'currentdate'),
3007 opts.get(b'currentdate'),
3010 opts.get(b'currentuser'),
3008 opts.get(b'currentuser'),
3011 opts.get(b'rev'),
3009 opts.get(b'rev'),
3012 )
3010 )
3013 ):
3011 ):
3014 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3012 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3015 return _stopgraft(ui, repo, graftstate)
3013 return _stopgraft(ui, repo, graftstate)
3016 elif opts.get(b'abort'):
3014 elif opts.get(b'abort'):
3017 if opts.get(b'continue'):
3015 if opts.get(b'continue'):
3018 raise error.Abort(
3016 raise error.Abort(
3019 _(b"cannot use '--continue' and '--abort' together")
3017 _(b"cannot use '--continue' and '--abort' together")
3020 )
3018 )
3021 if any(
3019 if any(
3022 (
3020 (
3023 opts.get(b'edit'),
3021 opts.get(b'edit'),
3024 opts.get(b'log'),
3022 opts.get(b'log'),
3025 opts.get(b'user'),
3023 opts.get(b'user'),
3026 opts.get(b'date'),
3024 opts.get(b'date'),
3027 opts.get(b'currentdate'),
3025 opts.get(b'currentdate'),
3028 opts.get(b'currentuser'),
3026 opts.get(b'currentuser'),
3029 opts.get(b'rev'),
3027 opts.get(b'rev'),
3030 )
3028 )
3031 ):
3029 ):
3032 raise error.Abort(
3030 raise error.Abort(
3033 _(b"cannot specify any other flag with '--abort'")
3031 _(b"cannot specify any other flag with '--abort'")
3034 )
3032 )
3035
3033
3036 return cmdutil.abortgraft(ui, repo, graftstate)
3034 return cmdutil.abortgraft(ui, repo, graftstate)
3037 elif opts.get(b'continue'):
3035 elif opts.get(b'continue'):
3038 cont = True
3036 cont = True
3039 if revs:
3037 if revs:
3040 raise error.Abort(_(b"can't specify --continue and revisions"))
3038 raise error.Abort(_(b"can't specify --continue and revisions"))
3041 # read in unfinished revisions
3039 # read in unfinished revisions
3042 if graftstate.exists():
3040 if graftstate.exists():
3043 statedata = cmdutil.readgraftstate(repo, graftstate)
3041 statedata = cmdutil.readgraftstate(repo, graftstate)
3044 if statedata.get(b'date'):
3042 if statedata.get(b'date'):
3045 opts[b'date'] = statedata[b'date']
3043 opts[b'date'] = statedata[b'date']
3046 if statedata.get(b'user'):
3044 if statedata.get(b'user'):
3047 opts[b'user'] = statedata[b'user']
3045 opts[b'user'] = statedata[b'user']
3048 if statedata.get(b'log'):
3046 if statedata.get(b'log'):
3049 opts[b'log'] = True
3047 opts[b'log'] = True
3050 if statedata.get(b'no_commit'):
3048 if statedata.get(b'no_commit'):
3051 opts[b'no_commit'] = statedata.get(b'no_commit')
3049 opts[b'no_commit'] = statedata.get(b'no_commit')
3052 nodes = statedata[b'nodes']
3050 nodes = statedata[b'nodes']
3053 revs = [repo[node].rev() for node in nodes]
3051 revs = [repo[node].rev() for node in nodes]
3054 else:
3052 else:
3055 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3053 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3056 else:
3054 else:
3057 if not revs:
3055 if not revs:
3058 raise error.Abort(_(b'no revisions specified'))
3056 raise error.Abort(_(b'no revisions specified'))
3059 cmdutil.checkunfinished(repo)
3057 cmdutil.checkunfinished(repo)
3060 cmdutil.bailifchanged(repo)
3058 cmdutil.bailifchanged(repo)
3061 revs = scmutil.revrange(repo, revs)
3059 revs = scmutil.revrange(repo, revs)
3062
3060
3063 skipped = set()
3061 skipped = set()
3064 if basectx is None:
3062 if basectx is None:
3065 # check for merges
3063 # check for merges
3066 for rev in repo.revs(b'%ld and merge()', revs):
3064 for rev in repo.revs(b'%ld and merge()', revs):
3067 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3065 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3068 skipped.add(rev)
3066 skipped.add(rev)
3069 revs = [r for r in revs if r not in skipped]
3067 revs = [r for r in revs if r not in skipped]
3070 if not revs:
3068 if not revs:
3071 return -1
3069 return -1
3072 if basectx is not None and len(revs) != 1:
3070 if basectx is not None and len(revs) != 1:
3073 raise error.Abort(_(b'only one revision allowed with --base '))
3071 raise error.Abort(_(b'only one revision allowed with --base '))
3074
3072
3075 # Don't check in the --continue case, in effect retaining --force across
3073 # Don't check in the --continue case, in effect retaining --force across
3076 # --continues. That's because without --force, any revisions we decided to
3074 # --continues. That's because without --force, any revisions we decided to
3077 # skip would have been filtered out here, so they wouldn't have made their
3075 # skip would have been filtered out here, so they wouldn't have made their
3078 # way to the graftstate. With --force, any revisions we would have otherwise
3076 # way to the graftstate. With --force, any revisions we would have otherwise
3079 # skipped would not have been filtered out, and if they hadn't been applied
3077 # skipped would not have been filtered out, and if they hadn't been applied
3080 # already, they'd have been in the graftstate.
3078 # already, they'd have been in the graftstate.
3081 if not (cont or opts.get(b'force')) and basectx is None:
3079 if not (cont or opts.get(b'force')) and basectx is None:
3082 # check for ancestors of dest branch
3080 # check for ancestors of dest branch
3083 crev = repo[b'.'].rev()
3081 crev = repo[b'.'].rev()
3084 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3082 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3085 # XXX make this lazy in the future
3083 # XXX make this lazy in the future
3086 # don't mutate while iterating, create a copy
3084 # don't mutate while iterating, create a copy
3087 for rev in list(revs):
3085 for rev in list(revs):
3088 if rev in ancestors:
3086 if rev in ancestors:
3089 ui.warn(
3087 ui.warn(
3090 _(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev])
3088 _(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev])
3091 )
3089 )
3092 # XXX remove on list is slow
3090 # XXX remove on list is slow
3093 revs.remove(rev)
3091 revs.remove(rev)
3094 if not revs:
3092 if not revs:
3095 return -1
3093 return -1
3096
3094
3097 # analyze revs for earlier grafts
3095 # analyze revs for earlier grafts
3098 ids = {}
3096 ids = {}
3099 for ctx in repo.set(b"%ld", revs):
3097 for ctx in repo.set(b"%ld", revs):
3100 ids[ctx.hex()] = ctx.rev()
3098 ids[ctx.hex()] = ctx.rev()
3101 n = ctx.extra().get(b'source')
3099 n = ctx.extra().get(b'source')
3102 if n:
3100 if n:
3103 ids[n] = ctx.rev()
3101 ids[n] = ctx.rev()
3104
3102
3105 # check ancestors for earlier grafts
3103 # check ancestors for earlier grafts
3106 ui.debug(b'scanning for duplicate grafts\n')
3104 ui.debug(b'scanning for duplicate grafts\n')
3107
3105
3108 # The only changesets we can be sure doesn't contain grafts of any
3106 # The only changesets we can be sure doesn't contain grafts of any
3109 # revs, are the ones that are common ancestors of *all* revs:
3107 # revs, are the ones that are common ancestors of *all* revs:
3110 for rev in repo.revs(b'only(%d,ancestor(%ld))', crev, revs):
3108 for rev in repo.revs(b'only(%d,ancestor(%ld))', crev, revs):
3111 ctx = repo[rev]
3109 ctx = repo[rev]
3112 n = ctx.extra().get(b'source')
3110 n = ctx.extra().get(b'source')
3113 if n in ids:
3111 if n in ids:
3114 try:
3112 try:
3115 r = repo[n].rev()
3113 r = repo[n].rev()
3116 except error.RepoLookupError:
3114 except error.RepoLookupError:
3117 r = None
3115 r = None
3118 if r in revs:
3116 if r in revs:
3119 ui.warn(
3117 ui.warn(
3120 _(
3118 _(
3121 b'skipping revision %d:%s '
3119 b'skipping revision %d:%s '
3122 b'(already grafted to %d:%s)\n'
3120 b'(already grafted to %d:%s)\n'
3123 )
3121 )
3124 % (r, repo[r], rev, ctx)
3122 % (r, repo[r], rev, ctx)
3125 )
3123 )
3126 revs.remove(r)
3124 revs.remove(r)
3127 elif ids[n] in revs:
3125 elif ids[n] in revs:
3128 if r is None:
3126 if r is None:
3129 ui.warn(
3127 ui.warn(
3130 _(
3128 _(
3131 b'skipping already grafted revision %d:%s '
3129 b'skipping already grafted revision %d:%s '
3132 b'(%d:%s also has unknown origin %s)\n'
3130 b'(%d:%s also has unknown origin %s)\n'
3133 )
3131 )
3134 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3132 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3135 )
3133 )
3136 else:
3134 else:
3137 ui.warn(
3135 ui.warn(
3138 _(
3136 _(
3139 b'skipping already grafted revision %d:%s '
3137 b'skipping already grafted revision %d:%s '
3140 b'(%d:%s also has origin %d:%s)\n'
3138 b'(%d:%s also has origin %d:%s)\n'
3141 )
3139 )
3142 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3140 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3143 )
3141 )
3144 revs.remove(ids[n])
3142 revs.remove(ids[n])
3145 elif ctx.hex() in ids:
3143 elif ctx.hex() in ids:
3146 r = ids[ctx.hex()]
3144 r = ids[ctx.hex()]
3147 if r in revs:
3145 if r in revs:
3148 ui.warn(
3146 ui.warn(
3149 _(
3147 _(
3150 b'skipping already grafted revision %d:%s '
3148 b'skipping already grafted revision %d:%s '
3151 b'(was grafted from %d:%s)\n'
3149 b'(was grafted from %d:%s)\n'
3152 )
3150 )
3153 % (r, repo[r], rev, ctx)
3151 % (r, repo[r], rev, ctx)
3154 )
3152 )
3155 revs.remove(r)
3153 revs.remove(r)
3156 if not revs:
3154 if not revs:
3157 return -1
3155 return -1
3158
3156
3159 if opts.get(b'no_commit'):
3157 if opts.get(b'no_commit'):
3160 statedata[b'no_commit'] = True
3158 statedata[b'no_commit'] = True
3161 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3159 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3162 desc = b'%d:%s "%s"' % (
3160 desc = b'%d:%s "%s"' % (
3163 ctx.rev(),
3161 ctx.rev(),
3164 ctx,
3162 ctx,
3165 ctx.description().split(b'\n', 1)[0],
3163 ctx.description().split(b'\n', 1)[0],
3166 )
3164 )
3167 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3165 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3168 if names:
3166 if names:
3169 desc += b' (%s)' % b' '.join(names)
3167 desc += b' (%s)' % b' '.join(names)
3170 ui.status(_(b'grafting %s\n') % desc)
3168 ui.status(_(b'grafting %s\n') % desc)
3171 if opts.get(b'dry_run'):
3169 if opts.get(b'dry_run'):
3172 continue
3170 continue
3173
3171
3174 source = ctx.extra().get(b'source')
3172 source = ctx.extra().get(b'source')
3175 extra = {}
3173 extra = {}
3176 if source:
3174 if source:
3177 extra[b'source'] = source
3175 extra[b'source'] = source
3178 extra[b'intermediate-source'] = ctx.hex()
3176 extra[b'intermediate-source'] = ctx.hex()
3179 else:
3177 else:
3180 extra[b'source'] = ctx.hex()
3178 extra[b'source'] = ctx.hex()
3181 user = ctx.user()
3179 user = ctx.user()
3182 if opts.get(b'user'):
3180 if opts.get(b'user'):
3183 user = opts[b'user']
3181 user = opts[b'user']
3184 statedata[b'user'] = user
3182 statedata[b'user'] = user
3185 date = ctx.date()
3183 date = ctx.date()
3186 if opts.get(b'date'):
3184 if opts.get(b'date'):
3187 date = opts[b'date']
3185 date = opts[b'date']
3188 statedata[b'date'] = date
3186 statedata[b'date'] = date
3189 message = ctx.description()
3187 message = ctx.description()
3190 if opts.get(b'log'):
3188 if opts.get(b'log'):
3191 message += b'\n(grafted from %s)' % ctx.hex()
3189 message += b'\n(grafted from %s)' % ctx.hex()
3192 statedata[b'log'] = True
3190 statedata[b'log'] = True
3193
3191
3194 # we don't merge the first commit when continuing
3192 # we don't merge the first commit when continuing
3195 if not cont:
3193 if not cont:
3196 # perform the graft merge with p1(rev) as 'ancestor'
3194 # perform the graft merge with p1(rev) as 'ancestor'
3197 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3195 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3198 base = ctx.p1() if basectx is None else basectx
3196 base = ctx.p1() if basectx is None else basectx
3199 with ui.configoverride(overrides, b'graft'):
3197 with ui.configoverride(overrides, b'graft'):
3200 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3198 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3201 # report any conflicts
3199 # report any conflicts
3202 if stats.unresolvedcount > 0:
3200 if stats.unresolvedcount > 0:
3203 # write out state for --continue
3201 # write out state for --continue
3204 nodes = [repo[rev].hex() for rev in revs[pos:]]
3202 nodes = [repo[rev].hex() for rev in revs[pos:]]
3205 statedata[b'nodes'] = nodes
3203 statedata[b'nodes'] = nodes
3206 stateversion = 1
3204 stateversion = 1
3207 graftstate.save(stateversion, statedata)
3205 graftstate.save(stateversion, statedata)
3208 hint = _(b"use 'hg resolve' and 'hg graft --continue'")
3206 hint = _(b"use 'hg resolve' and 'hg graft --continue'")
3209 raise error.Abort(
3207 raise error.Abort(
3210 _(b"unresolved conflicts, can't continue"), hint=hint
3208 _(b"unresolved conflicts, can't continue"), hint=hint
3211 )
3209 )
3212 else:
3210 else:
3213 cont = False
3211 cont = False
3214
3212
3215 # commit if --no-commit is false
3213 # commit if --no-commit is false
3216 if not opts.get(b'no_commit'):
3214 if not opts.get(b'no_commit'):
3217 node = repo.commit(
3215 node = repo.commit(
3218 text=message, user=user, date=date, extra=extra, editor=editor
3216 text=message, user=user, date=date, extra=extra, editor=editor
3219 )
3217 )
3220 if node is None:
3218 if node is None:
3221 ui.warn(
3219 ui.warn(
3222 _(b'note: graft of %d:%s created no changes to commit\n')
3220 _(b'note: graft of %d:%s created no changes to commit\n')
3223 % (ctx.rev(), ctx)
3221 % (ctx.rev(), ctx)
3224 )
3222 )
3225 # checking that newnodes exist because old state files won't have it
3223 # checking that newnodes exist because old state files won't have it
3226 elif statedata.get(b'newnodes') is not None:
3224 elif statedata.get(b'newnodes') is not None:
3227 statedata[b'newnodes'].append(node)
3225 statedata[b'newnodes'].append(node)
3228
3226
3229 # remove state when we complete successfully
3227 # remove state when we complete successfully
3230 if not opts.get(b'dry_run'):
3228 if not opts.get(b'dry_run'):
3231 graftstate.delete()
3229 graftstate.delete()
3232
3230
3233 return 0
3231 return 0
3234
3232
3235
3233
3236 def _stopgraft(ui, repo, graftstate):
3234 def _stopgraft(ui, repo, graftstate):
3237 """stop the interrupted graft"""
3235 """stop the interrupted graft"""
3238 if not graftstate.exists():
3236 if not graftstate.exists():
3239 raise error.Abort(_(b"no interrupted graft found"))
3237 raise error.Abort(_(b"no interrupted graft found"))
3240 pctx = repo[b'.']
3238 pctx = repo[b'.']
3241 hg.updaterepo(repo, pctx.node(), overwrite=True)
3239 hg.updaterepo(repo, pctx.node(), overwrite=True)
3242 graftstate.delete()
3240 graftstate.delete()
3243 ui.status(_(b"stopped the interrupted graft\n"))
3241 ui.status(_(b"stopped the interrupted graft\n"))
3244 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3242 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3245 return 0
3243 return 0
3246
3244
3247
3245
3248 statemod.addunfinished(
3246 statemod.addunfinished(
3249 b'graft',
3247 b'graft',
3250 fname=b'graftstate',
3248 fname=b'graftstate',
3251 clearable=True,
3249 clearable=True,
3252 stopflag=True,
3250 stopflag=True,
3253 continueflag=True,
3251 continueflag=True,
3254 abortfunc=cmdutil.hgabortgraft,
3252 abortfunc=cmdutil.hgabortgraft,
3255 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3253 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3256 )
3254 )
3257
3255
3258
3256
3259 @command(
3257 @command(
3260 b'grep',
3258 b'grep',
3261 [
3259 [
3262 (b'0', b'print0', None, _(b'end fields with NUL')),
3260 (b'0', b'print0', None, _(b'end fields with NUL')),
3263 (b'', b'all', None, _(b'print all revisions that match (DEPRECATED) ')),
3261 (b'', b'all', None, _(b'print all revisions that match (DEPRECATED) ')),
3264 (
3262 (
3265 b'',
3263 b'',
3266 b'diff',
3264 b'diff',
3267 None,
3265 None,
3268 _(
3266 _(
3269 b'search revision differences for when the pattern was added '
3267 b'search revision differences for when the pattern was added '
3270 b'or removed'
3268 b'or removed'
3271 ),
3269 ),
3272 ),
3270 ),
3273 (b'a', b'text', None, _(b'treat all files as text')),
3271 (b'a', b'text', None, _(b'treat all files as text')),
3274 (
3272 (
3275 b'f',
3273 b'f',
3276 b'follow',
3274 b'follow',
3277 None,
3275 None,
3278 _(
3276 _(
3279 b'follow changeset history,'
3277 b'follow changeset history,'
3280 b' or file history across copies and renames'
3278 b' or file history across copies and renames'
3281 ),
3279 ),
3282 ),
3280 ),
3283 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3281 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3284 (
3282 (
3285 b'l',
3283 b'l',
3286 b'files-with-matches',
3284 b'files-with-matches',
3287 None,
3285 None,
3288 _(b'print only filenames and revisions that match'),
3286 _(b'print only filenames and revisions that match'),
3289 ),
3287 ),
3290 (b'n', b'line-number', None, _(b'print matching line numbers')),
3288 (b'n', b'line-number', None, _(b'print matching line numbers')),
3291 (
3289 (
3292 b'r',
3290 b'r',
3293 b'rev',
3291 b'rev',
3294 [],
3292 [],
3295 _(b'search files changed within revision range'),
3293 _(b'search files changed within revision range'),
3296 _(b'REV'),
3294 _(b'REV'),
3297 ),
3295 ),
3298 (
3296 (
3299 b'',
3297 b'',
3300 b'all-files',
3298 b'all-files',
3301 None,
3299 None,
3302 _(
3300 _(
3303 b'include all files in the changeset while grepping (DEPRECATED)'
3301 b'include all files in the changeset while grepping (DEPRECATED)'
3304 ),
3302 ),
3305 ),
3303 ),
3306 (b'u', b'user', None, _(b'list the author (long with -v)')),
3304 (b'u', b'user', None, _(b'list the author (long with -v)')),
3307 (b'd', b'date', None, _(b'list the date (short with -q)')),
3305 (b'd', b'date', None, _(b'list the date (short with -q)')),
3308 ]
3306 ]
3309 + formatteropts
3307 + formatteropts
3310 + walkopts,
3308 + walkopts,
3311 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3309 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3312 helpcategory=command.CATEGORY_FILE_CONTENTS,
3310 helpcategory=command.CATEGORY_FILE_CONTENTS,
3313 inferrepo=True,
3311 inferrepo=True,
3314 intents={INTENT_READONLY},
3312 intents={INTENT_READONLY},
3315 )
3313 )
3316 def grep(ui, repo, pattern, *pats, **opts):
3314 def grep(ui, repo, pattern, *pats, **opts):
3317 """search for a pattern in specified files
3315 """search for a pattern in specified files
3318
3316
3319 Search the working directory or revision history for a regular
3317 Search the working directory or revision history for a regular
3320 expression in the specified files for the entire repository.
3318 expression in the specified files for the entire repository.
3321
3319
3322 By default, grep searches the repository files in the working
3320 By default, grep searches the repository files in the working
3323 directory and prints the files where it finds a match. To specify
3321 directory and prints the files where it finds a match. To specify
3324 historical revisions instead of the working directory, use the
3322 historical revisions instead of the working directory, use the
3325 --rev flag.
3323 --rev flag.
3326
3324
3327 To search instead historical revision differences that contains a
3325 To search instead historical revision differences that contains a
3328 change in match status ("-" for a match that becomes a non-match,
3326 change in match status ("-" for a match that becomes a non-match,
3329 or "+" for a non-match that becomes a match), use the --diff flag.
3327 or "+" for a non-match that becomes a match), use the --diff flag.
3330
3328
3331 PATTERN can be any Python (roughly Perl-compatible) regular
3329 PATTERN can be any Python (roughly Perl-compatible) regular
3332 expression.
3330 expression.
3333
3331
3334 If no FILEs are specified and the --rev flag isn't supplied, all
3332 If no FILEs are specified and the --rev flag isn't supplied, all
3335 files in the working directory are searched. When using the --rev
3333 files in the working directory are searched. When using the --rev
3336 flag and specifying FILEs, use the --follow argument to also
3334 flag and specifying FILEs, use the --follow argument to also
3337 follow the specified FILEs across renames and copies.
3335 follow the specified FILEs across renames and copies.
3338
3336
3339 .. container:: verbose
3337 .. container:: verbose
3340
3338
3341 Template:
3339 Template:
3342
3340
3343 The following keywords are supported in addition to the common template
3341 The following keywords are supported in addition to the common template
3344 keywords and functions. See also :hg:`help templates`.
3342 keywords and functions. See also :hg:`help templates`.
3345
3343
3346 :change: String. Character denoting insertion ``+`` or removal ``-``.
3344 :change: String. Character denoting insertion ``+`` or removal ``-``.
3347 Available if ``--diff`` is specified.
3345 Available if ``--diff`` is specified.
3348 :lineno: Integer. Line number of the match.
3346 :lineno: Integer. Line number of the match.
3349 :path: String. Repository-absolute path of the file.
3347 :path: String. Repository-absolute path of the file.
3350 :texts: List of text chunks.
3348 :texts: List of text chunks.
3351
3349
3352 And each entry of ``{texts}`` provides the following sub-keywords.
3350 And each entry of ``{texts}`` provides the following sub-keywords.
3353
3351
3354 :matched: Boolean. True if the chunk matches the specified pattern.
3352 :matched: Boolean. True if the chunk matches the specified pattern.
3355 :text: String. Chunk content.
3353 :text: String. Chunk content.
3356
3354
3357 See :hg:`help templates.operators` for the list expansion syntax.
3355 See :hg:`help templates.operators` for the list expansion syntax.
3358
3356
3359 Returns 0 if a match is found, 1 otherwise.
3357 Returns 0 if a match is found, 1 otherwise.
3360
3358
3361 """
3359 """
3362 opts = pycompat.byteskwargs(opts)
3360 opts = pycompat.byteskwargs(opts)
3363 diff = opts.get(b'all') or opts.get(b'diff')
3361 diff = opts.get(b'all') or opts.get(b'diff')
3364 if diff and opts.get(b'all_files'):
3362 if diff and opts.get(b'all_files'):
3365 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3363 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3366 if opts.get(b'all_files') is None and not diff:
3364 if opts.get(b'all_files') is None and not diff:
3367 opts[b'all_files'] = True
3365 opts[b'all_files'] = True
3368 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3366 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3369 all_files = opts.get(b'all_files')
3367 all_files = opts.get(b'all_files')
3370 if plaingrep:
3368 if plaingrep:
3371 opts[b'rev'] = [b'wdir()']
3369 opts[b'rev'] = [b'wdir()']
3372
3370
3373 reflags = re.M
3371 reflags = re.M
3374 if opts.get(b'ignore_case'):
3372 if opts.get(b'ignore_case'):
3375 reflags |= re.I
3373 reflags |= re.I
3376 try:
3374 try:
3377 regexp = util.re.compile(pattern, reflags)
3375 regexp = util.re.compile(pattern, reflags)
3378 except re.error as inst:
3376 except re.error as inst:
3379 ui.warn(
3377 ui.warn(
3380 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3378 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3381 )
3379 )
3382 return 1
3380 return 1
3383 sep, eol = b':', b'\n'
3381 sep, eol = b':', b'\n'
3384 if opts.get(b'print0'):
3382 if opts.get(b'print0'):
3385 sep = eol = b'\0'
3383 sep = eol = b'\0'
3386
3384
3387 getfile = util.lrucachefunc(repo.file)
3385 getfile = util.lrucachefunc(repo.file)
3388
3386
3389 def matchlines(body):
3387 def matchlines(body):
3390 begin = 0
3388 begin = 0
3391 linenum = 0
3389 linenum = 0
3392 while begin < len(body):
3390 while begin < len(body):
3393 match = regexp.search(body, begin)
3391 match = regexp.search(body, begin)
3394 if not match:
3392 if not match:
3395 break
3393 break
3396 mstart, mend = match.span()
3394 mstart, mend = match.span()
3397 linenum += body.count(b'\n', begin, mstart) + 1
3395 linenum += body.count(b'\n', begin, mstart) + 1
3398 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3396 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3399 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3397 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3400 lend = begin - 1
3398 lend = begin - 1
3401 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3399 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3402
3400
3403 class linestate(object):
3401 class linestate(object):
3404 def __init__(self, line, linenum, colstart, colend):
3402 def __init__(self, line, linenum, colstart, colend):
3405 self.line = line
3403 self.line = line
3406 self.linenum = linenum
3404 self.linenum = linenum
3407 self.colstart = colstart
3405 self.colstart = colstart
3408 self.colend = colend
3406 self.colend = colend
3409
3407
3410 def __hash__(self):
3408 def __hash__(self):
3411 return hash((self.linenum, self.line))
3409 return hash((self.linenum, self.line))
3412
3410
3413 def __eq__(self, other):
3411 def __eq__(self, other):
3414 return self.line == other.line
3412 return self.line == other.line
3415
3413
3416 def findpos(self):
3414 def findpos(self):
3417 """Iterate all (start, end) indices of matches"""
3415 """Iterate all (start, end) indices of matches"""
3418 yield self.colstart, self.colend
3416 yield self.colstart, self.colend
3419 p = self.colend
3417 p = self.colend
3420 while p < len(self.line):
3418 while p < len(self.line):
3421 m = regexp.search(self.line, p)
3419 m = regexp.search(self.line, p)
3422 if not m:
3420 if not m:
3423 break
3421 break
3424 yield m.span()
3422 yield m.span()
3425 p = m.end()
3423 p = m.end()
3426
3424
3427 matches = {}
3425 matches = {}
3428 copies = {}
3426 copies = {}
3429
3427
3430 def grepbody(fn, rev, body):
3428 def grepbody(fn, rev, body):
3431 matches[rev].setdefault(fn, [])
3429 matches[rev].setdefault(fn, [])
3432 m = matches[rev][fn]
3430 m = matches[rev][fn]
3433 if body is None:
3431 if body is None:
3434 return
3432 return
3435
3433
3436 for lnum, cstart, cend, line in matchlines(body):
3434 for lnum, cstart, cend, line in matchlines(body):
3437 s = linestate(line, lnum, cstart, cend)
3435 s = linestate(line, lnum, cstart, cend)
3438 m.append(s)
3436 m.append(s)
3439
3437
3440 def difflinestates(a, b):
3438 def difflinestates(a, b):
3441 sm = difflib.SequenceMatcher(None, a, b)
3439 sm = difflib.SequenceMatcher(None, a, b)
3442 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3440 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3443 if tag == 'insert':
3441 if tag == 'insert':
3444 for i in pycompat.xrange(blo, bhi):
3442 for i in pycompat.xrange(blo, bhi):
3445 yield (b'+', b[i])
3443 yield (b'+', b[i])
3446 elif tag == 'delete':
3444 elif tag == 'delete':
3447 for i in pycompat.xrange(alo, ahi):
3445 for i in pycompat.xrange(alo, ahi):
3448 yield (b'-', a[i])
3446 yield (b'-', a[i])
3449 elif tag == 'replace':
3447 elif tag == 'replace':
3450 for i in pycompat.xrange(alo, ahi):
3448 for i in pycompat.xrange(alo, ahi):
3451 yield (b'-', a[i])
3449 yield (b'-', a[i])
3452 for i in pycompat.xrange(blo, bhi):
3450 for i in pycompat.xrange(blo, bhi):
3453 yield (b'+', b[i])
3451 yield (b'+', b[i])
3454
3452
3455 uipathfn = scmutil.getuipathfn(repo)
3453 uipathfn = scmutil.getuipathfn(repo)
3456
3454
3457 def display(fm, fn, ctx, pstates, states):
3455 def display(fm, fn, ctx, pstates, states):
3458 rev = scmutil.intrev(ctx)
3456 rev = scmutil.intrev(ctx)
3459 if fm.isplain():
3457 if fm.isplain():
3460 formatuser = ui.shortuser
3458 formatuser = ui.shortuser
3461 else:
3459 else:
3462 formatuser = pycompat.bytestr
3460 formatuser = pycompat.bytestr
3463 if ui.quiet:
3461 if ui.quiet:
3464 datefmt = b'%Y-%m-%d'
3462 datefmt = b'%Y-%m-%d'
3465 else:
3463 else:
3466 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3464 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3467 found = False
3465 found = False
3468
3466
3469 @util.cachefunc
3467 @util.cachefunc
3470 def binary():
3468 def binary():
3471 flog = getfile(fn)
3469 flog = getfile(fn)
3472 try:
3470 try:
3473 return stringutil.binary(flog.read(ctx.filenode(fn)))
3471 return stringutil.binary(flog.read(ctx.filenode(fn)))
3474 except error.WdirUnsupported:
3472 except error.WdirUnsupported:
3475 return ctx[fn].isbinary()
3473 return ctx[fn].isbinary()
3476
3474
3477 fieldnamemap = {b'linenumber': b'lineno'}
3475 fieldnamemap = {b'linenumber': b'lineno'}
3478 if diff:
3476 if diff:
3479 iter = difflinestates(pstates, states)
3477 iter = difflinestates(pstates, states)
3480 else:
3478 else:
3481 iter = [(b'', l) for l in states]
3479 iter = [(b'', l) for l in states]
3482 for change, l in iter:
3480 for change, l in iter:
3483 fm.startitem()
3481 fm.startitem()
3484 fm.context(ctx=ctx)
3482 fm.context(ctx=ctx)
3485 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3483 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3486 fm.plain(uipathfn(fn), label=b'grep.filename')
3484 fm.plain(uipathfn(fn), label=b'grep.filename')
3487
3485
3488 cols = [
3486 cols = [
3489 (b'rev', b'%d', rev, not plaingrep, b''),
3487 (b'rev', b'%d', rev, not plaingrep, b''),
3490 (
3488 (
3491 b'linenumber',
3489 b'linenumber',
3492 b'%d',
3490 b'%d',
3493 l.linenum,
3491 l.linenum,
3494 opts.get(b'line_number'),
3492 opts.get(b'line_number'),
3495 b'',
3493 b'',
3496 ),
3494 ),
3497 ]
3495 ]
3498 if diff:
3496 if diff:
3499 cols.append(
3497 cols.append(
3500 (
3498 (
3501 b'change',
3499 b'change',
3502 b'%s',
3500 b'%s',
3503 change,
3501 change,
3504 True,
3502 True,
3505 b'grep.inserted '
3503 b'grep.inserted '
3506 if change == b'+'
3504 if change == b'+'
3507 else b'grep.deleted ',
3505 else b'grep.deleted ',
3508 )
3506 )
3509 )
3507 )
3510 cols.extend(
3508 cols.extend(
3511 [
3509 [
3512 (
3510 (
3513 b'user',
3511 b'user',
3514 b'%s',
3512 b'%s',
3515 formatuser(ctx.user()),
3513 formatuser(ctx.user()),
3516 opts.get(b'user'),
3514 opts.get(b'user'),
3517 b'',
3515 b'',
3518 ),
3516 ),
3519 (
3517 (
3520 b'date',
3518 b'date',
3521 b'%s',
3519 b'%s',
3522 fm.formatdate(ctx.date(), datefmt),
3520 fm.formatdate(ctx.date(), datefmt),
3523 opts.get(b'date'),
3521 opts.get(b'date'),
3524 b'',
3522 b'',
3525 ),
3523 ),
3526 ]
3524 ]
3527 )
3525 )
3528 for name, fmt, data, cond, extra_label in cols:
3526 for name, fmt, data, cond, extra_label in cols:
3529 if cond:
3527 if cond:
3530 fm.plain(sep, label=b'grep.sep')
3528 fm.plain(sep, label=b'grep.sep')
3531 field = fieldnamemap.get(name, name)
3529 field = fieldnamemap.get(name, name)
3532 label = extra_label + (b'grep.%s' % name)
3530 label = extra_label + (b'grep.%s' % name)
3533 fm.condwrite(cond, field, fmt, data, label=label)
3531 fm.condwrite(cond, field, fmt, data, label=label)
3534 if not opts.get(b'files_with_matches'):
3532 if not opts.get(b'files_with_matches'):
3535 fm.plain(sep, label=b'grep.sep')
3533 fm.plain(sep, label=b'grep.sep')
3536 if not opts.get(b'text') and binary():
3534 if not opts.get(b'text') and binary():
3537 fm.plain(_(b" Binary file matches"))
3535 fm.plain(_(b" Binary file matches"))
3538 else:
3536 else:
3539 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3537 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3540 fm.plain(eol)
3538 fm.plain(eol)
3541 found = True
3539 found = True
3542 if opts.get(b'files_with_matches'):
3540 if opts.get(b'files_with_matches'):
3543 break
3541 break
3544 return found
3542 return found
3545
3543
3546 def displaymatches(fm, l):
3544 def displaymatches(fm, l):
3547 p = 0
3545 p = 0
3548 for s, e in l.findpos():
3546 for s, e in l.findpos():
3549 if p < s:
3547 if p < s:
3550 fm.startitem()
3548 fm.startitem()
3551 fm.write(b'text', b'%s', l.line[p:s])
3549 fm.write(b'text', b'%s', l.line[p:s])
3552 fm.data(matched=False)
3550 fm.data(matched=False)
3553 fm.startitem()
3551 fm.startitem()
3554 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3552 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3555 fm.data(matched=True)
3553 fm.data(matched=True)
3556 p = e
3554 p = e
3557 if p < len(l.line):
3555 if p < len(l.line):
3558 fm.startitem()
3556 fm.startitem()
3559 fm.write(b'text', b'%s', l.line[p:])
3557 fm.write(b'text', b'%s', l.line[p:])
3560 fm.data(matched=False)
3558 fm.data(matched=False)
3561 fm.end()
3559 fm.end()
3562
3560
3563 skip = set()
3561 skip = set()
3564 revfiles = {}
3562 revfiles = {}
3565 match = scmutil.match(repo[None], pats, opts)
3563 match = scmutil.match(repo[None], pats, opts)
3566 found = False
3564 found = False
3567 follow = opts.get(b'follow')
3565 follow = opts.get(b'follow')
3568
3566
3569 getrenamed = scmutil.getrenamedfn(repo)
3567 getrenamed = scmutil.getrenamedfn(repo)
3570
3568
3571 def get_file_content(filename, filelog, filenode, context, revision):
3569 def get_file_content(filename, filelog, filenode, context, revision):
3572 try:
3570 try:
3573 content = filelog.read(filenode)
3571 content = filelog.read(filenode)
3574 except error.WdirUnsupported:
3572 except error.WdirUnsupported:
3575 content = context[filename].data()
3573 content = context[filename].data()
3576 except error.CensoredNodeError:
3574 except error.CensoredNodeError:
3577 content = None
3575 content = None
3578 ui.warn(
3576 ui.warn(
3579 _(b'cannot search in censored file: %(filename)s:%(revnum)s\n')
3577 _(b'cannot search in censored file: %(filename)s:%(revnum)s\n')
3580 % {b'filename': filename, b'revnum': pycompat.bytestr(revision)}
3578 % {b'filename': filename, b'revnum': pycompat.bytestr(revision)}
3581 )
3579 )
3582 return content
3580 return content
3583
3581
3584 def prep(ctx, fns):
3582 def prep(ctx, fns):
3585 rev = ctx.rev()
3583 rev = ctx.rev()
3586 pctx = ctx.p1()
3584 pctx = ctx.p1()
3587 parent = pctx.rev()
3585 parent = pctx.rev()
3588 matches.setdefault(rev, {})
3586 matches.setdefault(rev, {})
3589 matches.setdefault(parent, {})
3587 matches.setdefault(parent, {})
3590 files = revfiles.setdefault(rev, [])
3588 files = revfiles.setdefault(rev, [])
3591 for fn in fns:
3589 for fn in fns:
3592 flog = getfile(fn)
3590 flog = getfile(fn)
3593 try:
3591 try:
3594 fnode = ctx.filenode(fn)
3592 fnode = ctx.filenode(fn)
3595 except error.LookupError:
3593 except error.LookupError:
3596 continue
3594 continue
3597
3595
3598 copy = None
3596 copy = None
3599 if follow:
3597 if follow:
3600 copy = getrenamed(fn, rev)
3598 copy = getrenamed(fn, rev)
3601 if copy:
3599 if copy:
3602 copies.setdefault(rev, {})[fn] = copy
3600 copies.setdefault(rev, {})[fn] = copy
3603 if fn in skip:
3601 if fn in skip:
3604 skip.add(copy)
3602 skip.add(copy)
3605 if fn in skip:
3603 if fn in skip:
3606 continue
3604 continue
3607 files.append(fn)
3605 files.append(fn)
3608
3606
3609 if fn not in matches[rev]:
3607 if fn not in matches[rev]:
3610 content = get_file_content(fn, flog, fnode, ctx, rev)
3608 content = get_file_content(fn, flog, fnode, ctx, rev)
3611 grepbody(fn, rev, content)
3609 grepbody(fn, rev, content)
3612
3610
3613 pfn = copy or fn
3611 pfn = copy or fn
3614 if pfn not in matches[parent]:
3612 if pfn not in matches[parent]:
3615 try:
3613 try:
3616 pfnode = pctx.filenode(pfn)
3614 pfnode = pctx.filenode(pfn)
3617 pcontent = get_file_content(pfn, flog, pfnode, pctx, parent)
3615 pcontent = get_file_content(pfn, flog, pfnode, pctx, parent)
3618 grepbody(pfn, parent, pcontent)
3616 grepbody(pfn, parent, pcontent)
3619 except error.LookupError:
3617 except error.LookupError:
3620 pass
3618 pass
3621
3619
3622 ui.pager(b'grep')
3620 ui.pager(b'grep')
3623 fm = ui.formatter(b'grep', opts)
3621 fm = ui.formatter(b'grep', opts)
3624 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3622 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3625 rev = ctx.rev()
3623 rev = ctx.rev()
3626 parent = ctx.p1().rev()
3624 parent = ctx.p1().rev()
3627 for fn in sorted(revfiles.get(rev, [])):
3625 for fn in sorted(revfiles.get(rev, [])):
3628 states = matches[rev][fn]
3626 states = matches[rev][fn]
3629 copy = copies.get(rev, {}).get(fn)
3627 copy = copies.get(rev, {}).get(fn)
3630 if fn in skip:
3628 if fn in skip:
3631 if copy:
3629 if copy:
3632 skip.add(copy)
3630 skip.add(copy)
3633 continue
3631 continue
3634 pstates = matches.get(parent, {}).get(copy or fn, [])
3632 pstates = matches.get(parent, {}).get(copy or fn, [])
3635 if pstates or states:
3633 if pstates or states:
3636 r = display(fm, fn, ctx, pstates, states)
3634 r = display(fm, fn, ctx, pstates, states)
3637 found = found or r
3635 found = found or r
3638 if r and not diff and not all_files:
3636 if r and not diff and not all_files:
3639 skip.add(fn)
3637 skip.add(fn)
3640 if copy:
3638 if copy:
3641 skip.add(copy)
3639 skip.add(copy)
3642 del revfiles[rev]
3640 del revfiles[rev]
3643 # We will keep the matches dict for the duration of the window
3641 # We will keep the matches dict for the duration of the window
3644 # clear the matches dict once the window is over
3642 # clear the matches dict once the window is over
3645 if not revfiles:
3643 if not revfiles:
3646 matches.clear()
3644 matches.clear()
3647 fm.end()
3645 fm.end()
3648
3646
3649 return not found
3647 return not found
3650
3648
3651
3649
3652 @command(
3650 @command(
3653 b'heads',
3651 b'heads',
3654 [
3652 [
3655 (
3653 (
3656 b'r',
3654 b'r',
3657 b'rev',
3655 b'rev',
3658 b'',
3656 b'',
3659 _(b'show only heads which are descendants of STARTREV'),
3657 _(b'show only heads which are descendants of STARTREV'),
3660 _(b'STARTREV'),
3658 _(b'STARTREV'),
3661 ),
3659 ),
3662 (b't', b'topo', False, _(b'show topological heads only')),
3660 (b't', b'topo', False, _(b'show topological heads only')),
3663 (
3661 (
3664 b'a',
3662 b'a',
3665 b'active',
3663 b'active',
3666 False,
3664 False,
3667 _(b'show active branchheads only (DEPRECATED)'),
3665 _(b'show active branchheads only (DEPRECATED)'),
3668 ),
3666 ),
3669 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3667 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3670 ]
3668 ]
3671 + templateopts,
3669 + templateopts,
3672 _(b'[-ct] [-r STARTREV] [REV]...'),
3670 _(b'[-ct] [-r STARTREV] [REV]...'),
3673 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3671 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3674 intents={INTENT_READONLY},
3672 intents={INTENT_READONLY},
3675 )
3673 )
3676 def heads(ui, repo, *branchrevs, **opts):
3674 def heads(ui, repo, *branchrevs, **opts):
3677 """show branch heads
3675 """show branch heads
3678
3676
3679 With no arguments, show all open branch heads in the repository.
3677 With no arguments, show all open branch heads in the repository.
3680 Branch heads are changesets that have no descendants on the
3678 Branch heads are changesets that have no descendants on the
3681 same branch. They are where development generally takes place and
3679 same branch. They are where development generally takes place and
3682 are the usual targets for update and merge operations.
3680 are the usual targets for update and merge operations.
3683
3681
3684 If one or more REVs are given, only open branch heads on the
3682 If one or more REVs are given, only open branch heads on the
3685 branches associated with the specified changesets are shown. This
3683 branches associated with the specified changesets are shown. This
3686 means that you can use :hg:`heads .` to see the heads on the
3684 means that you can use :hg:`heads .` to see the heads on the
3687 currently checked-out branch.
3685 currently checked-out branch.
3688
3686
3689 If -c/--closed is specified, also show branch heads marked closed
3687 If -c/--closed is specified, also show branch heads marked closed
3690 (see :hg:`commit --close-branch`).
3688 (see :hg:`commit --close-branch`).
3691
3689
3692 If STARTREV is specified, only those heads that are descendants of
3690 If STARTREV is specified, only those heads that are descendants of
3693 STARTREV will be displayed.
3691 STARTREV will be displayed.
3694
3692
3695 If -t/--topo is specified, named branch mechanics will be ignored and only
3693 If -t/--topo is specified, named branch mechanics will be ignored and only
3696 topological heads (changesets with no children) will be shown.
3694 topological heads (changesets with no children) will be shown.
3697
3695
3698 Returns 0 if matching heads are found, 1 if not.
3696 Returns 0 if matching heads are found, 1 if not.
3699 """
3697 """
3700
3698
3701 opts = pycompat.byteskwargs(opts)
3699 opts = pycompat.byteskwargs(opts)
3702 start = None
3700 start = None
3703 rev = opts.get(b'rev')
3701 rev = opts.get(b'rev')
3704 if rev:
3702 if rev:
3705 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3703 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3706 start = scmutil.revsingle(repo, rev, None).node()
3704 start = scmutil.revsingle(repo, rev, None).node()
3707
3705
3708 if opts.get(b'topo'):
3706 if opts.get(b'topo'):
3709 heads = [repo[h] for h in repo.heads(start)]
3707 heads = [repo[h] for h in repo.heads(start)]
3710 else:
3708 else:
3711 heads = []
3709 heads = []
3712 for branch in repo.branchmap():
3710 for branch in repo.branchmap():
3713 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3711 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3714 heads = [repo[h] for h in heads]
3712 heads = [repo[h] for h in heads]
3715
3713
3716 if branchrevs:
3714 if branchrevs:
3717 branches = set(
3715 branches = set(
3718 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3716 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3719 )
3717 )
3720 heads = [h for h in heads if h.branch() in branches]
3718 heads = [h for h in heads if h.branch() in branches]
3721
3719
3722 if opts.get(b'active') and branchrevs:
3720 if opts.get(b'active') and branchrevs:
3723 dagheads = repo.heads(start)
3721 dagheads = repo.heads(start)
3724 heads = [h for h in heads if h.node() in dagheads]
3722 heads = [h for h in heads if h.node() in dagheads]
3725
3723
3726 if branchrevs:
3724 if branchrevs:
3727 haveheads = set(h.branch() for h in heads)
3725 haveheads = set(h.branch() for h in heads)
3728 if branches - haveheads:
3726 if branches - haveheads:
3729 headless = b', '.join(b for b in branches - haveheads)
3727 headless = b', '.join(b for b in branches - haveheads)
3730 msg = _(b'no open branch heads found on branches %s')
3728 msg = _(b'no open branch heads found on branches %s')
3731 if opts.get(b'rev'):
3729 if opts.get(b'rev'):
3732 msg += _(b' (started at %s)') % opts[b'rev']
3730 msg += _(b' (started at %s)') % opts[b'rev']
3733 ui.warn((msg + b'\n') % headless)
3731 ui.warn((msg + b'\n') % headless)
3734
3732
3735 if not heads:
3733 if not heads:
3736 return 1
3734 return 1
3737
3735
3738 ui.pager(b'heads')
3736 ui.pager(b'heads')
3739 heads = sorted(heads, key=lambda x: -(x.rev()))
3737 heads = sorted(heads, key=lambda x: -(x.rev()))
3740 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3738 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3741 for ctx in heads:
3739 for ctx in heads:
3742 displayer.show(ctx)
3740 displayer.show(ctx)
3743 displayer.close()
3741 displayer.close()
3744
3742
3745
3743
3746 @command(
3744 @command(
3747 b'help',
3745 b'help',
3748 [
3746 [
3749 (b'e', b'extension', None, _(b'show only help for extensions')),
3747 (b'e', b'extension', None, _(b'show only help for extensions')),
3750 (b'c', b'command', None, _(b'show only help for commands')),
3748 (b'c', b'command', None, _(b'show only help for commands')),
3751 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3749 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3752 (
3750 (
3753 b's',
3751 b's',
3754 b'system',
3752 b'system',
3755 [],
3753 [],
3756 _(b'show help for specific platform(s)'),
3754 _(b'show help for specific platform(s)'),
3757 _(b'PLATFORM'),
3755 _(b'PLATFORM'),
3758 ),
3756 ),
3759 ],
3757 ],
3760 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3758 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3761 helpcategory=command.CATEGORY_HELP,
3759 helpcategory=command.CATEGORY_HELP,
3762 norepo=True,
3760 norepo=True,
3763 intents={INTENT_READONLY},
3761 intents={INTENT_READONLY},
3764 )
3762 )
3765 def help_(ui, name=None, **opts):
3763 def help_(ui, name=None, **opts):
3766 """show help for a given topic or a help overview
3764 """show help for a given topic or a help overview
3767
3765
3768 With no arguments, print a list of commands with short help messages.
3766 With no arguments, print a list of commands with short help messages.
3769
3767
3770 Given a topic, extension, or command name, print help for that
3768 Given a topic, extension, or command name, print help for that
3771 topic.
3769 topic.
3772
3770
3773 Returns 0 if successful.
3771 Returns 0 if successful.
3774 """
3772 """
3775
3773
3776 keep = opts.get('system') or []
3774 keep = opts.get('system') or []
3777 if len(keep) == 0:
3775 if len(keep) == 0:
3778 if pycompat.sysplatform.startswith(b'win'):
3776 if pycompat.sysplatform.startswith(b'win'):
3779 keep.append(b'windows')
3777 keep.append(b'windows')
3780 elif pycompat.sysplatform == b'OpenVMS':
3778 elif pycompat.sysplatform == b'OpenVMS':
3781 keep.append(b'vms')
3779 keep.append(b'vms')
3782 elif pycompat.sysplatform == b'plan9':
3780 elif pycompat.sysplatform == b'plan9':
3783 keep.append(b'plan9')
3781 keep.append(b'plan9')
3784 else:
3782 else:
3785 keep.append(b'unix')
3783 keep.append(b'unix')
3786 keep.append(pycompat.sysplatform.lower())
3784 keep.append(pycompat.sysplatform.lower())
3787 if ui.verbose:
3785 if ui.verbose:
3788 keep.append(b'verbose')
3786 keep.append(b'verbose')
3789
3787
3790 commands = sys.modules[__name__]
3788 commands = sys.modules[__name__]
3791 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3789 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3792 ui.pager(b'help')
3790 ui.pager(b'help')
3793 ui.write(formatted)
3791 ui.write(formatted)
3794
3792
3795
3793
3796 @command(
3794 @command(
3797 b'identify|id',
3795 b'identify|id',
3798 [
3796 [
3799 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3797 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3800 (b'n', b'num', None, _(b'show local revision number')),
3798 (b'n', b'num', None, _(b'show local revision number')),
3801 (b'i', b'id', None, _(b'show global revision id')),
3799 (b'i', b'id', None, _(b'show global revision id')),
3802 (b'b', b'branch', None, _(b'show branch')),
3800 (b'b', b'branch', None, _(b'show branch')),
3803 (b't', b'tags', None, _(b'show tags')),
3801 (b't', b'tags', None, _(b'show tags')),
3804 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3802 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3805 ]
3803 ]
3806 + remoteopts
3804 + remoteopts
3807 + formatteropts,
3805 + formatteropts,
3808 _(b'[-nibtB] [-r REV] [SOURCE]'),
3806 _(b'[-nibtB] [-r REV] [SOURCE]'),
3809 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3807 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3810 optionalrepo=True,
3808 optionalrepo=True,
3811 intents={INTENT_READONLY},
3809 intents={INTENT_READONLY},
3812 )
3810 )
3813 def identify(
3811 def identify(
3814 ui,
3812 ui,
3815 repo,
3813 repo,
3816 source=None,
3814 source=None,
3817 rev=None,
3815 rev=None,
3818 num=None,
3816 num=None,
3819 id=None,
3817 id=None,
3820 branch=None,
3818 branch=None,
3821 tags=None,
3819 tags=None,
3822 bookmarks=None,
3820 bookmarks=None,
3823 **opts
3821 **opts
3824 ):
3822 ):
3825 """identify the working directory or specified revision
3823 """identify the working directory or specified revision
3826
3824
3827 Print a summary identifying the repository state at REV using one or
3825 Print a summary identifying the repository state at REV using one or
3828 two parent hash identifiers, followed by a "+" if the working
3826 two parent hash identifiers, followed by a "+" if the working
3829 directory has uncommitted changes, the branch name (if not default),
3827 directory has uncommitted changes, the branch name (if not default),
3830 a list of tags, and a list of bookmarks.
3828 a list of tags, and a list of bookmarks.
3831
3829
3832 When REV is not given, print a summary of the current state of the
3830 When REV is not given, print a summary of the current state of the
3833 repository including the working directory. Specify -r. to get information
3831 repository including the working directory. Specify -r. to get information
3834 of the working directory parent without scanning uncommitted changes.
3832 of the working directory parent without scanning uncommitted changes.
3835
3833
3836 Specifying a path to a repository root or Mercurial bundle will
3834 Specifying a path to a repository root or Mercurial bundle will
3837 cause lookup to operate on that repository/bundle.
3835 cause lookup to operate on that repository/bundle.
3838
3836
3839 .. container:: verbose
3837 .. container:: verbose
3840
3838
3841 Template:
3839 Template:
3842
3840
3843 The following keywords are supported in addition to the common template
3841 The following keywords are supported in addition to the common template
3844 keywords and functions. See also :hg:`help templates`.
3842 keywords and functions. See also :hg:`help templates`.
3845
3843
3846 :dirty: String. Character ``+`` denoting if the working directory has
3844 :dirty: String. Character ``+`` denoting if the working directory has
3847 uncommitted changes.
3845 uncommitted changes.
3848 :id: String. One or two nodes, optionally followed by ``+``.
3846 :id: String. One or two nodes, optionally followed by ``+``.
3849 :parents: List of strings. Parent nodes of the changeset.
3847 :parents: List of strings. Parent nodes of the changeset.
3850
3848
3851 Examples:
3849 Examples:
3852
3850
3853 - generate a build identifier for the working directory::
3851 - generate a build identifier for the working directory::
3854
3852
3855 hg id --id > build-id.dat
3853 hg id --id > build-id.dat
3856
3854
3857 - find the revision corresponding to a tag::
3855 - find the revision corresponding to a tag::
3858
3856
3859 hg id -n -r 1.3
3857 hg id -n -r 1.3
3860
3858
3861 - check the most recent revision of a remote repository::
3859 - check the most recent revision of a remote repository::
3862
3860
3863 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3861 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3864
3862
3865 See :hg:`log` for generating more information about specific revisions,
3863 See :hg:`log` for generating more information about specific revisions,
3866 including full hash identifiers.
3864 including full hash identifiers.
3867
3865
3868 Returns 0 if successful.
3866 Returns 0 if successful.
3869 """
3867 """
3870
3868
3871 opts = pycompat.byteskwargs(opts)
3869 opts = pycompat.byteskwargs(opts)
3872 if not repo and not source:
3870 if not repo and not source:
3873 raise error.Abort(
3871 raise error.Abort(
3874 _(b"there is no Mercurial repository here (.hg not found)")
3872 _(b"there is no Mercurial repository here (.hg not found)")
3875 )
3873 )
3876
3874
3877 default = not (num or id or branch or tags or bookmarks)
3875 default = not (num or id or branch or tags or bookmarks)
3878 output = []
3876 output = []
3879 revs = []
3877 revs = []
3880
3878
3881 if source:
3879 if source:
3882 source, branches = hg.parseurl(ui.expandpath(source))
3880 source, branches = hg.parseurl(ui.expandpath(source))
3883 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3881 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3884 repo = peer.local()
3882 repo = peer.local()
3885 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3883 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3886
3884
3887 fm = ui.formatter(b'identify', opts)
3885 fm = ui.formatter(b'identify', opts)
3888 fm.startitem()
3886 fm.startitem()
3889
3887
3890 if not repo:
3888 if not repo:
3891 if num or branch or tags:
3889 if num or branch or tags:
3892 raise error.Abort(
3890 raise error.Abort(
3893 _(b"can't query remote revision number, branch, or tags")
3891 _(b"can't query remote revision number, branch, or tags")
3894 )
3892 )
3895 if not rev and revs:
3893 if not rev and revs:
3896 rev = revs[0]
3894 rev = revs[0]
3897 if not rev:
3895 if not rev:
3898 rev = b"tip"
3896 rev = b"tip"
3899
3897
3900 remoterev = peer.lookup(rev)
3898 remoterev = peer.lookup(rev)
3901 hexrev = fm.hexfunc(remoterev)
3899 hexrev = fm.hexfunc(remoterev)
3902 if default or id:
3900 if default or id:
3903 output = [hexrev]
3901 output = [hexrev]
3904 fm.data(id=hexrev)
3902 fm.data(id=hexrev)
3905
3903
3906 @util.cachefunc
3904 @util.cachefunc
3907 def getbms():
3905 def getbms():
3908 bms = []
3906 bms = []
3909
3907
3910 if b'bookmarks' in peer.listkeys(b'namespaces'):
3908 if b'bookmarks' in peer.listkeys(b'namespaces'):
3911 hexremoterev = hex(remoterev)
3909 hexremoterev = hex(remoterev)
3912 bms = [
3910 bms = [
3913 bm
3911 bm
3914 for bm, bmr in pycompat.iteritems(
3912 for bm, bmr in pycompat.iteritems(
3915 peer.listkeys(b'bookmarks')
3913 peer.listkeys(b'bookmarks')
3916 )
3914 )
3917 if bmr == hexremoterev
3915 if bmr == hexremoterev
3918 ]
3916 ]
3919
3917
3920 return sorted(bms)
3918 return sorted(bms)
3921
3919
3922 if fm.isplain():
3920 if fm.isplain():
3923 if bookmarks:
3921 if bookmarks:
3924 output.extend(getbms())
3922 output.extend(getbms())
3925 elif default and not ui.quiet:
3923 elif default and not ui.quiet:
3926 # multiple bookmarks for a single parent separated by '/'
3924 # multiple bookmarks for a single parent separated by '/'
3927 bm = b'/'.join(getbms())
3925 bm = b'/'.join(getbms())
3928 if bm:
3926 if bm:
3929 output.append(bm)
3927 output.append(bm)
3930 else:
3928 else:
3931 fm.data(node=hex(remoterev))
3929 fm.data(node=hex(remoterev))
3932 if bookmarks or b'bookmarks' in fm.datahint():
3930 if bookmarks or b'bookmarks' in fm.datahint():
3933 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3931 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3934 else:
3932 else:
3935 if rev:
3933 if rev:
3936 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3934 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3937 ctx = scmutil.revsingle(repo, rev, None)
3935 ctx = scmutil.revsingle(repo, rev, None)
3938
3936
3939 if ctx.rev() is None:
3937 if ctx.rev() is None:
3940 ctx = repo[None]
3938 ctx = repo[None]
3941 parents = ctx.parents()
3939 parents = ctx.parents()
3942 taglist = []
3940 taglist = []
3943 for p in parents:
3941 for p in parents:
3944 taglist.extend(p.tags())
3942 taglist.extend(p.tags())
3945
3943
3946 dirty = b""
3944 dirty = b""
3947 if ctx.dirty(missing=True, merge=False, branch=False):
3945 if ctx.dirty(missing=True, merge=False, branch=False):
3948 dirty = b'+'
3946 dirty = b'+'
3949 fm.data(dirty=dirty)
3947 fm.data(dirty=dirty)
3950
3948
3951 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3949 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3952 if default or id:
3950 if default or id:
3953 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3951 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3954 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3952 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3955
3953
3956 if num:
3954 if num:
3957 numoutput = [b"%d" % p.rev() for p in parents]
3955 numoutput = [b"%d" % p.rev() for p in parents]
3958 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3956 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3959
3957
3960 fm.data(
3958 fm.data(
3961 parents=fm.formatlist(
3959 parents=fm.formatlist(
3962 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3960 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3963 )
3961 )
3964 )
3962 )
3965 else:
3963 else:
3966 hexoutput = fm.hexfunc(ctx.node())
3964 hexoutput = fm.hexfunc(ctx.node())
3967 if default or id:
3965 if default or id:
3968 output = [hexoutput]
3966 output = [hexoutput]
3969 fm.data(id=hexoutput)
3967 fm.data(id=hexoutput)
3970
3968
3971 if num:
3969 if num:
3972 output.append(pycompat.bytestr(ctx.rev()))
3970 output.append(pycompat.bytestr(ctx.rev()))
3973 taglist = ctx.tags()
3971 taglist = ctx.tags()
3974
3972
3975 if default and not ui.quiet:
3973 if default and not ui.quiet:
3976 b = ctx.branch()
3974 b = ctx.branch()
3977 if b != b'default':
3975 if b != b'default':
3978 output.append(b"(%s)" % b)
3976 output.append(b"(%s)" % b)
3979
3977
3980 # multiple tags for a single parent separated by '/'
3978 # multiple tags for a single parent separated by '/'
3981 t = b'/'.join(taglist)
3979 t = b'/'.join(taglist)
3982 if t:
3980 if t:
3983 output.append(t)
3981 output.append(t)
3984
3982
3985 # multiple bookmarks for a single parent separated by '/'
3983 # multiple bookmarks for a single parent separated by '/'
3986 bm = b'/'.join(ctx.bookmarks())
3984 bm = b'/'.join(ctx.bookmarks())
3987 if bm:
3985 if bm:
3988 output.append(bm)
3986 output.append(bm)
3989 else:
3987 else:
3990 if branch:
3988 if branch:
3991 output.append(ctx.branch())
3989 output.append(ctx.branch())
3992
3990
3993 if tags:
3991 if tags:
3994 output.extend(taglist)
3992 output.extend(taglist)
3995
3993
3996 if bookmarks:
3994 if bookmarks:
3997 output.extend(ctx.bookmarks())
3995 output.extend(ctx.bookmarks())
3998
3996
3999 fm.data(node=ctx.hex())
3997 fm.data(node=ctx.hex())
4000 fm.data(branch=ctx.branch())
3998 fm.data(branch=ctx.branch())
4001 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3999 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4002 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4000 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4003 fm.context(ctx=ctx)
4001 fm.context(ctx=ctx)
4004
4002
4005 fm.plain(b"%s\n" % b' '.join(output))
4003 fm.plain(b"%s\n" % b' '.join(output))
4006 fm.end()
4004 fm.end()
4007
4005
4008
4006
4009 @command(
4007 @command(
4010 b'import|patch',
4008 b'import|patch',
4011 [
4009 [
4012 (
4010 (
4013 b'p',
4011 b'p',
4014 b'strip',
4012 b'strip',
4015 1,
4013 1,
4016 _(
4014 _(
4017 b'directory strip option for patch. This has the same '
4015 b'directory strip option for patch. This has the same '
4018 b'meaning as the corresponding patch option'
4016 b'meaning as the corresponding patch option'
4019 ),
4017 ),
4020 _(b'NUM'),
4018 _(b'NUM'),
4021 ),
4019 ),
4022 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4020 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4023 (b'', b'secret', None, _(b'use the secret phase for committing')),
4021 (b'', b'secret', None, _(b'use the secret phase for committing')),
4024 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4022 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4025 (
4023 (
4026 b'f',
4024 b'f',
4027 b'force',
4025 b'force',
4028 None,
4026 None,
4029 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4027 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4030 ),
4028 ),
4031 (
4029 (
4032 b'',
4030 b'',
4033 b'no-commit',
4031 b'no-commit',
4034 None,
4032 None,
4035 _(b"don't commit, just update the working directory"),
4033 _(b"don't commit, just update the working directory"),
4036 ),
4034 ),
4037 (
4035 (
4038 b'',
4036 b'',
4039 b'bypass',
4037 b'bypass',
4040 None,
4038 None,
4041 _(b"apply patch without touching the working directory"),
4039 _(b"apply patch without touching the working directory"),
4042 ),
4040 ),
4043 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4041 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4044 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4042 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4045 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4043 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4046 (
4044 (
4047 b'',
4045 b'',
4048 b'import-branch',
4046 b'import-branch',
4049 None,
4047 None,
4050 _(b'use any branch information in patch (implied by --exact)'),
4048 _(b'use any branch information in patch (implied by --exact)'),
4051 ),
4049 ),
4052 ]
4050 ]
4053 + commitopts
4051 + commitopts
4054 + commitopts2
4052 + commitopts2
4055 + similarityopts,
4053 + similarityopts,
4056 _(b'[OPTION]... PATCH...'),
4054 _(b'[OPTION]... PATCH...'),
4057 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4055 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4058 )
4056 )
4059 def import_(ui, repo, patch1=None, *patches, **opts):
4057 def import_(ui, repo, patch1=None, *patches, **opts):
4060 """import an ordered set of patches
4058 """import an ordered set of patches
4061
4059
4062 Import a list of patches and commit them individually (unless
4060 Import a list of patches and commit them individually (unless
4063 --no-commit is specified).
4061 --no-commit is specified).
4064
4062
4065 To read a patch from standard input (stdin), use "-" as the patch
4063 To read a patch from standard input (stdin), use "-" as the patch
4066 name. If a URL is specified, the patch will be downloaded from
4064 name. If a URL is specified, the patch will be downloaded from
4067 there.
4065 there.
4068
4066
4069 Import first applies changes to the working directory (unless
4067 Import first applies changes to the working directory (unless
4070 --bypass is specified), import will abort if there are outstanding
4068 --bypass is specified), import will abort if there are outstanding
4071 changes.
4069 changes.
4072
4070
4073 Use --bypass to apply and commit patches directly to the
4071 Use --bypass to apply and commit patches directly to the
4074 repository, without affecting the working directory. Without
4072 repository, without affecting the working directory. Without
4075 --exact, patches will be applied on top of the working directory
4073 --exact, patches will be applied on top of the working directory
4076 parent revision.
4074 parent revision.
4077
4075
4078 You can import a patch straight from a mail message. Even patches
4076 You can import a patch straight from a mail message. Even patches
4079 as attachments work (to use the body part, it must have type
4077 as attachments work (to use the body part, it must have type
4080 text/plain or text/x-patch). From and Subject headers of email
4078 text/plain or text/x-patch). From and Subject headers of email
4081 message are used as default committer and commit message. All
4079 message are used as default committer and commit message. All
4082 text/plain body parts before first diff are added to the commit
4080 text/plain body parts before first diff are added to the commit
4083 message.
4081 message.
4084
4082
4085 If the imported patch was generated by :hg:`export`, user and
4083 If the imported patch was generated by :hg:`export`, user and
4086 description from patch override values from message headers and
4084 description from patch override values from message headers and
4087 body. Values given on command line with -m/--message and -u/--user
4085 body. Values given on command line with -m/--message and -u/--user
4088 override these.
4086 override these.
4089
4087
4090 If --exact is specified, import will set the working directory to
4088 If --exact is specified, import will set the working directory to
4091 the parent of each patch before applying it, and will abort if the
4089 the parent of each patch before applying it, and will abort if the
4092 resulting changeset has a different ID than the one recorded in
4090 resulting changeset has a different ID than the one recorded in
4093 the patch. This will guard against various ways that portable
4091 the patch. This will guard against various ways that portable
4094 patch formats and mail systems might fail to transfer Mercurial
4092 patch formats and mail systems might fail to transfer Mercurial
4095 data or metadata. See :hg:`bundle` for lossless transmission.
4093 data or metadata. See :hg:`bundle` for lossless transmission.
4096
4094
4097 Use --partial to ensure a changeset will be created from the patch
4095 Use --partial to ensure a changeset will be created from the patch
4098 even if some hunks fail to apply. Hunks that fail to apply will be
4096 even if some hunks fail to apply. Hunks that fail to apply will be
4099 written to a <target-file>.rej file. Conflicts can then be resolved
4097 written to a <target-file>.rej file. Conflicts can then be resolved
4100 by hand before :hg:`commit --amend` is run to update the created
4098 by hand before :hg:`commit --amend` is run to update the created
4101 changeset. This flag exists to let people import patches that
4099 changeset. This flag exists to let people import patches that
4102 partially apply without losing the associated metadata (author,
4100 partially apply without losing the associated metadata (author,
4103 date, description, ...).
4101 date, description, ...).
4104
4102
4105 .. note::
4103 .. note::
4106
4104
4107 When no hunks apply cleanly, :hg:`import --partial` will create
4105 When no hunks apply cleanly, :hg:`import --partial` will create
4108 an empty changeset, importing only the patch metadata.
4106 an empty changeset, importing only the patch metadata.
4109
4107
4110 With -s/--similarity, hg will attempt to discover renames and
4108 With -s/--similarity, hg will attempt to discover renames and
4111 copies in the patch in the same way as :hg:`addremove`.
4109 copies in the patch in the same way as :hg:`addremove`.
4112
4110
4113 It is possible to use external patch programs to perform the patch
4111 It is possible to use external patch programs to perform the patch
4114 by setting the ``ui.patch`` configuration option. For the default
4112 by setting the ``ui.patch`` configuration option. For the default
4115 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4113 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4116 See :hg:`help config` for more information about configuration
4114 See :hg:`help config` for more information about configuration
4117 files and how to use these options.
4115 files and how to use these options.
4118
4116
4119 See :hg:`help dates` for a list of formats valid for -d/--date.
4117 See :hg:`help dates` for a list of formats valid for -d/--date.
4120
4118
4121 .. container:: verbose
4119 .. container:: verbose
4122
4120
4123 Examples:
4121 Examples:
4124
4122
4125 - import a traditional patch from a website and detect renames::
4123 - import a traditional patch from a website and detect renames::
4126
4124
4127 hg import -s 80 http://example.com/bugfix.patch
4125 hg import -s 80 http://example.com/bugfix.patch
4128
4126
4129 - import a changeset from an hgweb server::
4127 - import a changeset from an hgweb server::
4130
4128
4131 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4129 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4132
4130
4133 - import all the patches in an Unix-style mbox::
4131 - import all the patches in an Unix-style mbox::
4134
4132
4135 hg import incoming-patches.mbox
4133 hg import incoming-patches.mbox
4136
4134
4137 - import patches from stdin::
4135 - import patches from stdin::
4138
4136
4139 hg import -
4137 hg import -
4140
4138
4141 - attempt to exactly restore an exported changeset (not always
4139 - attempt to exactly restore an exported changeset (not always
4142 possible)::
4140 possible)::
4143
4141
4144 hg import --exact proposed-fix.patch
4142 hg import --exact proposed-fix.patch
4145
4143
4146 - use an external tool to apply a patch which is too fuzzy for
4144 - use an external tool to apply a patch which is too fuzzy for
4147 the default internal tool.
4145 the default internal tool.
4148
4146
4149 hg import --config ui.patch="patch --merge" fuzzy.patch
4147 hg import --config ui.patch="patch --merge" fuzzy.patch
4150
4148
4151 - change the default fuzzing from 2 to a less strict 7
4149 - change the default fuzzing from 2 to a less strict 7
4152
4150
4153 hg import --config ui.fuzz=7 fuzz.patch
4151 hg import --config ui.fuzz=7 fuzz.patch
4154
4152
4155 Returns 0 on success, 1 on partial success (see --partial).
4153 Returns 0 on success, 1 on partial success (see --partial).
4156 """
4154 """
4157
4155
4158 opts = pycompat.byteskwargs(opts)
4156 opts = pycompat.byteskwargs(opts)
4159 if not patch1:
4157 if not patch1:
4160 raise error.Abort(_(b'need at least one patch to import'))
4158 raise error.Abort(_(b'need at least one patch to import'))
4161
4159
4162 patches = (patch1,) + patches
4160 patches = (patch1,) + patches
4163
4161
4164 date = opts.get(b'date')
4162 date = opts.get(b'date')
4165 if date:
4163 if date:
4166 opts[b'date'] = dateutil.parsedate(date)
4164 opts[b'date'] = dateutil.parsedate(date)
4167
4165
4168 exact = opts.get(b'exact')
4166 exact = opts.get(b'exact')
4169 update = not opts.get(b'bypass')
4167 update = not opts.get(b'bypass')
4170 if not update and opts.get(b'no_commit'):
4168 if not update and opts.get(b'no_commit'):
4171 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4169 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4172 if opts.get(b'secret') and opts.get(b'no_commit'):
4170 if opts.get(b'secret') and opts.get(b'no_commit'):
4173 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4171 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4174 try:
4172 try:
4175 sim = float(opts.get(b'similarity') or 0)
4173 sim = float(opts.get(b'similarity') or 0)
4176 except ValueError:
4174 except ValueError:
4177 raise error.Abort(_(b'similarity must be a number'))
4175 raise error.Abort(_(b'similarity must be a number'))
4178 if sim < 0 or sim > 100:
4176 if sim < 0 or sim > 100:
4179 raise error.Abort(_(b'similarity must be between 0 and 100'))
4177 raise error.Abort(_(b'similarity must be between 0 and 100'))
4180 if sim and not update:
4178 if sim and not update:
4181 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4179 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4182 if exact:
4180 if exact:
4183 if opts.get(b'edit'):
4181 if opts.get(b'edit'):
4184 raise error.Abort(_(b'cannot use --exact with --edit'))
4182 raise error.Abort(_(b'cannot use --exact with --edit'))
4185 if opts.get(b'prefix'):
4183 if opts.get(b'prefix'):
4186 raise error.Abort(_(b'cannot use --exact with --prefix'))
4184 raise error.Abort(_(b'cannot use --exact with --prefix'))
4187
4185
4188 base = opts[b"base"]
4186 base = opts[b"base"]
4189 msgs = []
4187 msgs = []
4190 ret = 0
4188 ret = 0
4191
4189
4192 with repo.wlock():
4190 with repo.wlock():
4193 if update:
4191 if update:
4194 cmdutil.checkunfinished(repo)
4192 cmdutil.checkunfinished(repo)
4195 if exact or not opts.get(b'force'):
4193 if exact or not opts.get(b'force'):
4196 cmdutil.bailifchanged(repo)
4194 cmdutil.bailifchanged(repo)
4197
4195
4198 if not opts.get(b'no_commit'):
4196 if not opts.get(b'no_commit'):
4199 lock = repo.lock
4197 lock = repo.lock
4200 tr = lambda: repo.transaction(b'import')
4198 tr = lambda: repo.transaction(b'import')
4201 dsguard = util.nullcontextmanager
4199 dsguard = util.nullcontextmanager
4202 else:
4200 else:
4203 lock = util.nullcontextmanager
4201 lock = util.nullcontextmanager
4204 tr = util.nullcontextmanager
4202 tr = util.nullcontextmanager
4205 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4203 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4206 with lock(), tr(), dsguard():
4204 with lock(), tr(), dsguard():
4207 parents = repo[None].parents()
4205 parents = repo[None].parents()
4208 for patchurl in patches:
4206 for patchurl in patches:
4209 if patchurl == b'-':
4207 if patchurl == b'-':
4210 ui.status(_(b'applying patch from stdin\n'))
4208 ui.status(_(b'applying patch from stdin\n'))
4211 patchfile = ui.fin
4209 patchfile = ui.fin
4212 patchurl = b'stdin' # for error message
4210 patchurl = b'stdin' # for error message
4213 else:
4211 else:
4214 patchurl = os.path.join(base, patchurl)
4212 patchurl = os.path.join(base, patchurl)
4215 ui.status(_(b'applying %s\n') % patchurl)
4213 ui.status(_(b'applying %s\n') % patchurl)
4216 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4214 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4217
4215
4218 haspatch = False
4216 haspatch = False
4219 for hunk in patch.split(patchfile):
4217 for hunk in patch.split(patchfile):
4220 with patch.extract(ui, hunk) as patchdata:
4218 with patch.extract(ui, hunk) as patchdata:
4221 msg, node, rej = cmdutil.tryimportone(
4219 msg, node, rej = cmdutil.tryimportone(
4222 ui, repo, patchdata, parents, opts, msgs, hg.clean
4220 ui, repo, patchdata, parents, opts, msgs, hg.clean
4223 )
4221 )
4224 if msg:
4222 if msg:
4225 haspatch = True
4223 haspatch = True
4226 ui.note(msg + b'\n')
4224 ui.note(msg + b'\n')
4227 if update or exact:
4225 if update or exact:
4228 parents = repo[None].parents()
4226 parents = repo[None].parents()
4229 else:
4227 else:
4230 parents = [repo[node]]
4228 parents = [repo[node]]
4231 if rej:
4229 if rej:
4232 ui.write_err(_(b"patch applied partially\n"))
4230 ui.write_err(_(b"patch applied partially\n"))
4233 ui.write_err(
4231 ui.write_err(
4234 _(
4232 _(
4235 b"(fix the .rej files and run "
4233 b"(fix the .rej files and run "
4236 b"`hg commit --amend`)\n"
4234 b"`hg commit --amend`)\n"
4237 )
4235 )
4238 )
4236 )
4239 ret = 1
4237 ret = 1
4240 break
4238 break
4241
4239
4242 if not haspatch:
4240 if not haspatch:
4243 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4241 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4244
4242
4245 if msgs:
4243 if msgs:
4246 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4244 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4247 return ret
4245 return ret
4248
4246
4249
4247
4250 @command(
4248 @command(
4251 b'incoming|in',
4249 b'incoming|in',
4252 [
4250 [
4253 (
4251 (
4254 b'f',
4252 b'f',
4255 b'force',
4253 b'force',
4256 None,
4254 None,
4257 _(b'run even if remote repository is unrelated'),
4255 _(b'run even if remote repository is unrelated'),
4258 ),
4256 ),
4259 (b'n', b'newest-first', None, _(b'show newest record first')),
4257 (b'n', b'newest-first', None, _(b'show newest record first')),
4260 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4258 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4261 (
4259 (
4262 b'r',
4260 b'r',
4263 b'rev',
4261 b'rev',
4264 [],
4262 [],
4265 _(b'a remote changeset intended to be added'),
4263 _(b'a remote changeset intended to be added'),
4266 _(b'REV'),
4264 _(b'REV'),
4267 ),
4265 ),
4268 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4266 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4269 (
4267 (
4270 b'b',
4268 b'b',
4271 b'branch',
4269 b'branch',
4272 [],
4270 [],
4273 _(b'a specific branch you would like to pull'),
4271 _(b'a specific branch you would like to pull'),
4274 _(b'BRANCH'),
4272 _(b'BRANCH'),
4275 ),
4273 ),
4276 ]
4274 ]
4277 + logopts
4275 + logopts
4278 + remoteopts
4276 + remoteopts
4279 + subrepoopts,
4277 + subrepoopts,
4280 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4278 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4281 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4279 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4282 )
4280 )
4283 def incoming(ui, repo, source=b"default", **opts):
4281 def incoming(ui, repo, source=b"default", **opts):
4284 """show new changesets found in source
4282 """show new changesets found in source
4285
4283
4286 Show new changesets found in the specified path/URL or the default
4284 Show new changesets found in the specified path/URL or the default
4287 pull location. These are the changesets that would have been pulled
4285 pull location. These are the changesets that would have been pulled
4288 by :hg:`pull` at the time you issued this command.
4286 by :hg:`pull` at the time you issued this command.
4289
4287
4290 See pull for valid source format details.
4288 See pull for valid source format details.
4291
4289
4292 .. container:: verbose
4290 .. container:: verbose
4293
4291
4294 With -B/--bookmarks, the result of bookmark comparison between
4292 With -B/--bookmarks, the result of bookmark comparison between
4295 local and remote repositories is displayed. With -v/--verbose,
4293 local and remote repositories is displayed. With -v/--verbose,
4296 status is also displayed for each bookmark like below::
4294 status is also displayed for each bookmark like below::
4297
4295
4298 BM1 01234567890a added
4296 BM1 01234567890a added
4299 BM2 1234567890ab advanced
4297 BM2 1234567890ab advanced
4300 BM3 234567890abc diverged
4298 BM3 234567890abc diverged
4301 BM4 34567890abcd changed
4299 BM4 34567890abcd changed
4302
4300
4303 The action taken locally when pulling depends on the
4301 The action taken locally when pulling depends on the
4304 status of each bookmark:
4302 status of each bookmark:
4305
4303
4306 :``added``: pull will create it
4304 :``added``: pull will create it
4307 :``advanced``: pull will update it
4305 :``advanced``: pull will update it
4308 :``diverged``: pull will create a divergent bookmark
4306 :``diverged``: pull will create a divergent bookmark
4309 :``changed``: result depends on remote changesets
4307 :``changed``: result depends on remote changesets
4310
4308
4311 From the point of view of pulling behavior, bookmark
4309 From the point of view of pulling behavior, bookmark
4312 existing only in the remote repository are treated as ``added``,
4310 existing only in the remote repository are treated as ``added``,
4313 even if it is in fact locally deleted.
4311 even if it is in fact locally deleted.
4314
4312
4315 .. container:: verbose
4313 .. container:: verbose
4316
4314
4317 For remote repository, using --bundle avoids downloading the
4315 For remote repository, using --bundle avoids downloading the
4318 changesets twice if the incoming is followed by a pull.
4316 changesets twice if the incoming is followed by a pull.
4319
4317
4320 Examples:
4318 Examples:
4321
4319
4322 - show incoming changes with patches and full description::
4320 - show incoming changes with patches and full description::
4323
4321
4324 hg incoming -vp
4322 hg incoming -vp
4325
4323
4326 - show incoming changes excluding merges, store a bundle::
4324 - show incoming changes excluding merges, store a bundle::
4327
4325
4328 hg in -vpM --bundle incoming.hg
4326 hg in -vpM --bundle incoming.hg
4329 hg pull incoming.hg
4327 hg pull incoming.hg
4330
4328
4331 - briefly list changes inside a bundle::
4329 - briefly list changes inside a bundle::
4332
4330
4333 hg in changes.hg -T "{desc|firstline}\\n"
4331 hg in changes.hg -T "{desc|firstline}\\n"
4334
4332
4335 Returns 0 if there are incoming changes, 1 otherwise.
4333 Returns 0 if there are incoming changes, 1 otherwise.
4336 """
4334 """
4337 opts = pycompat.byteskwargs(opts)
4335 opts = pycompat.byteskwargs(opts)
4338 if opts.get(b'graph'):
4336 if opts.get(b'graph'):
4339 logcmdutil.checkunsupportedgraphflags([], opts)
4337 logcmdutil.checkunsupportedgraphflags([], opts)
4340
4338
4341 def display(other, chlist, displayer):
4339 def display(other, chlist, displayer):
4342 revdag = logcmdutil.graphrevs(other, chlist, opts)
4340 revdag = logcmdutil.graphrevs(other, chlist, opts)
4343 logcmdutil.displaygraph(
4341 logcmdutil.displaygraph(
4344 ui, repo, revdag, displayer, graphmod.asciiedges
4342 ui, repo, revdag, displayer, graphmod.asciiedges
4345 )
4343 )
4346
4344
4347 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4345 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4348 return 0
4346 return 0
4349
4347
4350 if opts.get(b'bundle') and opts.get(b'subrepos'):
4348 if opts.get(b'bundle') and opts.get(b'subrepos'):
4351 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4349 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4352
4350
4353 if opts.get(b'bookmarks'):
4351 if opts.get(b'bookmarks'):
4354 source, branches = hg.parseurl(
4352 source, branches = hg.parseurl(
4355 ui.expandpath(source), opts.get(b'branch')
4353 ui.expandpath(source), opts.get(b'branch')
4356 )
4354 )
4357 other = hg.peer(repo, opts, source)
4355 other = hg.peer(repo, opts, source)
4358 if b'bookmarks' not in other.listkeys(b'namespaces'):
4356 if b'bookmarks' not in other.listkeys(b'namespaces'):
4359 ui.warn(_(b"remote doesn't support bookmarks\n"))
4357 ui.warn(_(b"remote doesn't support bookmarks\n"))
4360 return 0
4358 return 0
4361 ui.pager(b'incoming')
4359 ui.pager(b'incoming')
4362 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4360 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4363 return bookmarks.incoming(ui, repo, other)
4361 return bookmarks.incoming(ui, repo, other)
4364
4362
4365 repo._subtoppath = ui.expandpath(source)
4363 repo._subtoppath = ui.expandpath(source)
4366 try:
4364 try:
4367 return hg.incoming(ui, repo, source, opts)
4365 return hg.incoming(ui, repo, source, opts)
4368 finally:
4366 finally:
4369 del repo._subtoppath
4367 del repo._subtoppath
4370
4368
4371
4369
4372 @command(
4370 @command(
4373 b'init',
4371 b'init',
4374 remoteopts,
4372 remoteopts,
4375 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4373 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4376 helpcategory=command.CATEGORY_REPO_CREATION,
4374 helpcategory=command.CATEGORY_REPO_CREATION,
4377 helpbasic=True,
4375 helpbasic=True,
4378 norepo=True,
4376 norepo=True,
4379 )
4377 )
4380 def init(ui, dest=b".", **opts):
4378 def init(ui, dest=b".", **opts):
4381 """create a new repository in the given directory
4379 """create a new repository in the given directory
4382
4380
4383 Initialize a new repository in the given directory. If the given
4381 Initialize a new repository in the given directory. If the given
4384 directory does not exist, it will be created.
4382 directory does not exist, it will be created.
4385
4383
4386 If no directory is given, the current directory is used.
4384 If no directory is given, the current directory is used.
4387
4385
4388 It is possible to specify an ``ssh://`` URL as the destination.
4386 It is possible to specify an ``ssh://`` URL as the destination.
4389 See :hg:`help urls` for more information.
4387 See :hg:`help urls` for more information.
4390
4388
4391 Returns 0 on success.
4389 Returns 0 on success.
4392 """
4390 """
4393 opts = pycompat.byteskwargs(opts)
4391 opts = pycompat.byteskwargs(opts)
4394 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4392 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4395
4393
4396
4394
4397 @command(
4395 @command(
4398 b'locate',
4396 b'locate',
4399 [
4397 [
4400 (
4398 (
4401 b'r',
4399 b'r',
4402 b'rev',
4400 b'rev',
4403 b'',
4401 b'',
4404 _(b'search the repository as it is in REV'),
4402 _(b'search the repository as it is in REV'),
4405 _(b'REV'),
4403 _(b'REV'),
4406 ),
4404 ),
4407 (
4405 (
4408 b'0',
4406 b'0',
4409 b'print0',
4407 b'print0',
4410 None,
4408 None,
4411 _(b'end filenames with NUL, for use with xargs'),
4409 _(b'end filenames with NUL, for use with xargs'),
4412 ),
4410 ),
4413 (
4411 (
4414 b'f',
4412 b'f',
4415 b'fullpath',
4413 b'fullpath',
4416 None,
4414 None,
4417 _(b'print complete paths from the filesystem root'),
4415 _(b'print complete paths from the filesystem root'),
4418 ),
4416 ),
4419 ]
4417 ]
4420 + walkopts,
4418 + walkopts,
4421 _(b'[OPTION]... [PATTERN]...'),
4419 _(b'[OPTION]... [PATTERN]...'),
4422 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4420 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4423 )
4421 )
4424 def locate(ui, repo, *pats, **opts):
4422 def locate(ui, repo, *pats, **opts):
4425 """locate files matching specific patterns (DEPRECATED)
4423 """locate files matching specific patterns (DEPRECATED)
4426
4424
4427 Print files under Mercurial control in the working directory whose
4425 Print files under Mercurial control in the working directory whose
4428 names match the given patterns.
4426 names match the given patterns.
4429
4427
4430 By default, this command searches all directories in the working
4428 By default, this command searches all directories in the working
4431 directory. To search just the current directory and its
4429 directory. To search just the current directory and its
4432 subdirectories, use "--include .".
4430 subdirectories, use "--include .".
4433
4431
4434 If no patterns are given to match, this command prints the names
4432 If no patterns are given to match, this command prints the names
4435 of all files under Mercurial control in the working directory.
4433 of all files under Mercurial control in the working directory.
4436
4434
4437 If you want to feed the output of this command into the "xargs"
4435 If you want to feed the output of this command into the "xargs"
4438 command, use the -0 option to both this command and "xargs". This
4436 command, use the -0 option to both this command and "xargs". This
4439 will avoid the problem of "xargs" treating single filenames that
4437 will avoid the problem of "xargs" treating single filenames that
4440 contain whitespace as multiple filenames.
4438 contain whitespace as multiple filenames.
4441
4439
4442 See :hg:`help files` for a more versatile command.
4440 See :hg:`help files` for a more versatile command.
4443
4441
4444 Returns 0 if a match is found, 1 otherwise.
4442 Returns 0 if a match is found, 1 otherwise.
4445 """
4443 """
4446 opts = pycompat.byteskwargs(opts)
4444 opts = pycompat.byteskwargs(opts)
4447 if opts.get(b'print0'):
4445 if opts.get(b'print0'):
4448 end = b'\0'
4446 end = b'\0'
4449 else:
4447 else:
4450 end = b'\n'
4448 end = b'\n'
4451 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4449 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4452
4450
4453 ret = 1
4451 ret = 1
4454 m = scmutil.match(
4452 m = scmutil.match(
4455 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4453 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4456 )
4454 )
4457
4455
4458 ui.pager(b'locate')
4456 ui.pager(b'locate')
4459 if ctx.rev() is None:
4457 if ctx.rev() is None:
4460 # When run on the working copy, "locate" includes removed files, so
4458 # When run on the working copy, "locate" includes removed files, so
4461 # we get the list of files from the dirstate.
4459 # we get the list of files from the dirstate.
4462 filesgen = sorted(repo.dirstate.matches(m))
4460 filesgen = sorted(repo.dirstate.matches(m))
4463 else:
4461 else:
4464 filesgen = ctx.matches(m)
4462 filesgen = ctx.matches(m)
4465 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4463 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4466 for abs in filesgen:
4464 for abs in filesgen:
4467 if opts.get(b'fullpath'):
4465 if opts.get(b'fullpath'):
4468 ui.write(repo.wjoin(abs), end)
4466 ui.write(repo.wjoin(abs), end)
4469 else:
4467 else:
4470 ui.write(uipathfn(abs), end)
4468 ui.write(uipathfn(abs), end)
4471 ret = 0
4469 ret = 0
4472
4470
4473 return ret
4471 return ret
4474
4472
4475
4473
4476 @command(
4474 @command(
4477 b'log|history',
4475 b'log|history',
4478 [
4476 [
4479 (
4477 (
4480 b'f',
4478 b'f',
4481 b'follow',
4479 b'follow',
4482 None,
4480 None,
4483 _(
4481 _(
4484 b'follow changeset history, or file history across copies and renames'
4482 b'follow changeset history, or file history across copies and renames'
4485 ),
4483 ),
4486 ),
4484 ),
4487 (
4485 (
4488 b'',
4486 b'',
4489 b'follow-first',
4487 b'follow-first',
4490 None,
4488 None,
4491 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4489 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4492 ),
4490 ),
4493 (
4491 (
4494 b'd',
4492 b'd',
4495 b'date',
4493 b'date',
4496 b'',
4494 b'',
4497 _(b'show revisions matching date spec'),
4495 _(b'show revisions matching date spec'),
4498 _(b'DATE'),
4496 _(b'DATE'),
4499 ),
4497 ),
4500 (b'C', b'copies', None, _(b'show copied files')),
4498 (b'C', b'copies', None, _(b'show copied files')),
4501 (
4499 (
4502 b'k',
4500 b'k',
4503 b'keyword',
4501 b'keyword',
4504 [],
4502 [],
4505 _(b'do case-insensitive search for a given text'),
4503 _(b'do case-insensitive search for a given text'),
4506 _(b'TEXT'),
4504 _(b'TEXT'),
4507 ),
4505 ),
4508 (
4506 (
4509 b'r',
4507 b'r',
4510 b'rev',
4508 b'rev',
4511 [],
4509 [],
4512 _(b'show the specified revision or revset'),
4510 _(b'show the specified revision or revset'),
4513 _(b'REV'),
4511 _(b'REV'),
4514 ),
4512 ),
4515 (
4513 (
4516 b'L',
4514 b'L',
4517 b'line-range',
4515 b'line-range',
4518 [],
4516 [],
4519 _(b'follow line range of specified file (EXPERIMENTAL)'),
4517 _(b'follow line range of specified file (EXPERIMENTAL)'),
4520 _(b'FILE,RANGE'),
4518 _(b'FILE,RANGE'),
4521 ),
4519 ),
4522 (
4520 (
4523 b'',
4521 b'',
4524 b'removed',
4522 b'removed',
4525 None,
4523 None,
4526 _(b'include revisions where files were removed'),
4524 _(b'include revisions where files were removed'),
4527 ),
4525 ),
4528 (
4526 (
4529 b'm',
4527 b'm',
4530 b'only-merges',
4528 b'only-merges',
4531 None,
4529 None,
4532 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4530 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4533 ),
4531 ),
4534 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4532 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4535 (
4533 (
4536 b'',
4534 b'',
4537 b'only-branch',
4535 b'only-branch',
4538 [],
4536 [],
4539 _(
4537 _(
4540 b'show only changesets within the given named branch (DEPRECATED)'
4538 b'show only changesets within the given named branch (DEPRECATED)'
4541 ),
4539 ),
4542 _(b'BRANCH'),
4540 _(b'BRANCH'),
4543 ),
4541 ),
4544 (
4542 (
4545 b'b',
4543 b'b',
4546 b'branch',
4544 b'branch',
4547 [],
4545 [],
4548 _(b'show changesets within the given named branch'),
4546 _(b'show changesets within the given named branch'),
4549 _(b'BRANCH'),
4547 _(b'BRANCH'),
4550 ),
4548 ),
4551 (
4549 (
4552 b'P',
4550 b'P',
4553 b'prune',
4551 b'prune',
4554 [],
4552 [],
4555 _(b'do not display revision or any of its ancestors'),
4553 _(b'do not display revision or any of its ancestors'),
4556 _(b'REV'),
4554 _(b'REV'),
4557 ),
4555 ),
4558 ]
4556 ]
4559 + logopts
4557 + logopts
4560 + walkopts,
4558 + walkopts,
4561 _(b'[OPTION]... [FILE]'),
4559 _(b'[OPTION]... [FILE]'),
4562 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4560 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4563 helpbasic=True,
4561 helpbasic=True,
4564 inferrepo=True,
4562 inferrepo=True,
4565 intents={INTENT_READONLY},
4563 intents={INTENT_READONLY},
4566 )
4564 )
4567 def log(ui, repo, *pats, **opts):
4565 def log(ui, repo, *pats, **opts):
4568 """show revision history of entire repository or files
4566 """show revision history of entire repository or files
4569
4567
4570 Print the revision history of the specified files or the entire
4568 Print the revision history of the specified files or the entire
4571 project.
4569 project.
4572
4570
4573 If no revision range is specified, the default is ``tip:0`` unless
4571 If no revision range is specified, the default is ``tip:0`` unless
4574 --follow is set, in which case the working directory parent is
4572 --follow is set, in which case the working directory parent is
4575 used as the starting revision.
4573 used as the starting revision.
4576
4574
4577 File history is shown without following rename or copy history of
4575 File history is shown without following rename or copy history of
4578 files. Use -f/--follow with a filename to follow history across
4576 files. Use -f/--follow with a filename to follow history across
4579 renames and copies. --follow without a filename will only show
4577 renames and copies. --follow without a filename will only show
4580 ancestors of the starting revision.
4578 ancestors of the starting revision.
4581
4579
4582 By default this command prints revision number and changeset id,
4580 By default this command prints revision number and changeset id,
4583 tags, non-trivial parents, user, date and time, and a summary for
4581 tags, non-trivial parents, user, date and time, and a summary for
4584 each commit. When the -v/--verbose switch is used, the list of
4582 each commit. When the -v/--verbose switch is used, the list of
4585 changed files and full commit message are shown.
4583 changed files and full commit message are shown.
4586
4584
4587 With --graph the revisions are shown as an ASCII art DAG with the most
4585 With --graph the revisions are shown as an ASCII art DAG with the most
4588 recent changeset at the top.
4586 recent changeset at the top.
4589 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
4587 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
4590 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4588 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4591 changeset from the lines below is a parent of the 'o' merge on the same
4589 changeset from the lines below is a parent of the 'o' merge on the same
4592 line.
4590 line.
4593 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4591 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4594 of a '|' indicates one or more revisions in a path are omitted.
4592 of a '|' indicates one or more revisions in a path are omitted.
4595
4593
4596 .. container:: verbose
4594 .. container:: verbose
4597
4595
4598 Use -L/--line-range FILE,M:N options to follow the history of lines
4596 Use -L/--line-range FILE,M:N options to follow the history of lines
4599 from M to N in FILE. With -p/--patch only diff hunks affecting
4597 from M to N in FILE. With -p/--patch only diff hunks affecting
4600 specified line range will be shown. This option requires --follow;
4598 specified line range will be shown. This option requires --follow;
4601 it can be specified multiple times. Currently, this option is not
4599 it can be specified multiple times. Currently, this option is not
4602 compatible with --graph. This option is experimental.
4600 compatible with --graph. This option is experimental.
4603
4601
4604 .. note::
4602 .. note::
4605
4603
4606 :hg:`log --patch` may generate unexpected diff output for merge
4604 :hg:`log --patch` may generate unexpected diff output for merge
4607 changesets, as it will only compare the merge changeset against
4605 changesets, as it will only compare the merge changeset against
4608 its first parent. Also, only files different from BOTH parents
4606 its first parent. Also, only files different from BOTH parents
4609 will appear in files:.
4607 will appear in files:.
4610
4608
4611 .. note::
4609 .. note::
4612
4610
4613 For performance reasons, :hg:`log FILE` may omit duplicate changes
4611 For performance reasons, :hg:`log FILE` may omit duplicate changes
4614 made on branches and will not show removals or mode changes. To
4612 made on branches and will not show removals or mode changes. To
4615 see all such changes, use the --removed switch.
4613 see all such changes, use the --removed switch.
4616
4614
4617 .. container:: verbose
4615 .. container:: verbose
4618
4616
4619 .. note::
4617 .. note::
4620
4618
4621 The history resulting from -L/--line-range options depends on diff
4619 The history resulting from -L/--line-range options depends on diff
4622 options; for instance if white-spaces are ignored, respective changes
4620 options; for instance if white-spaces are ignored, respective changes
4623 with only white-spaces in specified line range will not be listed.
4621 with only white-spaces in specified line range will not be listed.
4624
4622
4625 .. container:: verbose
4623 .. container:: verbose
4626
4624
4627 Some examples:
4625 Some examples:
4628
4626
4629 - changesets with full descriptions and file lists::
4627 - changesets with full descriptions and file lists::
4630
4628
4631 hg log -v
4629 hg log -v
4632
4630
4633 - changesets ancestral to the working directory::
4631 - changesets ancestral to the working directory::
4634
4632
4635 hg log -f
4633 hg log -f
4636
4634
4637 - last 10 commits on the current branch::
4635 - last 10 commits on the current branch::
4638
4636
4639 hg log -l 10 -b .
4637 hg log -l 10 -b .
4640
4638
4641 - changesets showing all modifications of a file, including removals::
4639 - changesets showing all modifications of a file, including removals::
4642
4640
4643 hg log --removed file.c
4641 hg log --removed file.c
4644
4642
4645 - all changesets that touch a directory, with diffs, excluding merges::
4643 - all changesets that touch a directory, with diffs, excluding merges::
4646
4644
4647 hg log -Mp lib/
4645 hg log -Mp lib/
4648
4646
4649 - all revision numbers that match a keyword::
4647 - all revision numbers that match a keyword::
4650
4648
4651 hg log -k bug --template "{rev}\\n"
4649 hg log -k bug --template "{rev}\\n"
4652
4650
4653 - the full hash identifier of the working directory parent::
4651 - the full hash identifier of the working directory parent::
4654
4652
4655 hg log -r . --template "{node}\\n"
4653 hg log -r . --template "{node}\\n"
4656
4654
4657 - list available log templates::
4655 - list available log templates::
4658
4656
4659 hg log -T list
4657 hg log -T list
4660
4658
4661 - check if a given changeset is included in a tagged release::
4659 - check if a given changeset is included in a tagged release::
4662
4660
4663 hg log -r "a21ccf and ancestor(1.9)"
4661 hg log -r "a21ccf and ancestor(1.9)"
4664
4662
4665 - find all changesets by some user in a date range::
4663 - find all changesets by some user in a date range::
4666
4664
4667 hg log -k alice -d "may 2008 to jul 2008"
4665 hg log -k alice -d "may 2008 to jul 2008"
4668
4666
4669 - summary of all changesets after the last tag::
4667 - summary of all changesets after the last tag::
4670
4668
4671 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4669 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4672
4670
4673 - changesets touching lines 13 to 23 for file.c::
4671 - changesets touching lines 13 to 23 for file.c::
4674
4672
4675 hg log -L file.c,13:23
4673 hg log -L file.c,13:23
4676
4674
4677 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4675 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4678 main.c with patch::
4676 main.c with patch::
4679
4677
4680 hg log -L file.c,13:23 -L main.c,2:6 -p
4678 hg log -L file.c,13:23 -L main.c,2:6 -p
4681
4679
4682 See :hg:`help dates` for a list of formats valid for -d/--date.
4680 See :hg:`help dates` for a list of formats valid for -d/--date.
4683
4681
4684 See :hg:`help revisions` for more about specifying and ordering
4682 See :hg:`help revisions` for more about specifying and ordering
4685 revisions.
4683 revisions.
4686
4684
4687 See :hg:`help templates` for more about pre-packaged styles and
4685 See :hg:`help templates` for more about pre-packaged styles and
4688 specifying custom templates. The default template used by the log
4686 specifying custom templates. The default template used by the log
4689 command can be customized via the ``ui.logtemplate`` configuration
4687 command can be customized via the ``ui.logtemplate`` configuration
4690 setting.
4688 setting.
4691
4689
4692 Returns 0 on success.
4690 Returns 0 on success.
4693
4691
4694 """
4692 """
4695 opts = pycompat.byteskwargs(opts)
4693 opts = pycompat.byteskwargs(opts)
4696 linerange = opts.get(b'line_range')
4694 linerange = opts.get(b'line_range')
4697
4695
4698 if linerange and not opts.get(b'follow'):
4696 if linerange and not opts.get(b'follow'):
4699 raise error.Abort(_(b'--line-range requires --follow'))
4697 raise error.Abort(_(b'--line-range requires --follow'))
4700
4698
4701 if linerange and pats:
4699 if linerange and pats:
4702 # TODO: take pats as patterns with no line-range filter
4700 # TODO: take pats as patterns with no line-range filter
4703 raise error.Abort(
4701 raise error.Abort(
4704 _(b'FILE arguments are not compatible with --line-range option')
4702 _(b'FILE arguments are not compatible with --line-range option')
4705 )
4703 )
4706
4704
4707 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4705 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4708 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4706 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4709 if linerange:
4707 if linerange:
4710 # TODO: should follow file history from logcmdutil._initialrevs(),
4708 # TODO: should follow file history from logcmdutil._initialrevs(),
4711 # then filter the result by logcmdutil._makerevset() and --limit
4709 # then filter the result by logcmdutil._makerevset() and --limit
4712 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4710 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4713
4711
4714 getcopies = None
4712 getcopies = None
4715 if opts.get(b'copies'):
4713 if opts.get(b'copies'):
4716 endrev = None
4714 endrev = None
4717 if revs:
4715 if revs:
4718 endrev = revs.max() + 1
4716 endrev = revs.max() + 1
4719 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4717 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4720
4718
4721 ui.pager(b'log')
4719 ui.pager(b'log')
4722 displayer = logcmdutil.changesetdisplayer(
4720 displayer = logcmdutil.changesetdisplayer(
4723 ui, repo, opts, differ, buffered=True
4721 ui, repo, opts, differ, buffered=True
4724 )
4722 )
4725 if opts.get(b'graph'):
4723 if opts.get(b'graph'):
4726 displayfn = logcmdutil.displaygraphrevs
4724 displayfn = logcmdutil.displaygraphrevs
4727 else:
4725 else:
4728 displayfn = logcmdutil.displayrevs
4726 displayfn = logcmdutil.displayrevs
4729 displayfn(ui, repo, revs, displayer, getcopies)
4727 displayfn(ui, repo, revs, displayer, getcopies)
4730
4728
4731
4729
4732 @command(
4730 @command(
4733 b'manifest',
4731 b'manifest',
4734 [
4732 [
4735 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4733 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4736 (b'', b'all', False, _(b"list files from all revisions")),
4734 (b'', b'all', False, _(b"list files from all revisions")),
4737 ]
4735 ]
4738 + formatteropts,
4736 + formatteropts,
4739 _(b'[-r REV]'),
4737 _(b'[-r REV]'),
4740 helpcategory=command.CATEGORY_MAINTENANCE,
4738 helpcategory=command.CATEGORY_MAINTENANCE,
4741 intents={INTENT_READONLY},
4739 intents={INTENT_READONLY},
4742 )
4740 )
4743 def manifest(ui, repo, node=None, rev=None, **opts):
4741 def manifest(ui, repo, node=None, rev=None, **opts):
4744 """output the current or given revision of the project manifest
4742 """output the current or given revision of the project manifest
4745
4743
4746 Print a list of version controlled files for the given revision.
4744 Print a list of version controlled files for the given revision.
4747 If no revision is given, the first parent of the working directory
4745 If no revision is given, the first parent of the working directory
4748 is used, or the null revision if no revision is checked out.
4746 is used, or the null revision if no revision is checked out.
4749
4747
4750 With -v, print file permissions, symlink and executable bits.
4748 With -v, print file permissions, symlink and executable bits.
4751 With --debug, print file revision hashes.
4749 With --debug, print file revision hashes.
4752
4750
4753 If option --all is specified, the list of all files from all revisions
4751 If option --all is specified, the list of all files from all revisions
4754 is printed. This includes deleted and renamed files.
4752 is printed. This includes deleted and renamed files.
4755
4753
4756 Returns 0 on success.
4754 Returns 0 on success.
4757 """
4755 """
4758 opts = pycompat.byteskwargs(opts)
4756 opts = pycompat.byteskwargs(opts)
4759 fm = ui.formatter(b'manifest', opts)
4757 fm = ui.formatter(b'manifest', opts)
4760
4758
4761 if opts.get(b'all'):
4759 if opts.get(b'all'):
4762 if rev or node:
4760 if rev or node:
4763 raise error.Abort(_(b"can't specify a revision with --all"))
4761 raise error.Abort(_(b"can't specify a revision with --all"))
4764
4762
4765 res = set()
4763 res = set()
4766 for rev in repo:
4764 for rev in repo:
4767 ctx = repo[rev]
4765 ctx = repo[rev]
4768 res |= set(ctx.files())
4766 res |= set(ctx.files())
4769
4767
4770 ui.pager(b'manifest')
4768 ui.pager(b'manifest')
4771 for f in sorted(res):
4769 for f in sorted(res):
4772 fm.startitem()
4770 fm.startitem()
4773 fm.write(b"path", b'%s\n', f)
4771 fm.write(b"path", b'%s\n', f)
4774 fm.end()
4772 fm.end()
4775 return
4773 return
4776
4774
4777 if rev and node:
4775 if rev and node:
4778 raise error.Abort(_(b"please specify just one revision"))
4776 raise error.Abort(_(b"please specify just one revision"))
4779
4777
4780 if not node:
4778 if not node:
4781 node = rev
4779 node = rev
4782
4780
4783 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4781 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4784 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4782 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4785 if node:
4783 if node:
4786 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4784 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4787 ctx = scmutil.revsingle(repo, node)
4785 ctx = scmutil.revsingle(repo, node)
4788 mf = ctx.manifest()
4786 mf = ctx.manifest()
4789 ui.pager(b'manifest')
4787 ui.pager(b'manifest')
4790 for f in ctx:
4788 for f in ctx:
4791 fm.startitem()
4789 fm.startitem()
4792 fm.context(ctx=ctx)
4790 fm.context(ctx=ctx)
4793 fl = ctx[f].flags()
4791 fl = ctx[f].flags()
4794 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4792 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4795 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4793 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4796 fm.write(b'path', b'%s\n', f)
4794 fm.write(b'path', b'%s\n', f)
4797 fm.end()
4795 fm.end()
4798
4796
4799
4797
4800 @command(
4798 @command(
4801 b'merge',
4799 b'merge',
4802 [
4800 [
4803 (
4801 (
4804 b'f',
4802 b'f',
4805 b'force',
4803 b'force',
4806 None,
4804 None,
4807 _(b'force a merge including outstanding changes (DEPRECATED)'),
4805 _(b'force a merge including outstanding changes (DEPRECATED)'),
4808 ),
4806 ),
4809 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4807 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4810 (
4808 (
4811 b'P',
4809 b'P',
4812 b'preview',
4810 b'preview',
4813 None,
4811 None,
4814 _(b'review revisions to merge (no merge is performed)'),
4812 _(b'review revisions to merge (no merge is performed)'),
4815 ),
4813 ),
4816 (b'', b'abort', None, _(b'abort the ongoing merge')),
4814 (b'', b'abort', None, _(b'abort the ongoing merge')),
4817 ]
4815 ]
4818 + mergetoolopts,
4816 + mergetoolopts,
4819 _(b'[-P] [[-r] REV]'),
4817 _(b'[-P] [[-r] REV]'),
4820 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4818 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4821 helpbasic=True,
4819 helpbasic=True,
4822 )
4820 )
4823 def merge(ui, repo, node=None, **opts):
4821 def merge(ui, repo, node=None, **opts):
4824 """merge another revision into working directory
4822 """merge another revision into working directory
4825
4823
4826 The current working directory is updated with all changes made in
4824 The current working directory is updated with all changes made in
4827 the requested revision since the last common predecessor revision.
4825 the requested revision since the last common predecessor revision.
4828
4826
4829 Files that changed between either parent are marked as changed for
4827 Files that changed between either parent are marked as changed for
4830 the next commit and a commit must be performed before any further
4828 the next commit and a commit must be performed before any further
4831 updates to the repository are allowed. The next commit will have
4829 updates to the repository are allowed. The next commit will have
4832 two parents.
4830 two parents.
4833
4831
4834 ``--tool`` can be used to specify the merge tool used for file
4832 ``--tool`` can be used to specify the merge tool used for file
4835 merges. It overrides the HGMERGE environment variable and your
4833 merges. It overrides the HGMERGE environment variable and your
4836 configuration files. See :hg:`help merge-tools` for options.
4834 configuration files. See :hg:`help merge-tools` for options.
4837
4835
4838 If no revision is specified, the working directory's parent is a
4836 If no revision is specified, the working directory's parent is a
4839 head revision, and the current branch contains exactly one other
4837 head revision, and the current branch contains exactly one other
4840 head, the other head is merged with by default. Otherwise, an
4838 head, the other head is merged with by default. Otherwise, an
4841 explicit revision with which to merge must be provided.
4839 explicit revision with which to merge must be provided.
4842
4840
4843 See :hg:`help resolve` for information on handling file conflicts.
4841 See :hg:`help resolve` for information on handling file conflicts.
4844
4842
4845 To undo an uncommitted merge, use :hg:`merge --abort` which
4843 To undo an uncommitted merge, use :hg:`merge --abort` which
4846 will check out a clean copy of the original merge parent, losing
4844 will check out a clean copy of the original merge parent, losing
4847 all changes.
4845 all changes.
4848
4846
4849 Returns 0 on success, 1 if there are unresolved files.
4847 Returns 0 on success, 1 if there are unresolved files.
4850 """
4848 """
4851
4849
4852 opts = pycompat.byteskwargs(opts)
4850 opts = pycompat.byteskwargs(opts)
4853 abort = opts.get(b'abort')
4851 abort = opts.get(b'abort')
4854 if abort and repo.dirstate.p2() == nullid:
4852 if abort and repo.dirstate.p2() == nullid:
4855 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4853 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4856 if abort:
4854 if abort:
4857 state = cmdutil.getunfinishedstate(repo)
4855 state = cmdutil.getunfinishedstate(repo)
4858 if state and state._opname != b'merge':
4856 if state and state._opname != b'merge':
4859 raise error.Abort(
4857 raise error.Abort(
4860 _(b'cannot abort merge with %s in progress') % (state._opname),
4858 _(b'cannot abort merge with %s in progress') % (state._opname),
4861 hint=state.hint(),
4859 hint=state.hint(),
4862 )
4860 )
4863 if node:
4861 if node:
4864 raise error.Abort(_(b"cannot specify a node with --abort"))
4862 raise error.Abort(_(b"cannot specify a node with --abort"))
4865 if opts.get(b'rev'):
4863 if opts.get(b'rev'):
4866 raise error.Abort(_(b"cannot specify both --rev and --abort"))
4864 raise error.Abort(_(b"cannot specify both --rev and --abort"))
4867 if opts.get(b'preview'):
4865 if opts.get(b'preview'):
4868 raise error.Abort(_(b"cannot specify --preview with --abort"))
4866 raise error.Abort(_(b"cannot specify --preview with --abort"))
4869 if opts.get(b'rev') and node:
4867 if opts.get(b'rev') and node:
4870 raise error.Abort(_(b"please specify just one revision"))
4868 raise error.Abort(_(b"please specify just one revision"))
4871 if not node:
4869 if not node:
4872 node = opts.get(b'rev')
4870 node = opts.get(b'rev')
4873
4871
4874 if node:
4872 if node:
4875 node = scmutil.revsingle(repo, node).node()
4873 node = scmutil.revsingle(repo, node).node()
4876
4874
4877 if not node and not abort:
4875 if not node and not abort:
4878 if ui.configbool(b'commands', b'merge.require-rev'):
4876 if ui.configbool(b'commands', b'merge.require-rev'):
4879 raise error.Abort(
4877 raise error.Abort(
4880 _(
4878 _(
4881 b'configuration requires specifying revision to merge '
4879 b'configuration requires specifying revision to merge '
4882 b'with'
4880 b'with'
4883 )
4881 )
4884 )
4882 )
4885 node = repo[destutil.destmerge(repo)].node()
4883 node = repo[destutil.destmerge(repo)].node()
4886
4884
4887 if opts.get(b'preview'):
4885 if opts.get(b'preview'):
4888 # find nodes that are ancestors of p2 but not of p1
4886 # find nodes that are ancestors of p2 but not of p1
4889 p1 = repo.lookup(b'.')
4887 p1 = repo.lookup(b'.')
4890 p2 = node
4888 p2 = node
4891 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4889 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4892
4890
4893 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4891 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4894 for node in nodes:
4892 for node in nodes:
4895 displayer.show(repo[node])
4893 displayer.show(repo[node])
4896 displayer.close()
4894 displayer.close()
4897 return 0
4895 return 0
4898
4896
4899 # ui.forcemerge is an internal variable, do not document
4897 # ui.forcemerge is an internal variable, do not document
4900 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4898 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4901 with ui.configoverride(overrides, b'merge'):
4899 with ui.configoverride(overrides, b'merge'):
4902 force = opts.get(b'force')
4900 force = opts.get(b'force')
4903 labels = [b'working copy', b'merge rev']
4901 labels = [b'working copy', b'merge rev']
4904 return hg.merge(
4902 return hg.merge(
4905 repo,
4903 repo,
4906 node,
4904 node,
4907 force=force,
4905 force=force,
4908 mergeforce=force,
4906 mergeforce=force,
4909 labels=labels,
4907 labels=labels,
4910 abort=abort,
4908 abort=abort,
4911 )
4909 )
4912
4910
4913
4911
4914 statemod.addunfinished(
4912 statemod.addunfinished(
4915 b'merge',
4913 b'merge',
4916 fname=None,
4914 fname=None,
4917 clearable=True,
4915 clearable=True,
4918 allowcommit=True,
4916 allowcommit=True,
4919 cmdmsg=_(b'outstanding uncommitted merge'),
4917 cmdmsg=_(b'outstanding uncommitted merge'),
4920 abortfunc=hg.abortmerge,
4918 abortfunc=hg.abortmerge,
4921 statushint=_(
4919 statushint=_(
4922 b'To continue: hg commit\nTo abort: hg merge --abort'
4920 b'To continue: hg commit\nTo abort: hg merge --abort'
4923 ),
4921 ),
4924 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4922 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4925 )
4923 )
4926
4924
4927
4925
4928 @command(
4926 @command(
4929 b'outgoing|out',
4927 b'outgoing|out',
4930 [
4928 [
4931 (
4929 (
4932 b'f',
4930 b'f',
4933 b'force',
4931 b'force',
4934 None,
4932 None,
4935 _(b'run even when the destination is unrelated'),
4933 _(b'run even when the destination is unrelated'),
4936 ),
4934 ),
4937 (
4935 (
4938 b'r',
4936 b'r',
4939 b'rev',
4937 b'rev',
4940 [],
4938 [],
4941 _(b'a changeset intended to be included in the destination'),
4939 _(b'a changeset intended to be included in the destination'),
4942 _(b'REV'),
4940 _(b'REV'),
4943 ),
4941 ),
4944 (b'n', b'newest-first', None, _(b'show newest record first')),
4942 (b'n', b'newest-first', None, _(b'show newest record first')),
4945 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4943 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4946 (
4944 (
4947 b'b',
4945 b'b',
4948 b'branch',
4946 b'branch',
4949 [],
4947 [],
4950 _(b'a specific branch you would like to push'),
4948 _(b'a specific branch you would like to push'),
4951 _(b'BRANCH'),
4949 _(b'BRANCH'),
4952 ),
4950 ),
4953 ]
4951 ]
4954 + logopts
4952 + logopts
4955 + remoteopts
4953 + remoteopts
4956 + subrepoopts,
4954 + subrepoopts,
4957 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4955 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4958 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4956 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4959 )
4957 )
4960 def outgoing(ui, repo, dest=None, **opts):
4958 def outgoing(ui, repo, dest=None, **opts):
4961 """show changesets not found in the destination
4959 """show changesets not found in the destination
4962
4960
4963 Show changesets not found in the specified destination repository
4961 Show changesets not found in the specified destination repository
4964 or the default push location. These are the changesets that would
4962 or the default push location. These are the changesets that would
4965 be pushed if a push was requested.
4963 be pushed if a push was requested.
4966
4964
4967 See pull for details of valid destination formats.
4965 See pull for details of valid destination formats.
4968
4966
4969 .. container:: verbose
4967 .. container:: verbose
4970
4968
4971 With -B/--bookmarks, the result of bookmark comparison between
4969 With -B/--bookmarks, the result of bookmark comparison between
4972 local and remote repositories is displayed. With -v/--verbose,
4970 local and remote repositories is displayed. With -v/--verbose,
4973 status is also displayed for each bookmark like below::
4971 status is also displayed for each bookmark like below::
4974
4972
4975 BM1 01234567890a added
4973 BM1 01234567890a added
4976 BM2 deleted
4974 BM2 deleted
4977 BM3 234567890abc advanced
4975 BM3 234567890abc advanced
4978 BM4 34567890abcd diverged
4976 BM4 34567890abcd diverged
4979 BM5 4567890abcde changed
4977 BM5 4567890abcde changed
4980
4978
4981 The action taken when pushing depends on the
4979 The action taken when pushing depends on the
4982 status of each bookmark:
4980 status of each bookmark:
4983
4981
4984 :``added``: push with ``-B`` will create it
4982 :``added``: push with ``-B`` will create it
4985 :``deleted``: push with ``-B`` will delete it
4983 :``deleted``: push with ``-B`` will delete it
4986 :``advanced``: push will update it
4984 :``advanced``: push will update it
4987 :``diverged``: push with ``-B`` will update it
4985 :``diverged``: push with ``-B`` will update it
4988 :``changed``: push with ``-B`` will update it
4986 :``changed``: push with ``-B`` will update it
4989
4987
4990 From the point of view of pushing behavior, bookmarks
4988 From the point of view of pushing behavior, bookmarks
4991 existing only in the remote repository are treated as
4989 existing only in the remote repository are treated as
4992 ``deleted``, even if it is in fact added remotely.
4990 ``deleted``, even if it is in fact added remotely.
4993
4991
4994 Returns 0 if there are outgoing changes, 1 otherwise.
4992 Returns 0 if there are outgoing changes, 1 otherwise.
4995 """
4993 """
4996 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4994 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4997 # style URLs, so don't overwrite dest.
4995 # style URLs, so don't overwrite dest.
4998 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4996 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4999 if not path:
4997 if not path:
5000 raise error.Abort(
4998 raise error.Abort(
5001 _(b'default repository not configured!'),
4999 _(b'default repository not configured!'),
5002 hint=_(b"see 'hg help config.paths'"),
5000 hint=_(b"see 'hg help config.paths'"),
5003 )
5001 )
5004
5002
5005 opts = pycompat.byteskwargs(opts)
5003 opts = pycompat.byteskwargs(opts)
5006 if opts.get(b'graph'):
5004 if opts.get(b'graph'):
5007 logcmdutil.checkunsupportedgraphflags([], opts)
5005 logcmdutil.checkunsupportedgraphflags([], opts)
5008 o, other = hg._outgoing(ui, repo, dest, opts)
5006 o, other = hg._outgoing(ui, repo, dest, opts)
5009 if not o:
5007 if not o:
5010 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5008 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5011 return
5009 return
5012
5010
5013 revdag = logcmdutil.graphrevs(repo, o, opts)
5011 revdag = logcmdutil.graphrevs(repo, o, opts)
5014 ui.pager(b'outgoing')
5012 ui.pager(b'outgoing')
5015 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5013 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5016 logcmdutil.displaygraph(
5014 logcmdutil.displaygraph(
5017 ui, repo, revdag, displayer, graphmod.asciiedges
5015 ui, repo, revdag, displayer, graphmod.asciiedges
5018 )
5016 )
5019 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5017 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5020 return 0
5018 return 0
5021
5019
5022 if opts.get(b'bookmarks'):
5020 if opts.get(b'bookmarks'):
5023 dest = path.pushloc or path.loc
5021 dest = path.pushloc or path.loc
5024 other = hg.peer(repo, opts, dest)
5022 other = hg.peer(repo, opts, dest)
5025 if b'bookmarks' not in other.listkeys(b'namespaces'):
5023 if b'bookmarks' not in other.listkeys(b'namespaces'):
5026 ui.warn(_(b"remote doesn't support bookmarks\n"))
5024 ui.warn(_(b"remote doesn't support bookmarks\n"))
5027 return 0
5025 return 0
5028 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5026 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5029 ui.pager(b'outgoing')
5027 ui.pager(b'outgoing')
5030 return bookmarks.outgoing(ui, repo, other)
5028 return bookmarks.outgoing(ui, repo, other)
5031
5029
5032 repo._subtoppath = path.pushloc or path.loc
5030 repo._subtoppath = path.pushloc or path.loc
5033 try:
5031 try:
5034 return hg.outgoing(ui, repo, dest, opts)
5032 return hg.outgoing(ui, repo, dest, opts)
5035 finally:
5033 finally:
5036 del repo._subtoppath
5034 del repo._subtoppath
5037
5035
5038
5036
5039 @command(
5037 @command(
5040 b'parents',
5038 b'parents',
5041 [
5039 [
5042 (
5040 (
5043 b'r',
5041 b'r',
5044 b'rev',
5042 b'rev',
5045 b'',
5043 b'',
5046 _(b'show parents of the specified revision'),
5044 _(b'show parents of the specified revision'),
5047 _(b'REV'),
5045 _(b'REV'),
5048 ),
5046 ),
5049 ]
5047 ]
5050 + templateopts,
5048 + templateopts,
5051 _(b'[-r REV] [FILE]'),
5049 _(b'[-r REV] [FILE]'),
5052 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5050 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5053 inferrepo=True,
5051 inferrepo=True,
5054 )
5052 )
5055 def parents(ui, repo, file_=None, **opts):
5053 def parents(ui, repo, file_=None, **opts):
5056 """show the parents of the working directory or revision (DEPRECATED)
5054 """show the parents of the working directory or revision (DEPRECATED)
5057
5055
5058 Print the working directory's parent revisions. If a revision is
5056 Print the working directory's parent revisions. If a revision is
5059 given via -r/--rev, the parent of that revision will be printed.
5057 given via -r/--rev, the parent of that revision will be printed.
5060 If a file argument is given, the revision in which the file was
5058 If a file argument is given, the revision in which the file was
5061 last changed (before the working directory revision or the
5059 last changed (before the working directory revision or the
5062 argument to --rev if given) is printed.
5060 argument to --rev if given) is printed.
5063
5061
5064 This command is equivalent to::
5062 This command is equivalent to::
5065
5063
5066 hg log -r "p1()+p2()" or
5064 hg log -r "p1()+p2()" or
5067 hg log -r "p1(REV)+p2(REV)" or
5065 hg log -r "p1(REV)+p2(REV)" or
5068 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5066 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5069 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5067 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5070
5068
5071 See :hg:`summary` and :hg:`help revsets` for related information.
5069 See :hg:`summary` and :hg:`help revsets` for related information.
5072
5070
5073 Returns 0 on success.
5071 Returns 0 on success.
5074 """
5072 """
5075
5073
5076 opts = pycompat.byteskwargs(opts)
5074 opts = pycompat.byteskwargs(opts)
5077 rev = opts.get(b'rev')
5075 rev = opts.get(b'rev')
5078 if rev:
5076 if rev:
5079 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5077 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5080 ctx = scmutil.revsingle(repo, rev, None)
5078 ctx = scmutil.revsingle(repo, rev, None)
5081
5079
5082 if file_:
5080 if file_:
5083 m = scmutil.match(ctx, (file_,), opts)
5081 m = scmutil.match(ctx, (file_,), opts)
5084 if m.anypats() or len(m.files()) != 1:
5082 if m.anypats() or len(m.files()) != 1:
5085 raise error.Abort(_(b'can only specify an explicit filename'))
5083 raise error.Abort(_(b'can only specify an explicit filename'))
5086 file_ = m.files()[0]
5084 file_ = m.files()[0]
5087 filenodes = []
5085 filenodes = []
5088 for cp in ctx.parents():
5086 for cp in ctx.parents():
5089 if not cp:
5087 if not cp:
5090 continue
5088 continue
5091 try:
5089 try:
5092 filenodes.append(cp.filenode(file_))
5090 filenodes.append(cp.filenode(file_))
5093 except error.LookupError:
5091 except error.LookupError:
5094 pass
5092 pass
5095 if not filenodes:
5093 if not filenodes:
5096 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5094 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5097 p = []
5095 p = []
5098 for fn in filenodes:
5096 for fn in filenodes:
5099 fctx = repo.filectx(file_, fileid=fn)
5097 fctx = repo.filectx(file_, fileid=fn)
5100 p.append(fctx.node())
5098 p.append(fctx.node())
5101 else:
5099 else:
5102 p = [cp.node() for cp in ctx.parents()]
5100 p = [cp.node() for cp in ctx.parents()]
5103
5101
5104 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5102 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5105 for n in p:
5103 for n in p:
5106 if n != nullid:
5104 if n != nullid:
5107 displayer.show(repo[n])
5105 displayer.show(repo[n])
5108 displayer.close()
5106 displayer.close()
5109
5107
5110
5108
5111 @command(
5109 @command(
5112 b'paths',
5110 b'paths',
5113 formatteropts,
5111 formatteropts,
5114 _(b'[NAME]'),
5112 _(b'[NAME]'),
5115 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5113 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5116 optionalrepo=True,
5114 optionalrepo=True,
5117 intents={INTENT_READONLY},
5115 intents={INTENT_READONLY},
5118 )
5116 )
5119 def paths(ui, repo, search=None, **opts):
5117 def paths(ui, repo, search=None, **opts):
5120 """show aliases for remote repositories
5118 """show aliases for remote repositories
5121
5119
5122 Show definition of symbolic path name NAME. If no name is given,
5120 Show definition of symbolic path name NAME. If no name is given,
5123 show definition of all available names.
5121 show definition of all available names.
5124
5122
5125 Option -q/--quiet suppresses all output when searching for NAME
5123 Option -q/--quiet suppresses all output when searching for NAME
5126 and shows only the path names when listing all definitions.
5124 and shows only the path names when listing all definitions.
5127
5125
5128 Path names are defined in the [paths] section of your
5126 Path names are defined in the [paths] section of your
5129 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5127 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5130 repository, ``.hg/hgrc`` is used, too.
5128 repository, ``.hg/hgrc`` is used, too.
5131
5129
5132 The path names ``default`` and ``default-push`` have a special
5130 The path names ``default`` and ``default-push`` have a special
5133 meaning. When performing a push or pull operation, they are used
5131 meaning. When performing a push or pull operation, they are used
5134 as fallbacks if no location is specified on the command-line.
5132 as fallbacks if no location is specified on the command-line.
5135 When ``default-push`` is set, it will be used for push and
5133 When ``default-push`` is set, it will be used for push and
5136 ``default`` will be used for pull; otherwise ``default`` is used
5134 ``default`` will be used for pull; otherwise ``default`` is used
5137 as the fallback for both. When cloning a repository, the clone
5135 as the fallback for both. When cloning a repository, the clone
5138 source is written as ``default`` in ``.hg/hgrc``.
5136 source is written as ``default`` in ``.hg/hgrc``.
5139
5137
5140 .. note::
5138 .. note::
5141
5139
5142 ``default`` and ``default-push`` apply to all inbound (e.g.
5140 ``default`` and ``default-push`` apply to all inbound (e.g.
5143 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5141 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5144 and :hg:`bundle`) operations.
5142 and :hg:`bundle`) operations.
5145
5143
5146 See :hg:`help urls` for more information.
5144 See :hg:`help urls` for more information.
5147
5145
5148 .. container:: verbose
5146 .. container:: verbose
5149
5147
5150 Template:
5148 Template:
5151
5149
5152 The following keywords are supported. See also :hg:`help templates`.
5150 The following keywords are supported. See also :hg:`help templates`.
5153
5151
5154 :name: String. Symbolic name of the path alias.
5152 :name: String. Symbolic name of the path alias.
5155 :pushurl: String. URL for push operations.
5153 :pushurl: String. URL for push operations.
5156 :url: String. URL or directory path for the other operations.
5154 :url: String. URL or directory path for the other operations.
5157
5155
5158 Returns 0 on success.
5156 Returns 0 on success.
5159 """
5157 """
5160
5158
5161 opts = pycompat.byteskwargs(opts)
5159 opts = pycompat.byteskwargs(opts)
5162 ui.pager(b'paths')
5160 ui.pager(b'paths')
5163 if search:
5161 if search:
5164 pathitems = [
5162 pathitems = [
5165 (name, path)
5163 (name, path)
5166 for name, path in pycompat.iteritems(ui.paths)
5164 for name, path in pycompat.iteritems(ui.paths)
5167 if name == search
5165 if name == search
5168 ]
5166 ]
5169 else:
5167 else:
5170 pathitems = sorted(pycompat.iteritems(ui.paths))
5168 pathitems = sorted(pycompat.iteritems(ui.paths))
5171
5169
5172 fm = ui.formatter(b'paths', opts)
5170 fm = ui.formatter(b'paths', opts)
5173 if fm.isplain():
5171 if fm.isplain():
5174 hidepassword = util.hidepassword
5172 hidepassword = util.hidepassword
5175 else:
5173 else:
5176 hidepassword = bytes
5174 hidepassword = bytes
5177 if ui.quiet:
5175 if ui.quiet:
5178 namefmt = b'%s\n'
5176 namefmt = b'%s\n'
5179 else:
5177 else:
5180 namefmt = b'%s = '
5178 namefmt = b'%s = '
5181 showsubopts = not search and not ui.quiet
5179 showsubopts = not search and not ui.quiet
5182
5180
5183 for name, path in pathitems:
5181 for name, path in pathitems:
5184 fm.startitem()
5182 fm.startitem()
5185 fm.condwrite(not search, b'name', namefmt, name)
5183 fm.condwrite(not search, b'name', namefmt, name)
5186 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5184 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5187 for subopt, value in sorted(path.suboptions.items()):
5185 for subopt, value in sorted(path.suboptions.items()):
5188 assert subopt not in (b'name', b'url')
5186 assert subopt not in (b'name', b'url')
5189 if showsubopts:
5187 if showsubopts:
5190 fm.plain(b'%s:%s = ' % (name, subopt))
5188 fm.plain(b'%s:%s = ' % (name, subopt))
5191 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5189 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5192
5190
5193 fm.end()
5191 fm.end()
5194
5192
5195 if search and not pathitems:
5193 if search and not pathitems:
5196 if not ui.quiet:
5194 if not ui.quiet:
5197 ui.warn(_(b"not found!\n"))
5195 ui.warn(_(b"not found!\n"))
5198 return 1
5196 return 1
5199 else:
5197 else:
5200 return 0
5198 return 0
5201
5199
5202
5200
5203 @command(
5201 @command(
5204 b'phase',
5202 b'phase',
5205 [
5203 [
5206 (b'p', b'public', False, _(b'set changeset phase to public')),
5204 (b'p', b'public', False, _(b'set changeset phase to public')),
5207 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5205 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5208 (b's', b'secret', False, _(b'set changeset phase to secret')),
5206 (b's', b'secret', False, _(b'set changeset phase to secret')),
5209 (b'f', b'force', False, _(b'allow to move boundary backward')),
5207 (b'f', b'force', False, _(b'allow to move boundary backward')),
5210 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5208 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5211 ],
5209 ],
5212 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5210 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5213 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5211 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5214 )
5212 )
5215 def phase(ui, repo, *revs, **opts):
5213 def phase(ui, repo, *revs, **opts):
5216 """set or show the current phase name
5214 """set or show the current phase name
5217
5215
5218 With no argument, show the phase name of the current revision(s).
5216 With no argument, show the phase name of the current revision(s).
5219
5217
5220 With one of -p/--public, -d/--draft or -s/--secret, change the
5218 With one of -p/--public, -d/--draft or -s/--secret, change the
5221 phase value of the specified revisions.
5219 phase value of the specified revisions.
5222
5220
5223 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5221 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5224 lower phase to a higher phase. Phases are ordered as follows::
5222 lower phase to a higher phase. Phases are ordered as follows::
5225
5223
5226 public < draft < secret
5224 public < draft < secret
5227
5225
5228 Returns 0 on success, 1 if some phases could not be changed.
5226 Returns 0 on success, 1 if some phases could not be changed.
5229
5227
5230 (For more information about the phases concept, see :hg:`help phases`.)
5228 (For more information about the phases concept, see :hg:`help phases`.)
5231 """
5229 """
5232 opts = pycompat.byteskwargs(opts)
5230 opts = pycompat.byteskwargs(opts)
5233 # search for a unique phase argument
5231 # search for a unique phase argument
5234 targetphase = None
5232 targetphase = None
5235 for idx, name in enumerate(phases.cmdphasenames):
5233 for idx, name in enumerate(phases.cmdphasenames):
5236 if opts[name]:
5234 if opts[name]:
5237 if targetphase is not None:
5235 if targetphase is not None:
5238 raise error.Abort(_(b'only one phase can be specified'))
5236 raise error.Abort(_(b'only one phase can be specified'))
5239 targetphase = idx
5237 targetphase = idx
5240
5238
5241 # look for specified revision
5239 # look for specified revision
5242 revs = list(revs)
5240 revs = list(revs)
5243 revs.extend(opts[b'rev'])
5241 revs.extend(opts[b'rev'])
5244 if not revs:
5242 if not revs:
5245 # display both parents as the second parent phase can influence
5243 # display both parents as the second parent phase can influence
5246 # the phase of a merge commit
5244 # the phase of a merge commit
5247 revs = [c.rev() for c in repo[None].parents()]
5245 revs = [c.rev() for c in repo[None].parents()]
5248
5246
5249 revs = scmutil.revrange(repo, revs)
5247 revs = scmutil.revrange(repo, revs)
5250
5248
5251 ret = 0
5249 ret = 0
5252 if targetphase is None:
5250 if targetphase is None:
5253 # display
5251 # display
5254 for r in revs:
5252 for r in revs:
5255 ctx = repo[r]
5253 ctx = repo[r]
5256 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5254 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5257 else:
5255 else:
5258 with repo.lock(), repo.transaction(b"phase") as tr:
5256 with repo.lock(), repo.transaction(b"phase") as tr:
5259 # set phase
5257 # set phase
5260 if not revs:
5258 if not revs:
5261 raise error.Abort(_(b'empty revision set'))
5259 raise error.Abort(_(b'empty revision set'))
5262 nodes = [repo[r].node() for r in revs]
5260 nodes = [repo[r].node() for r in revs]
5263 # moving revision from public to draft may hide them
5261 # moving revision from public to draft may hide them
5264 # We have to check result on an unfiltered repository
5262 # We have to check result on an unfiltered repository
5265 unfi = repo.unfiltered()
5263 unfi = repo.unfiltered()
5266 getphase = unfi._phasecache.phase
5264 getphase = unfi._phasecache.phase
5267 olddata = [getphase(unfi, r) for r in unfi]
5265 olddata = [getphase(unfi, r) for r in unfi]
5268 phases.advanceboundary(repo, tr, targetphase, nodes)
5266 phases.advanceboundary(repo, tr, targetphase, nodes)
5269 if opts[b'force']:
5267 if opts[b'force']:
5270 phases.retractboundary(repo, tr, targetphase, nodes)
5268 phases.retractboundary(repo, tr, targetphase, nodes)
5271 getphase = unfi._phasecache.phase
5269 getphase = unfi._phasecache.phase
5272 newdata = [getphase(unfi, r) for r in unfi]
5270 newdata = [getphase(unfi, r) for r in unfi]
5273 changes = sum(newdata[r] != olddata[r] for r in unfi)
5271 changes = sum(newdata[r] != olddata[r] for r in unfi)
5274 cl = unfi.changelog
5272 cl = unfi.changelog
5275 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5273 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5276 if rejected:
5274 if rejected:
5277 ui.warn(
5275 ui.warn(
5278 _(
5276 _(
5279 b'cannot move %i changesets to a higher '
5277 b'cannot move %i changesets to a higher '
5280 b'phase, use --force\n'
5278 b'phase, use --force\n'
5281 )
5279 )
5282 % len(rejected)
5280 % len(rejected)
5283 )
5281 )
5284 ret = 1
5282 ret = 1
5285 if changes:
5283 if changes:
5286 msg = _(b'phase changed for %i changesets\n') % changes
5284 msg = _(b'phase changed for %i changesets\n') % changes
5287 if ret:
5285 if ret:
5288 ui.status(msg)
5286 ui.status(msg)
5289 else:
5287 else:
5290 ui.note(msg)
5288 ui.note(msg)
5291 else:
5289 else:
5292 ui.warn(_(b'no phases changed\n'))
5290 ui.warn(_(b'no phases changed\n'))
5293 return ret
5291 return ret
5294
5292
5295
5293
5296 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5294 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5297 """Run after a changegroup has been added via pull/unbundle
5295 """Run after a changegroup has been added via pull/unbundle
5298
5296
5299 This takes arguments below:
5297 This takes arguments below:
5300
5298
5301 :modheads: change of heads by pull/unbundle
5299 :modheads: change of heads by pull/unbundle
5302 :optupdate: updating working directory is needed or not
5300 :optupdate: updating working directory is needed or not
5303 :checkout: update destination revision (or None to default destination)
5301 :checkout: update destination revision (or None to default destination)
5304 :brev: a name, which might be a bookmark to be activated after updating
5302 :brev: a name, which might be a bookmark to be activated after updating
5305 """
5303 """
5306 if modheads == 0:
5304 if modheads == 0:
5307 return
5305 return
5308 if optupdate:
5306 if optupdate:
5309 try:
5307 try:
5310 return hg.updatetotally(ui, repo, checkout, brev)
5308 return hg.updatetotally(ui, repo, checkout, brev)
5311 except error.UpdateAbort as inst:
5309 except error.UpdateAbort as inst:
5312 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5310 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5313 hint = inst.hint
5311 hint = inst.hint
5314 raise error.UpdateAbort(msg, hint=hint)
5312 raise error.UpdateAbort(msg, hint=hint)
5315 if modheads is not None and modheads > 1:
5313 if modheads is not None and modheads > 1:
5316 currentbranchheads = len(repo.branchheads())
5314 currentbranchheads = len(repo.branchheads())
5317 if currentbranchheads == modheads:
5315 if currentbranchheads == modheads:
5318 ui.status(
5316 ui.status(
5319 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5317 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5320 )
5318 )
5321 elif currentbranchheads > 1:
5319 elif currentbranchheads > 1:
5322 ui.status(
5320 ui.status(
5323 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5321 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5324 )
5322 )
5325 else:
5323 else:
5326 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5324 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5327 elif not ui.configbool(b'commands', b'update.requiredest'):
5325 elif not ui.configbool(b'commands', b'update.requiredest'):
5328 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5326 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5329
5327
5330
5328
5331 @command(
5329 @command(
5332 b'pull',
5330 b'pull',
5333 [
5331 [
5334 (
5332 (
5335 b'u',
5333 b'u',
5336 b'update',
5334 b'update',
5337 None,
5335 None,
5338 _(b'update to new branch head if new descendants were pulled'),
5336 _(b'update to new branch head if new descendants were pulled'),
5339 ),
5337 ),
5340 (
5338 (
5341 b'f',
5339 b'f',
5342 b'force',
5340 b'force',
5343 None,
5341 None,
5344 _(b'run even when remote repository is unrelated'),
5342 _(b'run even when remote repository is unrelated'),
5345 ),
5343 ),
5346 (
5344 (
5347 b'r',
5345 b'r',
5348 b'rev',
5346 b'rev',
5349 [],
5347 [],
5350 _(b'a remote changeset intended to be added'),
5348 _(b'a remote changeset intended to be added'),
5351 _(b'REV'),
5349 _(b'REV'),
5352 ),
5350 ),
5353 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5351 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5354 (
5352 (
5355 b'b',
5353 b'b',
5356 b'branch',
5354 b'branch',
5357 [],
5355 [],
5358 _(b'a specific branch you would like to pull'),
5356 _(b'a specific branch you would like to pull'),
5359 _(b'BRANCH'),
5357 _(b'BRANCH'),
5360 ),
5358 ),
5361 ]
5359 ]
5362 + remoteopts,
5360 + remoteopts,
5363 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5361 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5364 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5362 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5365 helpbasic=True,
5363 helpbasic=True,
5366 )
5364 )
5367 def pull(ui, repo, source=b"default", **opts):
5365 def pull(ui, repo, source=b"default", **opts):
5368 """pull changes from the specified source
5366 """pull changes from the specified source
5369
5367
5370 Pull changes from a remote repository to a local one.
5368 Pull changes from a remote repository to a local one.
5371
5369
5372 This finds all changes from the repository at the specified path
5370 This finds all changes from the repository at the specified path
5373 or URL and adds them to a local repository (the current one unless
5371 or URL and adds them to a local repository (the current one unless
5374 -R is specified). By default, this does not update the copy of the
5372 -R is specified). By default, this does not update the copy of the
5375 project in the working directory.
5373 project in the working directory.
5376
5374
5377 When cloning from servers that support it, Mercurial may fetch
5375 When cloning from servers that support it, Mercurial may fetch
5378 pre-generated data. When this is done, hooks operating on incoming
5376 pre-generated data. When this is done, hooks operating on incoming
5379 changesets and changegroups may fire more than once, once for each
5377 changesets and changegroups may fire more than once, once for each
5380 pre-generated bundle and as well as for any additional remaining
5378 pre-generated bundle and as well as for any additional remaining
5381 data. See :hg:`help -e clonebundles` for more.
5379 data. See :hg:`help -e clonebundles` for more.
5382
5380
5383 Use :hg:`incoming` if you want to see what would have been added
5381 Use :hg:`incoming` if you want to see what would have been added
5384 by a pull at the time you issued this command. If you then decide
5382 by a pull at the time you issued this command. If you then decide
5385 to add those changes to the repository, you should use :hg:`pull
5383 to add those changes to the repository, you should use :hg:`pull
5386 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5384 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5387
5385
5388 If SOURCE is omitted, the 'default' path will be used.
5386 If SOURCE is omitted, the 'default' path will be used.
5389 See :hg:`help urls` for more information.
5387 See :hg:`help urls` for more information.
5390
5388
5391 Specifying bookmark as ``.`` is equivalent to specifying the active
5389 Specifying bookmark as ``.`` is equivalent to specifying the active
5392 bookmark's name.
5390 bookmark's name.
5393
5391
5394 Returns 0 on success, 1 if an update had unresolved files.
5392 Returns 0 on success, 1 if an update had unresolved files.
5395 """
5393 """
5396
5394
5397 opts = pycompat.byteskwargs(opts)
5395 opts = pycompat.byteskwargs(opts)
5398 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5396 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5399 b'update'
5397 b'update'
5400 ):
5398 ):
5401 msg = _(b'update destination required by configuration')
5399 msg = _(b'update destination required by configuration')
5402 hint = _(b'use hg pull followed by hg update DEST')
5400 hint = _(b'use hg pull followed by hg update DEST')
5403 raise error.Abort(msg, hint=hint)
5401 raise error.Abort(msg, hint=hint)
5404
5402
5405 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5403 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5406 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5404 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5407 other = hg.peer(repo, opts, source)
5405 other = hg.peer(repo, opts, source)
5408 try:
5406 try:
5409 revs, checkout = hg.addbranchrevs(
5407 revs, checkout = hg.addbranchrevs(
5410 repo, other, branches, opts.get(b'rev')
5408 repo, other, branches, opts.get(b'rev')
5411 )
5409 )
5412
5410
5413 pullopargs = {}
5411 pullopargs = {}
5414
5412
5415 nodes = None
5413 nodes = None
5416 if opts.get(b'bookmark') or revs:
5414 if opts.get(b'bookmark') or revs:
5417 # The list of bookmark used here is the same used to actually update
5415 # The list of bookmark used here is the same used to actually update
5418 # the bookmark names, to avoid the race from issue 4689 and we do
5416 # the bookmark names, to avoid the race from issue 4689 and we do
5419 # all lookup and bookmark queries in one go so they see the same
5417 # all lookup and bookmark queries in one go so they see the same
5420 # version of the server state (issue 4700).
5418 # version of the server state (issue 4700).
5421 nodes = []
5419 nodes = []
5422 fnodes = []
5420 fnodes = []
5423 revs = revs or []
5421 revs = revs or []
5424 if revs and not other.capable(b'lookup'):
5422 if revs and not other.capable(b'lookup'):
5425 err = _(
5423 err = _(
5426 b"other repository doesn't support revision lookup, "
5424 b"other repository doesn't support revision lookup, "
5427 b"so a rev cannot be specified."
5425 b"so a rev cannot be specified."
5428 )
5426 )
5429 raise error.Abort(err)
5427 raise error.Abort(err)
5430 with other.commandexecutor() as e:
5428 with other.commandexecutor() as e:
5431 fremotebookmarks = e.callcommand(
5429 fremotebookmarks = e.callcommand(
5432 b'listkeys', {b'namespace': b'bookmarks'}
5430 b'listkeys', {b'namespace': b'bookmarks'}
5433 )
5431 )
5434 for r in revs:
5432 for r in revs:
5435 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5433 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5436 remotebookmarks = fremotebookmarks.result()
5434 remotebookmarks = fremotebookmarks.result()
5437 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5435 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5438 pullopargs[b'remotebookmarks'] = remotebookmarks
5436 pullopargs[b'remotebookmarks'] = remotebookmarks
5439 for b in opts.get(b'bookmark', []):
5437 for b in opts.get(b'bookmark', []):
5440 b = repo._bookmarks.expandname(b)
5438 b = repo._bookmarks.expandname(b)
5441 if b not in remotebookmarks:
5439 if b not in remotebookmarks:
5442 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5440 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5443 nodes.append(remotebookmarks[b])
5441 nodes.append(remotebookmarks[b])
5444 for i, rev in enumerate(revs):
5442 for i, rev in enumerate(revs):
5445 node = fnodes[i].result()
5443 node = fnodes[i].result()
5446 nodes.append(node)
5444 nodes.append(node)
5447 if rev == checkout:
5445 if rev == checkout:
5448 checkout = node
5446 checkout = node
5449
5447
5450 wlock = util.nullcontextmanager()
5448 wlock = util.nullcontextmanager()
5451 if opts.get(b'update'):
5449 if opts.get(b'update'):
5452 wlock = repo.wlock()
5450 wlock = repo.wlock()
5453 with wlock:
5451 with wlock:
5454 pullopargs.update(opts.get(b'opargs', {}))
5452 pullopargs.update(opts.get(b'opargs', {}))
5455 modheads = exchange.pull(
5453 modheads = exchange.pull(
5456 repo,
5454 repo,
5457 other,
5455 other,
5458 heads=nodes,
5456 heads=nodes,
5459 force=opts.get(b'force'),
5457 force=opts.get(b'force'),
5460 bookmarks=opts.get(b'bookmark', ()),
5458 bookmarks=opts.get(b'bookmark', ()),
5461 opargs=pullopargs,
5459 opargs=pullopargs,
5462 ).cgresult
5460 ).cgresult
5463
5461
5464 # brev is a name, which might be a bookmark to be activated at
5462 # brev is a name, which might be a bookmark to be activated at
5465 # the end of the update. In other words, it is an explicit
5463 # the end of the update. In other words, it is an explicit
5466 # destination of the update
5464 # destination of the update
5467 brev = None
5465 brev = None
5468
5466
5469 if checkout:
5467 if checkout:
5470 checkout = repo.unfiltered().changelog.rev(checkout)
5468 checkout = repo.unfiltered().changelog.rev(checkout)
5471
5469
5472 # order below depends on implementation of
5470 # order below depends on implementation of
5473 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5471 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5474 # because 'checkout' is determined without it.
5472 # because 'checkout' is determined without it.
5475 if opts.get(b'rev'):
5473 if opts.get(b'rev'):
5476 brev = opts[b'rev'][0]
5474 brev = opts[b'rev'][0]
5477 elif opts.get(b'branch'):
5475 elif opts.get(b'branch'):
5478 brev = opts[b'branch'][0]
5476 brev = opts[b'branch'][0]
5479 else:
5477 else:
5480 brev = branches[0]
5478 brev = branches[0]
5481 repo._subtoppath = source
5479 repo._subtoppath = source
5482 try:
5480 try:
5483 ret = postincoming(
5481 ret = postincoming(
5484 ui, repo, modheads, opts.get(b'update'), checkout, brev
5482 ui, repo, modheads, opts.get(b'update'), checkout, brev
5485 )
5483 )
5486 except error.FilteredRepoLookupError as exc:
5484 except error.FilteredRepoLookupError as exc:
5487 msg = _(b'cannot update to target: %s') % exc.args[0]
5485 msg = _(b'cannot update to target: %s') % exc.args[0]
5488 exc.args = (msg,) + exc.args[1:]
5486 exc.args = (msg,) + exc.args[1:]
5489 raise
5487 raise
5490 finally:
5488 finally:
5491 del repo._subtoppath
5489 del repo._subtoppath
5492
5490
5493 finally:
5491 finally:
5494 other.close()
5492 other.close()
5495 return ret
5493 return ret
5496
5494
5497
5495
5498 @command(
5496 @command(
5499 b'push',
5497 b'push',
5500 [
5498 [
5501 (b'f', b'force', None, _(b'force push')),
5499 (b'f', b'force', None, _(b'force push')),
5502 (
5500 (
5503 b'r',
5501 b'r',
5504 b'rev',
5502 b'rev',
5505 [],
5503 [],
5506 _(b'a changeset intended to be included in the destination'),
5504 _(b'a changeset intended to be included in the destination'),
5507 _(b'REV'),
5505 _(b'REV'),
5508 ),
5506 ),
5509 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5507 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5510 (
5508 (
5511 b'b',
5509 b'b',
5512 b'branch',
5510 b'branch',
5513 [],
5511 [],
5514 _(b'a specific branch you would like to push'),
5512 _(b'a specific branch you would like to push'),
5515 _(b'BRANCH'),
5513 _(b'BRANCH'),
5516 ),
5514 ),
5517 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5515 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5518 (
5516 (
5519 b'',
5517 b'',
5520 b'pushvars',
5518 b'pushvars',
5521 [],
5519 [],
5522 _(b'variables that can be sent to server (ADVANCED)'),
5520 _(b'variables that can be sent to server (ADVANCED)'),
5523 ),
5521 ),
5524 (
5522 (
5525 b'',
5523 b'',
5526 b'publish',
5524 b'publish',
5527 False,
5525 False,
5528 _(b'push the changeset as public (EXPERIMENTAL)'),
5526 _(b'push the changeset as public (EXPERIMENTAL)'),
5529 ),
5527 ),
5530 ]
5528 ]
5531 + remoteopts,
5529 + remoteopts,
5532 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5530 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5533 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5531 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5534 helpbasic=True,
5532 helpbasic=True,
5535 )
5533 )
5536 def push(ui, repo, dest=None, **opts):
5534 def push(ui, repo, dest=None, **opts):
5537 """push changes to the specified destination
5535 """push changes to the specified destination
5538
5536
5539 Push changesets from the local repository to the specified
5537 Push changesets from the local repository to the specified
5540 destination.
5538 destination.
5541
5539
5542 This operation is symmetrical to pull: it is identical to a pull
5540 This operation is symmetrical to pull: it is identical to a pull
5543 in the destination repository from the current one.
5541 in the destination repository from the current one.
5544
5542
5545 By default, push will not allow creation of new heads at the
5543 By default, push will not allow creation of new heads at the
5546 destination, since multiple heads would make it unclear which head
5544 destination, since multiple heads would make it unclear which head
5547 to use. In this situation, it is recommended to pull and merge
5545 to use. In this situation, it is recommended to pull and merge
5548 before pushing.
5546 before pushing.
5549
5547
5550 Use --new-branch if you want to allow push to create a new named
5548 Use --new-branch if you want to allow push to create a new named
5551 branch that is not present at the destination. This allows you to
5549 branch that is not present at the destination. This allows you to
5552 only create a new branch without forcing other changes.
5550 only create a new branch without forcing other changes.
5553
5551
5554 .. note::
5552 .. note::
5555
5553
5556 Extra care should be taken with the -f/--force option,
5554 Extra care should be taken with the -f/--force option,
5557 which will push all new heads on all branches, an action which will
5555 which will push all new heads on all branches, an action which will
5558 almost always cause confusion for collaborators.
5556 almost always cause confusion for collaborators.
5559
5557
5560 If -r/--rev is used, the specified revision and all its ancestors
5558 If -r/--rev is used, the specified revision and all its ancestors
5561 will be pushed to the remote repository.
5559 will be pushed to the remote repository.
5562
5560
5563 If -B/--bookmark is used, the specified bookmarked revision, its
5561 If -B/--bookmark is used, the specified bookmarked revision, its
5564 ancestors, and the bookmark will be pushed to the remote
5562 ancestors, and the bookmark will be pushed to the remote
5565 repository. Specifying ``.`` is equivalent to specifying the active
5563 repository. Specifying ``.`` is equivalent to specifying the active
5566 bookmark's name.
5564 bookmark's name.
5567
5565
5568 Please see :hg:`help urls` for important details about ``ssh://``
5566 Please see :hg:`help urls` for important details about ``ssh://``
5569 URLs. If DESTINATION is omitted, a default path will be used.
5567 URLs. If DESTINATION is omitted, a default path will be used.
5570
5568
5571 .. container:: verbose
5569 .. container:: verbose
5572
5570
5573 The --pushvars option sends strings to the server that become
5571 The --pushvars option sends strings to the server that become
5574 environment variables prepended with ``HG_USERVAR_``. For example,
5572 environment variables prepended with ``HG_USERVAR_``. For example,
5575 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5573 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5576 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5574 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5577
5575
5578 pushvars can provide for user-overridable hooks as well as set debug
5576 pushvars can provide for user-overridable hooks as well as set debug
5579 levels. One example is having a hook that blocks commits containing
5577 levels. One example is having a hook that blocks commits containing
5580 conflict markers, but enables the user to override the hook if the file
5578 conflict markers, but enables the user to override the hook if the file
5581 is using conflict markers for testing purposes or the file format has
5579 is using conflict markers for testing purposes or the file format has
5582 strings that look like conflict markers.
5580 strings that look like conflict markers.
5583
5581
5584 By default, servers will ignore `--pushvars`. To enable it add the
5582 By default, servers will ignore `--pushvars`. To enable it add the
5585 following to your configuration file::
5583 following to your configuration file::
5586
5584
5587 [push]
5585 [push]
5588 pushvars.server = true
5586 pushvars.server = true
5589
5587
5590 Returns 0 if push was successful, 1 if nothing to push.
5588 Returns 0 if push was successful, 1 if nothing to push.
5591 """
5589 """
5592
5590
5593 opts = pycompat.byteskwargs(opts)
5591 opts = pycompat.byteskwargs(opts)
5594 if opts.get(b'bookmark'):
5592 if opts.get(b'bookmark'):
5595 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5593 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5596 for b in opts[b'bookmark']:
5594 for b in opts[b'bookmark']:
5597 # translate -B options to -r so changesets get pushed
5595 # translate -B options to -r so changesets get pushed
5598 b = repo._bookmarks.expandname(b)
5596 b = repo._bookmarks.expandname(b)
5599 if b in repo._bookmarks:
5597 if b in repo._bookmarks:
5600 opts.setdefault(b'rev', []).append(b)
5598 opts.setdefault(b'rev', []).append(b)
5601 else:
5599 else:
5602 # if we try to push a deleted bookmark, translate it to null
5600 # if we try to push a deleted bookmark, translate it to null
5603 # this lets simultaneous -r, -b options continue working
5601 # this lets simultaneous -r, -b options continue working
5604 opts.setdefault(b'rev', []).append(b"null")
5602 opts.setdefault(b'rev', []).append(b"null")
5605
5603
5606 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5604 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5607 if not path:
5605 if not path:
5608 raise error.Abort(
5606 raise error.Abort(
5609 _(b'default repository not configured!'),
5607 _(b'default repository not configured!'),
5610 hint=_(b"see 'hg help config.paths'"),
5608 hint=_(b"see 'hg help config.paths'"),
5611 )
5609 )
5612 dest = path.pushloc or path.loc
5610 dest = path.pushloc or path.loc
5613 branches = (path.branch, opts.get(b'branch') or [])
5611 branches = (path.branch, opts.get(b'branch') or [])
5614 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5612 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5615 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5613 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5616 other = hg.peer(repo, opts, dest)
5614 other = hg.peer(repo, opts, dest)
5617
5615
5618 if revs:
5616 if revs:
5619 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5617 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5620 if not revs:
5618 if not revs:
5621 raise error.Abort(
5619 raise error.Abort(
5622 _(b"specified revisions evaluate to an empty set"),
5620 _(b"specified revisions evaluate to an empty set"),
5623 hint=_(b"use different revision arguments"),
5621 hint=_(b"use different revision arguments"),
5624 )
5622 )
5625 elif path.pushrev:
5623 elif path.pushrev:
5626 # It doesn't make any sense to specify ancestor revisions. So limit
5624 # It doesn't make any sense to specify ancestor revisions. So limit
5627 # to DAG heads to make discovery simpler.
5625 # to DAG heads to make discovery simpler.
5628 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5626 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5629 revs = scmutil.revrange(repo, [expr])
5627 revs = scmutil.revrange(repo, [expr])
5630 revs = [repo[rev].node() for rev in revs]
5628 revs = [repo[rev].node() for rev in revs]
5631 if not revs:
5629 if not revs:
5632 raise error.Abort(
5630 raise error.Abort(
5633 _(b'default push revset for path evaluates to an empty set')
5631 _(b'default push revset for path evaluates to an empty set')
5634 )
5632 )
5635 elif ui.configbool(b'commands', b'push.require-revs'):
5633 elif ui.configbool(b'commands', b'push.require-revs'):
5636 raise error.Abort(
5634 raise error.Abort(
5637 _(b'no revisions specified to push'),
5635 _(b'no revisions specified to push'),
5638 hint=_(b'did you mean "hg push -r ."?'),
5636 hint=_(b'did you mean "hg push -r ."?'),
5639 )
5637 )
5640
5638
5641 repo._subtoppath = dest
5639 repo._subtoppath = dest
5642 try:
5640 try:
5643 # push subrepos depth-first for coherent ordering
5641 # push subrepos depth-first for coherent ordering
5644 c = repo[b'.']
5642 c = repo[b'.']
5645 subs = c.substate # only repos that are committed
5643 subs = c.substate # only repos that are committed
5646 for s in sorted(subs):
5644 for s in sorted(subs):
5647 result = c.sub(s).push(opts)
5645 result = c.sub(s).push(opts)
5648 if result == 0:
5646 if result == 0:
5649 return not result
5647 return not result
5650 finally:
5648 finally:
5651 del repo._subtoppath
5649 del repo._subtoppath
5652
5650
5653 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5651 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5654 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5652 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5655
5653
5656 pushop = exchange.push(
5654 pushop = exchange.push(
5657 repo,
5655 repo,
5658 other,
5656 other,
5659 opts.get(b'force'),
5657 opts.get(b'force'),
5660 revs=revs,
5658 revs=revs,
5661 newbranch=opts.get(b'new_branch'),
5659 newbranch=opts.get(b'new_branch'),
5662 bookmarks=opts.get(b'bookmark', ()),
5660 bookmarks=opts.get(b'bookmark', ()),
5663 publish=opts.get(b'publish'),
5661 publish=opts.get(b'publish'),
5664 opargs=opargs,
5662 opargs=opargs,
5665 )
5663 )
5666
5664
5667 result = not pushop.cgresult
5665 result = not pushop.cgresult
5668
5666
5669 if pushop.bkresult is not None:
5667 if pushop.bkresult is not None:
5670 if pushop.bkresult == 2:
5668 if pushop.bkresult == 2:
5671 result = 2
5669 result = 2
5672 elif not result and pushop.bkresult:
5670 elif not result and pushop.bkresult:
5673 result = 2
5671 result = 2
5674
5672
5675 return result
5673 return result
5676
5674
5677
5675
5678 @command(
5676 @command(
5679 b'recover',
5677 b'recover',
5680 [(b'', b'verify', True, b"run `hg verify` after succesful recover"),],
5678 [(b'', b'verify', True, b"run `hg verify` after succesful recover"),],
5681 helpcategory=command.CATEGORY_MAINTENANCE,
5679 helpcategory=command.CATEGORY_MAINTENANCE,
5682 )
5680 )
5683 def recover(ui, repo, **opts):
5681 def recover(ui, repo, **opts):
5684 """roll back an interrupted transaction
5682 """roll back an interrupted transaction
5685
5683
5686 Recover from an interrupted commit or pull.
5684 Recover from an interrupted commit or pull.
5687
5685
5688 This command tries to fix the repository status after an
5686 This command tries to fix the repository status after an
5689 interrupted operation. It should only be necessary when Mercurial
5687 interrupted operation. It should only be necessary when Mercurial
5690 suggests it.
5688 suggests it.
5691
5689
5692 Returns 0 if successful, 1 if nothing to recover or verify fails.
5690 Returns 0 if successful, 1 if nothing to recover or verify fails.
5693 """
5691 """
5694 ret = repo.recover()
5692 ret = repo.recover()
5695 if ret:
5693 if ret:
5696 if opts['verify']:
5694 if opts['verify']:
5697 return hg.verify(repo)
5695 return hg.verify(repo)
5698 else:
5696 else:
5699 msg = _(
5697 msg = _(
5700 b"(verify step skipped, run `hg verify` to check your "
5698 b"(verify step skipped, run `hg verify` to check your "
5701 b"repository content)\n"
5699 b"repository content)\n"
5702 )
5700 )
5703 ui.warn(msg)
5701 ui.warn(msg)
5704 return 0
5702 return 0
5705 return 1
5703 return 1
5706
5704
5707
5705
5708 @command(
5706 @command(
5709 b'remove|rm',
5707 b'remove|rm',
5710 [
5708 [
5711 (b'A', b'after', None, _(b'record delete for missing files')),
5709 (b'A', b'after', None, _(b'record delete for missing files')),
5712 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5710 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5713 ]
5711 ]
5714 + subrepoopts
5712 + subrepoopts
5715 + walkopts
5713 + walkopts
5716 + dryrunopts,
5714 + dryrunopts,
5717 _(b'[OPTION]... FILE...'),
5715 _(b'[OPTION]... FILE...'),
5718 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5716 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5719 helpbasic=True,
5717 helpbasic=True,
5720 inferrepo=True,
5718 inferrepo=True,
5721 )
5719 )
5722 def remove(ui, repo, *pats, **opts):
5720 def remove(ui, repo, *pats, **opts):
5723 """remove the specified files on the next commit
5721 """remove the specified files on the next commit
5724
5722
5725 Schedule the indicated files for removal from the current branch.
5723 Schedule the indicated files for removal from the current branch.
5726
5724
5727 This command schedules the files to be removed at the next commit.
5725 This command schedules the files to be removed at the next commit.
5728 To undo a remove before that, see :hg:`revert`. To undo added
5726 To undo a remove before that, see :hg:`revert`. To undo added
5729 files, see :hg:`forget`.
5727 files, see :hg:`forget`.
5730
5728
5731 .. container:: verbose
5729 .. container:: verbose
5732
5730
5733 -A/--after can be used to remove only files that have already
5731 -A/--after can be used to remove only files that have already
5734 been deleted, -f/--force can be used to force deletion, and -Af
5732 been deleted, -f/--force can be used to force deletion, and -Af
5735 can be used to remove files from the next revision without
5733 can be used to remove files from the next revision without
5736 deleting them from the working directory.
5734 deleting them from the working directory.
5737
5735
5738 The following table details the behavior of remove for different
5736 The following table details the behavior of remove for different
5739 file states (columns) and option combinations (rows). The file
5737 file states (columns) and option combinations (rows). The file
5740 states are Added [A], Clean [C], Modified [M] and Missing [!]
5738 states are Added [A], Clean [C], Modified [M] and Missing [!]
5741 (as reported by :hg:`status`). The actions are Warn, Remove
5739 (as reported by :hg:`status`). The actions are Warn, Remove
5742 (from branch) and Delete (from disk):
5740 (from branch) and Delete (from disk):
5743
5741
5744 ========= == == == ==
5742 ========= == == == ==
5745 opt/state A C M !
5743 opt/state A C M !
5746 ========= == == == ==
5744 ========= == == == ==
5747 none W RD W R
5745 none W RD W R
5748 -f R RD RD R
5746 -f R RD RD R
5749 -A W W W R
5747 -A W W W R
5750 -Af R R R R
5748 -Af R R R R
5751 ========= == == == ==
5749 ========= == == == ==
5752
5750
5753 .. note::
5751 .. note::
5754
5752
5755 :hg:`remove` never deletes files in Added [A] state from the
5753 :hg:`remove` never deletes files in Added [A] state from the
5756 working directory, not even if ``--force`` is specified.
5754 working directory, not even if ``--force`` is specified.
5757
5755
5758 Returns 0 on success, 1 if any warnings encountered.
5756 Returns 0 on success, 1 if any warnings encountered.
5759 """
5757 """
5760
5758
5761 opts = pycompat.byteskwargs(opts)
5759 opts = pycompat.byteskwargs(opts)
5762 after, force = opts.get(b'after'), opts.get(b'force')
5760 after, force = opts.get(b'after'), opts.get(b'force')
5763 dryrun = opts.get(b'dry_run')
5761 dryrun = opts.get(b'dry_run')
5764 if not pats and not after:
5762 if not pats and not after:
5765 raise error.Abort(_(b'no files specified'))
5763 raise error.Abort(_(b'no files specified'))
5766
5764
5767 m = scmutil.match(repo[None], pats, opts)
5765 m = scmutil.match(repo[None], pats, opts)
5768 subrepos = opts.get(b'subrepos')
5766 subrepos = opts.get(b'subrepos')
5769 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5767 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5770 return cmdutil.remove(
5768 return cmdutil.remove(
5771 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5769 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5772 )
5770 )
5773
5771
5774
5772
5775 @command(
5773 @command(
5776 b'rename|move|mv',
5774 b'rename|move|mv',
5777 [
5775 [
5778 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5776 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5779 (
5777 (
5780 b'f',
5778 b'f',
5781 b'force',
5779 b'force',
5782 None,
5780 None,
5783 _(b'forcibly move over an existing managed file'),
5781 _(b'forcibly move over an existing managed file'),
5784 ),
5782 ),
5785 ]
5783 ]
5786 + walkopts
5784 + walkopts
5787 + dryrunopts,
5785 + dryrunopts,
5788 _(b'[OPTION]... SOURCE... DEST'),
5786 _(b'[OPTION]... SOURCE... DEST'),
5789 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5787 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5790 )
5788 )
5791 def rename(ui, repo, *pats, **opts):
5789 def rename(ui, repo, *pats, **opts):
5792 """rename files; equivalent of copy + remove
5790 """rename files; equivalent of copy + remove
5793
5791
5794 Mark dest as copies of sources; mark sources for deletion. If dest
5792 Mark dest as copies of sources; mark sources for deletion. If dest
5795 is a directory, copies are put in that directory. If dest is a
5793 is a directory, copies are put in that directory. If dest is a
5796 file, there can only be one source.
5794 file, there can only be one source.
5797
5795
5798 By default, this command copies the contents of files as they
5796 By default, this command copies the contents of files as they
5799 exist in the working directory. If invoked with -A/--after, the
5797 exist in the working directory. If invoked with -A/--after, the
5800 operation is recorded, but no copying is performed.
5798 operation is recorded, but no copying is performed.
5801
5799
5802 This command takes effect at the next commit. To undo a rename
5800 This command takes effect at the next commit. To undo a rename
5803 before that, see :hg:`revert`.
5801 before that, see :hg:`revert`.
5804
5802
5805 Returns 0 on success, 1 if errors are encountered.
5803 Returns 0 on success, 1 if errors are encountered.
5806 """
5804 """
5807 opts = pycompat.byteskwargs(opts)
5805 opts = pycompat.byteskwargs(opts)
5808 with repo.wlock(False):
5806 with repo.wlock(False):
5809 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5807 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5810
5808
5811
5809
5812 @command(
5810 @command(
5813 b'resolve',
5811 b'resolve',
5814 [
5812 [
5815 (b'a', b'all', None, _(b'select all unresolved files')),
5813 (b'a', b'all', None, _(b'select all unresolved files')),
5816 (b'l', b'list', None, _(b'list state of files needing merge')),
5814 (b'l', b'list', None, _(b'list state of files needing merge')),
5817 (b'm', b'mark', None, _(b'mark files as resolved')),
5815 (b'm', b'mark', None, _(b'mark files as resolved')),
5818 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5816 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5819 (b'n', b'no-status', None, _(b'hide status prefix')),
5817 (b'n', b'no-status', None, _(b'hide status prefix')),
5820 (b'', b're-merge', None, _(b're-merge files')),
5818 (b'', b're-merge', None, _(b're-merge files')),
5821 ]
5819 ]
5822 + mergetoolopts
5820 + mergetoolopts
5823 + walkopts
5821 + walkopts
5824 + formatteropts,
5822 + formatteropts,
5825 _(b'[OPTION]... [FILE]...'),
5823 _(b'[OPTION]... [FILE]...'),
5826 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5824 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5827 inferrepo=True,
5825 inferrepo=True,
5828 )
5826 )
5829 def resolve(ui, repo, *pats, **opts):
5827 def resolve(ui, repo, *pats, **opts):
5830 """redo merges or set/view the merge status of files
5828 """redo merges or set/view the merge status of files
5831
5829
5832 Merges with unresolved conflicts are often the result of
5830 Merges with unresolved conflicts are often the result of
5833 non-interactive merging using the ``internal:merge`` configuration
5831 non-interactive merging using the ``internal:merge`` configuration
5834 setting, or a command-line merge tool like ``diff3``. The resolve
5832 setting, or a command-line merge tool like ``diff3``. The resolve
5835 command is used to manage the files involved in a merge, after
5833 command is used to manage the files involved in a merge, after
5836 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5834 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5837 working directory must have two parents). See :hg:`help
5835 working directory must have two parents). See :hg:`help
5838 merge-tools` for information on configuring merge tools.
5836 merge-tools` for information on configuring merge tools.
5839
5837
5840 The resolve command can be used in the following ways:
5838 The resolve command can be used in the following ways:
5841
5839
5842 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5840 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5843 the specified files, discarding any previous merge attempts. Re-merging
5841 the specified files, discarding any previous merge attempts. Re-merging
5844 is not performed for files already marked as resolved. Use ``--all/-a``
5842 is not performed for files already marked as resolved. Use ``--all/-a``
5845 to select all unresolved files. ``--tool`` can be used to specify
5843 to select all unresolved files. ``--tool`` can be used to specify
5846 the merge tool used for the given files. It overrides the HGMERGE
5844 the merge tool used for the given files. It overrides the HGMERGE
5847 environment variable and your configuration files. Previous file
5845 environment variable and your configuration files. Previous file
5848 contents are saved with a ``.orig`` suffix.
5846 contents are saved with a ``.orig`` suffix.
5849
5847
5850 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5848 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5851 (e.g. after having manually fixed-up the files). The default is
5849 (e.g. after having manually fixed-up the files). The default is
5852 to mark all unresolved files.
5850 to mark all unresolved files.
5853
5851
5854 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5852 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5855 default is to mark all resolved files.
5853 default is to mark all resolved files.
5856
5854
5857 - :hg:`resolve -l`: list files which had or still have conflicts.
5855 - :hg:`resolve -l`: list files which had or still have conflicts.
5858 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5856 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5859 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5857 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5860 the list. See :hg:`help filesets` for details.
5858 the list. See :hg:`help filesets` for details.
5861
5859
5862 .. note::
5860 .. note::
5863
5861
5864 Mercurial will not let you commit files with unresolved merge
5862 Mercurial will not let you commit files with unresolved merge
5865 conflicts. You must use :hg:`resolve -m ...` before you can
5863 conflicts. You must use :hg:`resolve -m ...` before you can
5866 commit after a conflicting merge.
5864 commit after a conflicting merge.
5867
5865
5868 .. container:: verbose
5866 .. container:: verbose
5869
5867
5870 Template:
5868 Template:
5871
5869
5872 The following keywords are supported in addition to the common template
5870 The following keywords are supported in addition to the common template
5873 keywords and functions. See also :hg:`help templates`.
5871 keywords and functions. See also :hg:`help templates`.
5874
5872
5875 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5873 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5876 :path: String. Repository-absolute path of the file.
5874 :path: String. Repository-absolute path of the file.
5877
5875
5878 Returns 0 on success, 1 if any files fail a resolve attempt.
5876 Returns 0 on success, 1 if any files fail a resolve attempt.
5879 """
5877 """
5880
5878
5881 opts = pycompat.byteskwargs(opts)
5879 opts = pycompat.byteskwargs(opts)
5882 confirm = ui.configbool(b'commands', b'resolve.confirm')
5880 confirm = ui.configbool(b'commands', b'resolve.confirm')
5883 flaglist = b'all mark unmark list no_status re_merge'.split()
5881 flaglist = b'all mark unmark list no_status re_merge'.split()
5884 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5882 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5885
5883
5886 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5884 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5887 if actioncount > 1:
5885 if actioncount > 1:
5888 raise error.Abort(_(b"too many actions specified"))
5886 raise error.Abort(_(b"too many actions specified"))
5889 elif actioncount == 0 and ui.configbool(
5887 elif actioncount == 0 and ui.configbool(
5890 b'commands', b'resolve.explicit-re-merge'
5888 b'commands', b'resolve.explicit-re-merge'
5891 ):
5889 ):
5892 hint = _(b'use --mark, --unmark, --list or --re-merge')
5890 hint = _(b'use --mark, --unmark, --list or --re-merge')
5893 raise error.Abort(_(b'no action specified'), hint=hint)
5891 raise error.Abort(_(b'no action specified'), hint=hint)
5894 if pats and all:
5892 if pats and all:
5895 raise error.Abort(_(b"can't specify --all and patterns"))
5893 raise error.Abort(_(b"can't specify --all and patterns"))
5896 if not (all or pats or show or mark or unmark):
5894 if not (all or pats or show or mark or unmark):
5897 raise error.Abort(
5895 raise error.Abort(
5898 _(b'no files or directories specified'),
5896 _(b'no files or directories specified'),
5899 hint=b'use --all to re-merge all unresolved files',
5897 hint=b'use --all to re-merge all unresolved files',
5900 )
5898 )
5901
5899
5902 if confirm:
5900 if confirm:
5903 if all:
5901 if all:
5904 if ui.promptchoice(
5902 if ui.promptchoice(
5905 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5903 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5906 ):
5904 ):
5907 raise error.Abort(_(b'user quit'))
5905 raise error.Abort(_(b'user quit'))
5908 if mark and not pats:
5906 if mark and not pats:
5909 if ui.promptchoice(
5907 if ui.promptchoice(
5910 _(
5908 _(
5911 b'mark all unresolved files as resolved (yn)?'
5909 b'mark all unresolved files as resolved (yn)?'
5912 b'$$ &Yes $$ &No'
5910 b'$$ &Yes $$ &No'
5913 )
5911 )
5914 ):
5912 ):
5915 raise error.Abort(_(b'user quit'))
5913 raise error.Abort(_(b'user quit'))
5916 if unmark and not pats:
5914 if unmark and not pats:
5917 if ui.promptchoice(
5915 if ui.promptchoice(
5918 _(
5916 _(
5919 b'mark all resolved files as unresolved (yn)?'
5917 b'mark all resolved files as unresolved (yn)?'
5920 b'$$ &Yes $$ &No'
5918 b'$$ &Yes $$ &No'
5921 )
5919 )
5922 ):
5920 ):
5923 raise error.Abort(_(b'user quit'))
5921 raise error.Abort(_(b'user quit'))
5924
5922
5925 uipathfn = scmutil.getuipathfn(repo)
5923 uipathfn = scmutil.getuipathfn(repo)
5926
5924
5927 if show:
5925 if show:
5928 ui.pager(b'resolve')
5926 ui.pager(b'resolve')
5929 fm = ui.formatter(b'resolve', opts)
5927 fm = ui.formatter(b'resolve', opts)
5930 ms = mergemod.mergestate.read(repo)
5928 ms = mergemod.mergestate.read(repo)
5931 wctx = repo[None]
5929 wctx = repo[None]
5932 m = scmutil.match(wctx, pats, opts)
5930 m = scmutil.match(wctx, pats, opts)
5933
5931
5934 # Labels and keys based on merge state. Unresolved path conflicts show
5932 # Labels and keys based on merge state. Unresolved path conflicts show
5935 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5933 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5936 # resolved conflicts.
5934 # resolved conflicts.
5937 mergestateinfo = {
5935 mergestateinfo = {
5938 mergemod.MERGE_RECORD_UNRESOLVED: (b'resolve.unresolved', b'U'),
5936 mergemod.MERGE_RECORD_UNRESOLVED: (b'resolve.unresolved', b'U'),
5939 mergemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5937 mergemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5940 mergemod.MERGE_RECORD_UNRESOLVED_PATH: (
5938 mergemod.MERGE_RECORD_UNRESOLVED_PATH: (
5941 b'resolve.unresolved',
5939 b'resolve.unresolved',
5942 b'P',
5940 b'P',
5943 ),
5941 ),
5944 mergemod.MERGE_RECORD_RESOLVED_PATH: (b'resolve.resolved', b'R'),
5942 mergemod.MERGE_RECORD_RESOLVED_PATH: (b'resolve.resolved', b'R'),
5945 mergemod.MERGE_RECORD_DRIVER_RESOLVED: (
5943 mergemod.MERGE_RECORD_DRIVER_RESOLVED: (
5946 b'resolve.driverresolved',
5944 b'resolve.driverresolved',
5947 b'D',
5945 b'D',
5948 ),
5946 ),
5949 }
5947 }
5950
5948
5951 for f in ms:
5949 for f in ms:
5952 if not m(f):
5950 if not m(f):
5953 continue
5951 continue
5954
5952
5955 label, key = mergestateinfo[ms[f]]
5953 label, key = mergestateinfo[ms[f]]
5956 fm.startitem()
5954 fm.startitem()
5957 fm.context(ctx=wctx)
5955 fm.context(ctx=wctx)
5958 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5956 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5959 fm.data(path=f)
5957 fm.data(path=f)
5960 fm.plain(b'%s\n' % uipathfn(f), label=label)
5958 fm.plain(b'%s\n' % uipathfn(f), label=label)
5961 fm.end()
5959 fm.end()
5962 return 0
5960 return 0
5963
5961
5964 with repo.wlock():
5962 with repo.wlock():
5965 ms = mergemod.mergestate.read(repo)
5963 ms = mergemod.mergestate.read(repo)
5966
5964
5967 if not (ms.active() or repo.dirstate.p2() != nullid):
5965 if not (ms.active() or repo.dirstate.p2() != nullid):
5968 raise error.Abort(
5966 raise error.Abort(
5969 _(b'resolve command not applicable when not merging')
5967 _(b'resolve command not applicable when not merging')
5970 )
5968 )
5971
5969
5972 wctx = repo[None]
5970 wctx = repo[None]
5973
5971
5974 if (
5972 if (
5975 ms.mergedriver
5973 ms.mergedriver
5976 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED
5974 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED
5977 ):
5975 ):
5978 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5976 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5979 ms.commit()
5977 ms.commit()
5980 # allow mark and unmark to go through
5978 # allow mark and unmark to go through
5981 if not mark and not unmark and not proceed:
5979 if not mark and not unmark and not proceed:
5982 return 1
5980 return 1
5983
5981
5984 m = scmutil.match(wctx, pats, opts)
5982 m = scmutil.match(wctx, pats, opts)
5985 ret = 0
5983 ret = 0
5986 didwork = False
5984 didwork = False
5987 runconclude = False
5985 runconclude = False
5988
5986
5989 tocomplete = []
5987 tocomplete = []
5990 hasconflictmarkers = []
5988 hasconflictmarkers = []
5991 if mark:
5989 if mark:
5992 markcheck = ui.config(b'commands', b'resolve.mark-check')
5990 markcheck = ui.config(b'commands', b'resolve.mark-check')
5993 if markcheck not in [b'warn', b'abort']:
5991 if markcheck not in [b'warn', b'abort']:
5994 # Treat all invalid / unrecognized values as 'none'.
5992 # Treat all invalid / unrecognized values as 'none'.
5995 markcheck = False
5993 markcheck = False
5996 for f in ms:
5994 for f in ms:
5997 if not m(f):
5995 if not m(f):
5998 continue
5996 continue
5999
5997
6000 didwork = True
5998 didwork = True
6001
5999
6002 # don't let driver-resolved files be marked, and run the conclude
6000 # don't let driver-resolved files be marked, and run the conclude
6003 # step if asked to resolve
6001 # step if asked to resolve
6004 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
6002 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
6005 exact = m.exact(f)
6003 exact = m.exact(f)
6006 if mark:
6004 if mark:
6007 if exact:
6005 if exact:
6008 ui.warn(
6006 ui.warn(
6009 _(b'not marking %s as it is driver-resolved\n')
6007 _(b'not marking %s as it is driver-resolved\n')
6010 % uipathfn(f)
6008 % uipathfn(f)
6011 )
6009 )
6012 elif unmark:
6010 elif unmark:
6013 if exact:
6011 if exact:
6014 ui.warn(
6012 ui.warn(
6015 _(b'not unmarking %s as it is driver-resolved\n')
6013 _(b'not unmarking %s as it is driver-resolved\n')
6016 % uipathfn(f)
6014 % uipathfn(f)
6017 )
6015 )
6018 else:
6016 else:
6019 runconclude = True
6017 runconclude = True
6020 continue
6018 continue
6021
6019
6022 # path conflicts must be resolved manually
6020 # path conflicts must be resolved manually
6023 if ms[f] in (
6021 if ms[f] in (
6024 mergemod.MERGE_RECORD_UNRESOLVED_PATH,
6022 mergemod.MERGE_RECORD_UNRESOLVED_PATH,
6025 mergemod.MERGE_RECORD_RESOLVED_PATH,
6023 mergemod.MERGE_RECORD_RESOLVED_PATH,
6026 ):
6024 ):
6027 if mark:
6025 if mark:
6028 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
6026 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
6029 elif unmark:
6027 elif unmark:
6030 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
6028 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
6031 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
6029 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
6032 ui.warn(
6030 ui.warn(
6033 _(b'%s: path conflict must be resolved manually\n')
6031 _(b'%s: path conflict must be resolved manually\n')
6034 % uipathfn(f)
6032 % uipathfn(f)
6035 )
6033 )
6036 continue
6034 continue
6037
6035
6038 if mark:
6036 if mark:
6039 if markcheck:
6037 if markcheck:
6040 fdata = repo.wvfs.tryread(f)
6038 fdata = repo.wvfs.tryread(f)
6041 if (
6039 if (
6042 filemerge.hasconflictmarkers(fdata)
6040 filemerge.hasconflictmarkers(fdata)
6043 and ms[f] != mergemod.MERGE_RECORD_RESOLVED
6041 and ms[f] != mergemod.MERGE_RECORD_RESOLVED
6044 ):
6042 ):
6045 hasconflictmarkers.append(f)
6043 hasconflictmarkers.append(f)
6046 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
6044 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
6047 elif unmark:
6045 elif unmark:
6048 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
6046 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
6049 else:
6047 else:
6050 # backup pre-resolve (merge uses .orig for its own purposes)
6048 # backup pre-resolve (merge uses .orig for its own purposes)
6051 a = repo.wjoin(f)
6049 a = repo.wjoin(f)
6052 try:
6050 try:
6053 util.copyfile(a, a + b".resolve")
6051 util.copyfile(a, a + b".resolve")
6054 except (IOError, OSError) as inst:
6052 except (IOError, OSError) as inst:
6055 if inst.errno != errno.ENOENT:
6053 if inst.errno != errno.ENOENT:
6056 raise
6054 raise
6057
6055
6058 try:
6056 try:
6059 # preresolve file
6057 # preresolve file
6060 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6058 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6061 with ui.configoverride(overrides, b'resolve'):
6059 with ui.configoverride(overrides, b'resolve'):
6062 complete, r = ms.preresolve(f, wctx)
6060 complete, r = ms.preresolve(f, wctx)
6063 if not complete:
6061 if not complete:
6064 tocomplete.append(f)
6062 tocomplete.append(f)
6065 elif r:
6063 elif r:
6066 ret = 1
6064 ret = 1
6067 finally:
6065 finally:
6068 ms.commit()
6066 ms.commit()
6069
6067
6070 # replace filemerge's .orig file with our resolve file, but only
6068 # replace filemerge's .orig file with our resolve file, but only
6071 # for merges that are complete
6069 # for merges that are complete
6072 if complete:
6070 if complete:
6073 try:
6071 try:
6074 util.rename(
6072 util.rename(
6075 a + b".resolve", scmutil.backuppath(ui, repo, f)
6073 a + b".resolve", scmutil.backuppath(ui, repo, f)
6076 )
6074 )
6077 except OSError as inst:
6075 except OSError as inst:
6078 if inst.errno != errno.ENOENT:
6076 if inst.errno != errno.ENOENT:
6079 raise
6077 raise
6080
6078
6081 if hasconflictmarkers:
6079 if hasconflictmarkers:
6082 ui.warn(
6080 ui.warn(
6083 _(
6081 _(
6084 b'warning: the following files still have conflict '
6082 b'warning: the following files still have conflict '
6085 b'markers:\n'
6083 b'markers:\n'
6086 )
6084 )
6087 + b''.join(
6085 + b''.join(
6088 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6086 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6089 )
6087 )
6090 )
6088 )
6091 if markcheck == b'abort' and not all and not pats:
6089 if markcheck == b'abort' and not all and not pats:
6092 raise error.Abort(
6090 raise error.Abort(
6093 _(b'conflict markers detected'),
6091 _(b'conflict markers detected'),
6094 hint=_(b'use --all to mark anyway'),
6092 hint=_(b'use --all to mark anyway'),
6095 )
6093 )
6096
6094
6097 for f in tocomplete:
6095 for f in tocomplete:
6098 try:
6096 try:
6099 # resolve file
6097 # resolve file
6100 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6098 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6101 with ui.configoverride(overrides, b'resolve'):
6099 with ui.configoverride(overrides, b'resolve'):
6102 r = ms.resolve(f, wctx)
6100 r = ms.resolve(f, wctx)
6103 if r:
6101 if r:
6104 ret = 1
6102 ret = 1
6105 finally:
6103 finally:
6106 ms.commit()
6104 ms.commit()
6107
6105
6108 # replace filemerge's .orig file with our resolve file
6106 # replace filemerge's .orig file with our resolve file
6109 a = repo.wjoin(f)
6107 a = repo.wjoin(f)
6110 try:
6108 try:
6111 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6109 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6112 except OSError as inst:
6110 except OSError as inst:
6113 if inst.errno != errno.ENOENT:
6111 if inst.errno != errno.ENOENT:
6114 raise
6112 raise
6115
6113
6116 ms.commit()
6114 ms.commit()
6117 ms.recordactions()
6115 ms.recordactions()
6118
6116
6119 if not didwork and pats:
6117 if not didwork and pats:
6120 hint = None
6118 hint = None
6121 if not any([p for p in pats if p.find(b':') >= 0]):
6119 if not any([p for p in pats if p.find(b':') >= 0]):
6122 pats = [b'path:%s' % p for p in pats]
6120 pats = [b'path:%s' % p for p in pats]
6123 m = scmutil.match(wctx, pats, opts)
6121 m = scmutil.match(wctx, pats, opts)
6124 for f in ms:
6122 for f in ms:
6125 if not m(f):
6123 if not m(f):
6126 continue
6124 continue
6127
6125
6128 def flag(o):
6126 def flag(o):
6129 if o == b're_merge':
6127 if o == b're_merge':
6130 return b'--re-merge '
6128 return b'--re-merge '
6131 return b'-%s ' % o[0:1]
6129 return b'-%s ' % o[0:1]
6132
6130
6133 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6131 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6134 hint = _(b"(try: hg resolve %s%s)\n") % (
6132 hint = _(b"(try: hg resolve %s%s)\n") % (
6135 flags,
6133 flags,
6136 b' '.join(pats),
6134 b' '.join(pats),
6137 )
6135 )
6138 break
6136 break
6139 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6137 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6140 if hint:
6138 if hint:
6141 ui.warn(hint)
6139 ui.warn(hint)
6142 elif ms.mergedriver and ms.mdstate() != b's':
6140 elif ms.mergedriver and ms.mdstate() != b's':
6143 # run conclude step when either a driver-resolved file is requested
6141 # run conclude step when either a driver-resolved file is requested
6144 # or there are no driver-resolved files
6142 # or there are no driver-resolved files
6145 # we can't use 'ret' to determine whether any files are unresolved
6143 # we can't use 'ret' to determine whether any files are unresolved
6146 # because we might not have tried to resolve some
6144 # because we might not have tried to resolve some
6147 if (runconclude or not list(ms.driverresolved())) and not list(
6145 if (runconclude or not list(ms.driverresolved())) and not list(
6148 ms.unresolved()
6146 ms.unresolved()
6149 ):
6147 ):
6150 proceed = mergemod.driverconclude(repo, ms, wctx)
6148 proceed = mergemod.driverconclude(repo, ms, wctx)
6151 ms.commit()
6149 ms.commit()
6152 if not proceed:
6150 if not proceed:
6153 return 1
6151 return 1
6154
6152
6155 # Nudge users into finishing an unfinished operation
6153 # Nudge users into finishing an unfinished operation
6156 unresolvedf = list(ms.unresolved())
6154 unresolvedf = list(ms.unresolved())
6157 driverresolvedf = list(ms.driverresolved())
6155 driverresolvedf = list(ms.driverresolved())
6158 if not unresolvedf and not driverresolvedf:
6156 if not unresolvedf and not driverresolvedf:
6159 ui.status(_(b'(no more unresolved files)\n'))
6157 ui.status(_(b'(no more unresolved files)\n'))
6160 cmdutil.checkafterresolved(repo)
6158 cmdutil.checkafterresolved(repo)
6161 elif not unresolvedf:
6159 elif not unresolvedf:
6162 ui.status(
6160 ui.status(
6163 _(
6161 _(
6164 b'(no more unresolved files -- '
6162 b'(no more unresolved files -- '
6165 b'run "hg resolve --all" to conclude)\n'
6163 b'run "hg resolve --all" to conclude)\n'
6166 )
6164 )
6167 )
6165 )
6168
6166
6169 return ret
6167 return ret
6170
6168
6171
6169
6172 @command(
6170 @command(
6173 b'revert',
6171 b'revert',
6174 [
6172 [
6175 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6173 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6176 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6174 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6177 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6175 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6178 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6176 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6179 (b'i', b'interactive', None, _(b'interactively select the changes')),
6177 (b'i', b'interactive', None, _(b'interactively select the changes')),
6180 ]
6178 ]
6181 + walkopts
6179 + walkopts
6182 + dryrunopts,
6180 + dryrunopts,
6183 _(b'[OPTION]... [-r REV] [NAME]...'),
6181 _(b'[OPTION]... [-r REV] [NAME]...'),
6184 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6182 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6185 )
6183 )
6186 def revert(ui, repo, *pats, **opts):
6184 def revert(ui, repo, *pats, **opts):
6187 """restore files to their checkout state
6185 """restore files to their checkout state
6188
6186
6189 .. note::
6187 .. note::
6190
6188
6191 To check out earlier revisions, you should use :hg:`update REV`.
6189 To check out earlier revisions, you should use :hg:`update REV`.
6192 To cancel an uncommitted merge (and lose your changes),
6190 To cancel an uncommitted merge (and lose your changes),
6193 use :hg:`merge --abort`.
6191 use :hg:`merge --abort`.
6194
6192
6195 With no revision specified, revert the specified files or directories
6193 With no revision specified, revert the specified files or directories
6196 to the contents they had in the parent of the working directory.
6194 to the contents they had in the parent of the working directory.
6197 This restores the contents of files to an unmodified
6195 This restores the contents of files to an unmodified
6198 state and unschedules adds, removes, copies, and renames. If the
6196 state and unschedules adds, removes, copies, and renames. If the
6199 working directory has two parents, you must explicitly specify a
6197 working directory has two parents, you must explicitly specify a
6200 revision.
6198 revision.
6201
6199
6202 Using the -r/--rev or -d/--date options, revert the given files or
6200 Using the -r/--rev or -d/--date options, revert the given files or
6203 directories to their states as of a specific revision. Because
6201 directories to their states as of a specific revision. Because
6204 revert does not change the working directory parents, this will
6202 revert does not change the working directory parents, this will
6205 cause these files to appear modified. This can be helpful to "back
6203 cause these files to appear modified. This can be helpful to "back
6206 out" some or all of an earlier change. See :hg:`backout` for a
6204 out" some or all of an earlier change. See :hg:`backout` for a
6207 related method.
6205 related method.
6208
6206
6209 Modified files are saved with a .orig suffix before reverting.
6207 Modified files are saved with a .orig suffix before reverting.
6210 To disable these backups, use --no-backup. It is possible to store
6208 To disable these backups, use --no-backup. It is possible to store
6211 the backup files in a custom directory relative to the root of the
6209 the backup files in a custom directory relative to the root of the
6212 repository by setting the ``ui.origbackuppath`` configuration
6210 repository by setting the ``ui.origbackuppath`` configuration
6213 option.
6211 option.
6214
6212
6215 See :hg:`help dates` for a list of formats valid for -d/--date.
6213 See :hg:`help dates` for a list of formats valid for -d/--date.
6216
6214
6217 See :hg:`help backout` for a way to reverse the effect of an
6215 See :hg:`help backout` for a way to reverse the effect of an
6218 earlier changeset.
6216 earlier changeset.
6219
6217
6220 Returns 0 on success.
6218 Returns 0 on success.
6221 """
6219 """
6222
6220
6223 opts = pycompat.byteskwargs(opts)
6221 opts = pycompat.byteskwargs(opts)
6224 if opts.get(b"date"):
6222 if opts.get(b"date"):
6225 if opts.get(b"rev"):
6223 if opts.get(b"rev"):
6226 raise error.Abort(_(b"you can't specify a revision and a date"))
6224 raise error.Abort(_(b"you can't specify a revision and a date"))
6227 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6225 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6228
6226
6229 parent, p2 = repo.dirstate.parents()
6227 parent, p2 = repo.dirstate.parents()
6230 if not opts.get(b'rev') and p2 != nullid:
6228 if not opts.get(b'rev') and p2 != nullid:
6231 # revert after merge is a trap for new users (issue2915)
6229 # revert after merge is a trap for new users (issue2915)
6232 raise error.Abort(
6230 raise error.Abort(
6233 _(b'uncommitted merge with no revision specified'),
6231 _(b'uncommitted merge with no revision specified'),
6234 hint=_(b"use 'hg update' or see 'hg help revert'"),
6232 hint=_(b"use 'hg update' or see 'hg help revert'"),
6235 )
6233 )
6236
6234
6237 rev = opts.get(b'rev')
6235 rev = opts.get(b'rev')
6238 if rev:
6236 if rev:
6239 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6237 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6240 ctx = scmutil.revsingle(repo, rev)
6238 ctx = scmutil.revsingle(repo, rev)
6241
6239
6242 if not (
6240 if not (
6243 pats
6241 pats
6244 or opts.get(b'include')
6242 or opts.get(b'include')
6245 or opts.get(b'exclude')
6243 or opts.get(b'exclude')
6246 or opts.get(b'all')
6244 or opts.get(b'all')
6247 or opts.get(b'interactive')
6245 or opts.get(b'interactive')
6248 ):
6246 ):
6249 msg = _(b"no files or directories specified")
6247 msg = _(b"no files or directories specified")
6250 if p2 != nullid:
6248 if p2 != nullid:
6251 hint = _(
6249 hint = _(
6252 b"uncommitted merge, use --all to discard all changes,"
6250 b"uncommitted merge, use --all to discard all changes,"
6253 b" or 'hg update -C .' to abort the merge"
6251 b" or 'hg update -C .' to abort the merge"
6254 )
6252 )
6255 raise error.Abort(msg, hint=hint)
6253 raise error.Abort(msg, hint=hint)
6256 dirty = any(repo.status())
6254 dirty = any(repo.status())
6257 node = ctx.node()
6255 node = ctx.node()
6258 if node != parent:
6256 if node != parent:
6259 if dirty:
6257 if dirty:
6260 hint = (
6258 hint = (
6261 _(
6259 _(
6262 b"uncommitted changes, use --all to discard all"
6260 b"uncommitted changes, use --all to discard all"
6263 b" changes, or 'hg update %d' to update"
6261 b" changes, or 'hg update %d' to update"
6264 )
6262 )
6265 % ctx.rev()
6263 % ctx.rev()
6266 )
6264 )
6267 else:
6265 else:
6268 hint = (
6266 hint = (
6269 _(
6267 _(
6270 b"use --all to revert all files,"
6268 b"use --all to revert all files,"
6271 b" or 'hg update %d' to update"
6269 b" or 'hg update %d' to update"
6272 )
6270 )
6273 % ctx.rev()
6271 % ctx.rev()
6274 )
6272 )
6275 elif dirty:
6273 elif dirty:
6276 hint = _(b"uncommitted changes, use --all to discard all changes")
6274 hint = _(b"uncommitted changes, use --all to discard all changes")
6277 else:
6275 else:
6278 hint = _(b"use --all to revert all files")
6276 hint = _(b"use --all to revert all files")
6279 raise error.Abort(msg, hint=hint)
6277 raise error.Abort(msg, hint=hint)
6280
6278
6281 return cmdutil.revert(
6279 return cmdutil.revert(
6282 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6280 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6283 )
6281 )
6284
6282
6285
6283
6286 @command(
6284 @command(
6287 b'rollback',
6285 b'rollback',
6288 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6286 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6289 helpcategory=command.CATEGORY_MAINTENANCE,
6287 helpcategory=command.CATEGORY_MAINTENANCE,
6290 )
6288 )
6291 def rollback(ui, repo, **opts):
6289 def rollback(ui, repo, **opts):
6292 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6290 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6293
6291
6294 Please use :hg:`commit --amend` instead of rollback to correct
6292 Please use :hg:`commit --amend` instead of rollback to correct
6295 mistakes in the last commit.
6293 mistakes in the last commit.
6296
6294
6297 This command should be used with care. There is only one level of
6295 This command should be used with care. There is only one level of
6298 rollback, and there is no way to undo a rollback. It will also
6296 rollback, and there is no way to undo a rollback. It will also
6299 restore the dirstate at the time of the last transaction, losing
6297 restore the dirstate at the time of the last transaction, losing
6300 any dirstate changes since that time. This command does not alter
6298 any dirstate changes since that time. This command does not alter
6301 the working directory.
6299 the working directory.
6302
6300
6303 Transactions are used to encapsulate the effects of all commands
6301 Transactions are used to encapsulate the effects of all commands
6304 that create new changesets or propagate existing changesets into a
6302 that create new changesets or propagate existing changesets into a
6305 repository.
6303 repository.
6306
6304
6307 .. container:: verbose
6305 .. container:: verbose
6308
6306
6309 For example, the following commands are transactional, and their
6307 For example, the following commands are transactional, and their
6310 effects can be rolled back:
6308 effects can be rolled back:
6311
6309
6312 - commit
6310 - commit
6313 - import
6311 - import
6314 - pull
6312 - pull
6315 - push (with this repository as the destination)
6313 - push (with this repository as the destination)
6316 - unbundle
6314 - unbundle
6317
6315
6318 To avoid permanent data loss, rollback will refuse to rollback a
6316 To avoid permanent data loss, rollback will refuse to rollback a
6319 commit transaction if it isn't checked out. Use --force to
6317 commit transaction if it isn't checked out. Use --force to
6320 override this protection.
6318 override this protection.
6321
6319
6322 The rollback command can be entirely disabled by setting the
6320 The rollback command can be entirely disabled by setting the
6323 ``ui.rollback`` configuration setting to false. If you're here
6321 ``ui.rollback`` configuration setting to false. If you're here
6324 because you want to use rollback and it's disabled, you can
6322 because you want to use rollback and it's disabled, you can
6325 re-enable the command by setting ``ui.rollback`` to true.
6323 re-enable the command by setting ``ui.rollback`` to true.
6326
6324
6327 This command is not intended for use on public repositories. Once
6325 This command is not intended for use on public repositories. Once
6328 changes are visible for pull by other users, rolling a transaction
6326 changes are visible for pull by other users, rolling a transaction
6329 back locally is ineffective (someone else may already have pulled
6327 back locally is ineffective (someone else may already have pulled
6330 the changes). Furthermore, a race is possible with readers of the
6328 the changes). Furthermore, a race is possible with readers of the
6331 repository; for example an in-progress pull from the repository
6329 repository; for example an in-progress pull from the repository
6332 may fail if a rollback is performed.
6330 may fail if a rollback is performed.
6333
6331
6334 Returns 0 on success, 1 if no rollback data is available.
6332 Returns 0 on success, 1 if no rollback data is available.
6335 """
6333 """
6336 if not ui.configbool(b'ui', b'rollback'):
6334 if not ui.configbool(b'ui', b'rollback'):
6337 raise error.Abort(
6335 raise error.Abort(
6338 _(b'rollback is disabled because it is unsafe'),
6336 _(b'rollback is disabled because it is unsafe'),
6339 hint=b'see `hg help -v rollback` for information',
6337 hint=b'see `hg help -v rollback` for information',
6340 )
6338 )
6341 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6339 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6342
6340
6343
6341
6344 @command(
6342 @command(
6345 b'root',
6343 b'root',
6346 [] + formatteropts,
6344 [] + formatteropts,
6347 intents={INTENT_READONLY},
6345 intents={INTENT_READONLY},
6348 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6346 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6349 )
6347 )
6350 def root(ui, repo, **opts):
6348 def root(ui, repo, **opts):
6351 """print the root (top) of the current working directory
6349 """print the root (top) of the current working directory
6352
6350
6353 Print the root directory of the current repository.
6351 Print the root directory of the current repository.
6354
6352
6355 .. container:: verbose
6353 .. container:: verbose
6356
6354
6357 Template:
6355 Template:
6358
6356
6359 The following keywords are supported in addition to the common template
6357 The following keywords are supported in addition to the common template
6360 keywords and functions. See also :hg:`help templates`.
6358 keywords and functions. See also :hg:`help templates`.
6361
6359
6362 :hgpath: String. Path to the .hg directory.
6360 :hgpath: String. Path to the .hg directory.
6363 :storepath: String. Path to the directory holding versioned data.
6361 :storepath: String. Path to the directory holding versioned data.
6364
6362
6365 Returns 0 on success.
6363 Returns 0 on success.
6366 """
6364 """
6367 opts = pycompat.byteskwargs(opts)
6365 opts = pycompat.byteskwargs(opts)
6368 with ui.formatter(b'root', opts) as fm:
6366 with ui.formatter(b'root', opts) as fm:
6369 fm.startitem()
6367 fm.startitem()
6370 fm.write(b'reporoot', b'%s\n', repo.root)
6368 fm.write(b'reporoot', b'%s\n', repo.root)
6371 fm.data(hgpath=repo.path, storepath=repo.spath)
6369 fm.data(hgpath=repo.path, storepath=repo.spath)
6372
6370
6373
6371
6374 @command(
6372 @command(
6375 b'serve',
6373 b'serve',
6376 [
6374 [
6377 (
6375 (
6378 b'A',
6376 b'A',
6379 b'accesslog',
6377 b'accesslog',
6380 b'',
6378 b'',
6381 _(b'name of access log file to write to'),
6379 _(b'name of access log file to write to'),
6382 _(b'FILE'),
6380 _(b'FILE'),
6383 ),
6381 ),
6384 (b'd', b'daemon', None, _(b'run server in background')),
6382 (b'd', b'daemon', None, _(b'run server in background')),
6385 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6383 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6386 (
6384 (
6387 b'E',
6385 b'E',
6388 b'errorlog',
6386 b'errorlog',
6389 b'',
6387 b'',
6390 _(b'name of error log file to write to'),
6388 _(b'name of error log file to write to'),
6391 _(b'FILE'),
6389 _(b'FILE'),
6392 ),
6390 ),
6393 # use string type, then we can check if something was passed
6391 # use string type, then we can check if something was passed
6394 (
6392 (
6395 b'p',
6393 b'p',
6396 b'port',
6394 b'port',
6397 b'',
6395 b'',
6398 _(b'port to listen on (default: 8000)'),
6396 _(b'port to listen on (default: 8000)'),
6399 _(b'PORT'),
6397 _(b'PORT'),
6400 ),
6398 ),
6401 (
6399 (
6402 b'a',
6400 b'a',
6403 b'address',
6401 b'address',
6404 b'',
6402 b'',
6405 _(b'address to listen on (default: all interfaces)'),
6403 _(b'address to listen on (default: all interfaces)'),
6406 _(b'ADDR'),
6404 _(b'ADDR'),
6407 ),
6405 ),
6408 (
6406 (
6409 b'',
6407 b'',
6410 b'prefix',
6408 b'prefix',
6411 b'',
6409 b'',
6412 _(b'prefix path to serve from (default: server root)'),
6410 _(b'prefix path to serve from (default: server root)'),
6413 _(b'PREFIX'),
6411 _(b'PREFIX'),
6414 ),
6412 ),
6415 (
6413 (
6416 b'n',
6414 b'n',
6417 b'name',
6415 b'name',
6418 b'',
6416 b'',
6419 _(b'name to show in web pages (default: working directory)'),
6417 _(b'name to show in web pages (default: working directory)'),
6420 _(b'NAME'),
6418 _(b'NAME'),
6421 ),
6419 ),
6422 (
6420 (
6423 b'',
6421 b'',
6424 b'web-conf',
6422 b'web-conf',
6425 b'',
6423 b'',
6426 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6424 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6427 _(b'FILE'),
6425 _(b'FILE'),
6428 ),
6426 ),
6429 (
6427 (
6430 b'',
6428 b'',
6431 b'webdir-conf',
6429 b'webdir-conf',
6432 b'',
6430 b'',
6433 _(b'name of the hgweb config file (DEPRECATED)'),
6431 _(b'name of the hgweb config file (DEPRECATED)'),
6434 _(b'FILE'),
6432 _(b'FILE'),
6435 ),
6433 ),
6436 (
6434 (
6437 b'',
6435 b'',
6438 b'pid-file',
6436 b'pid-file',
6439 b'',
6437 b'',
6440 _(b'name of file to write process ID to'),
6438 _(b'name of file to write process ID to'),
6441 _(b'FILE'),
6439 _(b'FILE'),
6442 ),
6440 ),
6443 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6441 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6444 (
6442 (
6445 b'',
6443 b'',
6446 b'cmdserver',
6444 b'cmdserver',
6447 b'',
6445 b'',
6448 _(b'for remote clients (ADVANCED)'),
6446 _(b'for remote clients (ADVANCED)'),
6449 _(b'MODE'),
6447 _(b'MODE'),
6450 ),
6448 ),
6451 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6449 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6452 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6450 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6453 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6451 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6454 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6452 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6455 (b'', b'print-url', None, _(b'start and print only the URL')),
6453 (b'', b'print-url', None, _(b'start and print only the URL')),
6456 ]
6454 ]
6457 + subrepoopts,
6455 + subrepoopts,
6458 _(b'[OPTION]...'),
6456 _(b'[OPTION]...'),
6459 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6457 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6460 helpbasic=True,
6458 helpbasic=True,
6461 optionalrepo=True,
6459 optionalrepo=True,
6462 )
6460 )
6463 def serve(ui, repo, **opts):
6461 def serve(ui, repo, **opts):
6464 """start stand-alone webserver
6462 """start stand-alone webserver
6465
6463
6466 Start a local HTTP repository browser and pull server. You can use
6464 Start a local HTTP repository browser and pull server. You can use
6467 this for ad-hoc sharing and browsing of repositories. It is
6465 this for ad-hoc sharing and browsing of repositories. It is
6468 recommended to use a real web server to serve a repository for
6466 recommended to use a real web server to serve a repository for
6469 longer periods of time.
6467 longer periods of time.
6470
6468
6471 Please note that the server does not implement access control.
6469 Please note that the server does not implement access control.
6472 This means that, by default, anybody can read from the server and
6470 This means that, by default, anybody can read from the server and
6473 nobody can write to it by default. Set the ``web.allow-push``
6471 nobody can write to it by default. Set the ``web.allow-push``
6474 option to ``*`` to allow everybody to push to the server. You
6472 option to ``*`` to allow everybody to push to the server. You
6475 should use a real web server if you need to authenticate users.
6473 should use a real web server if you need to authenticate users.
6476
6474
6477 By default, the server logs accesses to stdout and errors to
6475 By default, the server logs accesses to stdout and errors to
6478 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6476 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6479 files.
6477 files.
6480
6478
6481 To have the server choose a free port number to listen on, specify
6479 To have the server choose a free port number to listen on, specify
6482 a port number of 0; in this case, the server will print the port
6480 a port number of 0; in this case, the server will print the port
6483 number it uses.
6481 number it uses.
6484
6482
6485 Returns 0 on success.
6483 Returns 0 on success.
6486 """
6484 """
6487
6485
6488 opts = pycompat.byteskwargs(opts)
6486 opts = pycompat.byteskwargs(opts)
6489 if opts[b"stdio"] and opts[b"cmdserver"]:
6487 if opts[b"stdio"] and opts[b"cmdserver"]:
6490 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6488 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6491 if opts[b"print_url"] and ui.verbose:
6489 if opts[b"print_url"] and ui.verbose:
6492 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6490 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6493
6491
6494 if opts[b"stdio"]:
6492 if opts[b"stdio"]:
6495 if repo is None:
6493 if repo is None:
6496 raise error.RepoError(
6494 raise error.RepoError(
6497 _(b"there is no Mercurial repository here (.hg not found)")
6495 _(b"there is no Mercurial repository here (.hg not found)")
6498 )
6496 )
6499 s = wireprotoserver.sshserver(ui, repo)
6497 s = wireprotoserver.sshserver(ui, repo)
6500 s.serve_forever()
6498 s.serve_forever()
6501
6499
6502 service = server.createservice(ui, repo, opts)
6500 service = server.createservice(ui, repo, opts)
6503 return server.runservice(opts, initfn=service.init, runfn=service.run)
6501 return server.runservice(opts, initfn=service.init, runfn=service.run)
6504
6502
6505
6503
6506 @command(
6504 @command(
6507 b'shelve',
6505 b'shelve',
6508 [
6506 [
6509 (
6507 (
6510 b'A',
6508 b'A',
6511 b'addremove',
6509 b'addremove',
6512 None,
6510 None,
6513 _(b'mark new/missing files as added/removed before shelving'),
6511 _(b'mark new/missing files as added/removed before shelving'),
6514 ),
6512 ),
6515 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6513 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6516 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6514 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6517 (
6515 (
6518 b'',
6516 b'',
6519 b'date',
6517 b'date',
6520 b'',
6518 b'',
6521 _(b'shelve with the specified commit date'),
6519 _(b'shelve with the specified commit date'),
6522 _(b'DATE'),
6520 _(b'DATE'),
6523 ),
6521 ),
6524 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6522 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6525 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6523 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6526 (
6524 (
6527 b'k',
6525 b'k',
6528 b'keep',
6526 b'keep',
6529 False,
6527 False,
6530 _(b'shelve, but keep changes in the working directory'),
6528 _(b'shelve, but keep changes in the working directory'),
6531 ),
6529 ),
6532 (b'l', b'list', None, _(b'list current shelves')),
6530 (b'l', b'list', None, _(b'list current shelves')),
6533 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6531 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6534 (
6532 (
6535 b'n',
6533 b'n',
6536 b'name',
6534 b'name',
6537 b'',
6535 b'',
6538 _(b'use the given name for the shelved commit'),
6536 _(b'use the given name for the shelved commit'),
6539 _(b'NAME'),
6537 _(b'NAME'),
6540 ),
6538 ),
6541 (
6539 (
6542 b'p',
6540 b'p',
6543 b'patch',
6541 b'patch',
6544 None,
6542 None,
6545 _(
6543 _(
6546 b'output patches for changes (provide the names of the shelved '
6544 b'output patches for changes (provide the names of the shelved '
6547 b'changes as positional arguments)'
6545 b'changes as positional arguments)'
6548 ),
6546 ),
6549 ),
6547 ),
6550 (b'i', b'interactive', None, _(b'interactive mode')),
6548 (b'i', b'interactive', None, _(b'interactive mode')),
6551 (
6549 (
6552 b'',
6550 b'',
6553 b'stat',
6551 b'stat',
6554 None,
6552 None,
6555 _(
6553 _(
6556 b'output diffstat-style summary of changes (provide the names of '
6554 b'output diffstat-style summary of changes (provide the names of '
6557 b'the shelved changes as positional arguments)'
6555 b'the shelved changes as positional arguments)'
6558 ),
6556 ),
6559 ),
6557 ),
6560 ]
6558 ]
6561 + cmdutil.walkopts,
6559 + cmdutil.walkopts,
6562 _(b'hg shelve [OPTION]... [FILE]...'),
6560 _(b'hg shelve [OPTION]... [FILE]...'),
6563 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6561 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6564 )
6562 )
6565 def shelve(ui, repo, *pats, **opts):
6563 def shelve(ui, repo, *pats, **opts):
6566 '''save and set aside changes from the working directory
6564 '''save and set aside changes from the working directory
6567
6565
6568 Shelving takes files that "hg status" reports as not clean, saves
6566 Shelving takes files that "hg status" reports as not clean, saves
6569 the modifications to a bundle (a shelved change), and reverts the
6567 the modifications to a bundle (a shelved change), and reverts the
6570 files so that their state in the working directory becomes clean.
6568 files so that their state in the working directory becomes clean.
6571
6569
6572 To restore these changes to the working directory, using "hg
6570 To restore these changes to the working directory, using "hg
6573 unshelve"; this will work even if you switch to a different
6571 unshelve"; this will work even if you switch to a different
6574 commit.
6572 commit.
6575
6573
6576 When no files are specified, "hg shelve" saves all not-clean
6574 When no files are specified, "hg shelve" saves all not-clean
6577 files. If specific files or directories are named, only changes to
6575 files. If specific files or directories are named, only changes to
6578 those files are shelved.
6576 those files are shelved.
6579
6577
6580 In bare shelve (when no files are specified, without interactive,
6578 In bare shelve (when no files are specified, without interactive,
6581 include and exclude option), shelving remembers information if the
6579 include and exclude option), shelving remembers information if the
6582 working directory was on newly created branch, in other words working
6580 working directory was on newly created branch, in other words working
6583 directory was on different branch than its first parent. In this
6581 directory was on different branch than its first parent. In this
6584 situation unshelving restores branch information to the working directory.
6582 situation unshelving restores branch information to the working directory.
6585
6583
6586 Each shelved change has a name that makes it easier to find later.
6584 Each shelved change has a name that makes it easier to find later.
6587 The name of a shelved change defaults to being based on the active
6585 The name of a shelved change defaults to being based on the active
6588 bookmark, or if there is no active bookmark, the current named
6586 bookmark, or if there is no active bookmark, the current named
6589 branch. To specify a different name, use ``--name``.
6587 branch. To specify a different name, use ``--name``.
6590
6588
6591 To see a list of existing shelved changes, use the ``--list``
6589 To see a list of existing shelved changes, use the ``--list``
6592 option. For each shelved change, this will print its name, age,
6590 option. For each shelved change, this will print its name, age,
6593 and description; use ``--patch`` or ``--stat`` for more details.
6591 and description; use ``--patch`` or ``--stat`` for more details.
6594
6592
6595 To delete specific shelved changes, use ``--delete``. To delete
6593 To delete specific shelved changes, use ``--delete``. To delete
6596 all shelved changes, use ``--cleanup``.
6594 all shelved changes, use ``--cleanup``.
6597 '''
6595 '''
6598 opts = pycompat.byteskwargs(opts)
6596 opts = pycompat.byteskwargs(opts)
6599 allowables = [
6597 allowables = [
6600 (b'addremove', {b'create'}), # 'create' is pseudo action
6598 (b'addremove', {b'create'}), # 'create' is pseudo action
6601 (b'unknown', {b'create'}),
6599 (b'unknown', {b'create'}),
6602 (b'cleanup', {b'cleanup'}),
6600 (b'cleanup', {b'cleanup'}),
6603 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6601 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6604 (b'delete', {b'delete'}),
6602 (b'delete', {b'delete'}),
6605 (b'edit', {b'create'}),
6603 (b'edit', {b'create'}),
6606 (b'keep', {b'create'}),
6604 (b'keep', {b'create'}),
6607 (b'list', {b'list'}),
6605 (b'list', {b'list'}),
6608 (b'message', {b'create'}),
6606 (b'message', {b'create'}),
6609 (b'name', {b'create'}),
6607 (b'name', {b'create'}),
6610 (b'patch', {b'patch', b'list'}),
6608 (b'patch', {b'patch', b'list'}),
6611 (b'stat', {b'stat', b'list'}),
6609 (b'stat', {b'stat', b'list'}),
6612 ]
6610 ]
6613
6611
6614 def checkopt(opt):
6612 def checkopt(opt):
6615 if opts.get(opt):
6613 if opts.get(opt):
6616 for i, allowable in allowables:
6614 for i, allowable in allowables:
6617 if opts[i] and opt not in allowable:
6615 if opts[i] and opt not in allowable:
6618 raise error.Abort(
6616 raise error.Abort(
6619 _(
6617 _(
6620 b"options '--%s' and '--%s' may not be "
6618 b"options '--%s' and '--%s' may not be "
6621 b"used together"
6619 b"used together"
6622 )
6620 )
6623 % (opt, i)
6621 % (opt, i)
6624 )
6622 )
6625 return True
6623 return True
6626
6624
6627 if checkopt(b'cleanup'):
6625 if checkopt(b'cleanup'):
6628 if pats:
6626 if pats:
6629 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6627 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6630 return shelvemod.cleanupcmd(ui, repo)
6628 return shelvemod.cleanupcmd(ui, repo)
6631 elif checkopt(b'delete'):
6629 elif checkopt(b'delete'):
6632 return shelvemod.deletecmd(ui, repo, pats)
6630 return shelvemod.deletecmd(ui, repo, pats)
6633 elif checkopt(b'list'):
6631 elif checkopt(b'list'):
6634 return shelvemod.listcmd(ui, repo, pats, opts)
6632 return shelvemod.listcmd(ui, repo, pats, opts)
6635 elif checkopt(b'patch') or checkopt(b'stat'):
6633 elif checkopt(b'patch') or checkopt(b'stat'):
6636 return shelvemod.patchcmds(ui, repo, pats, opts)
6634 return shelvemod.patchcmds(ui, repo, pats, opts)
6637 else:
6635 else:
6638 return shelvemod.createcmd(ui, repo, pats, opts)
6636 return shelvemod.createcmd(ui, repo, pats, opts)
6639
6637
6640
6638
6641 _NOTTERSE = b'nothing'
6639 _NOTTERSE = b'nothing'
6642
6640
6643
6641
6644 @command(
6642 @command(
6645 b'status|st',
6643 b'status|st',
6646 [
6644 [
6647 (b'A', b'all', None, _(b'show status of all files')),
6645 (b'A', b'all', None, _(b'show status of all files')),
6648 (b'm', b'modified', None, _(b'show only modified files')),
6646 (b'm', b'modified', None, _(b'show only modified files')),
6649 (b'a', b'added', None, _(b'show only added files')),
6647 (b'a', b'added', None, _(b'show only added files')),
6650 (b'r', b'removed', None, _(b'show only removed files')),
6648 (b'r', b'removed', None, _(b'show only removed files')),
6651 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6649 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6652 (b'c', b'clean', None, _(b'show only files without changes')),
6650 (b'c', b'clean', None, _(b'show only files without changes')),
6653 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6651 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6654 (b'i', b'ignored', None, _(b'show only ignored files')),
6652 (b'i', b'ignored', None, _(b'show only ignored files')),
6655 (b'n', b'no-status', None, _(b'hide status prefix')),
6653 (b'n', b'no-status', None, _(b'hide status prefix')),
6656 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6654 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6657 (b'C', b'copies', None, _(b'show source of copied files')),
6655 (b'C', b'copies', None, _(b'show source of copied files')),
6658 (
6656 (
6659 b'0',
6657 b'0',
6660 b'print0',
6658 b'print0',
6661 None,
6659 None,
6662 _(b'end filenames with NUL, for use with xargs'),
6660 _(b'end filenames with NUL, for use with xargs'),
6663 ),
6661 ),
6664 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6662 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6665 (
6663 (
6666 b'',
6664 b'',
6667 b'change',
6665 b'change',
6668 b'',
6666 b'',
6669 _(b'list the changed files of a revision'),
6667 _(b'list the changed files of a revision'),
6670 _(b'REV'),
6668 _(b'REV'),
6671 ),
6669 ),
6672 ]
6670 ]
6673 + walkopts
6671 + walkopts
6674 + subrepoopts
6672 + subrepoopts
6675 + formatteropts,
6673 + formatteropts,
6676 _(b'[OPTION]... [FILE]...'),
6674 _(b'[OPTION]... [FILE]...'),
6677 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6675 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6678 helpbasic=True,
6676 helpbasic=True,
6679 inferrepo=True,
6677 inferrepo=True,
6680 intents={INTENT_READONLY},
6678 intents={INTENT_READONLY},
6681 )
6679 )
6682 def status(ui, repo, *pats, **opts):
6680 def status(ui, repo, *pats, **opts):
6683 """show changed files in the working directory
6681 """show changed files in the working directory
6684
6682
6685 Show status of files in the repository. If names are given, only
6683 Show status of files in the repository. If names are given, only
6686 files that match are shown. Files that are clean or ignored or
6684 files that match are shown. Files that are clean or ignored or
6687 the source of a copy/move operation, are not listed unless
6685 the source of a copy/move operation, are not listed unless
6688 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6686 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6689 Unless options described with "show only ..." are given, the
6687 Unless options described with "show only ..." are given, the
6690 options -mardu are used.
6688 options -mardu are used.
6691
6689
6692 Option -q/--quiet hides untracked (unknown and ignored) files
6690 Option -q/--quiet hides untracked (unknown and ignored) files
6693 unless explicitly requested with -u/--unknown or -i/--ignored.
6691 unless explicitly requested with -u/--unknown or -i/--ignored.
6694
6692
6695 .. note::
6693 .. note::
6696
6694
6697 :hg:`status` may appear to disagree with diff if permissions have
6695 :hg:`status` may appear to disagree with diff if permissions have
6698 changed or a merge has occurred. The standard diff format does
6696 changed or a merge has occurred. The standard diff format does
6699 not report permission changes and diff only reports changes
6697 not report permission changes and diff only reports changes
6700 relative to one merge parent.
6698 relative to one merge parent.
6701
6699
6702 If one revision is given, it is used as the base revision.
6700 If one revision is given, it is used as the base revision.
6703 If two revisions are given, the differences between them are
6701 If two revisions are given, the differences between them are
6704 shown. The --change option can also be used as a shortcut to list
6702 shown. The --change option can also be used as a shortcut to list
6705 the changed files of a revision from its first parent.
6703 the changed files of a revision from its first parent.
6706
6704
6707 The codes used to show the status of files are::
6705 The codes used to show the status of files are::
6708
6706
6709 M = modified
6707 M = modified
6710 A = added
6708 A = added
6711 R = removed
6709 R = removed
6712 C = clean
6710 C = clean
6713 ! = missing (deleted by non-hg command, but still tracked)
6711 ! = missing (deleted by non-hg command, but still tracked)
6714 ? = not tracked
6712 ? = not tracked
6715 I = ignored
6713 I = ignored
6716 = origin of the previous file (with --copies)
6714 = origin of the previous file (with --copies)
6717
6715
6718 .. container:: verbose
6716 .. container:: verbose
6719
6717
6720 The -t/--terse option abbreviates the output by showing only the directory
6718 The -t/--terse option abbreviates the output by showing only the directory
6721 name if all the files in it share the same status. The option takes an
6719 name if all the files in it share the same status. The option takes an
6722 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6720 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6723 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6721 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6724 for 'ignored' and 'c' for clean.
6722 for 'ignored' and 'c' for clean.
6725
6723
6726 It abbreviates only those statuses which are passed. Note that clean and
6724 It abbreviates only those statuses which are passed. Note that clean and
6727 ignored files are not displayed with '--terse ic' unless the -c/--clean
6725 ignored files are not displayed with '--terse ic' unless the -c/--clean
6728 and -i/--ignored options are also used.
6726 and -i/--ignored options are also used.
6729
6727
6730 The -v/--verbose option shows information when the repository is in an
6728 The -v/--verbose option shows information when the repository is in an
6731 unfinished merge, shelve, rebase state etc. You can have this behavior
6729 unfinished merge, shelve, rebase state etc. You can have this behavior
6732 turned on by default by enabling the ``commands.status.verbose`` option.
6730 turned on by default by enabling the ``commands.status.verbose`` option.
6733
6731
6734 You can skip displaying some of these states by setting
6732 You can skip displaying some of these states by setting
6735 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6733 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6736 'histedit', 'merge', 'rebase', or 'unshelve'.
6734 'histedit', 'merge', 'rebase', or 'unshelve'.
6737
6735
6738 Template:
6736 Template:
6739
6737
6740 The following keywords are supported in addition to the common template
6738 The following keywords are supported in addition to the common template
6741 keywords and functions. See also :hg:`help templates`.
6739 keywords and functions. See also :hg:`help templates`.
6742
6740
6743 :path: String. Repository-absolute path of the file.
6741 :path: String. Repository-absolute path of the file.
6744 :source: String. Repository-absolute path of the file originated from.
6742 :source: String. Repository-absolute path of the file originated from.
6745 Available if ``--copies`` is specified.
6743 Available if ``--copies`` is specified.
6746 :status: String. Character denoting file's status.
6744 :status: String. Character denoting file's status.
6747
6745
6748 Examples:
6746 Examples:
6749
6747
6750 - show changes in the working directory relative to a
6748 - show changes in the working directory relative to a
6751 changeset::
6749 changeset::
6752
6750
6753 hg status --rev 9353
6751 hg status --rev 9353
6754
6752
6755 - show changes in the working directory relative to the
6753 - show changes in the working directory relative to the
6756 current directory (see :hg:`help patterns` for more information)::
6754 current directory (see :hg:`help patterns` for more information)::
6757
6755
6758 hg status re:
6756 hg status re:
6759
6757
6760 - show all changes including copies in an existing changeset::
6758 - show all changes including copies in an existing changeset::
6761
6759
6762 hg status --copies --change 9353
6760 hg status --copies --change 9353
6763
6761
6764 - get a NUL separated list of added files, suitable for xargs::
6762 - get a NUL separated list of added files, suitable for xargs::
6765
6763
6766 hg status -an0
6764 hg status -an0
6767
6765
6768 - show more information about the repository status, abbreviating
6766 - show more information about the repository status, abbreviating
6769 added, removed, modified, deleted, and untracked paths::
6767 added, removed, modified, deleted, and untracked paths::
6770
6768
6771 hg status -v -t mardu
6769 hg status -v -t mardu
6772
6770
6773 Returns 0 on success.
6771 Returns 0 on success.
6774
6772
6775 """
6773 """
6776
6774
6777 opts = pycompat.byteskwargs(opts)
6775 opts = pycompat.byteskwargs(opts)
6778 revs = opts.get(b'rev')
6776 revs = opts.get(b'rev')
6779 change = opts.get(b'change')
6777 change = opts.get(b'change')
6780 terse = opts.get(b'terse')
6778 terse = opts.get(b'terse')
6781 if terse is _NOTTERSE:
6779 if terse is _NOTTERSE:
6782 if revs:
6780 if revs:
6783 terse = b''
6781 terse = b''
6784 else:
6782 else:
6785 terse = ui.config(b'commands', b'status.terse')
6783 terse = ui.config(b'commands', b'status.terse')
6786
6784
6787 if revs and change:
6785 if revs and change:
6788 msg = _(b'cannot specify --rev and --change at the same time')
6786 msg = _(b'cannot specify --rev and --change at the same time')
6789 raise error.Abort(msg)
6787 raise error.Abort(msg)
6790 elif revs and terse:
6788 elif revs and terse:
6791 msg = _(b'cannot use --terse with --rev')
6789 msg = _(b'cannot use --terse with --rev')
6792 raise error.Abort(msg)
6790 raise error.Abort(msg)
6793 elif change:
6791 elif change:
6794 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6792 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6795 ctx2 = scmutil.revsingle(repo, change, None)
6793 ctx2 = scmutil.revsingle(repo, change, None)
6796 ctx1 = ctx2.p1()
6794 ctx1 = ctx2.p1()
6797 else:
6795 else:
6798 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6796 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6799 ctx1, ctx2 = scmutil.revpair(repo, revs)
6797 ctx1, ctx2 = scmutil.revpair(repo, revs)
6800
6798
6801 forcerelativevalue = None
6799 forcerelativevalue = None
6802 if ui.hasconfig(b'commands', b'status.relative'):
6800 if ui.hasconfig(b'commands', b'status.relative'):
6803 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6801 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6804 uipathfn = scmutil.getuipathfn(
6802 uipathfn = scmutil.getuipathfn(
6805 repo,
6803 repo,
6806 legacyrelativevalue=bool(pats),
6804 legacyrelativevalue=bool(pats),
6807 forcerelativevalue=forcerelativevalue,
6805 forcerelativevalue=forcerelativevalue,
6808 )
6806 )
6809
6807
6810 if opts.get(b'print0'):
6808 if opts.get(b'print0'):
6811 end = b'\0'
6809 end = b'\0'
6812 else:
6810 else:
6813 end = b'\n'
6811 end = b'\n'
6814 states = b'modified added removed deleted unknown ignored clean'.split()
6812 states = b'modified added removed deleted unknown ignored clean'.split()
6815 show = [k for k in states if opts.get(k)]
6813 show = [k for k in states if opts.get(k)]
6816 if opts.get(b'all'):
6814 if opts.get(b'all'):
6817 show += ui.quiet and (states[:4] + [b'clean']) or states
6815 show += ui.quiet and (states[:4] + [b'clean']) or states
6818
6816
6819 if not show:
6817 if not show:
6820 if ui.quiet:
6818 if ui.quiet:
6821 show = states[:4]
6819 show = states[:4]
6822 else:
6820 else:
6823 show = states[:5]
6821 show = states[:5]
6824
6822
6825 m = scmutil.match(ctx2, pats, opts)
6823 m = scmutil.match(ctx2, pats, opts)
6826 if terse:
6824 if terse:
6827 # we need to compute clean and unknown to terse
6825 # we need to compute clean and unknown to terse
6828 stat = repo.status(
6826 stat = repo.status(
6829 ctx1.node(),
6827 ctx1.node(),
6830 ctx2.node(),
6828 ctx2.node(),
6831 m,
6829 m,
6832 b'ignored' in show or b'i' in terse,
6830 b'ignored' in show or b'i' in terse,
6833 clean=True,
6831 clean=True,
6834 unknown=True,
6832 unknown=True,
6835 listsubrepos=opts.get(b'subrepos'),
6833 listsubrepos=opts.get(b'subrepos'),
6836 )
6834 )
6837
6835
6838 stat = cmdutil.tersedir(stat, terse)
6836 stat = cmdutil.tersedir(stat, terse)
6839 else:
6837 else:
6840 stat = repo.status(
6838 stat = repo.status(
6841 ctx1.node(),
6839 ctx1.node(),
6842 ctx2.node(),
6840 ctx2.node(),
6843 m,
6841 m,
6844 b'ignored' in show,
6842 b'ignored' in show,
6845 b'clean' in show,
6843 b'clean' in show,
6846 b'unknown' in show,
6844 b'unknown' in show,
6847 opts.get(b'subrepos'),
6845 opts.get(b'subrepos'),
6848 )
6846 )
6849
6847
6850 changestates = zip(
6848 changestates = zip(
6851 states,
6849 states,
6852 pycompat.iterbytestr(b'MAR!?IC'),
6850 pycompat.iterbytestr(b'MAR!?IC'),
6853 [getattr(stat, s.decode('utf8')) for s in states],
6851 [getattr(stat, s.decode('utf8')) for s in states],
6854 )
6852 )
6855
6853
6856 copy = {}
6854 copy = {}
6857 if (
6855 if (
6858 opts.get(b'all')
6856 opts.get(b'all')
6859 or opts.get(b'copies')
6857 or opts.get(b'copies')
6860 or ui.configbool(b'ui', b'statuscopies')
6858 or ui.configbool(b'ui', b'statuscopies')
6861 ) and not opts.get(b'no_status'):
6859 ) and not opts.get(b'no_status'):
6862 copy = copies.pathcopies(ctx1, ctx2, m)
6860 copy = copies.pathcopies(ctx1, ctx2, m)
6863
6861
6864 morestatus = None
6862 morestatus = None
6865 if (
6863 if (
6866 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6864 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6867 ) and not ui.plain():
6865 ) and not ui.plain():
6868 morestatus = cmdutil.readmorestatus(repo)
6866 morestatus = cmdutil.readmorestatus(repo)
6869
6867
6870 ui.pager(b'status')
6868 ui.pager(b'status')
6871 fm = ui.formatter(b'status', opts)
6869 fm = ui.formatter(b'status', opts)
6872 fmt = b'%s' + end
6870 fmt = b'%s' + end
6873 showchar = not opts.get(b'no_status')
6871 showchar = not opts.get(b'no_status')
6874
6872
6875 for state, char, files in changestates:
6873 for state, char, files in changestates:
6876 if state in show:
6874 if state in show:
6877 label = b'status.' + state
6875 label = b'status.' + state
6878 for f in files:
6876 for f in files:
6879 fm.startitem()
6877 fm.startitem()
6880 fm.context(ctx=ctx2)
6878 fm.context(ctx=ctx2)
6881 fm.data(itemtype=b'file', path=f)
6879 fm.data(itemtype=b'file', path=f)
6882 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6880 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6883 fm.plain(fmt % uipathfn(f), label=label)
6881 fm.plain(fmt % uipathfn(f), label=label)
6884 if f in copy:
6882 if f in copy:
6885 fm.data(source=copy[f])
6883 fm.data(source=copy[f])
6886 fm.plain(
6884 fm.plain(
6887 (b' %s' + end) % uipathfn(copy[f]),
6885 (b' %s' + end) % uipathfn(copy[f]),
6888 label=b'status.copied',
6886 label=b'status.copied',
6889 )
6887 )
6890 if morestatus:
6888 if morestatus:
6891 morestatus.formatfile(f, fm)
6889 morestatus.formatfile(f, fm)
6892
6890
6893 if morestatus:
6891 if morestatus:
6894 morestatus.formatfooter(fm)
6892 morestatus.formatfooter(fm)
6895 fm.end()
6893 fm.end()
6896
6894
6897
6895
6898 @command(
6896 @command(
6899 b'summary|sum',
6897 b'summary|sum',
6900 [(b'', b'remote', None, _(b'check for push and pull'))],
6898 [(b'', b'remote', None, _(b'check for push and pull'))],
6901 b'[--remote]',
6899 b'[--remote]',
6902 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6900 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6903 helpbasic=True,
6901 helpbasic=True,
6904 intents={INTENT_READONLY},
6902 intents={INTENT_READONLY},
6905 )
6903 )
6906 def summary(ui, repo, **opts):
6904 def summary(ui, repo, **opts):
6907 """summarize working directory state
6905 """summarize working directory state
6908
6906
6909 This generates a brief summary of the working directory state,
6907 This generates a brief summary of the working directory state,
6910 including parents, branch, commit status, phase and available updates.
6908 including parents, branch, commit status, phase and available updates.
6911
6909
6912 With the --remote option, this will check the default paths for
6910 With the --remote option, this will check the default paths for
6913 incoming and outgoing changes. This can be time-consuming.
6911 incoming and outgoing changes. This can be time-consuming.
6914
6912
6915 Returns 0 on success.
6913 Returns 0 on success.
6916 """
6914 """
6917
6915
6918 opts = pycompat.byteskwargs(opts)
6916 opts = pycompat.byteskwargs(opts)
6919 ui.pager(b'summary')
6917 ui.pager(b'summary')
6920 ctx = repo[None]
6918 ctx = repo[None]
6921 parents = ctx.parents()
6919 parents = ctx.parents()
6922 pnode = parents[0].node()
6920 pnode = parents[0].node()
6923 marks = []
6921 marks = []
6924
6922
6925 try:
6923 try:
6926 ms = mergemod.mergestate.read(repo)
6924 ms = mergemod.mergestate.read(repo)
6927 except error.UnsupportedMergeRecords as e:
6925 except error.UnsupportedMergeRecords as e:
6928 s = b' '.join(e.recordtypes)
6926 s = b' '.join(e.recordtypes)
6929 ui.warn(
6927 ui.warn(
6930 _(b'warning: merge state has unsupported record types: %s\n') % s
6928 _(b'warning: merge state has unsupported record types: %s\n') % s
6931 )
6929 )
6932 unresolved = []
6930 unresolved = []
6933 else:
6931 else:
6934 unresolved = list(ms.unresolved())
6932 unresolved = list(ms.unresolved())
6935
6933
6936 for p in parents:
6934 for p in parents:
6937 # label with log.changeset (instead of log.parent) since this
6935 # label with log.changeset (instead of log.parent) since this
6938 # shows a working directory parent *changeset*:
6936 # shows a working directory parent *changeset*:
6939 # i18n: column positioning for "hg summary"
6937 # i18n: column positioning for "hg summary"
6940 ui.write(
6938 ui.write(
6941 _(b'parent: %d:%s ') % (p.rev(), p),
6939 _(b'parent: %d:%s ') % (p.rev(), p),
6942 label=logcmdutil.changesetlabels(p),
6940 label=logcmdutil.changesetlabels(p),
6943 )
6941 )
6944 ui.write(b' '.join(p.tags()), label=b'log.tag')
6942 ui.write(b' '.join(p.tags()), label=b'log.tag')
6945 if p.bookmarks():
6943 if p.bookmarks():
6946 marks.extend(p.bookmarks())
6944 marks.extend(p.bookmarks())
6947 if p.rev() == -1:
6945 if p.rev() == -1:
6948 if not len(repo):
6946 if not len(repo):
6949 ui.write(_(b' (empty repository)'))
6947 ui.write(_(b' (empty repository)'))
6950 else:
6948 else:
6951 ui.write(_(b' (no revision checked out)'))
6949 ui.write(_(b' (no revision checked out)'))
6952 if p.obsolete():
6950 if p.obsolete():
6953 ui.write(_(b' (obsolete)'))
6951 ui.write(_(b' (obsolete)'))
6954 if p.isunstable():
6952 if p.isunstable():
6955 instabilities = (
6953 instabilities = (
6956 ui.label(instability, b'trouble.%s' % instability)
6954 ui.label(instability, b'trouble.%s' % instability)
6957 for instability in p.instabilities()
6955 for instability in p.instabilities()
6958 )
6956 )
6959 ui.write(b' (' + b', '.join(instabilities) + b')')
6957 ui.write(b' (' + b', '.join(instabilities) + b')')
6960 ui.write(b'\n')
6958 ui.write(b'\n')
6961 if p.description():
6959 if p.description():
6962 ui.status(
6960 ui.status(
6963 b' ' + p.description().splitlines()[0].strip() + b'\n',
6961 b' ' + p.description().splitlines()[0].strip() + b'\n',
6964 label=b'log.summary',
6962 label=b'log.summary',
6965 )
6963 )
6966
6964
6967 branch = ctx.branch()
6965 branch = ctx.branch()
6968 bheads = repo.branchheads(branch)
6966 bheads = repo.branchheads(branch)
6969 # i18n: column positioning for "hg summary"
6967 # i18n: column positioning for "hg summary"
6970 m = _(b'branch: %s\n') % branch
6968 m = _(b'branch: %s\n') % branch
6971 if branch != b'default':
6969 if branch != b'default':
6972 ui.write(m, label=b'log.branch')
6970 ui.write(m, label=b'log.branch')
6973 else:
6971 else:
6974 ui.status(m, label=b'log.branch')
6972 ui.status(m, label=b'log.branch')
6975
6973
6976 if marks:
6974 if marks:
6977 active = repo._activebookmark
6975 active = repo._activebookmark
6978 # i18n: column positioning for "hg summary"
6976 # i18n: column positioning for "hg summary"
6979 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6977 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6980 if active is not None:
6978 if active is not None:
6981 if active in marks:
6979 if active in marks:
6982 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6980 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6983 marks.remove(active)
6981 marks.remove(active)
6984 else:
6982 else:
6985 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6983 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6986 for m in marks:
6984 for m in marks:
6987 ui.write(b' ' + m, label=b'log.bookmark')
6985 ui.write(b' ' + m, label=b'log.bookmark')
6988 ui.write(b'\n', label=b'log.bookmark')
6986 ui.write(b'\n', label=b'log.bookmark')
6989
6987
6990 status = repo.status(unknown=True)
6988 status = repo.status(unknown=True)
6991
6989
6992 c = repo.dirstate.copies()
6990 c = repo.dirstate.copies()
6993 copied, renamed = [], []
6991 copied, renamed = [], []
6994 for d, s in pycompat.iteritems(c):
6992 for d, s in pycompat.iteritems(c):
6995 if s in status.removed:
6993 if s in status.removed:
6996 status.removed.remove(s)
6994 status.removed.remove(s)
6997 renamed.append(d)
6995 renamed.append(d)
6998 else:
6996 else:
6999 copied.append(d)
6997 copied.append(d)
7000 if d in status.added:
6998 if d in status.added:
7001 status.added.remove(d)
6999 status.added.remove(d)
7002
7000
7003 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7001 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7004
7002
7005 labels = [
7003 labels = [
7006 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7004 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7007 (ui.label(_(b'%d added'), b'status.added'), status.added),
7005 (ui.label(_(b'%d added'), b'status.added'), status.added),
7008 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7006 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7009 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7007 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7010 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7008 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7011 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7009 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7012 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7010 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7013 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7011 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7014 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7012 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7015 ]
7013 ]
7016 t = []
7014 t = []
7017 for l, s in labels:
7015 for l, s in labels:
7018 if s:
7016 if s:
7019 t.append(l % len(s))
7017 t.append(l % len(s))
7020
7018
7021 t = b', '.join(t)
7019 t = b', '.join(t)
7022 cleanworkdir = False
7020 cleanworkdir = False
7023
7021
7024 if repo.vfs.exists(b'graftstate'):
7022 if repo.vfs.exists(b'graftstate'):
7025 t += _(b' (graft in progress)')
7023 t += _(b' (graft in progress)')
7026 if repo.vfs.exists(b'updatestate'):
7024 if repo.vfs.exists(b'updatestate'):
7027 t += _(b' (interrupted update)')
7025 t += _(b' (interrupted update)')
7028 elif len(parents) > 1:
7026 elif len(parents) > 1:
7029 t += _(b' (merge)')
7027 t += _(b' (merge)')
7030 elif branch != parents[0].branch():
7028 elif branch != parents[0].branch():
7031 t += _(b' (new branch)')
7029 t += _(b' (new branch)')
7032 elif parents[0].closesbranch() and pnode in repo.branchheads(
7030 elif parents[0].closesbranch() and pnode in repo.branchheads(
7033 branch, closed=True
7031 branch, closed=True
7034 ):
7032 ):
7035 t += _(b' (head closed)')
7033 t += _(b' (head closed)')
7036 elif not (
7034 elif not (
7037 status.modified
7035 status.modified
7038 or status.added
7036 or status.added
7039 or status.removed
7037 or status.removed
7040 or renamed
7038 or renamed
7041 or copied
7039 or copied
7042 or subs
7040 or subs
7043 ):
7041 ):
7044 t += _(b' (clean)')
7042 t += _(b' (clean)')
7045 cleanworkdir = True
7043 cleanworkdir = True
7046 elif pnode not in bheads:
7044 elif pnode not in bheads:
7047 t += _(b' (new branch head)')
7045 t += _(b' (new branch head)')
7048
7046
7049 if parents:
7047 if parents:
7050 pendingphase = max(p.phase() for p in parents)
7048 pendingphase = max(p.phase() for p in parents)
7051 else:
7049 else:
7052 pendingphase = phases.public
7050 pendingphase = phases.public
7053
7051
7054 if pendingphase > phases.newcommitphase(ui):
7052 if pendingphase > phases.newcommitphase(ui):
7055 t += b' (%s)' % phases.phasenames[pendingphase]
7053 t += b' (%s)' % phases.phasenames[pendingphase]
7056
7054
7057 if cleanworkdir:
7055 if cleanworkdir:
7058 # i18n: column positioning for "hg summary"
7056 # i18n: column positioning for "hg summary"
7059 ui.status(_(b'commit: %s\n') % t.strip())
7057 ui.status(_(b'commit: %s\n') % t.strip())
7060 else:
7058 else:
7061 # i18n: column positioning for "hg summary"
7059 # i18n: column positioning for "hg summary"
7062 ui.write(_(b'commit: %s\n') % t.strip())
7060 ui.write(_(b'commit: %s\n') % t.strip())
7063
7061
7064 # all ancestors of branch heads - all ancestors of parent = new csets
7062 # all ancestors of branch heads - all ancestors of parent = new csets
7065 new = len(
7063 new = len(
7066 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7064 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7067 )
7065 )
7068
7066
7069 if new == 0:
7067 if new == 0:
7070 # i18n: column positioning for "hg summary"
7068 # i18n: column positioning for "hg summary"
7071 ui.status(_(b'update: (current)\n'))
7069 ui.status(_(b'update: (current)\n'))
7072 elif pnode not in bheads:
7070 elif pnode not in bheads:
7073 # i18n: column positioning for "hg summary"
7071 # i18n: column positioning for "hg summary"
7074 ui.write(_(b'update: %d new changesets (update)\n') % new)
7072 ui.write(_(b'update: %d new changesets (update)\n') % new)
7075 else:
7073 else:
7076 # i18n: column positioning for "hg summary"
7074 # i18n: column positioning for "hg summary"
7077 ui.write(
7075 ui.write(
7078 _(b'update: %d new changesets, %d branch heads (merge)\n')
7076 _(b'update: %d new changesets, %d branch heads (merge)\n')
7079 % (new, len(bheads))
7077 % (new, len(bheads))
7080 )
7078 )
7081
7079
7082 t = []
7080 t = []
7083 draft = len(repo.revs(b'draft()'))
7081 draft = len(repo.revs(b'draft()'))
7084 if draft:
7082 if draft:
7085 t.append(_(b'%d draft') % draft)
7083 t.append(_(b'%d draft') % draft)
7086 secret = len(repo.revs(b'secret()'))
7084 secret = len(repo.revs(b'secret()'))
7087 if secret:
7085 if secret:
7088 t.append(_(b'%d secret') % secret)
7086 t.append(_(b'%d secret') % secret)
7089
7087
7090 if draft or secret:
7088 if draft or secret:
7091 ui.status(_(b'phases: %s\n') % b', '.join(t))
7089 ui.status(_(b'phases: %s\n') % b', '.join(t))
7092
7090
7093 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7091 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7094 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7092 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7095 numtrouble = len(repo.revs(trouble + b"()"))
7093 numtrouble = len(repo.revs(trouble + b"()"))
7096 # We write all the possibilities to ease translation
7094 # We write all the possibilities to ease translation
7097 troublemsg = {
7095 troublemsg = {
7098 b"orphan": _(b"orphan: %d changesets"),
7096 b"orphan": _(b"orphan: %d changesets"),
7099 b"contentdivergent": _(b"content-divergent: %d changesets"),
7097 b"contentdivergent": _(b"content-divergent: %d changesets"),
7100 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7098 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7101 }
7099 }
7102 if numtrouble > 0:
7100 if numtrouble > 0:
7103 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7101 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7104
7102
7105 cmdutil.summaryhooks(ui, repo)
7103 cmdutil.summaryhooks(ui, repo)
7106
7104
7107 if opts.get(b'remote'):
7105 if opts.get(b'remote'):
7108 needsincoming, needsoutgoing = True, True
7106 needsincoming, needsoutgoing = True, True
7109 else:
7107 else:
7110 needsincoming, needsoutgoing = False, False
7108 needsincoming, needsoutgoing = False, False
7111 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7109 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7112 if i:
7110 if i:
7113 needsincoming = True
7111 needsincoming = True
7114 if o:
7112 if o:
7115 needsoutgoing = True
7113 needsoutgoing = True
7116 if not needsincoming and not needsoutgoing:
7114 if not needsincoming and not needsoutgoing:
7117 return
7115 return
7118
7116
7119 def getincoming():
7117 def getincoming():
7120 source, branches = hg.parseurl(ui.expandpath(b'default'))
7118 source, branches = hg.parseurl(ui.expandpath(b'default'))
7121 sbranch = branches[0]
7119 sbranch = branches[0]
7122 try:
7120 try:
7123 other = hg.peer(repo, {}, source)
7121 other = hg.peer(repo, {}, source)
7124 except error.RepoError:
7122 except error.RepoError:
7125 if opts.get(b'remote'):
7123 if opts.get(b'remote'):
7126 raise
7124 raise
7127 return source, sbranch, None, None, None
7125 return source, sbranch, None, None, None
7128 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7126 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7129 if revs:
7127 if revs:
7130 revs = [other.lookup(rev) for rev in revs]
7128 revs = [other.lookup(rev) for rev in revs]
7131 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7129 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7132 repo.ui.pushbuffer()
7130 repo.ui.pushbuffer()
7133 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7131 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7134 repo.ui.popbuffer()
7132 repo.ui.popbuffer()
7135 return source, sbranch, other, commoninc, commoninc[1]
7133 return source, sbranch, other, commoninc, commoninc[1]
7136
7134
7137 if needsincoming:
7135 if needsincoming:
7138 source, sbranch, sother, commoninc, incoming = getincoming()
7136 source, sbranch, sother, commoninc, incoming = getincoming()
7139 else:
7137 else:
7140 source = sbranch = sother = commoninc = incoming = None
7138 source = sbranch = sother = commoninc = incoming = None
7141
7139
7142 def getoutgoing():
7140 def getoutgoing():
7143 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7141 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7144 dbranch = branches[0]
7142 dbranch = branches[0]
7145 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7143 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7146 if source != dest:
7144 if source != dest:
7147 try:
7145 try:
7148 dother = hg.peer(repo, {}, dest)
7146 dother = hg.peer(repo, {}, dest)
7149 except error.RepoError:
7147 except error.RepoError:
7150 if opts.get(b'remote'):
7148 if opts.get(b'remote'):
7151 raise
7149 raise
7152 return dest, dbranch, None, None
7150 return dest, dbranch, None, None
7153 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7151 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7154 elif sother is None:
7152 elif sother is None:
7155 # there is no explicit destination peer, but source one is invalid
7153 # there is no explicit destination peer, but source one is invalid
7156 return dest, dbranch, None, None
7154 return dest, dbranch, None, None
7157 else:
7155 else:
7158 dother = sother
7156 dother = sother
7159 if source != dest or (sbranch is not None and sbranch != dbranch):
7157 if source != dest or (sbranch is not None and sbranch != dbranch):
7160 common = None
7158 common = None
7161 else:
7159 else:
7162 common = commoninc
7160 common = commoninc
7163 if revs:
7161 if revs:
7164 revs = [repo.lookup(rev) for rev in revs]
7162 revs = [repo.lookup(rev) for rev in revs]
7165 repo.ui.pushbuffer()
7163 repo.ui.pushbuffer()
7166 outgoing = discovery.findcommonoutgoing(
7164 outgoing = discovery.findcommonoutgoing(
7167 repo, dother, onlyheads=revs, commoninc=common
7165 repo, dother, onlyheads=revs, commoninc=common
7168 )
7166 )
7169 repo.ui.popbuffer()
7167 repo.ui.popbuffer()
7170 return dest, dbranch, dother, outgoing
7168 return dest, dbranch, dother, outgoing
7171
7169
7172 if needsoutgoing:
7170 if needsoutgoing:
7173 dest, dbranch, dother, outgoing = getoutgoing()
7171 dest, dbranch, dother, outgoing = getoutgoing()
7174 else:
7172 else:
7175 dest = dbranch = dother = outgoing = None
7173 dest = dbranch = dother = outgoing = None
7176
7174
7177 if opts.get(b'remote'):
7175 if opts.get(b'remote'):
7178 t = []
7176 t = []
7179 if incoming:
7177 if incoming:
7180 t.append(_(b'1 or more incoming'))
7178 t.append(_(b'1 or more incoming'))
7181 o = outgoing.missing
7179 o = outgoing.missing
7182 if o:
7180 if o:
7183 t.append(_(b'%d outgoing') % len(o))
7181 t.append(_(b'%d outgoing') % len(o))
7184 other = dother or sother
7182 other = dother or sother
7185 if b'bookmarks' in other.listkeys(b'namespaces'):
7183 if b'bookmarks' in other.listkeys(b'namespaces'):
7186 counts = bookmarks.summary(repo, other)
7184 counts = bookmarks.summary(repo, other)
7187 if counts[0] > 0:
7185 if counts[0] > 0:
7188 t.append(_(b'%d incoming bookmarks') % counts[0])
7186 t.append(_(b'%d incoming bookmarks') % counts[0])
7189 if counts[1] > 0:
7187 if counts[1] > 0:
7190 t.append(_(b'%d outgoing bookmarks') % counts[1])
7188 t.append(_(b'%d outgoing bookmarks') % counts[1])
7191
7189
7192 if t:
7190 if t:
7193 # i18n: column positioning for "hg summary"
7191 # i18n: column positioning for "hg summary"
7194 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7192 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7195 else:
7193 else:
7196 # i18n: column positioning for "hg summary"
7194 # i18n: column positioning for "hg summary"
7197 ui.status(_(b'remote: (synced)\n'))
7195 ui.status(_(b'remote: (synced)\n'))
7198
7196
7199 cmdutil.summaryremotehooks(
7197 cmdutil.summaryremotehooks(
7200 ui,
7198 ui,
7201 repo,
7199 repo,
7202 opts,
7200 opts,
7203 (
7201 (
7204 (source, sbranch, sother, commoninc),
7202 (source, sbranch, sother, commoninc),
7205 (dest, dbranch, dother, outgoing),
7203 (dest, dbranch, dother, outgoing),
7206 ),
7204 ),
7207 )
7205 )
7208
7206
7209
7207
7210 @command(
7208 @command(
7211 b'tag',
7209 b'tag',
7212 [
7210 [
7213 (b'f', b'force', None, _(b'force tag')),
7211 (b'f', b'force', None, _(b'force tag')),
7214 (b'l', b'local', None, _(b'make the tag local')),
7212 (b'l', b'local', None, _(b'make the tag local')),
7215 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7213 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7216 (b'', b'remove', None, _(b'remove a tag')),
7214 (b'', b'remove', None, _(b'remove a tag')),
7217 # -l/--local is already there, commitopts cannot be used
7215 # -l/--local is already there, commitopts cannot be used
7218 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7216 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7219 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7217 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7220 ]
7218 ]
7221 + commitopts2,
7219 + commitopts2,
7222 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7220 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7223 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7221 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7224 )
7222 )
7225 def tag(ui, repo, name1, *names, **opts):
7223 def tag(ui, repo, name1, *names, **opts):
7226 """add one or more tags for the current or given revision
7224 """add one or more tags for the current or given revision
7227
7225
7228 Name a particular revision using <name>.
7226 Name a particular revision using <name>.
7229
7227
7230 Tags are used to name particular revisions of the repository and are
7228 Tags are used to name particular revisions of the repository and are
7231 very useful to compare different revisions, to go back to significant
7229 very useful to compare different revisions, to go back to significant
7232 earlier versions or to mark branch points as releases, etc. Changing
7230 earlier versions or to mark branch points as releases, etc. Changing
7233 an existing tag is normally disallowed; use -f/--force to override.
7231 an existing tag is normally disallowed; use -f/--force to override.
7234
7232
7235 If no revision is given, the parent of the working directory is
7233 If no revision is given, the parent of the working directory is
7236 used.
7234 used.
7237
7235
7238 To facilitate version control, distribution, and merging of tags,
7236 To facilitate version control, distribution, and merging of tags,
7239 they are stored as a file named ".hgtags" which is managed similarly
7237 they are stored as a file named ".hgtags" which is managed similarly
7240 to other project files and can be hand-edited if necessary. This
7238 to other project files and can be hand-edited if necessary. This
7241 also means that tagging creates a new commit. The file
7239 also means that tagging creates a new commit. The file
7242 ".hg/localtags" is used for local tags (not shared among
7240 ".hg/localtags" is used for local tags (not shared among
7243 repositories).
7241 repositories).
7244
7242
7245 Tag commits are usually made at the head of a branch. If the parent
7243 Tag commits are usually made at the head of a branch. If the parent
7246 of the working directory is not a branch head, :hg:`tag` aborts; use
7244 of the working directory is not a branch head, :hg:`tag` aborts; use
7247 -f/--force to force the tag commit to be based on a non-head
7245 -f/--force to force the tag commit to be based on a non-head
7248 changeset.
7246 changeset.
7249
7247
7250 See :hg:`help dates` for a list of formats valid for -d/--date.
7248 See :hg:`help dates` for a list of formats valid for -d/--date.
7251
7249
7252 Since tag names have priority over branch names during revision
7250 Since tag names have priority over branch names during revision
7253 lookup, using an existing branch name as a tag name is discouraged.
7251 lookup, using an existing branch name as a tag name is discouraged.
7254
7252
7255 Returns 0 on success.
7253 Returns 0 on success.
7256 """
7254 """
7257 opts = pycompat.byteskwargs(opts)
7255 opts = pycompat.byteskwargs(opts)
7258 with repo.wlock(), repo.lock():
7256 with repo.wlock(), repo.lock():
7259 rev_ = b"."
7257 rev_ = b"."
7260 names = [t.strip() for t in (name1,) + names]
7258 names = [t.strip() for t in (name1,) + names]
7261 if len(names) != len(set(names)):
7259 if len(names) != len(set(names)):
7262 raise error.Abort(_(b'tag names must be unique'))
7260 raise error.Abort(_(b'tag names must be unique'))
7263 for n in names:
7261 for n in names:
7264 scmutil.checknewlabel(repo, n, b'tag')
7262 scmutil.checknewlabel(repo, n, b'tag')
7265 if not n:
7263 if not n:
7266 raise error.Abort(
7264 raise error.Abort(
7267 _(b'tag names cannot consist entirely of whitespace')
7265 _(b'tag names cannot consist entirely of whitespace')
7268 )
7266 )
7269 if opts.get(b'rev') and opts.get(b'remove'):
7267 if opts.get(b'rev') and opts.get(b'remove'):
7270 raise error.Abort(_(b"--rev and --remove are incompatible"))
7268 raise error.Abort(_(b"--rev and --remove are incompatible"))
7271 if opts.get(b'rev'):
7269 if opts.get(b'rev'):
7272 rev_ = opts[b'rev']
7270 rev_ = opts[b'rev']
7273 message = opts.get(b'message')
7271 message = opts.get(b'message')
7274 if opts.get(b'remove'):
7272 if opts.get(b'remove'):
7275 if opts.get(b'local'):
7273 if opts.get(b'local'):
7276 expectedtype = b'local'
7274 expectedtype = b'local'
7277 else:
7275 else:
7278 expectedtype = b'global'
7276 expectedtype = b'global'
7279
7277
7280 for n in names:
7278 for n in names:
7281 if repo.tagtype(n) == b'global':
7279 if repo.tagtype(n) == b'global':
7282 alltags = tagsmod.findglobaltags(ui, repo)
7280 alltags = tagsmod.findglobaltags(ui, repo)
7283 if alltags[n][0] == nullid:
7281 if alltags[n][0] == nullid:
7284 raise error.Abort(_(b"tag '%s' is already removed") % n)
7282 raise error.Abort(_(b"tag '%s' is already removed") % n)
7285 if not repo.tagtype(n):
7283 if not repo.tagtype(n):
7286 raise error.Abort(_(b"tag '%s' does not exist") % n)
7284 raise error.Abort(_(b"tag '%s' does not exist") % n)
7287 if repo.tagtype(n) != expectedtype:
7285 if repo.tagtype(n) != expectedtype:
7288 if expectedtype == b'global':
7286 if expectedtype == b'global':
7289 raise error.Abort(
7287 raise error.Abort(
7290 _(b"tag '%s' is not a global tag") % n
7288 _(b"tag '%s' is not a global tag") % n
7291 )
7289 )
7292 else:
7290 else:
7293 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7291 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7294 rev_ = b'null'
7292 rev_ = b'null'
7295 if not message:
7293 if not message:
7296 # we don't translate commit messages
7294 # we don't translate commit messages
7297 message = b'Removed tag %s' % b', '.join(names)
7295 message = b'Removed tag %s' % b', '.join(names)
7298 elif not opts.get(b'force'):
7296 elif not opts.get(b'force'):
7299 for n in names:
7297 for n in names:
7300 if n in repo.tags():
7298 if n in repo.tags():
7301 raise error.Abort(
7299 raise error.Abort(
7302 _(b"tag '%s' already exists (use -f to force)") % n
7300 _(b"tag '%s' already exists (use -f to force)") % n
7303 )
7301 )
7304 if not opts.get(b'local'):
7302 if not opts.get(b'local'):
7305 p1, p2 = repo.dirstate.parents()
7303 p1, p2 = repo.dirstate.parents()
7306 if p2 != nullid:
7304 if p2 != nullid:
7307 raise error.Abort(_(b'uncommitted merge'))
7305 raise error.Abort(_(b'uncommitted merge'))
7308 bheads = repo.branchheads()
7306 bheads = repo.branchheads()
7309 if not opts.get(b'force') and bheads and p1 not in bheads:
7307 if not opts.get(b'force') and bheads and p1 not in bheads:
7310 raise error.Abort(
7308 raise error.Abort(
7311 _(
7309 _(
7312 b'working directory is not at a branch head '
7310 b'working directory is not at a branch head '
7313 b'(use -f to force)'
7311 b'(use -f to force)'
7314 )
7312 )
7315 )
7313 )
7316 node = scmutil.revsingle(repo, rev_).node()
7314 node = scmutil.revsingle(repo, rev_).node()
7317
7315
7318 if not message:
7316 if not message:
7319 # we don't translate commit messages
7317 # we don't translate commit messages
7320 message = b'Added tag %s for changeset %s' % (
7318 message = b'Added tag %s for changeset %s' % (
7321 b', '.join(names),
7319 b', '.join(names),
7322 short(node),
7320 short(node),
7323 )
7321 )
7324
7322
7325 date = opts.get(b'date')
7323 date = opts.get(b'date')
7326 if date:
7324 if date:
7327 date = dateutil.parsedate(date)
7325 date = dateutil.parsedate(date)
7328
7326
7329 if opts.get(b'remove'):
7327 if opts.get(b'remove'):
7330 editform = b'tag.remove'
7328 editform = b'tag.remove'
7331 else:
7329 else:
7332 editform = b'tag.add'
7330 editform = b'tag.add'
7333 editor = cmdutil.getcommiteditor(
7331 editor = cmdutil.getcommiteditor(
7334 editform=editform, **pycompat.strkwargs(opts)
7332 editform=editform, **pycompat.strkwargs(opts)
7335 )
7333 )
7336
7334
7337 # don't allow tagging the null rev
7335 # don't allow tagging the null rev
7338 if (
7336 if (
7339 not opts.get(b'remove')
7337 not opts.get(b'remove')
7340 and scmutil.revsingle(repo, rev_).rev() == nullrev
7338 and scmutil.revsingle(repo, rev_).rev() == nullrev
7341 ):
7339 ):
7342 raise error.Abort(_(b"cannot tag null revision"))
7340 raise error.Abort(_(b"cannot tag null revision"))
7343
7341
7344 tagsmod.tag(
7342 tagsmod.tag(
7345 repo,
7343 repo,
7346 names,
7344 names,
7347 node,
7345 node,
7348 message,
7346 message,
7349 opts.get(b'local'),
7347 opts.get(b'local'),
7350 opts.get(b'user'),
7348 opts.get(b'user'),
7351 date,
7349 date,
7352 editor=editor,
7350 editor=editor,
7353 )
7351 )
7354
7352
7355
7353
7356 @command(
7354 @command(
7357 b'tags',
7355 b'tags',
7358 formatteropts,
7356 formatteropts,
7359 b'',
7357 b'',
7360 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7358 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7361 intents={INTENT_READONLY},
7359 intents={INTENT_READONLY},
7362 )
7360 )
7363 def tags(ui, repo, **opts):
7361 def tags(ui, repo, **opts):
7364 """list repository tags
7362 """list repository tags
7365
7363
7366 This lists both regular and local tags. When the -v/--verbose
7364 This lists both regular and local tags. When the -v/--verbose
7367 switch is used, a third column "local" is printed for local tags.
7365 switch is used, a third column "local" is printed for local tags.
7368 When the -q/--quiet switch is used, only the tag name is printed.
7366 When the -q/--quiet switch is used, only the tag name is printed.
7369
7367
7370 .. container:: verbose
7368 .. container:: verbose
7371
7369
7372 Template:
7370 Template:
7373
7371
7374 The following keywords are supported in addition to the common template
7372 The following keywords are supported in addition to the common template
7375 keywords and functions such as ``{tag}``. See also
7373 keywords and functions such as ``{tag}``. See also
7376 :hg:`help templates`.
7374 :hg:`help templates`.
7377
7375
7378 :type: String. ``local`` for local tags.
7376 :type: String. ``local`` for local tags.
7379
7377
7380 Returns 0 on success.
7378 Returns 0 on success.
7381 """
7379 """
7382
7380
7383 opts = pycompat.byteskwargs(opts)
7381 opts = pycompat.byteskwargs(opts)
7384 ui.pager(b'tags')
7382 ui.pager(b'tags')
7385 fm = ui.formatter(b'tags', opts)
7383 fm = ui.formatter(b'tags', opts)
7386 hexfunc = fm.hexfunc
7384 hexfunc = fm.hexfunc
7387
7385
7388 for t, n in reversed(repo.tagslist()):
7386 for t, n in reversed(repo.tagslist()):
7389 hn = hexfunc(n)
7387 hn = hexfunc(n)
7390 label = b'tags.normal'
7388 label = b'tags.normal'
7391 tagtype = b''
7389 tagtype = b''
7392 if repo.tagtype(t) == b'local':
7390 if repo.tagtype(t) == b'local':
7393 label = b'tags.local'
7391 label = b'tags.local'
7394 tagtype = b'local'
7392 tagtype = b'local'
7395
7393
7396 fm.startitem()
7394 fm.startitem()
7397 fm.context(repo=repo)
7395 fm.context(repo=repo)
7398 fm.write(b'tag', b'%s', t, label=label)
7396 fm.write(b'tag', b'%s', t, label=label)
7399 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7397 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7400 fm.condwrite(
7398 fm.condwrite(
7401 not ui.quiet,
7399 not ui.quiet,
7402 b'rev node',
7400 b'rev node',
7403 fmt,
7401 fmt,
7404 repo.changelog.rev(n),
7402 repo.changelog.rev(n),
7405 hn,
7403 hn,
7406 label=label,
7404 label=label,
7407 )
7405 )
7408 fm.condwrite(
7406 fm.condwrite(
7409 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7407 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7410 )
7408 )
7411 fm.plain(b'\n')
7409 fm.plain(b'\n')
7412 fm.end()
7410 fm.end()
7413
7411
7414
7412
7415 @command(
7413 @command(
7416 b'tip',
7414 b'tip',
7417 [
7415 [
7418 (b'p', b'patch', None, _(b'show patch')),
7416 (b'p', b'patch', None, _(b'show patch')),
7419 (b'g', b'git', None, _(b'use git extended diff format')),
7417 (b'g', b'git', None, _(b'use git extended diff format')),
7420 ]
7418 ]
7421 + templateopts,
7419 + templateopts,
7422 _(b'[-p] [-g]'),
7420 _(b'[-p] [-g]'),
7423 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7421 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7424 )
7422 )
7425 def tip(ui, repo, **opts):
7423 def tip(ui, repo, **opts):
7426 """show the tip revision (DEPRECATED)
7424 """show the tip revision (DEPRECATED)
7427
7425
7428 The tip revision (usually just called the tip) is the changeset
7426 The tip revision (usually just called the tip) is the changeset
7429 most recently added to the repository (and therefore the most
7427 most recently added to the repository (and therefore the most
7430 recently changed head).
7428 recently changed head).
7431
7429
7432 If you have just made a commit, that commit will be the tip. If
7430 If you have just made a commit, that commit will be the tip. If
7433 you have just pulled changes from another repository, the tip of
7431 you have just pulled changes from another repository, the tip of
7434 that repository becomes the current tip. The "tip" tag is special
7432 that repository becomes the current tip. The "tip" tag is special
7435 and cannot be renamed or assigned to a different changeset.
7433 and cannot be renamed or assigned to a different changeset.
7436
7434
7437 This command is deprecated, please use :hg:`heads` instead.
7435 This command is deprecated, please use :hg:`heads` instead.
7438
7436
7439 Returns 0 on success.
7437 Returns 0 on success.
7440 """
7438 """
7441 opts = pycompat.byteskwargs(opts)
7439 opts = pycompat.byteskwargs(opts)
7442 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7440 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7443 displayer.show(repo[b'tip'])
7441 displayer.show(repo[b'tip'])
7444 displayer.close()
7442 displayer.close()
7445
7443
7446
7444
7447 @command(
7445 @command(
7448 b'unbundle',
7446 b'unbundle',
7449 [
7447 [
7450 (
7448 (
7451 b'u',
7449 b'u',
7452 b'update',
7450 b'update',
7453 None,
7451 None,
7454 _(b'update to new branch head if changesets were unbundled'),
7452 _(b'update to new branch head if changesets were unbundled'),
7455 )
7453 )
7456 ],
7454 ],
7457 _(b'[-u] FILE...'),
7455 _(b'[-u] FILE...'),
7458 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7456 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7459 )
7457 )
7460 def unbundle(ui, repo, fname1, *fnames, **opts):
7458 def unbundle(ui, repo, fname1, *fnames, **opts):
7461 """apply one or more bundle files
7459 """apply one or more bundle files
7462
7460
7463 Apply one or more bundle files generated by :hg:`bundle`.
7461 Apply one or more bundle files generated by :hg:`bundle`.
7464
7462
7465 Returns 0 on success, 1 if an update has unresolved files.
7463 Returns 0 on success, 1 if an update has unresolved files.
7466 """
7464 """
7467 fnames = (fname1,) + fnames
7465 fnames = (fname1,) + fnames
7468
7466
7469 with repo.lock():
7467 with repo.lock():
7470 for fname in fnames:
7468 for fname in fnames:
7471 f = hg.openpath(ui, fname)
7469 f = hg.openpath(ui, fname)
7472 gen = exchange.readbundle(ui, f, fname)
7470 gen = exchange.readbundle(ui, f, fname)
7473 if isinstance(gen, streamclone.streamcloneapplier):
7471 if isinstance(gen, streamclone.streamcloneapplier):
7474 raise error.Abort(
7472 raise error.Abort(
7475 _(
7473 _(
7476 b'packed bundles cannot be applied with '
7474 b'packed bundles cannot be applied with '
7477 b'"hg unbundle"'
7475 b'"hg unbundle"'
7478 ),
7476 ),
7479 hint=_(b'use "hg debugapplystreamclonebundle"'),
7477 hint=_(b'use "hg debugapplystreamclonebundle"'),
7480 )
7478 )
7481 url = b'bundle:' + fname
7479 url = b'bundle:' + fname
7482 try:
7480 try:
7483 txnname = b'unbundle'
7481 txnname = b'unbundle'
7484 if not isinstance(gen, bundle2.unbundle20):
7482 if not isinstance(gen, bundle2.unbundle20):
7485 txnname = b'unbundle\n%s' % util.hidepassword(url)
7483 txnname = b'unbundle\n%s' % util.hidepassword(url)
7486 with repo.transaction(txnname) as tr:
7484 with repo.transaction(txnname) as tr:
7487 op = bundle2.applybundle(
7485 op = bundle2.applybundle(
7488 repo, gen, tr, source=b'unbundle', url=url
7486 repo, gen, tr, source=b'unbundle', url=url
7489 )
7487 )
7490 except error.BundleUnknownFeatureError as exc:
7488 except error.BundleUnknownFeatureError as exc:
7491 raise error.Abort(
7489 raise error.Abort(
7492 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7490 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7493 hint=_(
7491 hint=_(
7494 b"see https://mercurial-scm.org/"
7492 b"see https://mercurial-scm.org/"
7495 b"wiki/BundleFeature for more "
7493 b"wiki/BundleFeature for more "
7496 b"information"
7494 b"information"
7497 ),
7495 ),
7498 )
7496 )
7499 modheads = bundle2.combinechangegroupresults(op)
7497 modheads = bundle2.combinechangegroupresults(op)
7500
7498
7501 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7499 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7502
7500
7503
7501
7504 @command(
7502 @command(
7505 b'unshelve',
7503 b'unshelve',
7506 [
7504 [
7507 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7505 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7508 (
7506 (
7509 b'c',
7507 b'c',
7510 b'continue',
7508 b'continue',
7511 None,
7509 None,
7512 _(b'continue an incomplete unshelve operation'),
7510 _(b'continue an incomplete unshelve operation'),
7513 ),
7511 ),
7514 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7512 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7515 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7513 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7516 (
7514 (
7517 b'n',
7515 b'n',
7518 b'name',
7516 b'name',
7519 b'',
7517 b'',
7520 _(b'restore shelved change with given name'),
7518 _(b'restore shelved change with given name'),
7521 _(b'NAME'),
7519 _(b'NAME'),
7522 ),
7520 ),
7523 (b't', b'tool', b'', _(b'specify merge tool')),
7521 (b't', b'tool', b'', _(b'specify merge tool')),
7524 (
7522 (
7525 b'',
7523 b'',
7526 b'date',
7524 b'date',
7527 b'',
7525 b'',
7528 _(b'set date for temporary commits (DEPRECATED)'),
7526 _(b'set date for temporary commits (DEPRECATED)'),
7529 _(b'DATE'),
7527 _(b'DATE'),
7530 ),
7528 ),
7531 ],
7529 ],
7532 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7530 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7533 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7531 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7534 )
7532 )
7535 def unshelve(ui, repo, *shelved, **opts):
7533 def unshelve(ui, repo, *shelved, **opts):
7536 """restore a shelved change to the working directory
7534 """restore a shelved change to the working directory
7537
7535
7538 This command accepts an optional name of a shelved change to
7536 This command accepts an optional name of a shelved change to
7539 restore. If none is given, the most recent shelved change is used.
7537 restore. If none is given, the most recent shelved change is used.
7540
7538
7541 If a shelved change is applied successfully, the bundle that
7539 If a shelved change is applied successfully, the bundle that
7542 contains the shelved changes is moved to a backup location
7540 contains the shelved changes is moved to a backup location
7543 (.hg/shelve-backup).
7541 (.hg/shelve-backup).
7544
7542
7545 Since you can restore a shelved change on top of an arbitrary
7543 Since you can restore a shelved change on top of an arbitrary
7546 commit, it is possible that unshelving will result in a conflict
7544 commit, it is possible that unshelving will result in a conflict
7547 between your changes and the commits you are unshelving onto. If
7545 between your changes and the commits you are unshelving onto. If
7548 this occurs, you must resolve the conflict, then use
7546 this occurs, you must resolve the conflict, then use
7549 ``--continue`` to complete the unshelve operation. (The bundle
7547 ``--continue`` to complete the unshelve operation. (The bundle
7550 will not be moved until you successfully complete the unshelve.)
7548 will not be moved until you successfully complete the unshelve.)
7551
7549
7552 (Alternatively, you can use ``--abort`` to abandon an unshelve
7550 (Alternatively, you can use ``--abort`` to abandon an unshelve
7553 that causes a conflict. This reverts the unshelved changes, and
7551 that causes a conflict. This reverts the unshelved changes, and
7554 leaves the bundle in place.)
7552 leaves the bundle in place.)
7555
7553
7556 If bare shelved change (without interactive, include and exclude
7554 If bare shelved change (without interactive, include and exclude
7557 option) was done on newly created branch it would restore branch
7555 option) was done on newly created branch it would restore branch
7558 information to the working directory.
7556 information to the working directory.
7559
7557
7560 After a successful unshelve, the shelved changes are stored in a
7558 After a successful unshelve, the shelved changes are stored in a
7561 backup directory. Only the N most recent backups are kept. N
7559 backup directory. Only the N most recent backups are kept. N
7562 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7560 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7563 configuration option.
7561 configuration option.
7564
7562
7565 .. container:: verbose
7563 .. container:: verbose
7566
7564
7567 Timestamp in seconds is used to decide order of backups. More
7565 Timestamp in seconds is used to decide order of backups. More
7568 than ``maxbackups`` backups are kept, if same timestamp
7566 than ``maxbackups`` backups are kept, if same timestamp
7569 prevents from deciding exact order of them, for safety.
7567 prevents from deciding exact order of them, for safety.
7570
7568
7571 Selected changes can be unshelved with ``--interactive`` flag.
7569 Selected changes can be unshelved with ``--interactive`` flag.
7572 The working directory is updated with the selected changes, and
7570 The working directory is updated with the selected changes, and
7573 only the unselected changes remain shelved.
7571 only the unselected changes remain shelved.
7574 Note: The whole shelve is applied to working directory first before
7572 Note: The whole shelve is applied to working directory first before
7575 running interactively. So, this will bring up all the conflicts between
7573 running interactively. So, this will bring up all the conflicts between
7576 working directory and the shelve, irrespective of which changes will be
7574 working directory and the shelve, irrespective of which changes will be
7577 unshelved.
7575 unshelved.
7578 """
7576 """
7579 with repo.wlock():
7577 with repo.wlock():
7580 return shelvemod.dounshelve(ui, repo, *shelved, **opts)
7578 return shelvemod.dounshelve(ui, repo, *shelved, **opts)
7581
7579
7582
7580
7583 statemod.addunfinished(
7581 statemod.addunfinished(
7584 b'unshelve',
7582 b'unshelve',
7585 fname=b'shelvedstate',
7583 fname=b'shelvedstate',
7586 continueflag=True,
7584 continueflag=True,
7587 abortfunc=shelvemod.hgabortunshelve,
7585 abortfunc=shelvemod.hgabortunshelve,
7588 continuefunc=shelvemod.hgcontinueunshelve,
7586 continuefunc=shelvemod.hgcontinueunshelve,
7589 cmdmsg=_(b'unshelve already in progress'),
7587 cmdmsg=_(b'unshelve already in progress'),
7590 )
7588 )
7591
7589
7592
7590
7593 @command(
7591 @command(
7594 b'update|up|checkout|co',
7592 b'update|up|checkout|co',
7595 [
7593 [
7596 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7594 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7597 (b'c', b'check', None, _(b'require clean working directory')),
7595 (b'c', b'check', None, _(b'require clean working directory')),
7598 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7596 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7599 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7597 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7600 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7598 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7601 ]
7599 ]
7602 + mergetoolopts,
7600 + mergetoolopts,
7603 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7601 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7604 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7602 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7605 helpbasic=True,
7603 helpbasic=True,
7606 )
7604 )
7607 def update(ui, repo, node=None, **opts):
7605 def update(ui, repo, node=None, **opts):
7608 """update working directory (or switch revisions)
7606 """update working directory (or switch revisions)
7609
7607
7610 Update the repository's working directory to the specified
7608 Update the repository's working directory to the specified
7611 changeset. If no changeset is specified, update to the tip of the
7609 changeset. If no changeset is specified, update to the tip of the
7612 current named branch and move the active bookmark (see :hg:`help
7610 current named branch and move the active bookmark (see :hg:`help
7613 bookmarks`).
7611 bookmarks`).
7614
7612
7615 Update sets the working directory's parent revision to the specified
7613 Update sets the working directory's parent revision to the specified
7616 changeset (see :hg:`help parents`).
7614 changeset (see :hg:`help parents`).
7617
7615
7618 If the changeset is not a descendant or ancestor of the working
7616 If the changeset is not a descendant or ancestor of the working
7619 directory's parent and there are uncommitted changes, the update is
7617 directory's parent and there are uncommitted changes, the update is
7620 aborted. With the -c/--check option, the working directory is checked
7618 aborted. With the -c/--check option, the working directory is checked
7621 for uncommitted changes; if none are found, the working directory is
7619 for uncommitted changes; if none are found, the working directory is
7622 updated to the specified changeset.
7620 updated to the specified changeset.
7623
7621
7624 .. container:: verbose
7622 .. container:: verbose
7625
7623
7626 The -C/--clean, -c/--check, and -m/--merge options control what
7624 The -C/--clean, -c/--check, and -m/--merge options control what
7627 happens if the working directory contains uncommitted changes.
7625 happens if the working directory contains uncommitted changes.
7628 At most of one of them can be specified.
7626 At most of one of them can be specified.
7629
7627
7630 1. If no option is specified, and if
7628 1. If no option is specified, and if
7631 the requested changeset is an ancestor or descendant of
7629 the requested changeset is an ancestor or descendant of
7632 the working directory's parent, the uncommitted changes
7630 the working directory's parent, the uncommitted changes
7633 are merged into the requested changeset and the merged
7631 are merged into the requested changeset and the merged
7634 result is left uncommitted. If the requested changeset is
7632 result is left uncommitted. If the requested changeset is
7635 not an ancestor or descendant (that is, it is on another
7633 not an ancestor or descendant (that is, it is on another
7636 branch), the update is aborted and the uncommitted changes
7634 branch), the update is aborted and the uncommitted changes
7637 are preserved.
7635 are preserved.
7638
7636
7639 2. With the -m/--merge option, the update is allowed even if the
7637 2. With the -m/--merge option, the update is allowed even if the
7640 requested changeset is not an ancestor or descendant of
7638 requested changeset is not an ancestor or descendant of
7641 the working directory's parent.
7639 the working directory's parent.
7642
7640
7643 3. With the -c/--check option, the update is aborted and the
7641 3. With the -c/--check option, the update is aborted and the
7644 uncommitted changes are preserved.
7642 uncommitted changes are preserved.
7645
7643
7646 4. With the -C/--clean option, uncommitted changes are discarded and
7644 4. With the -C/--clean option, uncommitted changes are discarded and
7647 the working directory is updated to the requested changeset.
7645 the working directory is updated to the requested changeset.
7648
7646
7649 To cancel an uncommitted merge (and lose your changes), use
7647 To cancel an uncommitted merge (and lose your changes), use
7650 :hg:`merge --abort`.
7648 :hg:`merge --abort`.
7651
7649
7652 Use null as the changeset to remove the working directory (like
7650 Use null as the changeset to remove the working directory (like
7653 :hg:`clone -U`).
7651 :hg:`clone -U`).
7654
7652
7655 If you want to revert just one file to an older revision, use
7653 If you want to revert just one file to an older revision, use
7656 :hg:`revert [-r REV] NAME`.
7654 :hg:`revert [-r REV] NAME`.
7657
7655
7658 See :hg:`help dates` for a list of formats valid for -d/--date.
7656 See :hg:`help dates` for a list of formats valid for -d/--date.
7659
7657
7660 Returns 0 on success, 1 if there are unresolved files.
7658 Returns 0 on success, 1 if there are unresolved files.
7661 """
7659 """
7662 rev = opts.get('rev')
7660 rev = opts.get('rev')
7663 date = opts.get('date')
7661 date = opts.get('date')
7664 clean = opts.get('clean')
7662 clean = opts.get('clean')
7665 check = opts.get('check')
7663 check = opts.get('check')
7666 merge = opts.get('merge')
7664 merge = opts.get('merge')
7667 if rev and node:
7665 if rev and node:
7668 raise error.Abort(_(b"please specify just one revision"))
7666 raise error.Abort(_(b"please specify just one revision"))
7669
7667
7670 if ui.configbool(b'commands', b'update.requiredest'):
7668 if ui.configbool(b'commands', b'update.requiredest'):
7671 if not node and not rev and not date:
7669 if not node and not rev and not date:
7672 raise error.Abort(
7670 raise error.Abort(
7673 _(b'you must specify a destination'),
7671 _(b'you must specify a destination'),
7674 hint=_(b'for example: hg update ".::"'),
7672 hint=_(b'for example: hg update ".::"'),
7675 )
7673 )
7676
7674
7677 if rev is None or rev == b'':
7675 if rev is None or rev == b'':
7678 rev = node
7676 rev = node
7679
7677
7680 if date and rev is not None:
7678 if date and rev is not None:
7681 raise error.Abort(_(b"you can't specify a revision and a date"))
7679 raise error.Abort(_(b"you can't specify a revision and a date"))
7682
7680
7683 if len([x for x in (clean, check, merge) if x]) > 1:
7681 if len([x for x in (clean, check, merge) if x]) > 1:
7684 raise error.Abort(
7682 raise error.Abort(
7685 _(
7683 _(
7686 b"can only specify one of -C/--clean, -c/--check, "
7684 b"can only specify one of -C/--clean, -c/--check, "
7687 b"or -m/--merge"
7685 b"or -m/--merge"
7688 )
7686 )
7689 )
7687 )
7690
7688
7691 updatecheck = None
7689 updatecheck = None
7692 if check:
7690 if check:
7693 updatecheck = b'abort'
7691 updatecheck = b'abort'
7694 elif merge:
7692 elif merge:
7695 updatecheck = b'none'
7693 updatecheck = b'none'
7696
7694
7697 with repo.wlock():
7695 with repo.wlock():
7698 cmdutil.clearunfinished(repo)
7696 cmdutil.clearunfinished(repo)
7699 if date:
7697 if date:
7700 rev = cmdutil.finddate(ui, repo, date)
7698 rev = cmdutil.finddate(ui, repo, date)
7701
7699
7702 # if we defined a bookmark, we have to remember the original name
7700 # if we defined a bookmark, we have to remember the original name
7703 brev = rev
7701 brev = rev
7704 if rev:
7702 if rev:
7705 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7703 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7706 ctx = scmutil.revsingle(repo, rev, default=None)
7704 ctx = scmutil.revsingle(repo, rev, default=None)
7707 rev = ctx.rev()
7705 rev = ctx.rev()
7708 hidden = ctx.hidden()
7706 hidden = ctx.hidden()
7709 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7707 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7710 with ui.configoverride(overrides, b'update'):
7708 with ui.configoverride(overrides, b'update'):
7711 ret = hg.updatetotally(
7709 ret = hg.updatetotally(
7712 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7710 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7713 )
7711 )
7714 if hidden:
7712 if hidden:
7715 ctxstr = ctx.hex()[:12]
7713 ctxstr = ctx.hex()[:12]
7716 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7714 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7717
7715
7718 if ctx.obsolete():
7716 if ctx.obsolete():
7719 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7717 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7720 ui.warn(b"(%s)\n" % obsfatemsg)
7718 ui.warn(b"(%s)\n" % obsfatemsg)
7721 return ret
7719 return ret
7722
7720
7723
7721
7724 @command(
7722 @command(
7725 b'verify',
7723 b'verify',
7726 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7724 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7727 helpcategory=command.CATEGORY_MAINTENANCE,
7725 helpcategory=command.CATEGORY_MAINTENANCE,
7728 )
7726 )
7729 def verify(ui, repo, **opts):
7727 def verify(ui, repo, **opts):
7730 """verify the integrity of the repository
7728 """verify the integrity of the repository
7731
7729
7732 Verify the integrity of the current repository.
7730 Verify the integrity of the current repository.
7733
7731
7734 This will perform an extensive check of the repository's
7732 This will perform an extensive check of the repository's
7735 integrity, validating the hashes and checksums of each entry in
7733 integrity, validating the hashes and checksums of each entry in
7736 the changelog, manifest, and tracked files, as well as the
7734 the changelog, manifest, and tracked files, as well as the
7737 integrity of their crosslinks and indices.
7735 integrity of their crosslinks and indices.
7738
7736
7739 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7737 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7740 for more information about recovery from corruption of the
7738 for more information about recovery from corruption of the
7741 repository.
7739 repository.
7742
7740
7743 Returns 0 on success, 1 if errors are encountered.
7741 Returns 0 on success, 1 if errors are encountered.
7744 """
7742 """
7745 opts = pycompat.byteskwargs(opts)
7743 opts = pycompat.byteskwargs(opts)
7746
7744
7747 level = None
7745 level = None
7748 if opts[b'full']:
7746 if opts[b'full']:
7749 level = verifymod.VERIFY_FULL
7747 level = verifymod.VERIFY_FULL
7750 return hg.verify(repo, level)
7748 return hg.verify(repo, level)
7751
7749
7752
7750
7753 @command(
7751 @command(
7754 b'version',
7752 b'version',
7755 [] + formatteropts,
7753 [] + formatteropts,
7756 helpcategory=command.CATEGORY_HELP,
7754 helpcategory=command.CATEGORY_HELP,
7757 norepo=True,
7755 norepo=True,
7758 intents={INTENT_READONLY},
7756 intents={INTENT_READONLY},
7759 )
7757 )
7760 def version_(ui, **opts):
7758 def version_(ui, **opts):
7761 """output version and copyright information
7759 """output version and copyright information
7762
7760
7763 .. container:: verbose
7761 .. container:: verbose
7764
7762
7765 Template:
7763 Template:
7766
7764
7767 The following keywords are supported. See also :hg:`help templates`.
7765 The following keywords are supported. See also :hg:`help templates`.
7768
7766
7769 :extensions: List of extensions.
7767 :extensions: List of extensions.
7770 :ver: String. Version number.
7768 :ver: String. Version number.
7771
7769
7772 And each entry of ``{extensions}`` provides the following sub-keywords
7770 And each entry of ``{extensions}`` provides the following sub-keywords
7773 in addition to ``{ver}``.
7771 in addition to ``{ver}``.
7774
7772
7775 :bundled: Boolean. True if included in the release.
7773 :bundled: Boolean. True if included in the release.
7776 :name: String. Extension name.
7774 :name: String. Extension name.
7777 """
7775 """
7778 opts = pycompat.byteskwargs(opts)
7776 opts = pycompat.byteskwargs(opts)
7779 if ui.verbose:
7777 if ui.verbose:
7780 ui.pager(b'version')
7778 ui.pager(b'version')
7781 fm = ui.formatter(b"version", opts)
7779 fm = ui.formatter(b"version", opts)
7782 fm.startitem()
7780 fm.startitem()
7783 fm.write(
7781 fm.write(
7784 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7782 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7785 )
7783 )
7786 license = _(
7784 license = _(
7787 b"(see https://mercurial-scm.org for more information)\n"
7785 b"(see https://mercurial-scm.org for more information)\n"
7788 b"\nCopyright (C) 2005-2019 Matt Mackall and others\n"
7786 b"\nCopyright (C) 2005-2019 Matt Mackall and others\n"
7789 b"This is free software; see the source for copying conditions. "
7787 b"This is free software; see the source for copying conditions. "
7790 b"There is NO\nwarranty; "
7788 b"There is NO\nwarranty; "
7791 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7789 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7792 )
7790 )
7793 if not ui.quiet:
7791 if not ui.quiet:
7794 fm.plain(license)
7792 fm.plain(license)
7795
7793
7796 if ui.verbose:
7794 if ui.verbose:
7797 fm.plain(_(b"\nEnabled extensions:\n\n"))
7795 fm.plain(_(b"\nEnabled extensions:\n\n"))
7798 # format names and versions into columns
7796 # format names and versions into columns
7799 names = []
7797 names = []
7800 vers = []
7798 vers = []
7801 isinternals = []
7799 isinternals = []
7802 for name, module in extensions.extensions():
7800 for name, module in extensions.extensions():
7803 names.append(name)
7801 names.append(name)
7804 vers.append(extensions.moduleversion(module) or None)
7802 vers.append(extensions.moduleversion(module) or None)
7805 isinternals.append(extensions.ismoduleinternal(module))
7803 isinternals.append(extensions.ismoduleinternal(module))
7806 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7804 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7807 if names:
7805 if names:
7808 namefmt = b" %%-%ds " % max(len(n) for n in names)
7806 namefmt = b" %%-%ds " % max(len(n) for n in names)
7809 places = [_(b"external"), _(b"internal")]
7807 places = [_(b"external"), _(b"internal")]
7810 for n, v, p in zip(names, vers, isinternals):
7808 for n, v, p in zip(names, vers, isinternals):
7811 fn.startitem()
7809 fn.startitem()
7812 fn.condwrite(ui.verbose, b"name", namefmt, n)
7810 fn.condwrite(ui.verbose, b"name", namefmt, n)
7813 if ui.verbose:
7811 if ui.verbose:
7814 fn.plain(b"%s " % places[p])
7812 fn.plain(b"%s " % places[p])
7815 fn.data(bundled=p)
7813 fn.data(bundled=p)
7816 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7814 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7817 if ui.verbose:
7815 if ui.verbose:
7818 fn.plain(b"\n")
7816 fn.plain(b"\n")
7819 fn.end()
7817 fn.end()
7820 fm.end()
7818 fm.end()
7821
7819
7822
7820
7823 def loadcmdtable(ui, name, cmdtable):
7821 def loadcmdtable(ui, name, cmdtable):
7824 """Load command functions from specified cmdtable
7822 """Load command functions from specified cmdtable
7825 """
7823 """
7826 overrides = [cmd for cmd in cmdtable if cmd in table]
7824 overrides = [cmd for cmd in cmdtable if cmd in table]
7827 if overrides:
7825 if overrides:
7828 ui.warn(
7826 ui.warn(
7829 _(b"extension '%s' overrides commands: %s\n")
7827 _(b"extension '%s' overrides commands: %s\n")
7830 % (name, b" ".join(overrides))
7828 % (name, b" ".join(overrides))
7831 )
7829 )
7832 table.update(cmdtable)
7830 table.update(cmdtable)
@@ -1,1257 +1,1257 b''
1
1
2 $ hg init repo
2 $ hg init repo
3 $ cd repo
3 $ cd repo
4
4
5 $ cat > $TESTTMP/hook.sh <<'EOF'
5 $ cat > $TESTTMP/hook.sh <<'EOF'
6 > echo "test-hook-bookmark: $HG_BOOKMARK: $HG_OLDNODE -> $HG_NODE"
6 > echo "test-hook-bookmark: $HG_BOOKMARK: $HG_OLDNODE -> $HG_NODE"
7 > EOF
7 > EOF
8 $ TESTHOOK="hooks.txnclose-bookmark.test=sh $TESTTMP/hook.sh"
8 $ TESTHOOK="hooks.txnclose-bookmark.test=sh $TESTTMP/hook.sh"
9
9
10 no bookmarks
10 no bookmarks
11
11
12 $ hg bookmarks
12 $ hg bookmarks
13 no bookmarks set
13 no bookmarks set
14
14
15 $ hg bookmarks -Tjson
15 $ hg bookmarks -Tjson
16 [
16 [
17 ]
17 ]
18
18
19 bookmark rev -1
19 bookmark rev -1
20
20
21 $ hg bookmark X --config "$TESTHOOK"
21 $ hg bookmark X --config "$TESTHOOK"
22 test-hook-bookmark: X: -> 0000000000000000000000000000000000000000
22 test-hook-bookmark: X: -> 0000000000000000000000000000000000000000
23
23
24 list bookmarks
24 list bookmarks
25
25
26 $ hg bookmarks
26 $ hg bookmarks
27 * X -1:000000000000
27 * X -1:000000000000
28
28
29 list bookmarks with color
29 list bookmarks with color
30
30
31 $ hg --config extensions.color= --config color.mode=ansi \
31 $ hg --config extensions.color= --config color.mode=ansi \
32 > bookmarks --color=always
32 > bookmarks --color=always
33 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
33 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
34
34
35 $ echo a > a
35 $ echo a > a
36 $ hg add a
36 $ hg add a
37 $ hg commit -m 0 --config "$TESTHOOK"
37 $ hg commit -m 0 --config "$TESTHOOK"
38 test-hook-bookmark: X: 0000000000000000000000000000000000000000 -> f7b1eb17ad24730a1651fccd46c43826d1bbc2ac
38 test-hook-bookmark: X: 0000000000000000000000000000000000000000 -> f7b1eb17ad24730a1651fccd46c43826d1bbc2ac
39
39
40 bookmark X moved to rev 0
40 bookmark X moved to rev 0
41
41
42 $ hg bookmarks
42 $ hg bookmarks
43 * X 0:f7b1eb17ad24
43 * X 0:f7b1eb17ad24
44
44
45 look up bookmark
45 look up bookmark
46
46
47 $ hg log -r X
47 $ hg log -r X
48 changeset: 0:f7b1eb17ad24
48 changeset: 0:f7b1eb17ad24
49 bookmark: X
49 bookmark: X
50 tag: tip
50 tag: tip
51 user: test
51 user: test
52 date: Thu Jan 01 00:00:00 1970 +0000
52 date: Thu Jan 01 00:00:00 1970 +0000
53 summary: 0
53 summary: 0
54
54
55
55
56 second bookmark for rev 0, command should work even with ui.strict on
56 second bookmark for rev 0, command should work even with ui.strict on
57
57
58 $ hg --config ui.strict=1 bookmark X2 --config "$TESTHOOK"
58 $ hg --config ui.strict=1 bookmark X2 --config "$TESTHOOK"
59 test-hook-bookmark: X2: -> f7b1eb17ad24730a1651fccd46c43826d1bbc2ac
59 test-hook-bookmark: X2: -> f7b1eb17ad24730a1651fccd46c43826d1bbc2ac
60
60
61 bookmark rev -1 again
61 bookmark rev -1 again
62
62
63 $ hg bookmark -r null Y
63 $ hg bookmark -r null Y
64
64
65 list bookmarks
65 list bookmarks
66
66
67 $ hg bookmarks
67 $ hg bookmarks
68 X 0:f7b1eb17ad24
68 X 0:f7b1eb17ad24
69 * X2 0:f7b1eb17ad24
69 * X2 0:f7b1eb17ad24
70 Y -1:000000000000
70 Y -1:000000000000
71 $ hg bookmarks -l
71 $ hg bookmarks -l
72 X 0:f7b1eb17ad24
72 X 0:f7b1eb17ad24
73 * X2 0:f7b1eb17ad24
73 * X2 0:f7b1eb17ad24
74 Y -1:000000000000
74 Y -1:000000000000
75 $ hg bookmarks -l X Y
75 $ hg bookmarks -l X Y
76 X 0:f7b1eb17ad24
76 X 0:f7b1eb17ad24
77 Y -1:000000000000
77 Y -1:000000000000
78 $ hg bookmarks -l .
78 $ hg bookmarks -l .
79 * X2 0:f7b1eb17ad24
79 * X2 0:f7b1eb17ad24
80 $ hg bookmarks -l X A Y
80 $ hg bookmarks -l X A Y
81 abort: bookmark 'A' does not exist
81 abort: bookmark 'A' does not exist
82 [255]
82 [255]
83 $ hg bookmarks -l -r0
83 $ hg bookmarks -l -r0
84 abort: --rev is incompatible with --list
84 abort: cannot specify both --list and --rev
85 [255]
85 [255]
86 $ hg bookmarks -l --inactive
86 $ hg bookmarks -l --inactive
87 abort: --inactive is incompatible with --list
87 abort: --inactive is incompatible with --list
88 [255]
88 [255]
89
89
90 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
90 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
91 0 X
91 0 X
92 0 X2
92 0 X2
93
93
94 $ echo b > b
94 $ echo b > b
95 $ hg add b
95 $ hg add b
96 $ hg commit -m 1 --config "$TESTHOOK"
96 $ hg commit -m 1 --config "$TESTHOOK"
97 test-hook-bookmark: X2: f7b1eb17ad24730a1651fccd46c43826d1bbc2ac -> 925d80f479bb026b0fb3deb27503780b13f74123
97 test-hook-bookmark: X2: f7b1eb17ad24730a1651fccd46c43826d1bbc2ac -> 925d80f479bb026b0fb3deb27503780b13f74123
98
98
99 $ hg bookmarks -T '{rev}:{node|shortest} {bookmark} {desc|firstline}\n'
99 $ hg bookmarks -T '{rev}:{node|shortest} {bookmark} {desc|firstline}\n'
100 0:f7b1 X 0
100 0:f7b1 X 0
101 1:925d X2 1
101 1:925d X2 1
102 -1:0000 Y
102 -1:0000 Y
103
103
104 $ hg bookmarks -Tjson
104 $ hg bookmarks -Tjson
105 [
105 [
106 {
106 {
107 "active": false,
107 "active": false,
108 "bookmark": "X",
108 "bookmark": "X",
109 "node": "f7b1eb17ad24730a1651fccd46c43826d1bbc2ac",
109 "node": "f7b1eb17ad24730a1651fccd46c43826d1bbc2ac",
110 "rev": 0
110 "rev": 0
111 },
111 },
112 {
112 {
113 "active": true,
113 "active": true,
114 "bookmark": "X2",
114 "bookmark": "X2",
115 "node": "925d80f479bb026b0fb3deb27503780b13f74123",
115 "node": "925d80f479bb026b0fb3deb27503780b13f74123",
116 "rev": 1
116 "rev": 1
117 },
117 },
118 {
118 {
119 "active": false,
119 "active": false,
120 "bookmark": "Y",
120 "bookmark": "Y",
121 "node": "0000000000000000000000000000000000000000",
121 "node": "0000000000000000000000000000000000000000",
122 "rev": -1
122 "rev": -1
123 }
123 }
124 ]
124 ]
125
125
126 bookmarks revset
126 bookmarks revset
127
127
128 $ hg log -r 'bookmark()'
128 $ hg log -r 'bookmark()'
129 changeset: 0:f7b1eb17ad24
129 changeset: 0:f7b1eb17ad24
130 bookmark: X
130 bookmark: X
131 user: test
131 user: test
132 date: Thu Jan 01 00:00:00 1970 +0000
132 date: Thu Jan 01 00:00:00 1970 +0000
133 summary: 0
133 summary: 0
134
134
135 changeset: 1:925d80f479bb
135 changeset: 1:925d80f479bb
136 bookmark: X2
136 bookmark: X2
137 tag: tip
137 tag: tip
138 user: test
138 user: test
139 date: Thu Jan 01 00:00:00 1970 +0000
139 date: Thu Jan 01 00:00:00 1970 +0000
140 summary: 1
140 summary: 1
141
141
142 $ hg log -r 'bookmark(Y)'
142 $ hg log -r 'bookmark(Y)'
143 $ hg log -r 'bookmark(X2)'
143 $ hg log -r 'bookmark(X2)'
144 changeset: 1:925d80f479bb
144 changeset: 1:925d80f479bb
145 bookmark: X2
145 bookmark: X2
146 tag: tip
146 tag: tip
147 user: test
147 user: test
148 date: Thu Jan 01 00:00:00 1970 +0000
148 date: Thu Jan 01 00:00:00 1970 +0000
149 summary: 1
149 summary: 1
150
150
151 $ hg log -r 'bookmark("re:X")'
151 $ hg log -r 'bookmark("re:X")'
152 changeset: 0:f7b1eb17ad24
152 changeset: 0:f7b1eb17ad24
153 bookmark: X
153 bookmark: X
154 user: test
154 user: test
155 date: Thu Jan 01 00:00:00 1970 +0000
155 date: Thu Jan 01 00:00:00 1970 +0000
156 summary: 0
156 summary: 0
157
157
158 changeset: 1:925d80f479bb
158 changeset: 1:925d80f479bb
159 bookmark: X2
159 bookmark: X2
160 tag: tip
160 tag: tip
161 user: test
161 user: test
162 date: Thu Jan 01 00:00:00 1970 +0000
162 date: Thu Jan 01 00:00:00 1970 +0000
163 summary: 1
163 summary: 1
164
164
165 $ hg log -r 'bookmark("literal:X")'
165 $ hg log -r 'bookmark("literal:X")'
166 changeset: 0:f7b1eb17ad24
166 changeset: 0:f7b1eb17ad24
167 bookmark: X
167 bookmark: X
168 user: test
168 user: test
169 date: Thu Jan 01 00:00:00 1970 +0000
169 date: Thu Jan 01 00:00:00 1970 +0000
170 summary: 0
170 summary: 0
171
171
172
172
173 "." is expanded to the active bookmark:
173 "." is expanded to the active bookmark:
174
174
175 $ hg log -r 'bookmark(.)'
175 $ hg log -r 'bookmark(.)'
176 changeset: 1:925d80f479bb
176 changeset: 1:925d80f479bb
177 bookmark: X2
177 bookmark: X2
178 tag: tip
178 tag: tip
179 user: test
179 user: test
180 date: Thu Jan 01 00:00:00 1970 +0000
180 date: Thu Jan 01 00:00:00 1970 +0000
181 summary: 1
181 summary: 1
182
182
183
183
184 but "literal:." is not since "." seems not a literal bookmark:
184 but "literal:." is not since "." seems not a literal bookmark:
185
185
186 $ hg log -r 'bookmark("literal:.")'
186 $ hg log -r 'bookmark("literal:.")'
187 abort: bookmark '.' does not exist!
187 abort: bookmark '.' does not exist!
188 [255]
188 [255]
189
189
190 "." should fail if there's no active bookmark:
190 "." should fail if there's no active bookmark:
191
191
192 $ hg bookmark --inactive
192 $ hg bookmark --inactive
193 $ hg log -r 'bookmark(.)'
193 $ hg log -r 'bookmark(.)'
194 abort: no active bookmark!
194 abort: no active bookmark!
195 [255]
195 [255]
196 $ hg log -r 'present(bookmark(.))'
196 $ hg log -r 'present(bookmark(.))'
197
197
198 $ hg log -r 'bookmark(unknown)'
198 $ hg log -r 'bookmark(unknown)'
199 abort: bookmark 'unknown' does not exist!
199 abort: bookmark 'unknown' does not exist!
200 [255]
200 [255]
201 $ hg log -r 'bookmark("literal:unknown")'
201 $ hg log -r 'bookmark("literal:unknown")'
202 abort: bookmark 'unknown' does not exist!
202 abort: bookmark 'unknown' does not exist!
203 [255]
203 [255]
204 $ hg log -r 'bookmark("re:unknown")'
204 $ hg log -r 'bookmark("re:unknown")'
205 $ hg log -r 'present(bookmark("literal:unknown"))'
205 $ hg log -r 'present(bookmark("literal:unknown"))'
206 $ hg log -r 'present(bookmark("re:unknown"))'
206 $ hg log -r 'present(bookmark("re:unknown"))'
207
207
208 $ hg help revsets | grep 'bookmark('
208 $ hg help revsets | grep 'bookmark('
209 "bookmark([name])"
209 "bookmark([name])"
210
210
211 reactivate "X2"
211 reactivate "X2"
212
212
213 $ hg update X2
213 $ hg update X2
214 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
214 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
215 (activating bookmark X2)
215 (activating bookmark X2)
216
216
217 bookmarks X and X2 moved to rev 1, Y at rev -1
217 bookmarks X and X2 moved to rev 1, Y at rev -1
218
218
219 $ hg bookmarks
219 $ hg bookmarks
220 X 0:f7b1eb17ad24
220 X 0:f7b1eb17ad24
221 * X2 1:925d80f479bb
221 * X2 1:925d80f479bb
222 Y -1:000000000000
222 Y -1:000000000000
223
223
224 bookmark rev 0 again
224 bookmark rev 0 again
225
225
226 $ hg bookmark -r 0 Z
226 $ hg bookmark -r 0 Z
227
227
228 $ hg update X
228 $ hg update X
229 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
229 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
230 (activating bookmark X)
230 (activating bookmark X)
231 $ echo c > c
231 $ echo c > c
232 $ hg add c
232 $ hg add c
233 $ hg commit -m 2
233 $ hg commit -m 2
234 created new head
234 created new head
235
235
236 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
236 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
237
237
238 $ hg bookmarks
238 $ hg bookmarks
239 * X 2:db815d6d32e6
239 * X 2:db815d6d32e6
240 X2 1:925d80f479bb
240 X2 1:925d80f479bb
241 Y -1:000000000000
241 Y -1:000000000000
242 Z 0:f7b1eb17ad24
242 Z 0:f7b1eb17ad24
243
243
244 rename nonexistent bookmark
244 rename nonexistent bookmark
245
245
246 $ hg bookmark -m A B
246 $ hg bookmark -m A B
247 abort: bookmark 'A' does not exist
247 abort: bookmark 'A' does not exist
248 [255]
248 [255]
249
249
250 rename to existent bookmark
250 rename to existent bookmark
251
251
252 $ hg bookmark -m X Y
252 $ hg bookmark -m X Y
253 abort: bookmark 'Y' already exists (use -f to force)
253 abort: bookmark 'Y' already exists (use -f to force)
254 [255]
254 [255]
255
255
256 force rename to existent bookmark
256 force rename to existent bookmark
257
257
258 $ hg bookmark -f -m X Y
258 $ hg bookmark -f -m X Y
259
259
260 rename bookmark using .
260 rename bookmark using .
261
261
262 $ hg book rename-me
262 $ hg book rename-me
263 $ hg book -m . renamed --config "$TESTHOOK"
263 $ hg book -m . renamed --config "$TESTHOOK"
264 test-hook-bookmark: rename-me: db815d6d32e69058eadefc8cffbad37675707975 ->
264 test-hook-bookmark: rename-me: db815d6d32e69058eadefc8cffbad37675707975 ->
265 test-hook-bookmark: renamed: -> db815d6d32e69058eadefc8cffbad37675707975
265 test-hook-bookmark: renamed: -> db815d6d32e69058eadefc8cffbad37675707975
266 $ hg bookmark
266 $ hg bookmark
267 X2 1:925d80f479bb
267 X2 1:925d80f479bb
268 Y 2:db815d6d32e6
268 Y 2:db815d6d32e6
269 Z 0:f7b1eb17ad24
269 Z 0:f7b1eb17ad24
270 * renamed 2:db815d6d32e6
270 * renamed 2:db815d6d32e6
271 $ hg up -q Y
271 $ hg up -q Y
272 $ hg book -d renamed --config "$TESTHOOK"
272 $ hg book -d renamed --config "$TESTHOOK"
273 test-hook-bookmark: renamed: db815d6d32e69058eadefc8cffbad37675707975 ->
273 test-hook-bookmark: renamed: db815d6d32e69058eadefc8cffbad37675707975 ->
274
274
275 rename bookmark using . with no active bookmark
275 rename bookmark using . with no active bookmark
276
276
277 $ hg book rename-me
277 $ hg book rename-me
278 $ hg book -i rename-me
278 $ hg book -i rename-me
279 $ hg book -m . renamed
279 $ hg book -m . renamed
280 abort: no active bookmark!
280 abort: no active bookmark!
281 [255]
281 [255]
282 $ hg up -q Y
282 $ hg up -q Y
283 $ hg book -d rename-me
283 $ hg book -d rename-me
284
284
285 delete bookmark using .
285 delete bookmark using .
286
286
287 $ hg book delete-me
287 $ hg book delete-me
288 $ hg book -d .
288 $ hg book -d .
289 $ hg bookmark
289 $ hg bookmark
290 X2 1:925d80f479bb
290 X2 1:925d80f479bb
291 Y 2:db815d6d32e6
291 Y 2:db815d6d32e6
292 Z 0:f7b1eb17ad24
292 Z 0:f7b1eb17ad24
293 $ hg up -q Y
293 $ hg up -q Y
294
294
295 delete bookmark using . with no active bookmark
295 delete bookmark using . with no active bookmark
296
296
297 $ hg book delete-me
297 $ hg book delete-me
298 $ hg book -i delete-me
298 $ hg book -i delete-me
299 $ hg book -d .
299 $ hg book -d .
300 abort: no active bookmark!
300 abort: no active bookmark!
301 [255]
301 [255]
302 $ hg up -q Y
302 $ hg up -q Y
303 $ hg book -d delete-me
303 $ hg book -d delete-me
304
304
305 list bookmarks
305 list bookmarks
306
306
307 $ hg bookmark
307 $ hg bookmark
308 X2 1:925d80f479bb
308 X2 1:925d80f479bb
309 * Y 2:db815d6d32e6
309 * Y 2:db815d6d32e6
310 Z 0:f7b1eb17ad24
310 Z 0:f7b1eb17ad24
311
311
312 bookmarks from a revset
312 bookmarks from a revset
313 $ hg bookmark -r '.^1' REVSET
313 $ hg bookmark -r '.^1' REVSET
314 $ hg bookmark -r ':tip' TIP
314 $ hg bookmark -r ':tip' TIP
315 $ hg up -q TIP
315 $ hg up -q TIP
316 $ hg bookmarks
316 $ hg bookmarks
317 REVSET 0:f7b1eb17ad24
317 REVSET 0:f7b1eb17ad24
318 * TIP 2:db815d6d32e6
318 * TIP 2:db815d6d32e6
319 X2 1:925d80f479bb
319 X2 1:925d80f479bb
320 Y 2:db815d6d32e6
320 Y 2:db815d6d32e6
321 Z 0:f7b1eb17ad24
321 Z 0:f7b1eb17ad24
322
322
323 $ hg bookmark -d REVSET
323 $ hg bookmark -d REVSET
324 $ hg bookmark -d TIP
324 $ hg bookmark -d TIP
325
325
326 rename without new name or multiple names
326 rename without new name or multiple names
327
327
328 $ hg bookmark -m Y
328 $ hg bookmark -m Y
329 abort: new bookmark name required
329 abort: new bookmark name required
330 [255]
330 [255]
331 $ hg bookmark -m Y Y2 Y3
331 $ hg bookmark -m Y Y2 Y3
332 abort: only one new bookmark name allowed
332 abort: only one new bookmark name allowed
333 [255]
333 [255]
334
334
335 delete without name
335 delete without name
336
336
337 $ hg bookmark -d
337 $ hg bookmark -d
338 abort: bookmark name required
338 abort: bookmark name required
339 [255]
339 [255]
340
340
341 delete nonexistent bookmark
341 delete nonexistent bookmark
342
342
343 $ hg bookmark -d A
343 $ hg bookmark -d A
344 abort: bookmark 'A' does not exist
344 abort: bookmark 'A' does not exist
345 [255]
345 [255]
346
346
347 delete with --inactive
347 delete with --inactive
348
348
349 $ hg bookmark -d --inactive Y
349 $ hg bookmark -d --inactive Y
350 abort: --inactive is incompatible with --delete
350 abort: --inactive is incompatible with --delete
351 [255]
351 [255]
352
352
353 bookmark name with spaces should be stripped
353 bookmark name with spaces should be stripped
354
354
355 $ hg bookmark ' x y '
355 $ hg bookmark ' x y '
356
356
357 list bookmarks
357 list bookmarks
358
358
359 $ hg bookmarks
359 $ hg bookmarks
360 X2 1:925d80f479bb
360 X2 1:925d80f479bb
361 Y 2:db815d6d32e6
361 Y 2:db815d6d32e6
362 Z 0:f7b1eb17ad24
362 Z 0:f7b1eb17ad24
363 * x y 2:db815d6d32e6
363 * x y 2:db815d6d32e6
364 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
364 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
365 2 Y
365 2 Y
366 2 x y
366 2 x y
367 1 X2
367 1 X2
368 0 Z
368 0 Z
369
369
370 look up stripped bookmark name
370 look up stripped bookmark name
371
371
372 $ hg log -r '"x y"'
372 $ hg log -r '"x y"'
373 changeset: 2:db815d6d32e6
373 changeset: 2:db815d6d32e6
374 bookmark: Y
374 bookmark: Y
375 bookmark: x y
375 bookmark: x y
376 tag: tip
376 tag: tip
377 parent: 0:f7b1eb17ad24
377 parent: 0:f7b1eb17ad24
378 user: test
378 user: test
379 date: Thu Jan 01 00:00:00 1970 +0000
379 date: Thu Jan 01 00:00:00 1970 +0000
380 summary: 2
380 summary: 2
381
381
382
382
383 reject bookmark name with newline
383 reject bookmark name with newline
384
384
385 $ hg bookmark '
385 $ hg bookmark '
386 > '
386 > '
387 abort: bookmark names cannot consist entirely of whitespace
387 abort: bookmark names cannot consist entirely of whitespace
388 [255]
388 [255]
389
389
390 $ hg bookmark -m Z '
390 $ hg bookmark -m Z '
391 > '
391 > '
392 abort: bookmark names cannot consist entirely of whitespace
392 abort: bookmark names cannot consist entirely of whitespace
393 [255]
393 [255]
394
394
395 bookmark with reserved name
395 bookmark with reserved name
396
396
397 $ hg bookmark tip
397 $ hg bookmark tip
398 abort: the name 'tip' is reserved
398 abort: the name 'tip' is reserved
399 [255]
399 [255]
400
400
401 $ hg bookmark .
401 $ hg bookmark .
402 abort: the name '.' is reserved
402 abort: the name '.' is reserved
403 [255]
403 [255]
404
404
405 $ hg bookmark null
405 $ hg bookmark null
406 abort: the name 'null' is reserved
406 abort: the name 'null' is reserved
407 [255]
407 [255]
408
408
409
409
410 bookmark with existing name
410 bookmark with existing name
411
411
412 $ hg bookmark X2
412 $ hg bookmark X2
413 abort: bookmark 'X2' already exists (use -f to force)
413 abort: bookmark 'X2' already exists (use -f to force)
414 [255]
414 [255]
415
415
416 $ hg bookmark -m Y Z
416 $ hg bookmark -m Y Z
417 abort: bookmark 'Z' already exists (use -f to force)
417 abort: bookmark 'Z' already exists (use -f to force)
418 [255]
418 [255]
419
419
420 bookmark with name of branch
420 bookmark with name of branch
421
421
422 $ hg bookmark default
422 $ hg bookmark default
423 abort: a bookmark cannot have the name of an existing branch
423 abort: a bookmark cannot have the name of an existing branch
424 [255]
424 [255]
425
425
426 $ hg bookmark -m Y default
426 $ hg bookmark -m Y default
427 abort: a bookmark cannot have the name of an existing branch
427 abort: a bookmark cannot have the name of an existing branch
428 [255]
428 [255]
429
429
430 bookmark with integer name
430 bookmark with integer name
431
431
432 $ hg bookmark 10
432 $ hg bookmark 10
433 abort: cannot use an integer as a name
433 abort: cannot use an integer as a name
434 [255]
434 [255]
435
435
436 bookmark with a name that matches a node id
436 bookmark with a name that matches a node id
437 $ hg bookmark 925d80f479bb db815d6d32e6 --config "$TESTHOOK"
437 $ hg bookmark 925d80f479bb db815d6d32e6 --config "$TESTHOOK"
438 bookmark 925d80f479bb matches a changeset hash
438 bookmark 925d80f479bb matches a changeset hash
439 (did you leave a -r out of an 'hg bookmark' command?)
439 (did you leave a -r out of an 'hg bookmark' command?)
440 bookmark db815d6d32e6 matches a changeset hash
440 bookmark db815d6d32e6 matches a changeset hash
441 (did you leave a -r out of an 'hg bookmark' command?)
441 (did you leave a -r out of an 'hg bookmark' command?)
442 test-hook-bookmark: 925d80f479bb: -> db815d6d32e69058eadefc8cffbad37675707975
442 test-hook-bookmark: 925d80f479bb: -> db815d6d32e69058eadefc8cffbad37675707975
443 test-hook-bookmark: db815d6d32e6: -> db815d6d32e69058eadefc8cffbad37675707975
443 test-hook-bookmark: db815d6d32e6: -> db815d6d32e69058eadefc8cffbad37675707975
444 $ hg bookmark -d 925d80f479bb
444 $ hg bookmark -d 925d80f479bb
445 $ hg bookmark -d db815d6d32e6
445 $ hg bookmark -d db815d6d32e6
446
446
447 $ cd ..
447 $ cd ..
448
448
449 bookmark with a name that matches an ambiguous node id
449 bookmark with a name that matches an ambiguous node id
450
450
451 $ hg init ambiguous
451 $ hg init ambiguous
452 $ cd ambiguous
452 $ cd ambiguous
453 $ echo 0 > a
453 $ echo 0 > a
454 $ hg ci -qAm 0
454 $ hg ci -qAm 0
455 $ for i in 1057 2857 4025; do
455 $ for i in 1057 2857 4025; do
456 > hg up -q 0
456 > hg up -q 0
457 > echo $i > a
457 > echo $i > a
458 > hg ci -qm $i
458 > hg ci -qm $i
459 > done
459 > done
460 $ hg up -q null
460 $ hg up -q null
461 $ hg log -r0: -T '{rev}:{node}\n'
461 $ hg log -r0: -T '{rev}:{node}\n'
462 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
462 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
463 1:c56256a09cd28e5764f32e8e2810d0f01e2e357a
463 1:c56256a09cd28e5764f32e8e2810d0f01e2e357a
464 2:c5623987d205cd6d9d8389bfc40fff9dbb670b48
464 2:c5623987d205cd6d9d8389bfc40fff9dbb670b48
465 3:c562ddd9c94164376c20b86b0b4991636a3bf84f
465 3:c562ddd9c94164376c20b86b0b4991636a3bf84f
466
466
467 $ hg bookmark -r0 c562
467 $ hg bookmark -r0 c562
468 $ hg bookmarks
468 $ hg bookmarks
469 c562 0:b4e73ffab476
469 c562 0:b4e73ffab476
470
470
471 $ cd ..
471 $ cd ..
472
472
473 incompatible options
473 incompatible options
474
474
475 $ cd repo
475 $ cd repo
476
476
477 $ hg bookmark -m Y -d Z
477 $ hg bookmark -m Y -d Z
478 abort: cannot specify both --delete and --rename
478 abort: cannot specify both --delete and --rename
479 [255]
479 [255]
480
480
481 $ hg bookmark -r 1 -d Z
481 $ hg bookmark -r 1 -d Z
482 abort: --rev is incompatible with --delete
482 abort: cannot specify both --delete and --rev
483 [255]
483 [255]
484
484
485 $ hg bookmark -r 1 -m Z Y
485 $ hg bookmark -r 1 -m Z Y
486 abort: --rev is incompatible with --rename
486 abort: cannot specify both --rename and --rev
487 [255]
487 [255]
488
488
489 force bookmark with existing name
489 force bookmark with existing name
490
490
491 $ hg bookmark -f X2 --config "$TESTHOOK"
491 $ hg bookmark -f X2 --config "$TESTHOOK"
492 test-hook-bookmark: X2: 925d80f479bb026b0fb3deb27503780b13f74123 -> db815d6d32e69058eadefc8cffbad37675707975
492 test-hook-bookmark: X2: 925d80f479bb026b0fb3deb27503780b13f74123 -> db815d6d32e69058eadefc8cffbad37675707975
493
493
494 force bookmark back to where it was, should deactivate it
494 force bookmark back to where it was, should deactivate it
495
495
496 $ hg bookmark -fr1 X2
496 $ hg bookmark -fr1 X2
497 $ hg bookmarks
497 $ hg bookmarks
498 X2 1:925d80f479bb
498 X2 1:925d80f479bb
499 Y 2:db815d6d32e6
499 Y 2:db815d6d32e6
500 Z 0:f7b1eb17ad24
500 Z 0:f7b1eb17ad24
501 x y 2:db815d6d32e6
501 x y 2:db815d6d32e6
502
502
503 forward bookmark to descendant without --force
503 forward bookmark to descendant without --force
504
504
505 $ hg bookmark Z
505 $ hg bookmark Z
506 moving bookmark 'Z' forward from f7b1eb17ad24
506 moving bookmark 'Z' forward from f7b1eb17ad24
507
507
508 list bookmarks
508 list bookmarks
509
509
510 $ hg bookmark
510 $ hg bookmark
511 X2 1:925d80f479bb
511 X2 1:925d80f479bb
512 Y 2:db815d6d32e6
512 Y 2:db815d6d32e6
513 * Z 2:db815d6d32e6
513 * Z 2:db815d6d32e6
514 x y 2:db815d6d32e6
514 x y 2:db815d6d32e6
515 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
515 $ hg log -T '{bookmarks % "{rev} {bookmark}\n"}'
516 2 Y
516 2 Y
517 2 Z
517 2 Z
518 2 x y
518 2 x y
519 1 X2
519 1 X2
520
520
521 revision but no bookmark name
521 revision but no bookmark name
522
522
523 $ hg bookmark -r .
523 $ hg bookmark -r .
524 abort: bookmark name required
524 abort: bookmark name required
525 [255]
525 [255]
526
526
527 bookmark name with whitespace only
527 bookmark name with whitespace only
528
528
529 $ hg bookmark ' '
529 $ hg bookmark ' '
530 abort: bookmark names cannot consist entirely of whitespace
530 abort: bookmark names cannot consist entirely of whitespace
531 [255]
531 [255]
532
532
533 $ hg bookmark -m Y ' '
533 $ hg bookmark -m Y ' '
534 abort: bookmark names cannot consist entirely of whitespace
534 abort: bookmark names cannot consist entirely of whitespace
535 [255]
535 [255]
536
536
537 invalid bookmark
537 invalid bookmark
538
538
539 $ hg bookmark 'foo:bar'
539 $ hg bookmark 'foo:bar'
540 abort: ':' cannot be used in a name
540 abort: ':' cannot be used in a name
541 [255]
541 [255]
542
542
543 $ hg bookmark 'foo
543 $ hg bookmark 'foo
544 > bar'
544 > bar'
545 abort: '\n' cannot be used in a name
545 abort: '\n' cannot be used in a name
546 [255]
546 [255]
547
547
548 the bookmark extension should be ignored now that it is part of core
548 the bookmark extension should be ignored now that it is part of core
549
549
550 $ echo "[extensions]" >> $HGRCPATH
550 $ echo "[extensions]" >> $HGRCPATH
551 $ echo "bookmarks=" >> $HGRCPATH
551 $ echo "bookmarks=" >> $HGRCPATH
552 $ hg bookmarks
552 $ hg bookmarks
553 X2 1:925d80f479bb
553 X2 1:925d80f479bb
554 Y 2:db815d6d32e6
554 Y 2:db815d6d32e6
555 * Z 2:db815d6d32e6
555 * Z 2:db815d6d32e6
556 x y 2:db815d6d32e6
556 x y 2:db815d6d32e6
557
557
558 test summary
558 test summary
559
559
560 $ hg summary
560 $ hg summary
561 parent: 2:db815d6d32e6 tip
561 parent: 2:db815d6d32e6 tip
562 2
562 2
563 branch: default
563 branch: default
564 bookmarks: *Z Y x y
564 bookmarks: *Z Y x y
565 commit: (clean)
565 commit: (clean)
566 update: 1 new changesets, 2 branch heads (merge)
566 update: 1 new changesets, 2 branch heads (merge)
567 phases: 3 draft
567 phases: 3 draft
568
568
569 test id
569 test id
570
570
571 $ hg id
571 $ hg id
572 db815d6d32e6 tip Y/Z/x y
572 db815d6d32e6 tip Y/Z/x y
573
573
574 test rollback
574 test rollback
575
575
576 $ echo foo > f1
576 $ echo foo > f1
577 $ hg bookmark tmp-rollback
577 $ hg bookmark tmp-rollback
578 $ hg ci -Amr
578 $ hg ci -Amr
579 adding f1
579 adding f1
580 $ hg bookmarks
580 $ hg bookmarks
581 X2 1:925d80f479bb
581 X2 1:925d80f479bb
582 Y 2:db815d6d32e6
582 Y 2:db815d6d32e6
583 Z 2:db815d6d32e6
583 Z 2:db815d6d32e6
584 * tmp-rollback 3:2bf5cfec5864
584 * tmp-rollback 3:2bf5cfec5864
585 x y 2:db815d6d32e6
585 x y 2:db815d6d32e6
586 $ hg rollback
586 $ hg rollback
587 repository tip rolled back to revision 2 (undo commit)
587 repository tip rolled back to revision 2 (undo commit)
588 working directory now based on revision 2
588 working directory now based on revision 2
589 $ hg bookmarks
589 $ hg bookmarks
590 X2 1:925d80f479bb
590 X2 1:925d80f479bb
591 Y 2:db815d6d32e6
591 Y 2:db815d6d32e6
592 Z 2:db815d6d32e6
592 Z 2:db815d6d32e6
593 * tmp-rollback 2:db815d6d32e6
593 * tmp-rollback 2:db815d6d32e6
594 x y 2:db815d6d32e6
594 x y 2:db815d6d32e6
595 $ hg bookmark -f Z -r 1
595 $ hg bookmark -f Z -r 1
596 $ hg rollback
596 $ hg rollback
597 repository tip rolled back to revision 2 (undo bookmark)
597 repository tip rolled back to revision 2 (undo bookmark)
598 $ hg bookmarks
598 $ hg bookmarks
599 X2 1:925d80f479bb
599 X2 1:925d80f479bb
600 Y 2:db815d6d32e6
600 Y 2:db815d6d32e6
601 Z 2:db815d6d32e6
601 Z 2:db815d6d32e6
602 * tmp-rollback 2:db815d6d32e6
602 * tmp-rollback 2:db815d6d32e6
603 x y 2:db815d6d32e6
603 x y 2:db815d6d32e6
604 $ hg bookmark -d tmp-rollback
604 $ hg bookmark -d tmp-rollback
605
605
606 activate bookmark on working dir parent without --force
606 activate bookmark on working dir parent without --force
607
607
608 $ hg bookmark --inactive Z
608 $ hg bookmark --inactive Z
609 $ hg bookmark Z
609 $ hg bookmark Z
610
610
611 deactivate current 'Z', but also add 'Y'
611 deactivate current 'Z', but also add 'Y'
612
612
613 $ hg bookmark -d Y
613 $ hg bookmark -d Y
614 $ hg bookmark --inactive Z Y
614 $ hg bookmark --inactive Z Y
615 $ hg bookmark -l
615 $ hg bookmark -l
616 X2 1:925d80f479bb
616 X2 1:925d80f479bb
617 Y 2:db815d6d32e6
617 Y 2:db815d6d32e6
618 Z 2:db815d6d32e6
618 Z 2:db815d6d32e6
619 x y 2:db815d6d32e6
619 x y 2:db815d6d32e6
620 $ hg bookmark Z
620 $ hg bookmark Z
621
621
622 bookmark wdir to activate it (issue6218)
622 bookmark wdir to activate it (issue6218)
623
623
624 $ hg bookmark -d Z
624 $ hg bookmark -d Z
625 $ hg bookmark -r 'wdir()' Z
625 $ hg bookmark -r 'wdir()' Z
626 $ hg bookmark -l
626 $ hg bookmark -l
627 X2 1:925d80f479bb
627 X2 1:925d80f479bb
628 Y 2:db815d6d32e6
628 Y 2:db815d6d32e6
629 * Z 2:db815d6d32e6
629 * Z 2:db815d6d32e6
630 x y 2:db815d6d32e6
630 x y 2:db815d6d32e6
631
631
632 test clone
632 test clone
633
633
634 $ hg bookmark -r 2 -i @
634 $ hg bookmark -r 2 -i @
635 $ hg bookmark -r 2 -i a@
635 $ hg bookmark -r 2 -i a@
636 $ hg bookmarks
636 $ hg bookmarks
637 @ 2:db815d6d32e6
637 @ 2:db815d6d32e6
638 X2 1:925d80f479bb
638 X2 1:925d80f479bb
639 Y 2:db815d6d32e6
639 Y 2:db815d6d32e6
640 * Z 2:db815d6d32e6
640 * Z 2:db815d6d32e6
641 a@ 2:db815d6d32e6
641 a@ 2:db815d6d32e6
642 x y 2:db815d6d32e6
642 x y 2:db815d6d32e6
643 $ hg clone . cloned-bookmarks
643 $ hg clone . cloned-bookmarks
644 updating to bookmark @
644 updating to bookmark @
645 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
645 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
646 $ hg -R cloned-bookmarks bookmarks
646 $ hg -R cloned-bookmarks bookmarks
647 * @ 2:db815d6d32e6
647 * @ 2:db815d6d32e6
648 X2 1:925d80f479bb
648 X2 1:925d80f479bb
649 Y 2:db815d6d32e6
649 Y 2:db815d6d32e6
650 Z 2:db815d6d32e6
650 Z 2:db815d6d32e6
651 a@ 2:db815d6d32e6
651 a@ 2:db815d6d32e6
652 x y 2:db815d6d32e6
652 x y 2:db815d6d32e6
653
653
654 test clone with pull protocol
654 test clone with pull protocol
655
655
656 $ hg clone --pull . cloned-bookmarks-pull
656 $ hg clone --pull . cloned-bookmarks-pull
657 requesting all changes
657 requesting all changes
658 adding changesets
658 adding changesets
659 adding manifests
659 adding manifests
660 adding file changes
660 adding file changes
661 added 3 changesets with 3 changes to 3 files (+1 heads)
661 added 3 changesets with 3 changes to 3 files (+1 heads)
662 new changesets f7b1eb17ad24:db815d6d32e6
662 new changesets f7b1eb17ad24:db815d6d32e6
663 updating to bookmark @
663 updating to bookmark @
664 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
664 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
665 $ hg -R cloned-bookmarks-pull bookmarks
665 $ hg -R cloned-bookmarks-pull bookmarks
666 * @ 2:db815d6d32e6
666 * @ 2:db815d6d32e6
667 X2 1:925d80f479bb
667 X2 1:925d80f479bb
668 Y 2:db815d6d32e6
668 Y 2:db815d6d32e6
669 Z 2:db815d6d32e6
669 Z 2:db815d6d32e6
670 a@ 2:db815d6d32e6
670 a@ 2:db815d6d32e6
671 x y 2:db815d6d32e6
671 x y 2:db815d6d32e6
672
672
673 delete multiple bookmarks at once
673 delete multiple bookmarks at once
674
674
675 $ hg bookmark -d @ a@
675 $ hg bookmark -d @ a@
676
676
677 test clone with a bookmark named "default" (issue3677)
677 test clone with a bookmark named "default" (issue3677)
678
678
679 $ hg bookmark -r 1 -f -i default
679 $ hg bookmark -r 1 -f -i default
680 $ hg clone . cloned-bookmark-default
680 $ hg clone . cloned-bookmark-default
681 updating to branch default
681 updating to branch default
682 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
682 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
683 $ hg -R cloned-bookmark-default bookmarks
683 $ hg -R cloned-bookmark-default bookmarks
684 X2 1:925d80f479bb
684 X2 1:925d80f479bb
685 Y 2:db815d6d32e6
685 Y 2:db815d6d32e6
686 Z 2:db815d6d32e6
686 Z 2:db815d6d32e6
687 default 1:925d80f479bb
687 default 1:925d80f479bb
688 x y 2:db815d6d32e6
688 x y 2:db815d6d32e6
689 $ hg -R cloned-bookmark-default parents -q
689 $ hg -R cloned-bookmark-default parents -q
690 2:db815d6d32e6
690 2:db815d6d32e6
691 $ hg bookmark -d default
691 $ hg bookmark -d default
692
692
693 test clone with a specific revision
693 test clone with a specific revision
694
694
695 $ hg clone -r 925d80 . cloned-bookmarks-rev
695 $ hg clone -r 925d80 . cloned-bookmarks-rev
696 adding changesets
696 adding changesets
697 adding manifests
697 adding manifests
698 adding file changes
698 adding file changes
699 added 2 changesets with 2 changes to 2 files
699 added 2 changesets with 2 changes to 2 files
700 new changesets f7b1eb17ad24:925d80f479bb
700 new changesets f7b1eb17ad24:925d80f479bb
701 updating to branch default
701 updating to branch default
702 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
702 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
703 $ hg -R cloned-bookmarks-rev bookmarks
703 $ hg -R cloned-bookmarks-rev bookmarks
704 X2 1:925d80f479bb
704 X2 1:925d80f479bb
705
705
706 test clone with update to a bookmark
706 test clone with update to a bookmark
707
707
708 $ hg clone -u Z . ../cloned-bookmarks-update
708 $ hg clone -u Z . ../cloned-bookmarks-update
709 updating to branch default
709 updating to branch default
710 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
710 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
711 $ hg -R ../cloned-bookmarks-update bookmarks
711 $ hg -R ../cloned-bookmarks-update bookmarks
712 X2 1:925d80f479bb
712 X2 1:925d80f479bb
713 Y 2:db815d6d32e6
713 Y 2:db815d6d32e6
714 * Z 2:db815d6d32e6
714 * Z 2:db815d6d32e6
715 x y 2:db815d6d32e6
715 x y 2:db815d6d32e6
716
716
717 create bundle with two heads
717 create bundle with two heads
718
718
719 $ hg clone . tobundle
719 $ hg clone . tobundle
720 updating to branch default
720 updating to branch default
721 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
721 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
722 $ echo x > tobundle/x
722 $ echo x > tobundle/x
723 $ hg -R tobundle add tobundle/x
723 $ hg -R tobundle add tobundle/x
724 $ hg -R tobundle commit -m'x'
724 $ hg -R tobundle commit -m'x'
725 $ hg -R tobundle update -r -2
725 $ hg -R tobundle update -r -2
726 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
726 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
727 $ echo y > tobundle/y
727 $ echo y > tobundle/y
728 $ hg -R tobundle branch test
728 $ hg -R tobundle branch test
729 marked working directory as branch test
729 marked working directory as branch test
730 (branches are permanent and global, did you want a bookmark?)
730 (branches are permanent and global, did you want a bookmark?)
731 $ hg -R tobundle add tobundle/y
731 $ hg -R tobundle add tobundle/y
732 $ hg -R tobundle commit -m'y'
732 $ hg -R tobundle commit -m'y'
733 $ hg -R tobundle bundle tobundle.hg
733 $ hg -R tobundle bundle tobundle.hg
734 searching for changes
734 searching for changes
735 2 changesets found
735 2 changesets found
736 $ hg unbundle tobundle.hg
736 $ hg unbundle tobundle.hg
737 adding changesets
737 adding changesets
738 adding manifests
738 adding manifests
739 adding file changes
739 adding file changes
740 added 2 changesets with 2 changes to 2 files (+1 heads)
740 added 2 changesets with 2 changes to 2 files (+1 heads)
741 new changesets 125c9a1d6df6:9ba5f110a0b3 (2 drafts)
741 new changesets 125c9a1d6df6:9ba5f110a0b3 (2 drafts)
742 (run 'hg heads' to see heads, 'hg merge' to merge)
742 (run 'hg heads' to see heads, 'hg merge' to merge)
743
743
744 update to active bookmark if it's not the parent
744 update to active bookmark if it's not the parent
745
745
746 (it is known issue that fsmonitor can't handle nested repositories. In
746 (it is known issue that fsmonitor can't handle nested repositories. In
747 this test scenario, cloned-bookmark-default and tobundle exist in the
747 this test scenario, cloned-bookmark-default and tobundle exist in the
748 working directory of current repository)
748 working directory of current repository)
749
749
750 $ hg summary
750 $ hg summary
751 parent: 2:db815d6d32e6
751 parent: 2:db815d6d32e6
752 2
752 2
753 branch: default
753 branch: default
754 bookmarks: *Z Y x y
754 bookmarks: *Z Y x y
755 commit: 1 added, 1 unknown (new branch head) (no-fsmonitor !)
755 commit: 1 added, 1 unknown (new branch head) (no-fsmonitor !)
756 commit: 1 added, * unknown (new branch head) (glob) (fsmonitor !)
756 commit: 1 added, * unknown (new branch head) (glob) (fsmonitor !)
757 update: 2 new changesets (update)
757 update: 2 new changesets (update)
758 phases: 5 draft
758 phases: 5 draft
759 $ hg update
759 $ hg update
760 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
760 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
761 updating bookmark Z
761 updating bookmark Z
762 $ hg bookmarks
762 $ hg bookmarks
763 X2 1:925d80f479bb
763 X2 1:925d80f479bb
764 Y 2:db815d6d32e6
764 Y 2:db815d6d32e6
765 * Z 3:125c9a1d6df6
765 * Z 3:125c9a1d6df6
766 x y 2:db815d6d32e6
766 x y 2:db815d6d32e6
767
767
768 pull --update works the same as pull && update
768 pull --update works the same as pull && update
769
769
770 $ hg bookmark -r3 Y
770 $ hg bookmark -r3 Y
771 moving bookmark 'Y' forward from db815d6d32e6
771 moving bookmark 'Y' forward from db815d6d32e6
772 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
772 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
773 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update-with-divergence
773 $ cp -R ../cloned-bookmarks-update ../cloned-bookmarks-manual-update-with-divergence
774
774
775 (manual version)
775 (manual version)
776
776
777 $ hg -R ../cloned-bookmarks-manual-update update Y
777 $ hg -R ../cloned-bookmarks-manual-update update Y
778 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
778 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
779 (activating bookmark Y)
779 (activating bookmark Y)
780 $ hg -R ../cloned-bookmarks-manual-update pull .
780 $ hg -R ../cloned-bookmarks-manual-update pull .
781 pulling from .
781 pulling from .
782 searching for changes
782 searching for changes
783 adding changesets
783 adding changesets
784 adding manifests
784 adding manifests
785 adding file changes
785 adding file changes
786 updating bookmark Y
786 updating bookmark Y
787 updating bookmark Z
787 updating bookmark Z
788 added 2 changesets with 2 changes to 2 files (+1 heads)
788 added 2 changesets with 2 changes to 2 files (+1 heads)
789 new changesets 125c9a1d6df6:9ba5f110a0b3
789 new changesets 125c9a1d6df6:9ba5f110a0b3
790 (run 'hg heads' to see heads, 'hg merge' to merge)
790 (run 'hg heads' to see heads, 'hg merge' to merge)
791
791
792 (# tests strange but with --date crashing when bookmark have to move)
792 (# tests strange but with --date crashing when bookmark have to move)
793
793
794 $ hg -R ../cloned-bookmarks-manual-update update -d 1986
794 $ hg -R ../cloned-bookmarks-manual-update update -d 1986
795 abort: revision matching date not found
795 abort: revision matching date not found
796 [255]
796 [255]
797 $ hg -R ../cloned-bookmarks-manual-update update
797 $ hg -R ../cloned-bookmarks-manual-update update
798 updating to active bookmark Y
798 updating to active bookmark Y
799 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
799 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
800
800
801 (all in one version)
801 (all in one version)
802
802
803 $ hg -R ../cloned-bookmarks-update update Y
803 $ hg -R ../cloned-bookmarks-update update Y
804 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
804 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
805 (activating bookmark Y)
805 (activating bookmark Y)
806 $ hg -R ../cloned-bookmarks-update pull --update .
806 $ hg -R ../cloned-bookmarks-update pull --update .
807 pulling from .
807 pulling from .
808 searching for changes
808 searching for changes
809 adding changesets
809 adding changesets
810 adding manifests
810 adding manifests
811 adding file changes
811 adding file changes
812 updating bookmark Y
812 updating bookmark Y
813 updating bookmark Z
813 updating bookmark Z
814 added 2 changesets with 2 changes to 2 files (+1 heads)
814 added 2 changesets with 2 changes to 2 files (+1 heads)
815 new changesets 125c9a1d6df6:9ba5f110a0b3
815 new changesets 125c9a1d6df6:9ba5f110a0b3
816 updating to active bookmark Y
816 updating to active bookmark Y
817 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
817 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
818
818
819 We warn about divergent during bare update to the active bookmark
819 We warn about divergent during bare update to the active bookmark
820
820
821 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update Y
821 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update Y
822 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
822 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
823 (activating bookmark Y)
823 (activating bookmark Y)
824 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks -r X2 Y@1
824 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks -r X2 Y@1
825 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks
825 $ hg -R ../cloned-bookmarks-manual-update-with-divergence bookmarks
826 X2 1:925d80f479bb
826 X2 1:925d80f479bb
827 * Y 2:db815d6d32e6
827 * Y 2:db815d6d32e6
828 Y@1 1:925d80f479bb
828 Y@1 1:925d80f479bb
829 Z 2:db815d6d32e6
829 Z 2:db815d6d32e6
830 x y 2:db815d6d32e6
830 x y 2:db815d6d32e6
831 $ hg -R ../cloned-bookmarks-manual-update-with-divergence pull
831 $ hg -R ../cloned-bookmarks-manual-update-with-divergence pull
832 pulling from $TESTTMP/repo
832 pulling from $TESTTMP/repo
833 searching for changes
833 searching for changes
834 adding changesets
834 adding changesets
835 adding manifests
835 adding manifests
836 adding file changes
836 adding file changes
837 updating bookmark Y
837 updating bookmark Y
838 updating bookmark Z
838 updating bookmark Z
839 added 2 changesets with 2 changes to 2 files (+1 heads)
839 added 2 changesets with 2 changes to 2 files (+1 heads)
840 new changesets 125c9a1d6df6:9ba5f110a0b3
840 new changesets 125c9a1d6df6:9ba5f110a0b3
841 (run 'hg heads' to see heads, 'hg merge' to merge)
841 (run 'hg heads' to see heads, 'hg merge' to merge)
842 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update
842 $ hg -R ../cloned-bookmarks-manual-update-with-divergence update
843 updating to active bookmark Y
843 updating to active bookmark Y
844 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
844 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
845 1 other divergent bookmarks for "Y"
845 1 other divergent bookmarks for "Y"
846
846
847 test wrongly formated bookmark
847 test wrongly formated bookmark
848
848
849 $ echo '' >> .hg/bookmarks
849 $ echo '' >> .hg/bookmarks
850 $ hg bookmarks
850 $ hg bookmarks
851 X2 1:925d80f479bb
851 X2 1:925d80f479bb
852 Y 3:125c9a1d6df6
852 Y 3:125c9a1d6df6
853 * Z 3:125c9a1d6df6
853 * Z 3:125c9a1d6df6
854 x y 2:db815d6d32e6
854 x y 2:db815d6d32e6
855 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
855 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
856 $ hg bookmarks
856 $ hg bookmarks
857 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
857 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
858 X2 1:925d80f479bb
858 X2 1:925d80f479bb
859 Y 3:125c9a1d6df6
859 Y 3:125c9a1d6df6
860 * Z 3:125c9a1d6df6
860 * Z 3:125c9a1d6df6
861 x y 2:db815d6d32e6
861 x y 2:db815d6d32e6
862
862
863 test missing revisions
863 test missing revisions
864
864
865 $ echo "925d80f479b925d80f479bc925d80f479bccabab z" > .hg/bookmarks
865 $ echo "925d80f479b925d80f479bc925d80f479bccabab z" > .hg/bookmarks
866 $ hg book
866 $ hg book
867 no bookmarks set
867 no bookmarks set
868
868
869 test stripping a non-checked-out but bookmarked revision
869 test stripping a non-checked-out but bookmarked revision
870
870
871 $ hg log --graph
871 $ hg log --graph
872 o changeset: 4:9ba5f110a0b3
872 o changeset: 4:9ba5f110a0b3
873 | branch: test
873 | branch: test
874 | tag: tip
874 | tag: tip
875 | parent: 2:db815d6d32e6
875 | parent: 2:db815d6d32e6
876 | user: test
876 | user: test
877 | date: Thu Jan 01 00:00:00 1970 +0000
877 | date: Thu Jan 01 00:00:00 1970 +0000
878 | summary: y
878 | summary: y
879 |
879 |
880 | @ changeset: 3:125c9a1d6df6
880 | @ changeset: 3:125c9a1d6df6
881 |/ user: test
881 |/ user: test
882 | date: Thu Jan 01 00:00:00 1970 +0000
882 | date: Thu Jan 01 00:00:00 1970 +0000
883 | summary: x
883 | summary: x
884 |
884 |
885 o changeset: 2:db815d6d32e6
885 o changeset: 2:db815d6d32e6
886 | parent: 0:f7b1eb17ad24
886 | parent: 0:f7b1eb17ad24
887 | user: test
887 | user: test
888 | date: Thu Jan 01 00:00:00 1970 +0000
888 | date: Thu Jan 01 00:00:00 1970 +0000
889 | summary: 2
889 | summary: 2
890 |
890 |
891 | o changeset: 1:925d80f479bb
891 | o changeset: 1:925d80f479bb
892 |/ user: test
892 |/ user: test
893 | date: Thu Jan 01 00:00:00 1970 +0000
893 | date: Thu Jan 01 00:00:00 1970 +0000
894 | summary: 1
894 | summary: 1
895 |
895 |
896 o changeset: 0:f7b1eb17ad24
896 o changeset: 0:f7b1eb17ad24
897 user: test
897 user: test
898 date: Thu Jan 01 00:00:00 1970 +0000
898 date: Thu Jan 01 00:00:00 1970 +0000
899 summary: 0
899 summary: 0
900
900
901 $ hg book should-end-on-two
901 $ hg book should-end-on-two
902 $ hg co --clean 4
902 $ hg co --clean 4
903 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
903 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
904 (leaving bookmark should-end-on-two)
904 (leaving bookmark should-end-on-two)
905 $ hg book four
905 $ hg book four
906 $ hg --config extensions.mq= strip 3
906 $ hg --config extensions.mq= strip 3
907 saved backup bundle to * (glob)
907 saved backup bundle to * (glob)
908 should-end-on-two should end up pointing to revision 2, as that's the
908 should-end-on-two should end up pointing to revision 2, as that's the
909 tipmost surviving ancestor of the stripped revision.
909 tipmost surviving ancestor of the stripped revision.
910 $ hg log --graph
910 $ hg log --graph
911 @ changeset: 3:9ba5f110a0b3
911 @ changeset: 3:9ba5f110a0b3
912 | branch: test
912 | branch: test
913 | bookmark: four
913 | bookmark: four
914 | tag: tip
914 | tag: tip
915 | user: test
915 | user: test
916 | date: Thu Jan 01 00:00:00 1970 +0000
916 | date: Thu Jan 01 00:00:00 1970 +0000
917 | summary: y
917 | summary: y
918 |
918 |
919 o changeset: 2:db815d6d32e6
919 o changeset: 2:db815d6d32e6
920 | bookmark: should-end-on-two
920 | bookmark: should-end-on-two
921 | parent: 0:f7b1eb17ad24
921 | parent: 0:f7b1eb17ad24
922 | user: test
922 | user: test
923 | date: Thu Jan 01 00:00:00 1970 +0000
923 | date: Thu Jan 01 00:00:00 1970 +0000
924 | summary: 2
924 | summary: 2
925 |
925 |
926 | o changeset: 1:925d80f479bb
926 | o changeset: 1:925d80f479bb
927 |/ user: test
927 |/ user: test
928 | date: Thu Jan 01 00:00:00 1970 +0000
928 | date: Thu Jan 01 00:00:00 1970 +0000
929 | summary: 1
929 | summary: 1
930 |
930 |
931 o changeset: 0:f7b1eb17ad24
931 o changeset: 0:f7b1eb17ad24
932 user: test
932 user: test
933 date: Thu Jan 01 00:00:00 1970 +0000
933 date: Thu Jan 01 00:00:00 1970 +0000
934 summary: 0
934 summary: 0
935
935
936
936
937 no-op update doesn't deactivate bookmarks
937 no-op update doesn't deactivate bookmarks
938
938
939 (it is known issue that fsmonitor can't handle nested repositories. In
939 (it is known issue that fsmonitor can't handle nested repositories. In
940 this test scenario, cloned-bookmark-default and tobundle exist in the
940 this test scenario, cloned-bookmark-default and tobundle exist in the
941 working directory of current repository)
941 working directory of current repository)
942
942
943 $ hg bookmarks
943 $ hg bookmarks
944 * four 3:9ba5f110a0b3
944 * four 3:9ba5f110a0b3
945 should-end-on-two 2:db815d6d32e6
945 should-end-on-two 2:db815d6d32e6
946 $ hg up four
946 $ hg up four
947 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
947 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
948 $ hg up
948 $ hg up
949 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
949 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
950 $ hg sum
950 $ hg sum
951 parent: 3:9ba5f110a0b3 tip
951 parent: 3:9ba5f110a0b3 tip
952 y
952 y
953 branch: test
953 branch: test
954 bookmarks: *four
954 bookmarks: *four
955 commit: 2 unknown (clean) (no-fsmonitor !)
955 commit: 2 unknown (clean) (no-fsmonitor !)
956 commit: * unknown (clean) (glob) (fsmonitor !)
956 commit: * unknown (clean) (glob) (fsmonitor !)
957 update: (current)
957 update: (current)
958 phases: 4 draft
958 phases: 4 draft
959
959
960 test clearing divergent bookmarks of linear ancestors
960 test clearing divergent bookmarks of linear ancestors
961
961
962 $ hg bookmark Z -r 0
962 $ hg bookmark Z -r 0
963 $ hg bookmark Z@1 -r 1
963 $ hg bookmark Z@1 -r 1
964 $ hg bookmark Z@2 -r 2
964 $ hg bookmark Z@2 -r 2
965 $ hg bookmark Z@3 -r 3
965 $ hg bookmark Z@3 -r 3
966 $ hg book
966 $ hg book
967 Z 0:f7b1eb17ad24
967 Z 0:f7b1eb17ad24
968 Z@1 1:925d80f479bb
968 Z@1 1:925d80f479bb
969 Z@2 2:db815d6d32e6
969 Z@2 2:db815d6d32e6
970 Z@3 3:9ba5f110a0b3
970 Z@3 3:9ba5f110a0b3
971 * four 3:9ba5f110a0b3
971 * four 3:9ba5f110a0b3
972 should-end-on-two 2:db815d6d32e6
972 should-end-on-two 2:db815d6d32e6
973 $ hg bookmark Z
973 $ hg bookmark Z
974 moving bookmark 'Z' forward from f7b1eb17ad24
974 moving bookmark 'Z' forward from f7b1eb17ad24
975 $ hg book
975 $ hg book
976 * Z 3:9ba5f110a0b3
976 * Z 3:9ba5f110a0b3
977 Z@1 1:925d80f479bb
977 Z@1 1:925d80f479bb
978 four 3:9ba5f110a0b3
978 four 3:9ba5f110a0b3
979 should-end-on-two 2:db815d6d32e6
979 should-end-on-two 2:db815d6d32e6
980
980
981 test clearing only a single divergent bookmark across branches
981 test clearing only a single divergent bookmark across branches
982
982
983 $ hg book foo -r 1
983 $ hg book foo -r 1
984 $ hg book foo@1 -r 0
984 $ hg book foo@1 -r 0
985 $ hg book foo@2 -r 2
985 $ hg book foo@2 -r 2
986 $ hg book foo@3 -r 3
986 $ hg book foo@3 -r 3
987 $ hg book foo -r foo@3
987 $ hg book foo -r foo@3
988 $ hg book
988 $ hg book
989 * Z 3:9ba5f110a0b3
989 * Z 3:9ba5f110a0b3
990 Z@1 1:925d80f479bb
990 Z@1 1:925d80f479bb
991 foo 3:9ba5f110a0b3
991 foo 3:9ba5f110a0b3
992 foo@1 0:f7b1eb17ad24
992 foo@1 0:f7b1eb17ad24
993 foo@2 2:db815d6d32e6
993 foo@2 2:db815d6d32e6
994 four 3:9ba5f110a0b3
994 four 3:9ba5f110a0b3
995 should-end-on-two 2:db815d6d32e6
995 should-end-on-two 2:db815d6d32e6
996
996
997 pull --update works the same as pull && update (case #2)
997 pull --update works the same as pull && update (case #2)
998
998
999 It is assumed that "hg pull" itself doesn't update current active
999 It is assumed that "hg pull" itself doesn't update current active
1000 bookmark ('Y' in tests below).
1000 bookmark ('Y' in tests below).
1001
1001
1002 $ hg pull -q ../cloned-bookmarks-update
1002 $ hg pull -q ../cloned-bookmarks-update
1003 divergent bookmark Z stored as Z@2
1003 divergent bookmark Z stored as Z@2
1004
1004
1005 (pulling revision on another named branch with --update updates
1005 (pulling revision on another named branch with --update updates
1006 neither the working directory nor current active bookmark: "no-op"
1006 neither the working directory nor current active bookmark: "no-op"
1007 case)
1007 case)
1008
1008
1009 $ echo yy >> y
1009 $ echo yy >> y
1010 $ hg commit -m yy
1010 $ hg commit -m yy
1011
1011
1012 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1012 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1013 * Y 3:125c9a1d6df6
1013 * Y 3:125c9a1d6df6
1014 $ hg -R ../cloned-bookmarks-update pull . --update
1014 $ hg -R ../cloned-bookmarks-update pull . --update
1015 pulling from .
1015 pulling from .
1016 searching for changes
1016 searching for changes
1017 adding changesets
1017 adding changesets
1018 adding manifests
1018 adding manifests
1019 adding file changes
1019 adding file changes
1020 divergent bookmark Z stored as Z@default
1020 divergent bookmark Z stored as Z@default
1021 adding remote bookmark foo
1021 adding remote bookmark foo
1022 adding remote bookmark four
1022 adding remote bookmark four
1023 adding remote bookmark should-end-on-two
1023 adding remote bookmark should-end-on-two
1024 added 1 changesets with 1 changes to 1 files
1024 added 1 changesets with 1 changes to 1 files
1025 new changesets 5fb12f0f2d51
1025 new changesets 5fb12f0f2d51
1026 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1026 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1027 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
1027 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
1028 3:125c9a1d6df6
1028 3:125c9a1d6df6
1029 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1029 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1030 * Y 3:125c9a1d6df6
1030 * Y 3:125c9a1d6df6
1031
1031
1032 (pulling revision on current named/topological branch with --update
1032 (pulling revision on current named/topological branch with --update
1033 updates the working directory and current active bookmark)
1033 updates the working directory and current active bookmark)
1034
1034
1035 $ hg update -C -q 125c9a1d6df6
1035 $ hg update -C -q 125c9a1d6df6
1036 $ echo xx >> x
1036 $ echo xx >> x
1037 $ hg commit -m xx
1037 $ hg commit -m xx
1038
1038
1039 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1039 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1040 * Y 3:125c9a1d6df6
1040 * Y 3:125c9a1d6df6
1041 $ hg -R ../cloned-bookmarks-update pull . --update
1041 $ hg -R ../cloned-bookmarks-update pull . --update
1042 pulling from .
1042 pulling from .
1043 searching for changes
1043 searching for changes
1044 adding changesets
1044 adding changesets
1045 adding manifests
1045 adding manifests
1046 adding file changes
1046 adding file changes
1047 divergent bookmark Z stored as Z@default
1047 divergent bookmark Z stored as Z@default
1048 added 1 changesets with 1 changes to 1 files
1048 added 1 changesets with 1 changes to 1 files
1049 new changesets 81dcce76aa0b
1049 new changesets 81dcce76aa0b
1050 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1050 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1051 updating bookmark Y
1051 updating bookmark Y
1052 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
1052 $ hg -R ../cloned-bookmarks-update parents -T "{rev}:{node|short}\n"
1053 6:81dcce76aa0b
1053 6:81dcce76aa0b
1054 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1054 $ hg -R ../cloned-bookmarks-update bookmarks | grep ' Y '
1055 * Y 6:81dcce76aa0b
1055 * Y 6:81dcce76aa0b
1056
1056
1057 $ cd ..
1057 $ cd ..
1058
1058
1059 ensure changelog is written before bookmarks
1059 ensure changelog is written before bookmarks
1060 $ hg init orderrepo
1060 $ hg init orderrepo
1061 $ cd orderrepo
1061 $ cd orderrepo
1062 $ touch a
1062 $ touch a
1063 $ hg commit -Aqm one
1063 $ hg commit -Aqm one
1064 $ hg book mybook
1064 $ hg book mybook
1065 $ echo a > a
1065 $ echo a > a
1066
1066
1067 $ cat > $TESTTMP/pausefinalize.py <<EOF
1067 $ cat > $TESTTMP/pausefinalize.py <<EOF
1068 > from __future__ import absolute_import
1068 > from __future__ import absolute_import
1069 > import os
1069 > import os
1070 > import time
1070 > import time
1071 > from mercurial import extensions, localrepo
1071 > from mercurial import extensions, localrepo
1072 > def transaction(orig, self, desc, report=None):
1072 > def transaction(orig, self, desc, report=None):
1073 > tr = orig(self, desc, report)
1073 > tr = orig(self, desc, report)
1074 > def sleep(*args, **kwargs):
1074 > def sleep(*args, **kwargs):
1075 > retry = 20
1075 > retry = 20
1076 > while retry > 0 and not os.path.exists(b"$TESTTMP/unpause"):
1076 > while retry > 0 and not os.path.exists(b"$TESTTMP/unpause"):
1077 > retry -= 1
1077 > retry -= 1
1078 > time.sleep(0.5)
1078 > time.sleep(0.5)
1079 > if os.path.exists(b"$TESTTMP/unpause"):
1079 > if os.path.exists(b"$TESTTMP/unpause"):
1080 > os.remove(b"$TESTTMP/unpause")
1080 > os.remove(b"$TESTTMP/unpause")
1081 > # It is important that this finalizer start with 'a', so it runs before
1081 > # It is important that this finalizer start with 'a', so it runs before
1082 > # the changelog finalizer appends to the changelog.
1082 > # the changelog finalizer appends to the changelog.
1083 > tr.addfinalize(b'a-sleep', sleep)
1083 > tr.addfinalize(b'a-sleep', sleep)
1084 > return tr
1084 > return tr
1085 >
1085 >
1086 > def extsetup(ui):
1086 > def extsetup(ui):
1087 > # This extension inserts an artifical pause during the transaction
1087 > # This extension inserts an artifical pause during the transaction
1088 > # finalizer, so we can run commands mid-transaction-close.
1088 > # finalizer, so we can run commands mid-transaction-close.
1089 > extensions.wrapfunction(localrepo.localrepository, 'transaction',
1089 > extensions.wrapfunction(localrepo.localrepository, 'transaction',
1090 > transaction)
1090 > transaction)
1091 > EOF
1091 > EOF
1092 $ hg commit -qm two --config extensions.pausefinalize=$TESTTMP/pausefinalize.py &
1092 $ hg commit -qm two --config extensions.pausefinalize=$TESTTMP/pausefinalize.py &
1093 $ sleep 2
1093 $ sleep 2
1094 $ hg log -r .
1094 $ hg log -r .
1095 changeset: 0:867bc5792c8c
1095 changeset: 0:867bc5792c8c
1096 bookmark: mybook
1096 bookmark: mybook
1097 tag: tip
1097 tag: tip
1098 user: test
1098 user: test
1099 date: Thu Jan 01 00:00:00 1970 +0000
1099 date: Thu Jan 01 00:00:00 1970 +0000
1100 summary: one
1100 summary: one
1101
1101
1102 $ hg bookmarks
1102 $ hg bookmarks
1103 * mybook 0:867bc5792c8c
1103 * mybook 0:867bc5792c8c
1104 $ touch $TESTTMP/unpause
1104 $ touch $TESTTMP/unpause
1105
1105
1106 $ cd ..
1106 $ cd ..
1107
1107
1108 check whether HG_PENDING makes pending changes only in related
1108 check whether HG_PENDING makes pending changes only in related
1109 repositories visible to an external hook.
1109 repositories visible to an external hook.
1110
1110
1111 (emulate a transaction running concurrently by copied
1111 (emulate a transaction running concurrently by copied
1112 .hg/bookmarks.pending in subsequent test)
1112 .hg/bookmarks.pending in subsequent test)
1113
1113
1114 $ cat > $TESTTMP/savepending.sh <<EOF
1114 $ cat > $TESTTMP/savepending.sh <<EOF
1115 > cp .hg/bookmarks.pending .hg/bookmarks.pending.saved
1115 > cp .hg/bookmarks.pending .hg/bookmarks.pending.saved
1116 > exit 1 # to avoid adding new bookmark for subsequent tests
1116 > exit 1 # to avoid adding new bookmark for subsequent tests
1117 > EOF
1117 > EOF
1118
1118
1119 $ hg init unrelated
1119 $ hg init unrelated
1120 $ cd unrelated
1120 $ cd unrelated
1121 $ echo a > a
1121 $ echo a > a
1122 $ hg add a
1122 $ hg add a
1123 $ hg commit -m '#0'
1123 $ hg commit -m '#0'
1124 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" bookmarks INVISIBLE
1124 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" bookmarks INVISIBLE
1125 transaction abort!
1125 transaction abort!
1126 rollback completed
1126 rollback completed
1127 abort: pretxnclose hook exited with status 1
1127 abort: pretxnclose hook exited with status 1
1128 [255]
1128 [255]
1129 $ cp .hg/bookmarks.pending.saved .hg/bookmarks.pending
1129 $ cp .hg/bookmarks.pending.saved .hg/bookmarks.pending
1130
1130
1131 (check visible bookmarks while transaction running in repo)
1131 (check visible bookmarks while transaction running in repo)
1132
1132
1133 $ cat > $TESTTMP/checkpending.sh <<EOF
1133 $ cat > $TESTTMP/checkpending.sh <<EOF
1134 > echo "@repo"
1134 > echo "@repo"
1135 > hg -R "$TESTTMP/repo" bookmarks
1135 > hg -R "$TESTTMP/repo" bookmarks
1136 > echo "@unrelated"
1136 > echo "@unrelated"
1137 > hg -R "$TESTTMP/unrelated" bookmarks
1137 > hg -R "$TESTTMP/unrelated" bookmarks
1138 > exit 1 # to avoid adding new bookmark for subsequent tests
1138 > exit 1 # to avoid adding new bookmark for subsequent tests
1139 > EOF
1139 > EOF
1140
1140
1141 $ cd ../repo
1141 $ cd ../repo
1142 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" bookmarks NEW
1142 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" bookmarks NEW
1143 @repo
1143 @repo
1144 * NEW 6:81dcce76aa0b
1144 * NEW 6:81dcce76aa0b
1145 X2 1:925d80f479bb
1145 X2 1:925d80f479bb
1146 Y 4:125c9a1d6df6
1146 Y 4:125c9a1d6df6
1147 Z 5:5fb12f0f2d51
1147 Z 5:5fb12f0f2d51
1148 Z@1 1:925d80f479bb
1148 Z@1 1:925d80f479bb
1149 Z@2 4:125c9a1d6df6
1149 Z@2 4:125c9a1d6df6
1150 foo 3:9ba5f110a0b3
1150 foo 3:9ba5f110a0b3
1151 foo@1 0:f7b1eb17ad24
1151 foo@1 0:f7b1eb17ad24
1152 foo@2 2:db815d6d32e6
1152 foo@2 2:db815d6d32e6
1153 four 3:9ba5f110a0b3
1153 four 3:9ba5f110a0b3
1154 should-end-on-two 2:db815d6d32e6
1154 should-end-on-two 2:db815d6d32e6
1155 x y 2:db815d6d32e6
1155 x y 2:db815d6d32e6
1156 @unrelated
1156 @unrelated
1157 no bookmarks set
1157 no bookmarks set
1158 transaction abort!
1158 transaction abort!
1159 rollback completed
1159 rollback completed
1160 abort: pretxnclose hook exited with status 1
1160 abort: pretxnclose hook exited with status 1
1161 [255]
1161 [255]
1162
1162
1163 Check pretxnclose-bookmark can abort a transaction
1163 Check pretxnclose-bookmark can abort a transaction
1164 --------------------------------------------------
1164 --------------------------------------------------
1165
1165
1166 add hooks:
1166 add hooks:
1167
1167
1168 * to prevent NEW bookmark on a non-public changeset
1168 * to prevent NEW bookmark on a non-public changeset
1169 * to prevent non-forward move of NEW bookmark
1169 * to prevent non-forward move of NEW bookmark
1170
1170
1171 $ cat << EOF >> .hg/hgrc
1171 $ cat << EOF >> .hg/hgrc
1172 > [hooks]
1172 > [hooks]
1173 > pretxnclose-bookmark.force-public = sh -c "(echo \$HG_BOOKMARK| grep -v NEW > /dev/null) || [ -z \"\$HG_NODE\" ] || (hg log -r \"\$HG_NODE\" -T '{phase}' | grep public > /dev/null)"
1173 > pretxnclose-bookmark.force-public = sh -c "(echo \$HG_BOOKMARK| grep -v NEW > /dev/null) || [ -z \"\$HG_NODE\" ] || (hg log -r \"\$HG_NODE\" -T '{phase}' | grep public > /dev/null)"
1174 > pretxnclose-bookmark.force-forward = sh -c "(echo \$HG_BOOKMARK| grep -v NEW > /dev/null) || [ -z \"\$HG_NODE\" ] || (hg log -r \"max(\$HG_OLDNODE::\$HG_NODE)\" -T 'MATCH' | grep MATCH > /dev/null)"
1174 > pretxnclose-bookmark.force-forward = sh -c "(echo \$HG_BOOKMARK| grep -v NEW > /dev/null) || [ -z \"\$HG_NODE\" ] || (hg log -r \"max(\$HG_OLDNODE::\$HG_NODE)\" -T 'MATCH' | grep MATCH > /dev/null)"
1175 > EOF
1175 > EOF
1176
1176
1177 $ hg log -G -T phases
1177 $ hg log -G -T phases
1178 @ changeset: 6:81dcce76aa0b
1178 @ changeset: 6:81dcce76aa0b
1179 | tag: tip
1179 | tag: tip
1180 | phase: draft
1180 | phase: draft
1181 | parent: 4:125c9a1d6df6
1181 | parent: 4:125c9a1d6df6
1182 | user: test
1182 | user: test
1183 | date: Thu Jan 01 00:00:00 1970 +0000
1183 | date: Thu Jan 01 00:00:00 1970 +0000
1184 | summary: xx
1184 | summary: xx
1185 |
1185 |
1186 | o changeset: 5:5fb12f0f2d51
1186 | o changeset: 5:5fb12f0f2d51
1187 | | branch: test
1187 | | branch: test
1188 | | bookmark: Z
1188 | | bookmark: Z
1189 | | phase: draft
1189 | | phase: draft
1190 | | parent: 3:9ba5f110a0b3
1190 | | parent: 3:9ba5f110a0b3
1191 | | user: test
1191 | | user: test
1192 | | date: Thu Jan 01 00:00:00 1970 +0000
1192 | | date: Thu Jan 01 00:00:00 1970 +0000
1193 | | summary: yy
1193 | | summary: yy
1194 | |
1194 | |
1195 o | changeset: 4:125c9a1d6df6
1195 o | changeset: 4:125c9a1d6df6
1196 | | bookmark: Y
1196 | | bookmark: Y
1197 | | bookmark: Z@2
1197 | | bookmark: Z@2
1198 | | phase: public
1198 | | phase: public
1199 | | parent: 2:db815d6d32e6
1199 | | parent: 2:db815d6d32e6
1200 | | user: test
1200 | | user: test
1201 | | date: Thu Jan 01 00:00:00 1970 +0000
1201 | | date: Thu Jan 01 00:00:00 1970 +0000
1202 | | summary: x
1202 | | summary: x
1203 | |
1203 | |
1204 | o changeset: 3:9ba5f110a0b3
1204 | o changeset: 3:9ba5f110a0b3
1205 |/ branch: test
1205 |/ branch: test
1206 | bookmark: foo
1206 | bookmark: foo
1207 | bookmark: four
1207 | bookmark: four
1208 | phase: public
1208 | phase: public
1209 | user: test
1209 | user: test
1210 | date: Thu Jan 01 00:00:00 1970 +0000
1210 | date: Thu Jan 01 00:00:00 1970 +0000
1211 | summary: y
1211 | summary: y
1212 |
1212 |
1213 o changeset: 2:db815d6d32e6
1213 o changeset: 2:db815d6d32e6
1214 | bookmark: foo@2
1214 | bookmark: foo@2
1215 | bookmark: should-end-on-two
1215 | bookmark: should-end-on-two
1216 | bookmark: x y
1216 | bookmark: x y
1217 | phase: public
1217 | phase: public
1218 | parent: 0:f7b1eb17ad24
1218 | parent: 0:f7b1eb17ad24
1219 | user: test
1219 | user: test
1220 | date: Thu Jan 01 00:00:00 1970 +0000
1220 | date: Thu Jan 01 00:00:00 1970 +0000
1221 | summary: 2
1221 | summary: 2
1222 |
1222 |
1223 | o changeset: 1:925d80f479bb
1223 | o changeset: 1:925d80f479bb
1224 |/ bookmark: X2
1224 |/ bookmark: X2
1225 | bookmark: Z@1
1225 | bookmark: Z@1
1226 | phase: public
1226 | phase: public
1227 | user: test
1227 | user: test
1228 | date: Thu Jan 01 00:00:00 1970 +0000
1228 | date: Thu Jan 01 00:00:00 1970 +0000
1229 | summary: 1
1229 | summary: 1
1230 |
1230 |
1231 o changeset: 0:f7b1eb17ad24
1231 o changeset: 0:f7b1eb17ad24
1232 bookmark: foo@1
1232 bookmark: foo@1
1233 phase: public
1233 phase: public
1234 user: test
1234 user: test
1235 date: Thu Jan 01 00:00:00 1970 +0000
1235 date: Thu Jan 01 00:00:00 1970 +0000
1236 summary: 0
1236 summary: 0
1237
1237
1238
1238
1239 attempt to create on a default changeset
1239 attempt to create on a default changeset
1240
1240
1241 $ hg bookmark -r 81dcce76aa0b NEW
1241 $ hg bookmark -r 81dcce76aa0b NEW
1242 transaction abort!
1242 transaction abort!
1243 rollback completed
1243 rollback completed
1244 abort: pretxnclose-bookmark.force-public hook exited with status 1
1244 abort: pretxnclose-bookmark.force-public hook exited with status 1
1245 [255]
1245 [255]
1246
1246
1247 create on a public changeset
1247 create on a public changeset
1248
1248
1249 $ hg bookmark -r 9ba5f110a0b3 NEW
1249 $ hg bookmark -r 9ba5f110a0b3 NEW
1250
1250
1251 move to the other branch
1251 move to the other branch
1252
1252
1253 $ hg bookmark -f -r 125c9a1d6df6 NEW
1253 $ hg bookmark -f -r 125c9a1d6df6 NEW
1254 transaction abort!
1254 transaction abort!
1255 rollback completed
1255 rollback completed
1256 abort: pretxnclose-bookmark.force-forward hook exited with status 1
1256 abort: pretxnclose-bookmark.force-forward hook exited with status 1
1257 [255]
1257 [255]
General Comments 0
You need to be logged in to leave comments. Login now