##// END OF EJS Templates
graft: leverage cmdutil.check_at_most_one_arg() for --abort/--stop/--continue...
Martin von Zweigbergk -
r45548:7d494425 default
parent child Browse files
Show More
@@ -1,7863 +1,7854 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 mergestate as mergestatemod,
49 mergestate as mergestatemod,
50 narrowspec,
50 narrowspec,
51 obsolete,
51 obsolete,
52 obsutil,
52 obsutil,
53 patch,
53 patch,
54 phases,
54 phases,
55 pycompat,
55 pycompat,
56 rcutil,
56 rcutil,
57 registrar,
57 registrar,
58 revsetlang,
58 revsetlang,
59 rewriteutil,
59 rewriteutil,
60 scmutil,
60 scmutil,
61 server,
61 server,
62 shelve as shelvemod,
62 shelve as shelvemod,
63 state as statemod,
63 state as statemod,
64 streamclone,
64 streamclone,
65 tags as tagsmod,
65 tags as tagsmod,
66 ui as uimod,
66 ui as uimod,
67 util,
67 util,
68 verify as verifymod,
68 verify as verifymod,
69 wireprotoserver,
69 wireprotoserver,
70 )
70 )
71 from .utils import (
71 from .utils import (
72 dateutil,
72 dateutil,
73 stringutil,
73 stringutil,
74 )
74 )
75
75
76 table = {}
76 table = {}
77 table.update(debugcommandsmod.command._table)
77 table.update(debugcommandsmod.command._table)
78
78
79 command = registrar.command(table)
79 command = registrar.command(table)
80 INTENT_READONLY = registrar.INTENT_READONLY
80 INTENT_READONLY = registrar.INTENT_READONLY
81
81
82 # common command options
82 # common command options
83
83
84 globalopts = [
84 globalopts = [
85 (
85 (
86 b'R',
86 b'R',
87 b'repository',
87 b'repository',
88 b'',
88 b'',
89 _(b'repository root directory or name of overlay bundle file'),
89 _(b'repository root directory or name of overlay bundle file'),
90 _(b'REPO'),
90 _(b'REPO'),
91 ),
91 ),
92 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
92 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
93 (
93 (
94 b'y',
94 b'y',
95 b'noninteractive',
95 b'noninteractive',
96 None,
96 None,
97 _(
97 _(
98 b'do not prompt, automatically pick the first choice for all prompts'
98 b'do not prompt, automatically pick the first choice for all prompts'
99 ),
99 ),
100 ),
100 ),
101 (b'q', b'quiet', None, _(b'suppress output')),
101 (b'q', b'quiet', None, _(b'suppress output')),
102 (b'v', b'verbose', None, _(b'enable additional output')),
102 (b'v', b'verbose', None, _(b'enable additional output')),
103 (
103 (
104 b'',
104 b'',
105 b'color',
105 b'color',
106 b'',
106 b'',
107 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
107 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
108 # and should not be translated
108 # and should not be translated
109 _(b"when to colorize (boolean, always, auto, never, or debug)"),
109 _(b"when to colorize (boolean, always, auto, never, or debug)"),
110 _(b'TYPE'),
110 _(b'TYPE'),
111 ),
111 ),
112 (
112 (
113 b'',
113 b'',
114 b'config',
114 b'config',
115 [],
115 [],
116 _(b'set/override config option (use \'section.name=value\')'),
116 _(b'set/override config option (use \'section.name=value\')'),
117 _(b'CONFIG'),
117 _(b'CONFIG'),
118 ),
118 ),
119 (b'', b'debug', None, _(b'enable debugging output')),
119 (b'', b'debug', None, _(b'enable debugging output')),
120 (b'', b'debugger', None, _(b'start debugger')),
120 (b'', b'debugger', None, _(b'start debugger')),
121 (
121 (
122 b'',
122 b'',
123 b'encoding',
123 b'encoding',
124 encoding.encoding,
124 encoding.encoding,
125 _(b'set the charset encoding'),
125 _(b'set the charset encoding'),
126 _(b'ENCODE'),
126 _(b'ENCODE'),
127 ),
127 ),
128 (
128 (
129 b'',
129 b'',
130 b'encodingmode',
130 b'encodingmode',
131 encoding.encodingmode,
131 encoding.encodingmode,
132 _(b'set the charset encoding mode'),
132 _(b'set the charset encoding mode'),
133 _(b'MODE'),
133 _(b'MODE'),
134 ),
134 ),
135 (b'', b'traceback', None, _(b'always print a traceback on exception')),
135 (b'', b'traceback', None, _(b'always print a traceback on exception')),
136 (b'', b'time', None, _(b'time how long the command takes')),
136 (b'', b'time', None, _(b'time how long the command takes')),
137 (b'', b'profile', None, _(b'print command execution profile')),
137 (b'', b'profile', None, _(b'print command execution profile')),
138 (b'', b'version', None, _(b'output version information and exit')),
138 (b'', b'version', None, _(b'output version information and exit')),
139 (b'h', b'help', None, _(b'display help and exit')),
139 (b'h', b'help', None, _(b'display help and exit')),
140 (b'', b'hidden', False, _(b'consider hidden changesets')),
140 (b'', b'hidden', False, _(b'consider hidden changesets')),
141 (
141 (
142 b'',
142 b'',
143 b'pager',
143 b'pager',
144 b'auto',
144 b'auto',
145 _(b"when to paginate (boolean, always, auto, or never)"),
145 _(b"when to paginate (boolean, always, auto, or never)"),
146 _(b'TYPE'),
146 _(b'TYPE'),
147 ),
147 ),
148 ]
148 ]
149
149
150 dryrunopts = cmdutil.dryrunopts
150 dryrunopts = cmdutil.dryrunopts
151 remoteopts = cmdutil.remoteopts
151 remoteopts = cmdutil.remoteopts
152 walkopts = cmdutil.walkopts
152 walkopts = cmdutil.walkopts
153 commitopts = cmdutil.commitopts
153 commitopts = cmdutil.commitopts
154 commitopts2 = cmdutil.commitopts2
154 commitopts2 = cmdutil.commitopts2
155 commitopts3 = cmdutil.commitopts3
155 commitopts3 = cmdutil.commitopts3
156 formatteropts = cmdutil.formatteropts
156 formatteropts = cmdutil.formatteropts
157 templateopts = cmdutil.templateopts
157 templateopts = cmdutil.templateopts
158 logopts = cmdutil.logopts
158 logopts = cmdutil.logopts
159 diffopts = cmdutil.diffopts
159 diffopts = cmdutil.diffopts
160 diffwsopts = cmdutil.diffwsopts
160 diffwsopts = cmdutil.diffwsopts
161 diffopts2 = cmdutil.diffopts2
161 diffopts2 = cmdutil.diffopts2
162 mergetoolopts = cmdutil.mergetoolopts
162 mergetoolopts = cmdutil.mergetoolopts
163 similarityopts = cmdutil.similarityopts
163 similarityopts = cmdutil.similarityopts
164 subrepoopts = cmdutil.subrepoopts
164 subrepoopts = cmdutil.subrepoopts
165 debugrevlogopts = cmdutil.debugrevlogopts
165 debugrevlogopts = cmdutil.debugrevlogopts
166
166
167 # Commands start here, listed alphabetically
167 # Commands start here, listed alphabetically
168
168
169
169
170 @command(
170 @command(
171 b'abort',
171 b'abort',
172 dryrunopts,
172 dryrunopts,
173 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
173 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
174 helpbasic=True,
174 helpbasic=True,
175 )
175 )
176 def abort(ui, repo, **opts):
176 def abort(ui, repo, **opts):
177 """abort an unfinished operation (EXPERIMENTAL)
177 """abort an unfinished operation (EXPERIMENTAL)
178
178
179 Aborts a multistep operation like graft, histedit, rebase, merge,
179 Aborts a multistep operation like graft, histedit, rebase, merge,
180 and unshelve if they are in an unfinished state.
180 and unshelve if they are in an unfinished state.
181
181
182 use --dry-run/-n to dry run the command.
182 use --dry-run/-n to dry run the command.
183 """
183 """
184 dryrun = opts.get('dry_run')
184 dryrun = opts.get('dry_run')
185 abortstate = cmdutil.getunfinishedstate(repo)
185 abortstate = cmdutil.getunfinishedstate(repo)
186 if not abortstate:
186 if not abortstate:
187 raise error.Abort(_(b'no operation in progress'))
187 raise error.Abort(_(b'no operation in progress'))
188 if not abortstate.abortfunc:
188 if not abortstate.abortfunc:
189 raise error.Abort(
189 raise error.Abort(
190 (
190 (
191 _(b"%s in progress but does not support 'hg abort'")
191 _(b"%s in progress but does not support 'hg abort'")
192 % (abortstate._opname)
192 % (abortstate._opname)
193 ),
193 ),
194 hint=abortstate.hint(),
194 hint=abortstate.hint(),
195 )
195 )
196 if dryrun:
196 if dryrun:
197 ui.status(
197 ui.status(
198 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
198 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
199 )
199 )
200 return
200 return
201 return abortstate.abortfunc(ui, repo)
201 return abortstate.abortfunc(ui, repo)
202
202
203
203
204 @command(
204 @command(
205 b'add',
205 b'add',
206 walkopts + subrepoopts + dryrunopts,
206 walkopts + subrepoopts + dryrunopts,
207 _(b'[OPTION]... [FILE]...'),
207 _(b'[OPTION]... [FILE]...'),
208 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
208 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
209 helpbasic=True,
209 helpbasic=True,
210 inferrepo=True,
210 inferrepo=True,
211 )
211 )
212 def add(ui, repo, *pats, **opts):
212 def add(ui, repo, *pats, **opts):
213 """add the specified files on the next commit
213 """add the specified files on the next commit
214
214
215 Schedule files to be version controlled and added to the
215 Schedule files to be version controlled and added to the
216 repository.
216 repository.
217
217
218 The files will be added to the repository at the next commit. To
218 The files will be added to the repository at the next commit. To
219 undo an add before that, see :hg:`forget`.
219 undo an add before that, see :hg:`forget`.
220
220
221 If no names are given, add all files to the repository (except
221 If no names are given, add all files to the repository (except
222 files matching ``.hgignore``).
222 files matching ``.hgignore``).
223
223
224 .. container:: verbose
224 .. container:: verbose
225
225
226 Examples:
226 Examples:
227
227
228 - New (unknown) files are added
228 - New (unknown) files are added
229 automatically by :hg:`add`::
229 automatically by :hg:`add`::
230
230
231 $ ls
231 $ ls
232 foo.c
232 foo.c
233 $ hg status
233 $ hg status
234 ? foo.c
234 ? foo.c
235 $ hg add
235 $ hg add
236 adding foo.c
236 adding foo.c
237 $ hg status
237 $ hg status
238 A foo.c
238 A foo.c
239
239
240 - Specific files to be added can be specified::
240 - Specific files to be added can be specified::
241
241
242 $ ls
242 $ ls
243 bar.c foo.c
243 bar.c foo.c
244 $ hg status
244 $ hg status
245 ? bar.c
245 ? bar.c
246 ? foo.c
246 ? foo.c
247 $ hg add bar.c
247 $ hg add bar.c
248 $ hg status
248 $ hg status
249 A bar.c
249 A bar.c
250 ? foo.c
250 ? foo.c
251
251
252 Returns 0 if all files are successfully added.
252 Returns 0 if all files are successfully added.
253 """
253 """
254
254
255 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
255 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
256 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
256 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
257 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
257 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
258 return rejected and 1 or 0
258 return rejected and 1 or 0
259
259
260
260
261 @command(
261 @command(
262 b'addremove',
262 b'addremove',
263 similarityopts + subrepoopts + walkopts + dryrunopts,
263 similarityopts + subrepoopts + walkopts + dryrunopts,
264 _(b'[OPTION]... [FILE]...'),
264 _(b'[OPTION]... [FILE]...'),
265 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
265 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
266 inferrepo=True,
266 inferrepo=True,
267 )
267 )
268 def addremove(ui, repo, *pats, **opts):
268 def addremove(ui, repo, *pats, **opts):
269 """add all new files, delete all missing files
269 """add all new files, delete all missing files
270
270
271 Add all new files and remove all missing files from the
271 Add all new files and remove all missing files from the
272 repository.
272 repository.
273
273
274 Unless names are given, new files are ignored if they match any of
274 Unless names are given, new files are ignored if they match any of
275 the patterns in ``.hgignore``. As with add, these changes take
275 the patterns in ``.hgignore``. As with add, these changes take
276 effect at the next commit.
276 effect at the next commit.
277
277
278 Use the -s/--similarity option to detect renamed files. This
278 Use the -s/--similarity option to detect renamed files. This
279 option takes a percentage between 0 (disabled) and 100 (files must
279 option takes a percentage between 0 (disabled) and 100 (files must
280 be identical) as its parameter. With a parameter greater than 0,
280 be identical) as its parameter. With a parameter greater than 0,
281 this compares every removed file with every added file and records
281 this compares every removed file with every added file and records
282 those similar enough as renames. Detecting renamed files this way
282 those similar enough as renames. Detecting renamed files this way
283 can be expensive. After using this option, :hg:`status -C` can be
283 can be expensive. After using this option, :hg:`status -C` can be
284 used to check which files were identified as moved or renamed. If
284 used to check which files were identified as moved or renamed. If
285 not specified, -s/--similarity defaults to 100 and only renames of
285 not specified, -s/--similarity defaults to 100 and only renames of
286 identical files are detected.
286 identical files are detected.
287
287
288 .. container:: verbose
288 .. container:: verbose
289
289
290 Examples:
290 Examples:
291
291
292 - A number of files (bar.c and foo.c) are new,
292 - A number of files (bar.c and foo.c) are new,
293 while foobar.c has been removed (without using :hg:`remove`)
293 while foobar.c has been removed (without using :hg:`remove`)
294 from the repository::
294 from the repository::
295
295
296 $ ls
296 $ ls
297 bar.c foo.c
297 bar.c foo.c
298 $ hg status
298 $ hg status
299 ! foobar.c
299 ! foobar.c
300 ? bar.c
300 ? bar.c
301 ? foo.c
301 ? foo.c
302 $ hg addremove
302 $ hg addremove
303 adding bar.c
303 adding bar.c
304 adding foo.c
304 adding foo.c
305 removing foobar.c
305 removing foobar.c
306 $ hg status
306 $ hg status
307 A bar.c
307 A bar.c
308 A foo.c
308 A foo.c
309 R foobar.c
309 R foobar.c
310
310
311 - A file foobar.c was moved to foo.c without using :hg:`rename`.
311 - A file foobar.c was moved to foo.c without using :hg:`rename`.
312 Afterwards, it was edited slightly::
312 Afterwards, it was edited slightly::
313
313
314 $ ls
314 $ ls
315 foo.c
315 foo.c
316 $ hg status
316 $ hg status
317 ! foobar.c
317 ! foobar.c
318 ? foo.c
318 ? foo.c
319 $ hg addremove --similarity 90
319 $ hg addremove --similarity 90
320 removing foobar.c
320 removing foobar.c
321 adding foo.c
321 adding foo.c
322 recording removal of foobar.c as rename to foo.c (94% similar)
322 recording removal of foobar.c as rename to foo.c (94% similar)
323 $ hg status -C
323 $ hg status -C
324 A foo.c
324 A foo.c
325 foobar.c
325 foobar.c
326 R foobar.c
326 R foobar.c
327
327
328 Returns 0 if all files are successfully added.
328 Returns 0 if all files are successfully added.
329 """
329 """
330 opts = pycompat.byteskwargs(opts)
330 opts = pycompat.byteskwargs(opts)
331 if not opts.get(b'similarity'):
331 if not opts.get(b'similarity'):
332 opts[b'similarity'] = b'100'
332 opts[b'similarity'] = b'100'
333 matcher = scmutil.match(repo[None], pats, opts)
333 matcher = scmutil.match(repo[None], pats, opts)
334 relative = scmutil.anypats(pats, opts)
334 relative = scmutil.anypats(pats, opts)
335 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
335 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
336 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
336 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
337
337
338
338
339 @command(
339 @command(
340 b'annotate|blame',
340 b'annotate|blame',
341 [
341 [
342 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
342 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
343 (
343 (
344 b'',
344 b'',
345 b'follow',
345 b'follow',
346 None,
346 None,
347 _(b'follow copies/renames and list the filename (DEPRECATED)'),
347 _(b'follow copies/renames and list the filename (DEPRECATED)'),
348 ),
348 ),
349 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
349 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
350 (b'a', b'text', None, _(b'treat all files as text')),
350 (b'a', b'text', None, _(b'treat all files as text')),
351 (b'u', b'user', None, _(b'list the author (long with -v)')),
351 (b'u', b'user', None, _(b'list the author (long with -v)')),
352 (b'f', b'file', None, _(b'list the filename')),
352 (b'f', b'file', None, _(b'list the filename')),
353 (b'd', b'date', None, _(b'list the date (short with -q)')),
353 (b'd', b'date', None, _(b'list the date (short with -q)')),
354 (b'n', b'number', None, _(b'list the revision number (default)')),
354 (b'n', b'number', None, _(b'list the revision number (default)')),
355 (b'c', b'changeset', None, _(b'list the changeset')),
355 (b'c', b'changeset', None, _(b'list the changeset')),
356 (
356 (
357 b'l',
357 b'l',
358 b'line-number',
358 b'line-number',
359 None,
359 None,
360 _(b'show line number at the first appearance'),
360 _(b'show line number at the first appearance'),
361 ),
361 ),
362 (
362 (
363 b'',
363 b'',
364 b'skip',
364 b'skip',
365 [],
365 [],
366 _(b'revset to not display (EXPERIMENTAL)'),
366 _(b'revset to not display (EXPERIMENTAL)'),
367 _(b'REV'),
367 _(b'REV'),
368 ),
368 ),
369 ]
369 ]
370 + diffwsopts
370 + diffwsopts
371 + walkopts
371 + walkopts
372 + formatteropts,
372 + formatteropts,
373 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
373 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
374 helpcategory=command.CATEGORY_FILE_CONTENTS,
374 helpcategory=command.CATEGORY_FILE_CONTENTS,
375 helpbasic=True,
375 helpbasic=True,
376 inferrepo=True,
376 inferrepo=True,
377 )
377 )
378 def annotate(ui, repo, *pats, **opts):
378 def annotate(ui, repo, *pats, **opts):
379 """show changeset information by line for each file
379 """show changeset information by line for each file
380
380
381 List changes in files, showing the revision id responsible for
381 List changes in files, showing the revision id responsible for
382 each line.
382 each line.
383
383
384 This command is useful for discovering when a change was made and
384 This command is useful for discovering when a change was made and
385 by whom.
385 by whom.
386
386
387 If you include --file, --user, or --date, the revision number is
387 If you include --file, --user, or --date, the revision number is
388 suppressed unless you also include --number.
388 suppressed unless you also include --number.
389
389
390 Without the -a/--text option, annotate will avoid processing files
390 Without the -a/--text option, annotate will avoid processing files
391 it detects as binary. With -a, annotate will annotate the file
391 it detects as binary. With -a, annotate will annotate the file
392 anyway, although the results will probably be neither useful
392 anyway, although the results will probably be neither useful
393 nor desirable.
393 nor desirable.
394
394
395 .. container:: verbose
395 .. container:: verbose
396
396
397 Template:
397 Template:
398
398
399 The following keywords are supported in addition to the common template
399 The following keywords are supported in addition to the common template
400 keywords and functions. See also :hg:`help templates`.
400 keywords and functions. See also :hg:`help templates`.
401
401
402 :lines: List of lines with annotation data.
402 :lines: List of lines with annotation data.
403 :path: String. Repository-absolute path of the specified file.
403 :path: String. Repository-absolute path of the specified file.
404
404
405 And each entry of ``{lines}`` provides the following sub-keywords in
405 And each entry of ``{lines}`` provides the following sub-keywords in
406 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
406 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
407
407
408 :line: String. Line content.
408 :line: String. Line content.
409 :lineno: Integer. Line number at that revision.
409 :lineno: Integer. Line number at that revision.
410 :path: String. Repository-absolute path of the file at that revision.
410 :path: String. Repository-absolute path of the file at that revision.
411
411
412 See :hg:`help templates.operators` for the list expansion syntax.
412 See :hg:`help templates.operators` for the list expansion syntax.
413
413
414 Returns 0 on success.
414 Returns 0 on success.
415 """
415 """
416 opts = pycompat.byteskwargs(opts)
416 opts = pycompat.byteskwargs(opts)
417 if not pats:
417 if not pats:
418 raise error.Abort(_(b'at least one filename or pattern is required'))
418 raise error.Abort(_(b'at least one filename or pattern is required'))
419
419
420 if opts.get(b'follow'):
420 if opts.get(b'follow'):
421 # --follow is deprecated and now just an alias for -f/--file
421 # --follow is deprecated and now just an alias for -f/--file
422 # to mimic the behavior of Mercurial before version 1.5
422 # to mimic the behavior of Mercurial before version 1.5
423 opts[b'file'] = True
423 opts[b'file'] = True
424
424
425 if (
425 if (
426 not opts.get(b'user')
426 not opts.get(b'user')
427 and not opts.get(b'changeset')
427 and not opts.get(b'changeset')
428 and not opts.get(b'date')
428 and not opts.get(b'date')
429 and not opts.get(b'file')
429 and not opts.get(b'file')
430 ):
430 ):
431 opts[b'number'] = True
431 opts[b'number'] = True
432
432
433 linenumber = opts.get(b'line_number') is not None
433 linenumber = opts.get(b'line_number') is not None
434 if (
434 if (
435 linenumber
435 linenumber
436 and (not opts.get(b'changeset'))
436 and (not opts.get(b'changeset'))
437 and (not opts.get(b'number'))
437 and (not opts.get(b'number'))
438 ):
438 ):
439 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
439 raise error.Abort(_(b'at least one of -n/-c is required for -l'))
440
440
441 rev = opts.get(b'rev')
441 rev = opts.get(b'rev')
442 if rev:
442 if rev:
443 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
443 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
444 ctx = scmutil.revsingle(repo, rev)
444 ctx = scmutil.revsingle(repo, rev)
445
445
446 ui.pager(b'annotate')
446 ui.pager(b'annotate')
447 rootfm = ui.formatter(b'annotate', opts)
447 rootfm = ui.formatter(b'annotate', opts)
448 if ui.debugflag:
448 if ui.debugflag:
449 shorthex = pycompat.identity
449 shorthex = pycompat.identity
450 else:
450 else:
451
451
452 def shorthex(h):
452 def shorthex(h):
453 return h[:12]
453 return h[:12]
454
454
455 if ui.quiet:
455 if ui.quiet:
456 datefunc = dateutil.shortdate
456 datefunc = dateutil.shortdate
457 else:
457 else:
458 datefunc = dateutil.datestr
458 datefunc = dateutil.datestr
459 if ctx.rev() is None:
459 if ctx.rev() is None:
460 if opts.get(b'changeset'):
460 if opts.get(b'changeset'):
461 # omit "+" suffix which is appended to node hex
461 # omit "+" suffix which is appended to node hex
462 def formatrev(rev):
462 def formatrev(rev):
463 if rev == wdirrev:
463 if rev == wdirrev:
464 return b'%d' % ctx.p1().rev()
464 return b'%d' % ctx.p1().rev()
465 else:
465 else:
466 return b'%d' % rev
466 return b'%d' % rev
467
467
468 else:
468 else:
469
469
470 def formatrev(rev):
470 def formatrev(rev):
471 if rev == wdirrev:
471 if rev == wdirrev:
472 return b'%d+' % ctx.p1().rev()
472 return b'%d+' % ctx.p1().rev()
473 else:
473 else:
474 return b'%d ' % rev
474 return b'%d ' % rev
475
475
476 def formathex(h):
476 def formathex(h):
477 if h == wdirhex:
477 if h == wdirhex:
478 return b'%s+' % shorthex(hex(ctx.p1().node()))
478 return b'%s+' % shorthex(hex(ctx.p1().node()))
479 else:
479 else:
480 return b'%s ' % shorthex(h)
480 return b'%s ' % shorthex(h)
481
481
482 else:
482 else:
483 formatrev = b'%d'.__mod__
483 formatrev = b'%d'.__mod__
484 formathex = shorthex
484 formathex = shorthex
485
485
486 opmap = [
486 opmap = [
487 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
487 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
488 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
488 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
489 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
489 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
490 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
490 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
491 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
491 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
492 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
492 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
493 ]
493 ]
494 opnamemap = {
494 opnamemap = {
495 b'rev': b'number',
495 b'rev': b'number',
496 b'node': b'changeset',
496 b'node': b'changeset',
497 b'path': b'file',
497 b'path': b'file',
498 b'lineno': b'line_number',
498 b'lineno': b'line_number',
499 }
499 }
500
500
501 if rootfm.isplain():
501 if rootfm.isplain():
502
502
503 def makefunc(get, fmt):
503 def makefunc(get, fmt):
504 return lambda x: fmt(get(x))
504 return lambda x: fmt(get(x))
505
505
506 else:
506 else:
507
507
508 def makefunc(get, fmt):
508 def makefunc(get, fmt):
509 return get
509 return get
510
510
511 datahint = rootfm.datahint()
511 datahint = rootfm.datahint()
512 funcmap = [
512 funcmap = [
513 (makefunc(get, fmt), sep)
513 (makefunc(get, fmt), sep)
514 for fn, sep, get, fmt in opmap
514 for fn, sep, get, fmt in opmap
515 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
515 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
516 ]
516 ]
517 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
517 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
518 fields = b' '.join(
518 fields = b' '.join(
519 fn
519 fn
520 for fn, sep, get, fmt in opmap
520 for fn, sep, get, fmt in opmap
521 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
521 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
522 )
522 )
523
523
524 def bad(x, y):
524 def bad(x, y):
525 raise error.Abort(b"%s: %s" % (x, y))
525 raise error.Abort(b"%s: %s" % (x, y))
526
526
527 m = scmutil.match(ctx, pats, opts, badfn=bad)
527 m = scmutil.match(ctx, pats, opts, badfn=bad)
528
528
529 follow = not opts.get(b'no_follow')
529 follow = not opts.get(b'no_follow')
530 diffopts = patch.difffeatureopts(
530 diffopts = patch.difffeatureopts(
531 ui, opts, section=b'annotate', whitespace=True
531 ui, opts, section=b'annotate', whitespace=True
532 )
532 )
533 skiprevs = opts.get(b'skip')
533 skiprevs = opts.get(b'skip')
534 if skiprevs:
534 if skiprevs:
535 skiprevs = scmutil.revrange(repo, skiprevs)
535 skiprevs = scmutil.revrange(repo, skiprevs)
536
536
537 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
537 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
538 for abs in ctx.walk(m):
538 for abs in ctx.walk(m):
539 fctx = ctx[abs]
539 fctx = ctx[abs]
540 rootfm.startitem()
540 rootfm.startitem()
541 rootfm.data(path=abs)
541 rootfm.data(path=abs)
542 if not opts.get(b'text') and fctx.isbinary():
542 if not opts.get(b'text') and fctx.isbinary():
543 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
543 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
544 continue
544 continue
545
545
546 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
546 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
547 lines = fctx.annotate(
547 lines = fctx.annotate(
548 follow=follow, skiprevs=skiprevs, diffopts=diffopts
548 follow=follow, skiprevs=skiprevs, diffopts=diffopts
549 )
549 )
550 if not lines:
550 if not lines:
551 fm.end()
551 fm.end()
552 continue
552 continue
553 formats = []
553 formats = []
554 pieces = []
554 pieces = []
555
555
556 for f, sep in funcmap:
556 for f, sep in funcmap:
557 l = [f(n) for n in lines]
557 l = [f(n) for n in lines]
558 if fm.isplain():
558 if fm.isplain():
559 sizes = [encoding.colwidth(x) for x in l]
559 sizes = [encoding.colwidth(x) for x in l]
560 ml = max(sizes)
560 ml = max(sizes)
561 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
561 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
562 else:
562 else:
563 formats.append([b'%s'] * len(l))
563 formats.append([b'%s'] * len(l))
564 pieces.append(l)
564 pieces.append(l)
565
565
566 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
566 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
567 fm.startitem()
567 fm.startitem()
568 fm.context(fctx=n.fctx)
568 fm.context(fctx=n.fctx)
569 fm.write(fields, b"".join(f), *p)
569 fm.write(fields, b"".join(f), *p)
570 if n.skip:
570 if n.skip:
571 fmt = b"* %s"
571 fmt = b"* %s"
572 else:
572 else:
573 fmt = b": %s"
573 fmt = b": %s"
574 fm.write(b'line', fmt, n.text)
574 fm.write(b'line', fmt, n.text)
575
575
576 if not lines[-1].text.endswith(b'\n'):
576 if not lines[-1].text.endswith(b'\n'):
577 fm.plain(b'\n')
577 fm.plain(b'\n')
578 fm.end()
578 fm.end()
579
579
580 rootfm.end()
580 rootfm.end()
581
581
582
582
583 @command(
583 @command(
584 b'archive',
584 b'archive',
585 [
585 [
586 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
586 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
587 (
587 (
588 b'p',
588 b'p',
589 b'prefix',
589 b'prefix',
590 b'',
590 b'',
591 _(b'directory prefix for files in archive'),
591 _(b'directory prefix for files in archive'),
592 _(b'PREFIX'),
592 _(b'PREFIX'),
593 ),
593 ),
594 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
594 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
595 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
595 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
596 ]
596 ]
597 + subrepoopts
597 + subrepoopts
598 + walkopts,
598 + walkopts,
599 _(b'[OPTION]... DEST'),
599 _(b'[OPTION]... DEST'),
600 helpcategory=command.CATEGORY_IMPORT_EXPORT,
600 helpcategory=command.CATEGORY_IMPORT_EXPORT,
601 )
601 )
602 def archive(ui, repo, dest, **opts):
602 def archive(ui, repo, dest, **opts):
603 '''create an unversioned archive of a repository revision
603 '''create an unversioned archive of a repository revision
604
604
605 By default, the revision used is the parent of the working
605 By default, the revision used is the parent of the working
606 directory; use -r/--rev to specify a different revision.
606 directory; use -r/--rev to specify a different revision.
607
607
608 The archive type is automatically detected based on file
608 The archive type is automatically detected based on file
609 extension (to override, use -t/--type).
609 extension (to override, use -t/--type).
610
610
611 .. container:: verbose
611 .. container:: verbose
612
612
613 Examples:
613 Examples:
614
614
615 - create a zip file containing the 1.0 release::
615 - create a zip file containing the 1.0 release::
616
616
617 hg archive -r 1.0 project-1.0.zip
617 hg archive -r 1.0 project-1.0.zip
618
618
619 - create a tarball excluding .hg files::
619 - create a tarball excluding .hg files::
620
620
621 hg archive project.tar.gz -X ".hg*"
621 hg archive project.tar.gz -X ".hg*"
622
622
623 Valid types are:
623 Valid types are:
624
624
625 :``files``: a directory full of files (default)
625 :``files``: a directory full of files (default)
626 :``tar``: tar archive, uncompressed
626 :``tar``: tar archive, uncompressed
627 :``tbz2``: tar archive, compressed using bzip2
627 :``tbz2``: tar archive, compressed using bzip2
628 :``tgz``: tar archive, compressed using gzip
628 :``tgz``: tar archive, compressed using gzip
629 :``txz``: tar archive, compressed using lzma (only in Python 3)
629 :``txz``: tar archive, compressed using lzma (only in Python 3)
630 :``uzip``: zip archive, uncompressed
630 :``uzip``: zip archive, uncompressed
631 :``zip``: zip archive, compressed using deflate
631 :``zip``: zip archive, compressed using deflate
632
632
633 The exact name of the destination archive or directory is given
633 The exact name of the destination archive or directory is given
634 using a format string; see :hg:`help export` for details.
634 using a format string; see :hg:`help export` for details.
635
635
636 Each member added to an archive file has a directory prefix
636 Each member added to an archive file has a directory prefix
637 prepended. Use -p/--prefix to specify a format string for the
637 prepended. Use -p/--prefix to specify a format string for the
638 prefix. The default is the basename of the archive, with suffixes
638 prefix. The default is the basename of the archive, with suffixes
639 removed.
639 removed.
640
640
641 Returns 0 on success.
641 Returns 0 on success.
642 '''
642 '''
643
643
644 opts = pycompat.byteskwargs(opts)
644 opts = pycompat.byteskwargs(opts)
645 rev = opts.get(b'rev')
645 rev = opts.get(b'rev')
646 if rev:
646 if rev:
647 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
647 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
648 ctx = scmutil.revsingle(repo, rev)
648 ctx = scmutil.revsingle(repo, rev)
649 if not ctx:
649 if not ctx:
650 raise error.Abort(_(b'no working directory: please specify a revision'))
650 raise error.Abort(_(b'no working directory: please specify a revision'))
651 node = ctx.node()
651 node = ctx.node()
652 dest = cmdutil.makefilename(ctx, dest)
652 dest = cmdutil.makefilename(ctx, dest)
653 if os.path.realpath(dest) == repo.root:
653 if os.path.realpath(dest) == repo.root:
654 raise error.Abort(_(b'repository root cannot be destination'))
654 raise error.Abort(_(b'repository root cannot be destination'))
655
655
656 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
656 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
657 prefix = opts.get(b'prefix')
657 prefix = opts.get(b'prefix')
658
658
659 if dest == b'-':
659 if dest == b'-':
660 if kind == b'files':
660 if kind == b'files':
661 raise error.Abort(_(b'cannot archive plain files to stdout'))
661 raise error.Abort(_(b'cannot archive plain files to stdout'))
662 dest = cmdutil.makefileobj(ctx, dest)
662 dest = cmdutil.makefileobj(ctx, dest)
663 if not prefix:
663 if not prefix:
664 prefix = os.path.basename(repo.root) + b'-%h'
664 prefix = os.path.basename(repo.root) + b'-%h'
665
665
666 prefix = cmdutil.makefilename(ctx, prefix)
666 prefix = cmdutil.makefilename(ctx, prefix)
667 match = scmutil.match(ctx, [], opts)
667 match = scmutil.match(ctx, [], opts)
668 archival.archive(
668 archival.archive(
669 repo,
669 repo,
670 dest,
670 dest,
671 node,
671 node,
672 kind,
672 kind,
673 not opts.get(b'no_decode'),
673 not opts.get(b'no_decode'),
674 match,
674 match,
675 prefix,
675 prefix,
676 subrepos=opts.get(b'subrepos'),
676 subrepos=opts.get(b'subrepos'),
677 )
677 )
678
678
679
679
680 @command(
680 @command(
681 b'backout',
681 b'backout',
682 [
682 [
683 (
683 (
684 b'',
684 b'',
685 b'merge',
685 b'merge',
686 None,
686 None,
687 _(b'merge with old dirstate parent after backout'),
687 _(b'merge with old dirstate parent after backout'),
688 ),
688 ),
689 (
689 (
690 b'',
690 b'',
691 b'commit',
691 b'commit',
692 None,
692 None,
693 _(b'commit if no conflicts were encountered (DEPRECATED)'),
693 _(b'commit if no conflicts were encountered (DEPRECATED)'),
694 ),
694 ),
695 (b'', b'no-commit', None, _(b'do not commit')),
695 (b'', b'no-commit', None, _(b'do not commit')),
696 (
696 (
697 b'',
697 b'',
698 b'parent',
698 b'parent',
699 b'',
699 b'',
700 _(b'parent to choose when backing out merge (DEPRECATED)'),
700 _(b'parent to choose when backing out merge (DEPRECATED)'),
701 _(b'REV'),
701 _(b'REV'),
702 ),
702 ),
703 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
703 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
704 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
704 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
705 ]
705 ]
706 + mergetoolopts
706 + mergetoolopts
707 + walkopts
707 + walkopts
708 + commitopts
708 + commitopts
709 + commitopts2,
709 + commitopts2,
710 _(b'[OPTION]... [-r] REV'),
710 _(b'[OPTION]... [-r] REV'),
711 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
711 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
712 )
712 )
713 def backout(ui, repo, node=None, rev=None, **opts):
713 def backout(ui, repo, node=None, rev=None, **opts):
714 '''reverse effect of earlier changeset
714 '''reverse effect of earlier changeset
715
715
716 Prepare a new changeset with the effect of REV undone in the
716 Prepare a new changeset with the effect of REV undone in the
717 current working directory. If no conflicts were encountered,
717 current working directory. If no conflicts were encountered,
718 it will be committed immediately.
718 it will be committed immediately.
719
719
720 If REV is the parent of the working directory, then this new changeset
720 If REV is the parent of the working directory, then this new changeset
721 is committed automatically (unless --no-commit is specified).
721 is committed automatically (unless --no-commit is specified).
722
722
723 .. note::
723 .. note::
724
724
725 :hg:`backout` cannot be used to fix either an unwanted or
725 :hg:`backout` cannot be used to fix either an unwanted or
726 incorrect merge.
726 incorrect merge.
727
727
728 .. container:: verbose
728 .. container:: verbose
729
729
730 Examples:
730 Examples:
731
731
732 - Reverse the effect of the parent of the working directory.
732 - Reverse the effect of the parent of the working directory.
733 This backout will be committed immediately::
733 This backout will be committed immediately::
734
734
735 hg backout -r .
735 hg backout -r .
736
736
737 - Reverse the effect of previous bad revision 23::
737 - Reverse the effect of previous bad revision 23::
738
738
739 hg backout -r 23
739 hg backout -r 23
740
740
741 - Reverse the effect of previous bad revision 23 and
741 - Reverse the effect of previous bad revision 23 and
742 leave changes uncommitted::
742 leave changes uncommitted::
743
743
744 hg backout -r 23 --no-commit
744 hg backout -r 23 --no-commit
745 hg commit -m "Backout revision 23"
745 hg commit -m "Backout revision 23"
746
746
747 By default, the pending changeset will have one parent,
747 By default, the pending changeset will have one parent,
748 maintaining a linear history. With --merge, the pending
748 maintaining a linear history. With --merge, the pending
749 changeset will instead have two parents: the old parent of the
749 changeset will instead have two parents: the old parent of the
750 working directory and a new child of REV that simply undoes REV.
750 working directory and a new child of REV that simply undoes REV.
751
751
752 Before version 1.7, the behavior without --merge was equivalent
752 Before version 1.7, the behavior without --merge was equivalent
753 to specifying --merge followed by :hg:`update --clean .` to
753 to specifying --merge followed by :hg:`update --clean .` to
754 cancel the merge and leave the child of REV as a head to be
754 cancel the merge and leave the child of REV as a head to be
755 merged separately.
755 merged separately.
756
756
757 See :hg:`help dates` for a list of formats valid for -d/--date.
757 See :hg:`help dates` for a list of formats valid for -d/--date.
758
758
759 See :hg:`help revert` for a way to restore files to the state
759 See :hg:`help revert` for a way to restore files to the state
760 of another revision.
760 of another revision.
761
761
762 Returns 0 on success, 1 if nothing to backout or there are unresolved
762 Returns 0 on success, 1 if nothing to backout or there are unresolved
763 files.
763 files.
764 '''
764 '''
765 with repo.wlock(), repo.lock():
765 with repo.wlock(), repo.lock():
766 return _dobackout(ui, repo, node, rev, **opts)
766 return _dobackout(ui, repo, node, rev, **opts)
767
767
768
768
769 def _dobackout(ui, repo, node=None, rev=None, **opts):
769 def _dobackout(ui, repo, node=None, rev=None, **opts):
770 opts = pycompat.byteskwargs(opts)
770 opts = pycompat.byteskwargs(opts)
771 if opts.get(b'commit') and opts.get(b'no_commit'):
771 if opts.get(b'commit') and opts.get(b'no_commit'):
772 raise error.Abort(_(b"cannot use --commit with --no-commit"))
772 raise error.Abort(_(b"cannot use --commit with --no-commit"))
773 if opts.get(b'merge') and opts.get(b'no_commit'):
773 if opts.get(b'merge') and opts.get(b'no_commit'):
774 raise error.Abort(_(b"cannot use --merge with --no-commit"))
774 raise error.Abort(_(b"cannot use --merge with --no-commit"))
775
775
776 if rev and node:
776 if rev and node:
777 raise error.Abort(_(b"please specify just one revision"))
777 raise error.Abort(_(b"please specify just one revision"))
778
778
779 if not rev:
779 if not rev:
780 rev = node
780 rev = node
781
781
782 if not rev:
782 if not rev:
783 raise error.Abort(_(b"please specify a revision to backout"))
783 raise error.Abort(_(b"please specify a revision to backout"))
784
784
785 date = opts.get(b'date')
785 date = opts.get(b'date')
786 if date:
786 if date:
787 opts[b'date'] = dateutil.parsedate(date)
787 opts[b'date'] = dateutil.parsedate(date)
788
788
789 cmdutil.checkunfinished(repo)
789 cmdutil.checkunfinished(repo)
790 cmdutil.bailifchanged(repo)
790 cmdutil.bailifchanged(repo)
791 node = scmutil.revsingle(repo, rev).node()
791 node = scmutil.revsingle(repo, rev).node()
792
792
793 op1, op2 = repo.dirstate.parents()
793 op1, op2 = repo.dirstate.parents()
794 if not repo.changelog.isancestor(node, op1):
794 if not repo.changelog.isancestor(node, op1):
795 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
795 raise error.Abort(_(b'cannot backout change that is not an ancestor'))
796
796
797 p1, p2 = repo.changelog.parents(node)
797 p1, p2 = repo.changelog.parents(node)
798 if p1 == nullid:
798 if p1 == nullid:
799 raise error.Abort(_(b'cannot backout a change with no parents'))
799 raise error.Abort(_(b'cannot backout a change with no parents'))
800 if p2 != nullid:
800 if p2 != nullid:
801 if not opts.get(b'parent'):
801 if not opts.get(b'parent'):
802 raise error.Abort(_(b'cannot backout a merge changeset'))
802 raise error.Abort(_(b'cannot backout a merge changeset'))
803 p = repo.lookup(opts[b'parent'])
803 p = repo.lookup(opts[b'parent'])
804 if p not in (p1, p2):
804 if p not in (p1, p2):
805 raise error.Abort(
805 raise error.Abort(
806 _(b'%s is not a parent of %s') % (short(p), short(node))
806 _(b'%s is not a parent of %s') % (short(p), short(node))
807 )
807 )
808 parent = p
808 parent = p
809 else:
809 else:
810 if opts.get(b'parent'):
810 if opts.get(b'parent'):
811 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
811 raise error.Abort(_(b'cannot use --parent on non-merge changeset'))
812 parent = p1
812 parent = p1
813
813
814 # the backout should appear on the same branch
814 # the backout should appear on the same branch
815 branch = repo.dirstate.branch()
815 branch = repo.dirstate.branch()
816 bheads = repo.branchheads(branch)
816 bheads = repo.branchheads(branch)
817 rctx = scmutil.revsingle(repo, hex(parent))
817 rctx = scmutil.revsingle(repo, hex(parent))
818 if not opts.get(b'merge') and op1 != node:
818 if not opts.get(b'merge') and op1 != node:
819 with dirstateguard.dirstateguard(repo, b'backout'):
819 with dirstateguard.dirstateguard(repo, b'backout'):
820 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
820 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
821 with ui.configoverride(overrides, b'backout'):
821 with ui.configoverride(overrides, b'backout'):
822 stats = mergemod.update(
822 stats = mergemod.update(
823 repo,
823 repo,
824 parent,
824 parent,
825 branchmerge=True,
825 branchmerge=True,
826 force=True,
826 force=True,
827 ancestor=node,
827 ancestor=node,
828 mergeancestor=False,
828 mergeancestor=False,
829 )
829 )
830 repo.setparents(op1, op2)
830 repo.setparents(op1, op2)
831 hg._showstats(repo, stats)
831 hg._showstats(repo, stats)
832 if stats.unresolvedcount:
832 if stats.unresolvedcount:
833 repo.ui.status(
833 repo.ui.status(
834 _(b"use 'hg resolve' to retry unresolved file merges\n")
834 _(b"use 'hg resolve' to retry unresolved file merges\n")
835 )
835 )
836 return 1
836 return 1
837 else:
837 else:
838 hg.clean(repo, node, show_stats=False)
838 hg.clean(repo, node, show_stats=False)
839 repo.dirstate.setbranch(branch)
839 repo.dirstate.setbranch(branch)
840 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
840 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
841
841
842 if opts.get(b'no_commit'):
842 if opts.get(b'no_commit'):
843 msg = _(b"changeset %s backed out, don't forget to commit.\n")
843 msg = _(b"changeset %s backed out, don't forget to commit.\n")
844 ui.status(msg % short(node))
844 ui.status(msg % short(node))
845 return 0
845 return 0
846
846
847 def commitfunc(ui, repo, message, match, opts):
847 def commitfunc(ui, repo, message, match, opts):
848 editform = b'backout'
848 editform = b'backout'
849 e = cmdutil.getcommiteditor(
849 e = cmdutil.getcommiteditor(
850 editform=editform, **pycompat.strkwargs(opts)
850 editform=editform, **pycompat.strkwargs(opts)
851 )
851 )
852 if not message:
852 if not message:
853 # we don't translate commit messages
853 # we don't translate commit messages
854 message = b"Backed out changeset %s" % short(node)
854 message = b"Backed out changeset %s" % short(node)
855 e = cmdutil.getcommiteditor(edit=True, editform=editform)
855 e = cmdutil.getcommiteditor(edit=True, editform=editform)
856 return repo.commit(
856 return repo.commit(
857 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
857 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
858 )
858 )
859
859
860 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
860 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
861 if not newnode:
861 if not newnode:
862 ui.status(_(b"nothing changed\n"))
862 ui.status(_(b"nothing changed\n"))
863 return 1
863 return 1
864 cmdutil.commitstatus(repo, newnode, branch, bheads)
864 cmdutil.commitstatus(repo, newnode, branch, bheads)
865
865
866 def nice(node):
866 def nice(node):
867 return b'%d:%s' % (repo.changelog.rev(node), short(node))
867 return b'%d:%s' % (repo.changelog.rev(node), short(node))
868
868
869 ui.status(
869 ui.status(
870 _(b'changeset %s backs out changeset %s\n')
870 _(b'changeset %s backs out changeset %s\n')
871 % (nice(repo.changelog.tip()), nice(node))
871 % (nice(repo.changelog.tip()), nice(node))
872 )
872 )
873 if opts.get(b'merge') and op1 != node:
873 if opts.get(b'merge') and op1 != node:
874 hg.clean(repo, op1, show_stats=False)
874 hg.clean(repo, op1, show_stats=False)
875 ui.status(
875 ui.status(
876 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
876 _(b'merging with changeset %s\n') % nice(repo.changelog.tip())
877 )
877 )
878 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
878 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
879 with ui.configoverride(overrides, b'backout'):
879 with ui.configoverride(overrides, b'backout'):
880 return hg.merge(repo[b'tip'])
880 return hg.merge(repo[b'tip'])
881 return 0
881 return 0
882
882
883
883
884 @command(
884 @command(
885 b'bisect',
885 b'bisect',
886 [
886 [
887 (b'r', b'reset', False, _(b'reset bisect state')),
887 (b'r', b'reset', False, _(b'reset bisect state')),
888 (b'g', b'good', False, _(b'mark changeset good')),
888 (b'g', b'good', False, _(b'mark changeset good')),
889 (b'b', b'bad', False, _(b'mark changeset bad')),
889 (b'b', b'bad', False, _(b'mark changeset bad')),
890 (b's', b'skip', False, _(b'skip testing changeset')),
890 (b's', b'skip', False, _(b'skip testing changeset')),
891 (b'e', b'extend', False, _(b'extend the bisect range')),
891 (b'e', b'extend', False, _(b'extend the bisect range')),
892 (
892 (
893 b'c',
893 b'c',
894 b'command',
894 b'command',
895 b'',
895 b'',
896 _(b'use command to check changeset state'),
896 _(b'use command to check changeset state'),
897 _(b'CMD'),
897 _(b'CMD'),
898 ),
898 ),
899 (b'U', b'noupdate', False, _(b'do not update to target')),
899 (b'U', b'noupdate', False, _(b'do not update to target')),
900 ],
900 ],
901 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
901 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
902 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
902 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
903 )
903 )
904 def bisect(
904 def bisect(
905 ui,
905 ui,
906 repo,
906 repo,
907 rev=None,
907 rev=None,
908 extra=None,
908 extra=None,
909 command=None,
909 command=None,
910 reset=None,
910 reset=None,
911 good=None,
911 good=None,
912 bad=None,
912 bad=None,
913 skip=None,
913 skip=None,
914 extend=None,
914 extend=None,
915 noupdate=None,
915 noupdate=None,
916 ):
916 ):
917 """subdivision search of changesets
917 """subdivision search of changesets
918
918
919 This command helps to find changesets which introduce problems. To
919 This command helps to find changesets which introduce problems. To
920 use, mark the earliest changeset you know exhibits the problem as
920 use, mark the earliest changeset you know exhibits the problem as
921 bad, then mark the latest changeset which is free from the problem
921 bad, then mark the latest changeset which is free from the problem
922 as good. Bisect will update your working directory to a revision
922 as good. Bisect will update your working directory to a revision
923 for testing (unless the -U/--noupdate option is specified). Once
923 for testing (unless the -U/--noupdate option is specified). Once
924 you have performed tests, mark the working directory as good or
924 you have performed tests, mark the working directory as good or
925 bad, and bisect will either update to another candidate changeset
925 bad, and bisect will either update to another candidate changeset
926 or announce that it has found the bad revision.
926 or announce that it has found the bad revision.
927
927
928 As a shortcut, you can also use the revision argument to mark a
928 As a shortcut, you can also use the revision argument to mark a
929 revision as good or bad without checking it out first.
929 revision as good or bad without checking it out first.
930
930
931 If you supply a command, it will be used for automatic bisection.
931 If you supply a command, it will be used for automatic bisection.
932 The environment variable HG_NODE will contain the ID of the
932 The environment variable HG_NODE will contain the ID of the
933 changeset being tested. The exit status of the command will be
933 changeset being tested. The exit status of the command will be
934 used to mark revisions as good or bad: status 0 means good, 125
934 used to mark revisions as good or bad: status 0 means good, 125
935 means to skip the revision, 127 (command not found) will abort the
935 means to skip the revision, 127 (command not found) will abort the
936 bisection, and any other non-zero exit status means the revision
936 bisection, and any other non-zero exit status means the revision
937 is bad.
937 is bad.
938
938
939 .. container:: verbose
939 .. container:: verbose
940
940
941 Some examples:
941 Some examples:
942
942
943 - start a bisection with known bad revision 34, and good revision 12::
943 - start a bisection with known bad revision 34, and good revision 12::
944
944
945 hg bisect --bad 34
945 hg bisect --bad 34
946 hg bisect --good 12
946 hg bisect --good 12
947
947
948 - advance the current bisection by marking current revision as good or
948 - advance the current bisection by marking current revision as good or
949 bad::
949 bad::
950
950
951 hg bisect --good
951 hg bisect --good
952 hg bisect --bad
952 hg bisect --bad
953
953
954 - mark the current revision, or a known revision, to be skipped (e.g. if
954 - mark the current revision, or a known revision, to be skipped (e.g. if
955 that revision is not usable because of another issue)::
955 that revision is not usable because of another issue)::
956
956
957 hg bisect --skip
957 hg bisect --skip
958 hg bisect --skip 23
958 hg bisect --skip 23
959
959
960 - skip all revisions that do not touch directories ``foo`` or ``bar``::
960 - skip all revisions that do not touch directories ``foo`` or ``bar``::
961
961
962 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
962 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
963
963
964 - forget the current bisection::
964 - forget the current bisection::
965
965
966 hg bisect --reset
966 hg bisect --reset
967
967
968 - use 'make && make tests' to automatically find the first broken
968 - use 'make && make tests' to automatically find the first broken
969 revision::
969 revision::
970
970
971 hg bisect --reset
971 hg bisect --reset
972 hg bisect --bad 34
972 hg bisect --bad 34
973 hg bisect --good 12
973 hg bisect --good 12
974 hg bisect --command "make && make tests"
974 hg bisect --command "make && make tests"
975
975
976 - see all changesets whose states are already known in the current
976 - see all changesets whose states are already known in the current
977 bisection::
977 bisection::
978
978
979 hg log -r "bisect(pruned)"
979 hg log -r "bisect(pruned)"
980
980
981 - see the changeset currently being bisected (especially useful
981 - see the changeset currently being bisected (especially useful
982 if running with -U/--noupdate)::
982 if running with -U/--noupdate)::
983
983
984 hg log -r "bisect(current)"
984 hg log -r "bisect(current)"
985
985
986 - see all changesets that took part in the current bisection::
986 - see all changesets that took part in the current bisection::
987
987
988 hg log -r "bisect(range)"
988 hg log -r "bisect(range)"
989
989
990 - you can even get a nice graph::
990 - you can even get a nice graph::
991
991
992 hg log --graph -r "bisect(range)"
992 hg log --graph -r "bisect(range)"
993
993
994 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
994 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
995
995
996 Returns 0 on success.
996 Returns 0 on success.
997 """
997 """
998 # backward compatibility
998 # backward compatibility
999 if rev in b"good bad reset init".split():
999 if rev in b"good bad reset init".split():
1000 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1000 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1001 cmd, rev, extra = rev, extra, None
1001 cmd, rev, extra = rev, extra, None
1002 if cmd == b"good":
1002 if cmd == b"good":
1003 good = True
1003 good = True
1004 elif cmd == b"bad":
1004 elif cmd == b"bad":
1005 bad = True
1005 bad = True
1006 else:
1006 else:
1007 reset = True
1007 reset = True
1008 elif extra:
1008 elif extra:
1009 raise error.Abort(_(b'incompatible arguments'))
1009 raise error.Abort(_(b'incompatible arguments'))
1010
1010
1011 incompatibles = {
1011 incompatibles = {
1012 b'--bad': bad,
1012 b'--bad': bad,
1013 b'--command': bool(command),
1013 b'--command': bool(command),
1014 b'--extend': extend,
1014 b'--extend': extend,
1015 b'--good': good,
1015 b'--good': good,
1016 b'--reset': reset,
1016 b'--reset': reset,
1017 b'--skip': skip,
1017 b'--skip': skip,
1018 }
1018 }
1019
1019
1020 enabled = [x for x in incompatibles if incompatibles[x]]
1020 enabled = [x for x in incompatibles if incompatibles[x]]
1021
1021
1022 if len(enabled) > 1:
1022 if len(enabled) > 1:
1023 raise error.Abort(
1023 raise error.Abort(
1024 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1024 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1025 )
1025 )
1026
1026
1027 if reset:
1027 if reset:
1028 hbisect.resetstate(repo)
1028 hbisect.resetstate(repo)
1029 return
1029 return
1030
1030
1031 state = hbisect.load_state(repo)
1031 state = hbisect.load_state(repo)
1032
1032
1033 # update state
1033 # update state
1034 if good or bad or skip:
1034 if good or bad or skip:
1035 if rev:
1035 if rev:
1036 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1036 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
1037 else:
1037 else:
1038 nodes = [repo.lookup(b'.')]
1038 nodes = [repo.lookup(b'.')]
1039 if good:
1039 if good:
1040 state[b'good'] += nodes
1040 state[b'good'] += nodes
1041 elif bad:
1041 elif bad:
1042 state[b'bad'] += nodes
1042 state[b'bad'] += nodes
1043 elif skip:
1043 elif skip:
1044 state[b'skip'] += nodes
1044 state[b'skip'] += nodes
1045 hbisect.save_state(repo, state)
1045 hbisect.save_state(repo, state)
1046 if not (state[b'good'] and state[b'bad']):
1046 if not (state[b'good'] and state[b'bad']):
1047 return
1047 return
1048
1048
1049 def mayupdate(repo, node, show_stats=True):
1049 def mayupdate(repo, node, show_stats=True):
1050 """common used update sequence"""
1050 """common used update sequence"""
1051 if noupdate:
1051 if noupdate:
1052 return
1052 return
1053 cmdutil.checkunfinished(repo)
1053 cmdutil.checkunfinished(repo)
1054 cmdutil.bailifchanged(repo)
1054 cmdutil.bailifchanged(repo)
1055 return hg.clean(repo, node, show_stats=show_stats)
1055 return hg.clean(repo, node, show_stats=show_stats)
1056
1056
1057 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1057 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1058
1058
1059 if command:
1059 if command:
1060 changesets = 1
1060 changesets = 1
1061 if noupdate:
1061 if noupdate:
1062 try:
1062 try:
1063 node = state[b'current'][0]
1063 node = state[b'current'][0]
1064 except LookupError:
1064 except LookupError:
1065 raise error.Abort(
1065 raise error.Abort(
1066 _(
1066 _(
1067 b'current bisect revision is unknown - '
1067 b'current bisect revision is unknown - '
1068 b'start a new bisect to fix'
1068 b'start a new bisect to fix'
1069 )
1069 )
1070 )
1070 )
1071 else:
1071 else:
1072 node, p2 = repo.dirstate.parents()
1072 node, p2 = repo.dirstate.parents()
1073 if p2 != nullid:
1073 if p2 != nullid:
1074 raise error.Abort(_(b'current bisect revision is a merge'))
1074 raise error.Abort(_(b'current bisect revision is a merge'))
1075 if rev:
1075 if rev:
1076 node = repo[scmutil.revsingle(repo, rev, node)].node()
1076 node = repo[scmutil.revsingle(repo, rev, node)].node()
1077 with hbisect.restore_state(repo, state, node):
1077 with hbisect.restore_state(repo, state, node):
1078 while changesets:
1078 while changesets:
1079 # update state
1079 # update state
1080 state[b'current'] = [node]
1080 state[b'current'] = [node]
1081 hbisect.save_state(repo, state)
1081 hbisect.save_state(repo, state)
1082 status = ui.system(
1082 status = ui.system(
1083 command,
1083 command,
1084 environ={b'HG_NODE': hex(node)},
1084 environ={b'HG_NODE': hex(node)},
1085 blockedtag=b'bisect_check',
1085 blockedtag=b'bisect_check',
1086 )
1086 )
1087 if status == 125:
1087 if status == 125:
1088 transition = b"skip"
1088 transition = b"skip"
1089 elif status == 0:
1089 elif status == 0:
1090 transition = b"good"
1090 transition = b"good"
1091 # status < 0 means process was killed
1091 # status < 0 means process was killed
1092 elif status == 127:
1092 elif status == 127:
1093 raise error.Abort(_(b"failed to execute %s") % command)
1093 raise error.Abort(_(b"failed to execute %s") % command)
1094 elif status < 0:
1094 elif status < 0:
1095 raise error.Abort(_(b"%s killed") % command)
1095 raise error.Abort(_(b"%s killed") % command)
1096 else:
1096 else:
1097 transition = b"bad"
1097 transition = b"bad"
1098 state[transition].append(node)
1098 state[transition].append(node)
1099 ctx = repo[node]
1099 ctx = repo[node]
1100 ui.status(
1100 ui.status(
1101 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1101 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1102 )
1102 )
1103 hbisect.checkstate(state)
1103 hbisect.checkstate(state)
1104 # bisect
1104 # bisect
1105 nodes, changesets, bgood = hbisect.bisect(repo, state)
1105 nodes, changesets, bgood = hbisect.bisect(repo, state)
1106 # update to next check
1106 # update to next check
1107 node = nodes[0]
1107 node = nodes[0]
1108 mayupdate(repo, node, show_stats=False)
1108 mayupdate(repo, node, show_stats=False)
1109 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1109 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1110 return
1110 return
1111
1111
1112 hbisect.checkstate(state)
1112 hbisect.checkstate(state)
1113
1113
1114 # actually bisect
1114 # actually bisect
1115 nodes, changesets, good = hbisect.bisect(repo, state)
1115 nodes, changesets, good = hbisect.bisect(repo, state)
1116 if extend:
1116 if extend:
1117 if not changesets:
1117 if not changesets:
1118 extendnode = hbisect.extendrange(repo, state, nodes, good)
1118 extendnode = hbisect.extendrange(repo, state, nodes, good)
1119 if extendnode is not None:
1119 if extendnode is not None:
1120 ui.write(
1120 ui.write(
1121 _(b"Extending search to changeset %d:%s\n")
1121 _(b"Extending search to changeset %d:%s\n")
1122 % (extendnode.rev(), extendnode)
1122 % (extendnode.rev(), extendnode)
1123 )
1123 )
1124 state[b'current'] = [extendnode.node()]
1124 state[b'current'] = [extendnode.node()]
1125 hbisect.save_state(repo, state)
1125 hbisect.save_state(repo, state)
1126 return mayupdate(repo, extendnode.node())
1126 return mayupdate(repo, extendnode.node())
1127 raise error.Abort(_(b"nothing to extend"))
1127 raise error.Abort(_(b"nothing to extend"))
1128
1128
1129 if changesets == 0:
1129 if changesets == 0:
1130 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1130 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1131 else:
1131 else:
1132 assert len(nodes) == 1 # only a single node can be tested next
1132 assert len(nodes) == 1 # only a single node can be tested next
1133 node = nodes[0]
1133 node = nodes[0]
1134 # compute the approximate number of remaining tests
1134 # compute the approximate number of remaining tests
1135 tests, size = 0, 2
1135 tests, size = 0, 2
1136 while size <= changesets:
1136 while size <= changesets:
1137 tests, size = tests + 1, size * 2
1137 tests, size = tests + 1, size * 2
1138 rev = repo.changelog.rev(node)
1138 rev = repo.changelog.rev(node)
1139 ui.write(
1139 ui.write(
1140 _(
1140 _(
1141 b"Testing changeset %d:%s "
1141 b"Testing changeset %d:%s "
1142 b"(%d changesets remaining, ~%d tests)\n"
1142 b"(%d changesets remaining, ~%d tests)\n"
1143 )
1143 )
1144 % (rev, short(node), changesets, tests)
1144 % (rev, short(node), changesets, tests)
1145 )
1145 )
1146 state[b'current'] = [node]
1146 state[b'current'] = [node]
1147 hbisect.save_state(repo, state)
1147 hbisect.save_state(repo, state)
1148 return mayupdate(repo, node)
1148 return mayupdate(repo, node)
1149
1149
1150
1150
1151 @command(
1151 @command(
1152 b'bookmarks|bookmark',
1152 b'bookmarks|bookmark',
1153 [
1153 [
1154 (b'f', b'force', False, _(b'force')),
1154 (b'f', b'force', False, _(b'force')),
1155 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1155 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1156 (b'd', b'delete', False, _(b'delete a given bookmark')),
1156 (b'd', b'delete', False, _(b'delete a given bookmark')),
1157 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1157 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1158 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1158 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1159 (b'l', b'list', False, _(b'list existing bookmarks')),
1159 (b'l', b'list', False, _(b'list existing bookmarks')),
1160 ]
1160 ]
1161 + formatteropts,
1161 + formatteropts,
1162 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1162 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1163 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1163 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1164 )
1164 )
1165 def bookmark(ui, repo, *names, **opts):
1165 def bookmark(ui, repo, *names, **opts):
1166 '''create a new bookmark or list existing bookmarks
1166 '''create a new bookmark or list existing bookmarks
1167
1167
1168 Bookmarks are labels on changesets to help track lines of development.
1168 Bookmarks are labels on changesets to help track lines of development.
1169 Bookmarks are unversioned and can be moved, renamed and deleted.
1169 Bookmarks are unversioned and can be moved, renamed and deleted.
1170 Deleting or moving a bookmark has no effect on the associated changesets.
1170 Deleting or moving a bookmark has no effect on the associated changesets.
1171
1171
1172 Creating or updating to a bookmark causes it to be marked as 'active'.
1172 Creating or updating to a bookmark causes it to be marked as 'active'.
1173 The active bookmark is indicated with a '*'.
1173 The active bookmark is indicated with a '*'.
1174 When a commit is made, the active bookmark will advance to the new commit.
1174 When a commit is made, the active bookmark will advance to the new commit.
1175 A plain :hg:`update` will also advance an active bookmark, if possible.
1175 A plain :hg:`update` will also advance an active bookmark, if possible.
1176 Updating away from a bookmark will cause it to be deactivated.
1176 Updating away from a bookmark will cause it to be deactivated.
1177
1177
1178 Bookmarks can be pushed and pulled between repositories (see
1178 Bookmarks can be pushed and pulled between repositories (see
1179 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1179 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1180 diverged, a new 'divergent bookmark' of the form 'name@path' will
1180 diverged, a new 'divergent bookmark' of the form 'name@path' will
1181 be created. Using :hg:`merge` will resolve the divergence.
1181 be created. Using :hg:`merge` will resolve the divergence.
1182
1182
1183 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1183 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1184 the active bookmark's name.
1184 the active bookmark's name.
1185
1185
1186 A bookmark named '@' has the special property that :hg:`clone` will
1186 A bookmark named '@' has the special property that :hg:`clone` will
1187 check it out by default if it exists.
1187 check it out by default if it exists.
1188
1188
1189 .. container:: verbose
1189 .. container:: verbose
1190
1190
1191 Template:
1191 Template:
1192
1192
1193 The following keywords are supported in addition to the common template
1193 The following keywords are supported in addition to the common template
1194 keywords and functions such as ``{bookmark}``. See also
1194 keywords and functions such as ``{bookmark}``. See also
1195 :hg:`help templates`.
1195 :hg:`help templates`.
1196
1196
1197 :active: Boolean. True if the bookmark is active.
1197 :active: Boolean. True if the bookmark is active.
1198
1198
1199 Examples:
1199 Examples:
1200
1200
1201 - create an active bookmark for a new line of development::
1201 - create an active bookmark for a new line of development::
1202
1202
1203 hg book new-feature
1203 hg book new-feature
1204
1204
1205 - create an inactive bookmark as a place marker::
1205 - create an inactive bookmark as a place marker::
1206
1206
1207 hg book -i reviewed
1207 hg book -i reviewed
1208
1208
1209 - create an inactive bookmark on another changeset::
1209 - create an inactive bookmark on another changeset::
1210
1210
1211 hg book -r .^ tested
1211 hg book -r .^ tested
1212
1212
1213 - rename bookmark turkey to dinner::
1213 - rename bookmark turkey to dinner::
1214
1214
1215 hg book -m turkey dinner
1215 hg book -m turkey dinner
1216
1216
1217 - move the '@' bookmark from another branch::
1217 - move the '@' bookmark from another branch::
1218
1218
1219 hg book -f @
1219 hg book -f @
1220
1220
1221 - print only the active bookmark name::
1221 - print only the active bookmark name::
1222
1222
1223 hg book -ql .
1223 hg book -ql .
1224 '''
1224 '''
1225 opts = pycompat.byteskwargs(opts)
1225 opts = pycompat.byteskwargs(opts)
1226 force = opts.get(b'force')
1226 force = opts.get(b'force')
1227 rev = opts.get(b'rev')
1227 rev = opts.get(b'rev')
1228 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1228 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1229
1229
1230 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1230 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1231 if action:
1231 if action:
1232 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1232 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1233 elif names or rev:
1233 elif names or rev:
1234 action = b'add'
1234 action = b'add'
1235 elif inactive:
1235 elif inactive:
1236 action = b'inactive' # meaning deactivate
1236 action = b'inactive' # meaning deactivate
1237 else:
1237 else:
1238 action = b'list'
1238 action = b'list'
1239
1239
1240 cmdutil.check_incompatible_arguments(
1240 cmdutil.check_incompatible_arguments(
1241 opts, b'inactive', [b'delete', b'list']
1241 opts, b'inactive', [b'delete', b'list']
1242 )
1242 )
1243 if not names and action in {b'add', b'delete'}:
1243 if not names and action in {b'add', b'delete'}:
1244 raise error.Abort(_(b"bookmark name required"))
1244 raise error.Abort(_(b"bookmark name required"))
1245
1245
1246 if action in {b'add', b'delete', b'rename', b'inactive'}:
1246 if action in {b'add', b'delete', b'rename', b'inactive'}:
1247 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1247 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1248 if action == b'delete':
1248 if action == b'delete':
1249 names = pycompat.maplist(repo._bookmarks.expandname, names)
1249 names = pycompat.maplist(repo._bookmarks.expandname, names)
1250 bookmarks.delete(repo, tr, names)
1250 bookmarks.delete(repo, tr, names)
1251 elif action == b'rename':
1251 elif action == b'rename':
1252 if not names:
1252 if not names:
1253 raise error.Abort(_(b"new bookmark name required"))
1253 raise error.Abort(_(b"new bookmark name required"))
1254 elif len(names) > 1:
1254 elif len(names) > 1:
1255 raise error.Abort(_(b"only one new bookmark name allowed"))
1255 raise error.Abort(_(b"only one new bookmark name allowed"))
1256 oldname = repo._bookmarks.expandname(opts[b'rename'])
1256 oldname = repo._bookmarks.expandname(opts[b'rename'])
1257 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1257 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1258 elif action == b'add':
1258 elif action == b'add':
1259 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1259 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1260 elif action == b'inactive':
1260 elif action == b'inactive':
1261 if len(repo._bookmarks) == 0:
1261 if len(repo._bookmarks) == 0:
1262 ui.status(_(b"no bookmarks set\n"))
1262 ui.status(_(b"no bookmarks set\n"))
1263 elif not repo._activebookmark:
1263 elif not repo._activebookmark:
1264 ui.status(_(b"no active bookmark\n"))
1264 ui.status(_(b"no active bookmark\n"))
1265 else:
1265 else:
1266 bookmarks.deactivate(repo)
1266 bookmarks.deactivate(repo)
1267 elif action == b'list':
1267 elif action == b'list':
1268 names = pycompat.maplist(repo._bookmarks.expandname, names)
1268 names = pycompat.maplist(repo._bookmarks.expandname, names)
1269 with ui.formatter(b'bookmarks', opts) as fm:
1269 with ui.formatter(b'bookmarks', opts) as fm:
1270 bookmarks.printbookmarks(ui, repo, fm, names)
1270 bookmarks.printbookmarks(ui, repo, fm, names)
1271 else:
1271 else:
1272 raise error.ProgrammingError(b'invalid action: %s' % action)
1272 raise error.ProgrammingError(b'invalid action: %s' % action)
1273
1273
1274
1274
1275 @command(
1275 @command(
1276 b'branch',
1276 b'branch',
1277 [
1277 [
1278 (
1278 (
1279 b'f',
1279 b'f',
1280 b'force',
1280 b'force',
1281 None,
1281 None,
1282 _(b'set branch name even if it shadows an existing branch'),
1282 _(b'set branch name even if it shadows an existing branch'),
1283 ),
1283 ),
1284 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1284 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1285 (
1285 (
1286 b'r',
1286 b'r',
1287 b'rev',
1287 b'rev',
1288 [],
1288 [],
1289 _(b'change branches of the given revs (EXPERIMENTAL)'),
1289 _(b'change branches of the given revs (EXPERIMENTAL)'),
1290 ),
1290 ),
1291 ],
1291 ],
1292 _(b'[-fC] [NAME]'),
1292 _(b'[-fC] [NAME]'),
1293 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1293 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1294 )
1294 )
1295 def branch(ui, repo, label=None, **opts):
1295 def branch(ui, repo, label=None, **opts):
1296 """set or show the current branch name
1296 """set or show the current branch name
1297
1297
1298 .. note::
1298 .. note::
1299
1299
1300 Branch names are permanent and global. Use :hg:`bookmark` to create a
1300 Branch names are permanent and global. Use :hg:`bookmark` to create a
1301 light-weight bookmark instead. See :hg:`help glossary` for more
1301 light-weight bookmark instead. See :hg:`help glossary` for more
1302 information about named branches and bookmarks.
1302 information about named branches and bookmarks.
1303
1303
1304 With no argument, show the current branch name. With one argument,
1304 With no argument, show the current branch name. With one argument,
1305 set the working directory branch name (the branch will not exist
1305 set the working directory branch name (the branch will not exist
1306 in the repository until the next commit). Standard practice
1306 in the repository until the next commit). Standard practice
1307 recommends that primary development take place on the 'default'
1307 recommends that primary development take place on the 'default'
1308 branch.
1308 branch.
1309
1309
1310 Unless -f/--force is specified, branch will not let you set a
1310 Unless -f/--force is specified, branch will not let you set a
1311 branch name that already exists.
1311 branch name that already exists.
1312
1312
1313 Use -C/--clean to reset the working directory branch to that of
1313 Use -C/--clean to reset the working directory branch to that of
1314 the parent of the working directory, negating a previous branch
1314 the parent of the working directory, negating a previous branch
1315 change.
1315 change.
1316
1316
1317 Use the command :hg:`update` to switch to an existing branch. Use
1317 Use the command :hg:`update` to switch to an existing branch. Use
1318 :hg:`commit --close-branch` to mark this branch head as closed.
1318 :hg:`commit --close-branch` to mark this branch head as closed.
1319 When all heads of a branch are closed, the branch will be
1319 When all heads of a branch are closed, the branch will be
1320 considered closed.
1320 considered closed.
1321
1321
1322 Returns 0 on success.
1322 Returns 0 on success.
1323 """
1323 """
1324 opts = pycompat.byteskwargs(opts)
1324 opts = pycompat.byteskwargs(opts)
1325 revs = opts.get(b'rev')
1325 revs = opts.get(b'rev')
1326 if label:
1326 if label:
1327 label = label.strip()
1327 label = label.strip()
1328
1328
1329 if not opts.get(b'clean') and not label:
1329 if not opts.get(b'clean') and not label:
1330 if revs:
1330 if revs:
1331 raise error.Abort(_(b"no branch name specified for the revisions"))
1331 raise error.Abort(_(b"no branch name specified for the revisions"))
1332 ui.write(b"%s\n" % repo.dirstate.branch())
1332 ui.write(b"%s\n" % repo.dirstate.branch())
1333 return
1333 return
1334
1334
1335 with repo.wlock():
1335 with repo.wlock():
1336 if opts.get(b'clean'):
1336 if opts.get(b'clean'):
1337 label = repo[b'.'].branch()
1337 label = repo[b'.'].branch()
1338 repo.dirstate.setbranch(label)
1338 repo.dirstate.setbranch(label)
1339 ui.status(_(b'reset working directory to branch %s\n') % label)
1339 ui.status(_(b'reset working directory to branch %s\n') % label)
1340 elif label:
1340 elif label:
1341
1341
1342 scmutil.checknewlabel(repo, label, b'branch')
1342 scmutil.checknewlabel(repo, label, b'branch')
1343 if revs:
1343 if revs:
1344 return cmdutil.changebranch(ui, repo, revs, label, opts)
1344 return cmdutil.changebranch(ui, repo, revs, label, opts)
1345
1345
1346 if not opts.get(b'force') and label in repo.branchmap():
1346 if not opts.get(b'force') and label in repo.branchmap():
1347 if label not in [p.branch() for p in repo[None].parents()]:
1347 if label not in [p.branch() for p in repo[None].parents()]:
1348 raise error.Abort(
1348 raise error.Abort(
1349 _(b'a branch of the same name already exists'),
1349 _(b'a branch of the same name already exists'),
1350 # i18n: "it" refers to an existing branch
1350 # i18n: "it" refers to an existing branch
1351 hint=_(b"use 'hg update' to switch to it"),
1351 hint=_(b"use 'hg update' to switch to it"),
1352 )
1352 )
1353
1353
1354 repo.dirstate.setbranch(label)
1354 repo.dirstate.setbranch(label)
1355 ui.status(_(b'marked working directory as branch %s\n') % label)
1355 ui.status(_(b'marked working directory as branch %s\n') % label)
1356
1356
1357 # find any open named branches aside from default
1357 # find any open named branches aside from default
1358 for n, h, t, c in repo.branchmap().iterbranches():
1358 for n, h, t, c in repo.branchmap().iterbranches():
1359 if n != b"default" and not c:
1359 if n != b"default" and not c:
1360 return 0
1360 return 0
1361 ui.status(
1361 ui.status(
1362 _(
1362 _(
1363 b'(branches are permanent and global, '
1363 b'(branches are permanent and global, '
1364 b'did you want a bookmark?)\n'
1364 b'did you want a bookmark?)\n'
1365 )
1365 )
1366 )
1366 )
1367
1367
1368
1368
1369 @command(
1369 @command(
1370 b'branches',
1370 b'branches',
1371 [
1371 [
1372 (
1372 (
1373 b'a',
1373 b'a',
1374 b'active',
1374 b'active',
1375 False,
1375 False,
1376 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1376 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1377 ),
1377 ),
1378 (b'c', b'closed', False, _(b'show normal and closed branches')),
1378 (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')),
1379 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1380 ]
1380 ]
1381 + formatteropts,
1381 + formatteropts,
1382 _(b'[-c]'),
1382 _(b'[-c]'),
1383 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1383 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1384 intents={INTENT_READONLY},
1384 intents={INTENT_READONLY},
1385 )
1385 )
1386 def branches(ui, repo, active=False, closed=False, **opts):
1386 def branches(ui, repo, active=False, closed=False, **opts):
1387 """list repository named branches
1387 """list repository named branches
1388
1388
1389 List the repository's named branches, indicating which ones are
1389 List the repository's named branches, indicating which ones are
1390 inactive. If -c/--closed is specified, also list branches which have
1390 inactive. If -c/--closed is specified, also list branches which have
1391 been marked closed (see :hg:`commit --close-branch`).
1391 been marked closed (see :hg:`commit --close-branch`).
1392
1392
1393 Use the command :hg:`update` to switch to an existing branch.
1393 Use the command :hg:`update` to switch to an existing branch.
1394
1394
1395 .. container:: verbose
1395 .. container:: verbose
1396
1396
1397 Template:
1397 Template:
1398
1398
1399 The following keywords are supported in addition to the common template
1399 The following keywords are supported in addition to the common template
1400 keywords and functions such as ``{branch}``. See also
1400 keywords and functions such as ``{branch}``. See also
1401 :hg:`help templates`.
1401 :hg:`help templates`.
1402
1402
1403 :active: Boolean. True if the branch is active.
1403 :active: Boolean. True if the branch is active.
1404 :closed: Boolean. True if the branch is closed.
1404 :closed: Boolean. True if the branch is closed.
1405 :current: Boolean. True if it is the current branch.
1405 :current: Boolean. True if it is the current branch.
1406
1406
1407 Returns 0.
1407 Returns 0.
1408 """
1408 """
1409
1409
1410 opts = pycompat.byteskwargs(opts)
1410 opts = pycompat.byteskwargs(opts)
1411 revs = opts.get(b'rev')
1411 revs = opts.get(b'rev')
1412 selectedbranches = None
1412 selectedbranches = None
1413 if revs:
1413 if revs:
1414 revs = scmutil.revrange(repo, revs)
1414 revs = scmutil.revrange(repo, revs)
1415 getbi = repo.revbranchcache().branchinfo
1415 getbi = repo.revbranchcache().branchinfo
1416 selectedbranches = {getbi(r)[0] for r in revs}
1416 selectedbranches = {getbi(r)[0] for r in revs}
1417
1417
1418 ui.pager(b'branches')
1418 ui.pager(b'branches')
1419 fm = ui.formatter(b'branches', opts)
1419 fm = ui.formatter(b'branches', opts)
1420 hexfunc = fm.hexfunc
1420 hexfunc = fm.hexfunc
1421
1421
1422 allheads = set(repo.heads())
1422 allheads = set(repo.heads())
1423 branches = []
1423 branches = []
1424 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1424 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1425 if selectedbranches is not None and tag not in selectedbranches:
1425 if selectedbranches is not None and tag not in selectedbranches:
1426 continue
1426 continue
1427 isactive = False
1427 isactive = False
1428 if not isclosed:
1428 if not isclosed:
1429 openheads = set(repo.branchmap().iteropen(heads))
1429 openheads = set(repo.branchmap().iteropen(heads))
1430 isactive = bool(openheads & allheads)
1430 isactive = bool(openheads & allheads)
1431 branches.append((tag, repo[tip], isactive, not isclosed))
1431 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)
1432 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1433
1433
1434 for tag, ctx, isactive, isopen in branches:
1434 for tag, ctx, isactive, isopen in branches:
1435 if active and not isactive:
1435 if active and not isactive:
1436 continue
1436 continue
1437 if isactive:
1437 if isactive:
1438 label = b'branches.active'
1438 label = b'branches.active'
1439 notice = b''
1439 notice = b''
1440 elif not isopen:
1440 elif not isopen:
1441 if not closed:
1441 if not closed:
1442 continue
1442 continue
1443 label = b'branches.closed'
1443 label = b'branches.closed'
1444 notice = _(b' (closed)')
1444 notice = _(b' (closed)')
1445 else:
1445 else:
1446 label = b'branches.inactive'
1446 label = b'branches.inactive'
1447 notice = _(b' (inactive)')
1447 notice = _(b' (inactive)')
1448 current = tag == repo.dirstate.branch()
1448 current = tag == repo.dirstate.branch()
1449 if current:
1449 if current:
1450 label = b'branches.current'
1450 label = b'branches.current'
1451
1451
1452 fm.startitem()
1452 fm.startitem()
1453 fm.write(b'branch', b'%s', tag, label=label)
1453 fm.write(b'branch', b'%s', tag, label=label)
1454 rev = ctx.rev()
1454 rev = ctx.rev()
1455 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1455 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1456 fmt = b' ' * padsize + b' %d:%s'
1456 fmt = b' ' * padsize + b' %d:%s'
1457 fm.condwrite(
1457 fm.condwrite(
1458 not ui.quiet,
1458 not ui.quiet,
1459 b'rev node',
1459 b'rev node',
1460 fmt,
1460 fmt,
1461 rev,
1461 rev,
1462 hexfunc(ctx.node()),
1462 hexfunc(ctx.node()),
1463 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1463 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1464 )
1464 )
1465 fm.context(ctx=ctx)
1465 fm.context(ctx=ctx)
1466 fm.data(active=isactive, closed=not isopen, current=current)
1466 fm.data(active=isactive, closed=not isopen, current=current)
1467 if not ui.quiet:
1467 if not ui.quiet:
1468 fm.plain(notice)
1468 fm.plain(notice)
1469 fm.plain(b'\n')
1469 fm.plain(b'\n')
1470 fm.end()
1470 fm.end()
1471
1471
1472
1472
1473 @command(
1473 @command(
1474 b'bundle',
1474 b'bundle',
1475 [
1475 [
1476 (
1476 (
1477 b'f',
1477 b'f',
1478 b'force',
1478 b'force',
1479 None,
1479 None,
1480 _(b'run even when the destination is unrelated'),
1480 _(b'run even when the destination is unrelated'),
1481 ),
1481 ),
1482 (
1482 (
1483 b'r',
1483 b'r',
1484 b'rev',
1484 b'rev',
1485 [],
1485 [],
1486 _(b'a changeset intended to be added to the destination'),
1486 _(b'a changeset intended to be added to the destination'),
1487 _(b'REV'),
1487 _(b'REV'),
1488 ),
1488 ),
1489 (
1489 (
1490 b'b',
1490 b'b',
1491 b'branch',
1491 b'branch',
1492 [],
1492 [],
1493 _(b'a specific branch you would like to bundle'),
1493 _(b'a specific branch you would like to bundle'),
1494 _(b'BRANCH'),
1494 _(b'BRANCH'),
1495 ),
1495 ),
1496 (
1496 (
1497 b'',
1497 b'',
1498 b'base',
1498 b'base',
1499 [],
1499 [],
1500 _(b'a base changeset assumed to be available at the destination'),
1500 _(b'a base changeset assumed to be available at the destination'),
1501 _(b'REV'),
1501 _(b'REV'),
1502 ),
1502 ),
1503 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1503 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1504 (
1504 (
1505 b't',
1505 b't',
1506 b'type',
1506 b'type',
1507 b'bzip2',
1507 b'bzip2',
1508 _(b'bundle compression type to use'),
1508 _(b'bundle compression type to use'),
1509 _(b'TYPE'),
1509 _(b'TYPE'),
1510 ),
1510 ),
1511 ]
1511 ]
1512 + remoteopts,
1512 + remoteopts,
1513 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1513 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1514 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1514 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1515 )
1515 )
1516 def bundle(ui, repo, fname, dest=None, **opts):
1516 def bundle(ui, repo, fname, dest=None, **opts):
1517 """create a bundle file
1517 """create a bundle file
1518
1518
1519 Generate a bundle file containing data to be transferred to another
1519 Generate a bundle file containing data to be transferred to another
1520 repository.
1520 repository.
1521
1521
1522 To create a bundle containing all changesets, use -a/--all
1522 To create a bundle containing all changesets, use -a/--all
1523 (or --base null). Otherwise, hg assumes the destination will have
1523 (or --base null). Otherwise, hg assumes the destination will have
1524 all the nodes you specify with --base parameters. Otherwise, hg
1524 all the nodes you specify with --base parameters. Otherwise, hg
1525 will assume the repository has all the nodes in destination, or
1525 will assume the repository has all the nodes in destination, or
1526 default-push/default if no destination is specified, where destination
1526 default-push/default if no destination is specified, where destination
1527 is the repository you provide through DEST option.
1527 is the repository you provide through DEST option.
1528
1528
1529 You can change bundle format with the -t/--type option. See
1529 You can change bundle format with the -t/--type option. See
1530 :hg:`help bundlespec` for documentation on this format. By default,
1530 :hg:`help bundlespec` for documentation on this format. By default,
1531 the most appropriate format is used and compression defaults to
1531 the most appropriate format is used and compression defaults to
1532 bzip2.
1532 bzip2.
1533
1533
1534 The bundle file can then be transferred using conventional means
1534 The bundle file can then be transferred using conventional means
1535 and applied to another repository with the unbundle or pull
1535 and applied to another repository with the unbundle or pull
1536 command. This is useful when direct push and pull are not
1536 command. This is useful when direct push and pull are not
1537 available or when exporting an entire repository is undesirable.
1537 available or when exporting an entire repository is undesirable.
1538
1538
1539 Applying bundles preserves all changeset contents including
1539 Applying bundles preserves all changeset contents including
1540 permissions, copy/rename information, and revision history.
1540 permissions, copy/rename information, and revision history.
1541
1541
1542 Returns 0 on success, 1 if no changes found.
1542 Returns 0 on success, 1 if no changes found.
1543 """
1543 """
1544 opts = pycompat.byteskwargs(opts)
1544 opts = pycompat.byteskwargs(opts)
1545 revs = None
1545 revs = None
1546 if b'rev' in opts:
1546 if b'rev' in opts:
1547 revstrings = opts[b'rev']
1547 revstrings = opts[b'rev']
1548 revs = scmutil.revrange(repo, revstrings)
1548 revs = scmutil.revrange(repo, revstrings)
1549 if revstrings and not revs:
1549 if revstrings and not revs:
1550 raise error.Abort(_(b'no commits to bundle'))
1550 raise error.Abort(_(b'no commits to bundle'))
1551
1551
1552 bundletype = opts.get(b'type', b'bzip2').lower()
1552 bundletype = opts.get(b'type', b'bzip2').lower()
1553 try:
1553 try:
1554 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1554 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1555 except error.UnsupportedBundleSpecification as e:
1555 except error.UnsupportedBundleSpecification as e:
1556 raise error.Abort(
1556 raise error.Abort(
1557 pycompat.bytestr(e),
1557 pycompat.bytestr(e),
1558 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1558 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1559 )
1559 )
1560 cgversion = bundlespec.contentopts[b"cg.version"]
1560 cgversion = bundlespec.contentopts[b"cg.version"]
1561
1561
1562 # Packed bundles are a pseudo bundle format for now.
1562 # Packed bundles are a pseudo bundle format for now.
1563 if cgversion == b's1':
1563 if cgversion == b's1':
1564 raise error.Abort(
1564 raise error.Abort(
1565 _(b'packed bundles cannot be produced by "hg bundle"'),
1565 _(b'packed bundles cannot be produced by "hg bundle"'),
1566 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1566 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1567 )
1567 )
1568
1568
1569 if opts.get(b'all'):
1569 if opts.get(b'all'):
1570 if dest:
1570 if dest:
1571 raise error.Abort(
1571 raise error.Abort(
1572 _(b"--all is incompatible with specifying a destination")
1572 _(b"--all is incompatible with specifying a destination")
1573 )
1573 )
1574 if opts.get(b'base'):
1574 if opts.get(b'base'):
1575 ui.warn(_(b"ignoring --base because --all was specified\n"))
1575 ui.warn(_(b"ignoring --base because --all was specified\n"))
1576 base = [nullrev]
1576 base = [nullrev]
1577 else:
1577 else:
1578 base = scmutil.revrange(repo, opts.get(b'base'))
1578 base = scmutil.revrange(repo, opts.get(b'base'))
1579 if cgversion not in changegroup.supportedoutgoingversions(repo):
1579 if cgversion not in changegroup.supportedoutgoingversions(repo):
1580 raise error.Abort(
1580 raise error.Abort(
1581 _(b"repository does not support bundle version %s") % cgversion
1581 _(b"repository does not support bundle version %s") % cgversion
1582 )
1582 )
1583
1583
1584 if base:
1584 if base:
1585 if dest:
1585 if dest:
1586 raise error.Abort(
1586 raise error.Abort(
1587 _(b"--base is incompatible with specifying a destination")
1587 _(b"--base is incompatible with specifying a destination")
1588 )
1588 )
1589 common = [repo[rev].node() for rev in base]
1589 common = [repo[rev].node() for rev in base]
1590 heads = [repo[r].node() for r in revs] if revs else None
1590 heads = [repo[r].node() for r in revs] if revs else None
1591 outgoing = discovery.outgoing(repo, common, heads)
1591 outgoing = discovery.outgoing(repo, common, heads)
1592 else:
1592 else:
1593 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1593 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1594 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1594 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1595 other = hg.peer(repo, opts, dest)
1595 other = hg.peer(repo, opts, dest)
1596 revs = [repo[r].hex() for r in revs]
1596 revs = [repo[r].hex() for r in revs]
1597 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1597 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1598 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1598 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1599 outgoing = discovery.findcommonoutgoing(
1599 outgoing = discovery.findcommonoutgoing(
1600 repo,
1600 repo,
1601 other,
1601 other,
1602 onlyheads=heads,
1602 onlyheads=heads,
1603 force=opts.get(b'force'),
1603 force=opts.get(b'force'),
1604 portable=True,
1604 portable=True,
1605 )
1605 )
1606
1606
1607 if not outgoing.missing:
1607 if not outgoing.missing:
1608 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1608 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1609 return 1
1609 return 1
1610
1610
1611 if cgversion == b'01': # bundle1
1611 if cgversion == b'01': # bundle1
1612 bversion = b'HG10' + bundlespec.wirecompression
1612 bversion = b'HG10' + bundlespec.wirecompression
1613 bcompression = None
1613 bcompression = None
1614 elif cgversion in (b'02', b'03'):
1614 elif cgversion in (b'02', b'03'):
1615 bversion = b'HG20'
1615 bversion = b'HG20'
1616 bcompression = bundlespec.wirecompression
1616 bcompression = bundlespec.wirecompression
1617 else:
1617 else:
1618 raise error.ProgrammingError(
1618 raise error.ProgrammingError(
1619 b'bundle: unexpected changegroup version %s' % cgversion
1619 b'bundle: unexpected changegroup version %s' % cgversion
1620 )
1620 )
1621
1621
1622 # TODO compression options should be derived from bundlespec parsing.
1622 # TODO compression options should be derived from bundlespec parsing.
1623 # This is a temporary hack to allow adjusting bundle compression
1623 # This is a temporary hack to allow adjusting bundle compression
1624 # level without a) formalizing the bundlespec changes to declare it
1624 # level without a) formalizing the bundlespec changes to declare it
1625 # b) introducing a command flag.
1625 # b) introducing a command flag.
1626 compopts = {}
1626 compopts = {}
1627 complevel = ui.configint(
1627 complevel = ui.configint(
1628 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1628 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1629 )
1629 )
1630 if complevel is None:
1630 if complevel is None:
1631 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1631 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1632 if complevel is not None:
1632 if complevel is not None:
1633 compopts[b'level'] = complevel
1633 compopts[b'level'] = complevel
1634
1634
1635 # Allow overriding the bundling of obsmarker in phases through
1635 # Allow overriding the bundling of obsmarker in phases through
1636 # configuration while we don't have a bundle version that include them
1636 # configuration while we don't have a bundle version that include them
1637 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1637 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1638 bundlespec.contentopts[b'obsolescence'] = True
1638 bundlespec.contentopts[b'obsolescence'] = True
1639 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1639 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1640 bundlespec.contentopts[b'phases'] = True
1640 bundlespec.contentopts[b'phases'] = True
1641
1641
1642 bundle2.writenewbundle(
1642 bundle2.writenewbundle(
1643 ui,
1643 ui,
1644 repo,
1644 repo,
1645 b'bundle',
1645 b'bundle',
1646 fname,
1646 fname,
1647 bversion,
1647 bversion,
1648 outgoing,
1648 outgoing,
1649 bundlespec.contentopts,
1649 bundlespec.contentopts,
1650 compression=bcompression,
1650 compression=bcompression,
1651 compopts=compopts,
1651 compopts=compopts,
1652 )
1652 )
1653
1653
1654
1654
1655 @command(
1655 @command(
1656 b'cat',
1656 b'cat',
1657 [
1657 [
1658 (
1658 (
1659 b'o',
1659 b'o',
1660 b'output',
1660 b'output',
1661 b'',
1661 b'',
1662 _(b'print output to file with formatted name'),
1662 _(b'print output to file with formatted name'),
1663 _(b'FORMAT'),
1663 _(b'FORMAT'),
1664 ),
1664 ),
1665 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1665 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1666 (b'', b'decode', None, _(b'apply any matching decode filter')),
1666 (b'', b'decode', None, _(b'apply any matching decode filter')),
1667 ]
1667 ]
1668 + walkopts
1668 + walkopts
1669 + formatteropts,
1669 + formatteropts,
1670 _(b'[OPTION]... FILE...'),
1670 _(b'[OPTION]... FILE...'),
1671 helpcategory=command.CATEGORY_FILE_CONTENTS,
1671 helpcategory=command.CATEGORY_FILE_CONTENTS,
1672 inferrepo=True,
1672 inferrepo=True,
1673 intents={INTENT_READONLY},
1673 intents={INTENT_READONLY},
1674 )
1674 )
1675 def cat(ui, repo, file1, *pats, **opts):
1675 def cat(ui, repo, file1, *pats, **opts):
1676 """output the current or given revision of files
1676 """output the current or given revision of files
1677
1677
1678 Print the specified files as they were at the given revision. If
1678 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.
1679 no revision is given, the parent of the working directory is used.
1680
1680
1681 Output may be to a file, in which case the name of the file is
1681 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
1682 given using a template string. See :hg:`help templates`. In addition
1683 to the common template keywords, the following formatting rules are
1683 to the common template keywords, the following formatting rules are
1684 supported:
1684 supported:
1685
1685
1686 :``%%``: literal "%" character
1686 :``%%``: literal "%" character
1687 :``%s``: basename of file being printed
1687 :``%s``: basename of file being printed
1688 :``%d``: dirname of file being printed, or '.' if in repository root
1688 :``%d``: dirname of file being printed, or '.' if in repository root
1689 :``%p``: root-relative path name of file being printed
1689 :``%p``: root-relative path name of file being printed
1690 :``%H``: changeset hash (40 hexadecimal digits)
1690 :``%H``: changeset hash (40 hexadecimal digits)
1691 :``%R``: changeset revision number
1691 :``%R``: changeset revision number
1692 :``%h``: short-form changeset hash (12 hexadecimal digits)
1692 :``%h``: short-form changeset hash (12 hexadecimal digits)
1693 :``%r``: zero-padded changeset revision number
1693 :``%r``: zero-padded changeset revision number
1694 :``%b``: basename of the exporting repository
1694 :``%b``: basename of the exporting repository
1695 :``\\``: literal "\\" character
1695 :``\\``: literal "\\" character
1696
1696
1697 .. container:: verbose
1697 .. container:: verbose
1698
1698
1699 Template:
1699 Template:
1700
1700
1701 The following keywords are supported in addition to the common template
1701 The following keywords are supported in addition to the common template
1702 keywords and functions. See also :hg:`help templates`.
1702 keywords and functions. See also :hg:`help templates`.
1703
1703
1704 :data: String. File content.
1704 :data: String. File content.
1705 :path: String. Repository-absolute path of the file.
1705 :path: String. Repository-absolute path of the file.
1706
1706
1707 Returns 0 on success.
1707 Returns 0 on success.
1708 """
1708 """
1709 opts = pycompat.byteskwargs(opts)
1709 opts = pycompat.byteskwargs(opts)
1710 rev = opts.get(b'rev')
1710 rev = opts.get(b'rev')
1711 if rev:
1711 if rev:
1712 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1712 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1713 ctx = scmutil.revsingle(repo, rev)
1713 ctx = scmutil.revsingle(repo, rev)
1714 m = scmutil.match(ctx, (file1,) + pats, opts)
1714 m = scmutil.match(ctx, (file1,) + pats, opts)
1715 fntemplate = opts.pop(b'output', b'')
1715 fntemplate = opts.pop(b'output', b'')
1716 if cmdutil.isstdiofilename(fntemplate):
1716 if cmdutil.isstdiofilename(fntemplate):
1717 fntemplate = b''
1717 fntemplate = b''
1718
1718
1719 if fntemplate:
1719 if fntemplate:
1720 fm = formatter.nullformatter(ui, b'cat', opts)
1720 fm = formatter.nullformatter(ui, b'cat', opts)
1721 else:
1721 else:
1722 ui.pager(b'cat')
1722 ui.pager(b'cat')
1723 fm = ui.formatter(b'cat', opts)
1723 fm = ui.formatter(b'cat', opts)
1724 with fm:
1724 with fm:
1725 return cmdutil.cat(
1725 return cmdutil.cat(
1726 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1726 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1727 )
1727 )
1728
1728
1729
1729
1730 @command(
1730 @command(
1731 b'clone',
1731 b'clone',
1732 [
1732 [
1733 (
1733 (
1734 b'U',
1734 b'U',
1735 b'noupdate',
1735 b'noupdate',
1736 None,
1736 None,
1737 _(
1737 _(
1738 b'the clone will include an empty working '
1738 b'the clone will include an empty working '
1739 b'directory (only a repository)'
1739 b'directory (only a repository)'
1740 ),
1740 ),
1741 ),
1741 ),
1742 (
1742 (
1743 b'u',
1743 b'u',
1744 b'updaterev',
1744 b'updaterev',
1745 b'',
1745 b'',
1746 _(b'revision, tag, or branch to check out'),
1746 _(b'revision, tag, or branch to check out'),
1747 _(b'REV'),
1747 _(b'REV'),
1748 ),
1748 ),
1749 (
1749 (
1750 b'r',
1750 b'r',
1751 b'rev',
1751 b'rev',
1752 [],
1752 [],
1753 _(
1753 _(
1754 b'do not clone everything, but include this changeset'
1754 b'do not clone everything, but include this changeset'
1755 b' and its ancestors'
1755 b' and its ancestors'
1756 ),
1756 ),
1757 _(b'REV'),
1757 _(b'REV'),
1758 ),
1758 ),
1759 (
1759 (
1760 b'b',
1760 b'b',
1761 b'branch',
1761 b'branch',
1762 [],
1762 [],
1763 _(
1763 _(
1764 b'do not clone everything, but include this branch\'s'
1764 b'do not clone everything, but include this branch\'s'
1765 b' changesets and their ancestors'
1765 b' changesets and their ancestors'
1766 ),
1766 ),
1767 _(b'BRANCH'),
1767 _(b'BRANCH'),
1768 ),
1768 ),
1769 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1769 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1770 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1770 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1771 (b'', b'stream', None, _(b'clone with minimal data processing')),
1771 (b'', b'stream', None, _(b'clone with minimal data processing')),
1772 ]
1772 ]
1773 + remoteopts,
1773 + remoteopts,
1774 _(b'[OPTION]... SOURCE [DEST]'),
1774 _(b'[OPTION]... SOURCE [DEST]'),
1775 helpcategory=command.CATEGORY_REPO_CREATION,
1775 helpcategory=command.CATEGORY_REPO_CREATION,
1776 helpbasic=True,
1776 helpbasic=True,
1777 norepo=True,
1777 norepo=True,
1778 )
1778 )
1779 def clone(ui, source, dest=None, **opts):
1779 def clone(ui, source, dest=None, **opts):
1780 """make a copy of an existing repository
1780 """make a copy of an existing repository
1781
1781
1782 Create a copy of an existing repository in a new directory.
1782 Create a copy of an existing repository in a new directory.
1783
1783
1784 If no destination directory name is specified, it defaults to the
1784 If no destination directory name is specified, it defaults to the
1785 basename of the source.
1785 basename of the source.
1786
1786
1787 The location of the source is added to the new repository's
1787 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.
1788 ``.hg/hgrc`` file, as the default to be used for future pulls.
1789
1789
1790 Only local paths and ``ssh://`` URLs are supported as
1790 Only local paths and ``ssh://`` URLs are supported as
1791 destinations. For ``ssh://`` destinations, no working directory or
1791 destinations. For ``ssh://`` destinations, no working directory or
1792 ``.hg/hgrc`` will be created on the remote side.
1792 ``.hg/hgrc`` will be created on the remote side.
1793
1793
1794 If the source repository has a bookmark called '@' set, that
1794 If the source repository has a bookmark called '@' set, that
1795 revision will be checked out in the new repository by default.
1795 revision will be checked out in the new repository by default.
1796
1796
1797 To check out a particular version, use -u/--update, or
1797 To check out a particular version, use -u/--update, or
1798 -U/--noupdate to create a clone with no working directory.
1798 -U/--noupdate to create a clone with no working directory.
1799
1799
1800 To pull only a subset of changesets, specify one or more revisions
1800 To pull only a subset of changesets, specify one or more revisions
1801 identifiers with -r/--rev or branches with -b/--branch. The
1801 identifiers with -r/--rev or branches with -b/--branch. The
1802 resulting clone will contain only the specified changesets and
1802 resulting clone will contain only the specified changesets and
1803 their ancestors. These options (or 'clone src#rev dest') imply
1803 their ancestors. These options (or 'clone src#rev dest') imply
1804 --pull, even for local source repositories.
1804 --pull, even for local source repositories.
1805
1805
1806 In normal clone mode, the remote normalizes repository data into a common
1806 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
1807 exchange format and the receiving end translates this data into its local
1808 storage format. --stream activates a different clone mode that essentially
1808 storage format. --stream activates a different clone mode that essentially
1809 copies repository files from the remote with minimal data processing. This
1809 copies repository files from the remote with minimal data processing. This
1810 significantly reduces the CPU cost of a clone both remotely and locally.
1810 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
1811 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,
1812 result in substantially faster clones where I/O throughput is plentiful,
1813 especially for larger repositories. A side-effect of --stream clones is
1813 especially for larger repositories. A side-effect of --stream clones is
1814 that storage settings and requirements on the remote are applied locally:
1814 that storage settings and requirements on the remote are applied locally:
1815 a modern client may inherit legacy or inefficient storage used by the
1815 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
1816 remote or a legacy Mercurial client may not be able to clone from a
1817 modern Mercurial remote.
1817 modern Mercurial remote.
1818
1818
1819 .. note::
1819 .. note::
1820
1820
1821 Specifying a tag will include the tagged changeset but not the
1821 Specifying a tag will include the tagged changeset but not the
1822 changeset containing the tag.
1822 changeset containing the tag.
1823
1823
1824 .. container:: verbose
1824 .. container:: verbose
1825
1825
1826 For efficiency, hardlinks are used for cloning whenever the
1826 For efficiency, hardlinks are used for cloning whenever the
1827 source and destination are on the same filesystem (note this
1827 source and destination are on the same filesystem (note this
1828 applies only to the repository data, not to the working
1828 applies only to the repository data, not to the working
1829 directory). Some filesystems, such as AFS, implement hardlinking
1829 directory). Some filesystems, such as AFS, implement hardlinking
1830 incorrectly, but do not report errors. In these cases, use the
1830 incorrectly, but do not report errors. In these cases, use the
1831 --pull option to avoid hardlinking.
1831 --pull option to avoid hardlinking.
1832
1832
1833 Mercurial will update the working directory to the first applicable
1833 Mercurial will update the working directory to the first applicable
1834 revision from this list:
1834 revision from this list:
1835
1835
1836 a) null if -U or the source repository has no changesets
1836 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
1837 b) if -u . and the source repository is local, the first parent of
1838 the source repository's working directory
1838 the source repository's working directory
1839 c) the changeset specified with -u (if a branch name, this means the
1839 c) the changeset specified with -u (if a branch name, this means the
1840 latest head of that branch)
1840 latest head of that branch)
1841 d) the changeset specified with -r
1841 d) the changeset specified with -r
1842 e) the tipmost head specified with -b
1842 e) the tipmost head specified with -b
1843 f) the tipmost head specified with the url#branch source syntax
1843 f) the tipmost head specified with the url#branch source syntax
1844 g) the revision marked with the '@' bookmark, if present
1844 g) the revision marked with the '@' bookmark, if present
1845 h) the tipmost head of the default branch
1845 h) the tipmost head of the default branch
1846 i) tip
1846 i) tip
1847
1847
1848 When cloning from servers that support it, Mercurial may fetch
1848 When cloning from servers that support it, Mercurial may fetch
1849 pre-generated data from a server-advertised URL or inline from the
1849 pre-generated data from a server-advertised URL or inline from the
1850 same stream. When this is done, hooks operating on incoming changesets
1850 same stream. When this is done, hooks operating on incoming changesets
1851 and changegroups may fire more than once, once for each pre-generated
1851 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,
1852 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
1853 if an error occurs, the repository may be rolled back to a partial
1854 clone. This behavior may change in future releases.
1854 clone. This behavior may change in future releases.
1855 See :hg:`help -e clonebundles` for more.
1855 See :hg:`help -e clonebundles` for more.
1856
1856
1857 Examples:
1857 Examples:
1858
1858
1859 - clone a remote repository to a new directory named hg/::
1859 - clone a remote repository to a new directory named hg/::
1860
1860
1861 hg clone https://www.mercurial-scm.org/repo/hg/
1861 hg clone https://www.mercurial-scm.org/repo/hg/
1862
1862
1863 - create a lightweight local clone::
1863 - create a lightweight local clone::
1864
1864
1865 hg clone project/ project-feature/
1865 hg clone project/ project-feature/
1866
1866
1867 - clone from an absolute path on an ssh server (note double-slash)::
1867 - clone from an absolute path on an ssh server (note double-slash)::
1868
1868
1869 hg clone ssh://user@server//home/projects/alpha/
1869 hg clone ssh://user@server//home/projects/alpha/
1870
1870
1871 - do a streaming clone while checking out a specified version::
1871 - do a streaming clone while checking out a specified version::
1872
1872
1873 hg clone --stream http://server/repo -u 1.5
1873 hg clone --stream http://server/repo -u 1.5
1874
1874
1875 - create a repository without changesets after a particular revision::
1875 - create a repository without changesets after a particular revision::
1876
1876
1877 hg clone -r 04e544 experimental/ good/
1877 hg clone -r 04e544 experimental/ good/
1878
1878
1879 - clone (and track) a particular named branch::
1879 - clone (and track) a particular named branch::
1880
1880
1881 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1881 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1882
1882
1883 See :hg:`help urls` for details on specifying URLs.
1883 See :hg:`help urls` for details on specifying URLs.
1884
1884
1885 Returns 0 on success.
1885 Returns 0 on success.
1886 """
1886 """
1887 opts = pycompat.byteskwargs(opts)
1887 opts = pycompat.byteskwargs(opts)
1888 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1888 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1889
1889
1890 # --include/--exclude can come from narrow or sparse.
1890 # --include/--exclude can come from narrow or sparse.
1891 includepats, excludepats = None, None
1891 includepats, excludepats = None, None
1892
1892
1893 # hg.clone() differentiates between None and an empty set. So make sure
1893 # hg.clone() differentiates between None and an empty set. So make sure
1894 # patterns are sets if narrow is requested without patterns.
1894 # patterns are sets if narrow is requested without patterns.
1895 if opts.get(b'narrow'):
1895 if opts.get(b'narrow'):
1896 includepats = set()
1896 includepats = set()
1897 excludepats = set()
1897 excludepats = set()
1898
1898
1899 if opts.get(b'include'):
1899 if opts.get(b'include'):
1900 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1900 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1901 if opts.get(b'exclude'):
1901 if opts.get(b'exclude'):
1902 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1902 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1903
1903
1904 r = hg.clone(
1904 r = hg.clone(
1905 ui,
1905 ui,
1906 opts,
1906 opts,
1907 source,
1907 source,
1908 dest,
1908 dest,
1909 pull=opts.get(b'pull'),
1909 pull=opts.get(b'pull'),
1910 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1910 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1911 revs=opts.get(b'rev'),
1911 revs=opts.get(b'rev'),
1912 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1912 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1913 branch=opts.get(b'branch'),
1913 branch=opts.get(b'branch'),
1914 shareopts=opts.get(b'shareopts'),
1914 shareopts=opts.get(b'shareopts'),
1915 storeincludepats=includepats,
1915 storeincludepats=includepats,
1916 storeexcludepats=excludepats,
1916 storeexcludepats=excludepats,
1917 depth=opts.get(b'depth') or None,
1917 depth=opts.get(b'depth') or None,
1918 )
1918 )
1919
1919
1920 return r is None
1920 return r is None
1921
1921
1922
1922
1923 @command(
1923 @command(
1924 b'commit|ci',
1924 b'commit|ci',
1925 [
1925 [
1926 (
1926 (
1927 b'A',
1927 b'A',
1928 b'addremove',
1928 b'addremove',
1929 None,
1929 None,
1930 _(b'mark new/missing files as added/removed before committing'),
1930 _(b'mark new/missing files as added/removed before committing'),
1931 ),
1931 ),
1932 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1932 (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')),
1933 (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')),
1934 (b's', b'secret', None, _(b'use the secret phase for committing')),
1935 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1935 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1936 (
1936 (
1937 b'',
1937 b'',
1938 b'force-close-branch',
1938 b'force-close-branch',
1939 None,
1939 None,
1940 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1940 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1941 ),
1941 ),
1942 (b'i', b'interactive', None, _(b'use interactive mode')),
1942 (b'i', b'interactive', None, _(b'use interactive mode')),
1943 ]
1943 ]
1944 + walkopts
1944 + walkopts
1945 + commitopts
1945 + commitopts
1946 + commitopts2
1946 + commitopts2
1947 + subrepoopts,
1947 + subrepoopts,
1948 _(b'[OPTION]... [FILE]...'),
1948 _(b'[OPTION]... [FILE]...'),
1949 helpcategory=command.CATEGORY_COMMITTING,
1949 helpcategory=command.CATEGORY_COMMITTING,
1950 helpbasic=True,
1950 helpbasic=True,
1951 inferrepo=True,
1951 inferrepo=True,
1952 )
1952 )
1953 def commit(ui, repo, *pats, **opts):
1953 def commit(ui, repo, *pats, **opts):
1954 """commit the specified files or all outstanding changes
1954 """commit the specified files or all outstanding changes
1955
1955
1956 Commit changes to the given files into the repository. Unlike a
1956 Commit changes to the given files into the repository. Unlike a
1957 centralized SCM, this operation is a local operation. See
1957 centralized SCM, this operation is a local operation. See
1958 :hg:`push` for a way to actively distribute your changes.
1958 :hg:`push` for a way to actively distribute your changes.
1959
1959
1960 If a list of files is omitted, all changes reported by :hg:`status`
1960 If a list of files is omitted, all changes reported by :hg:`status`
1961 will be committed.
1961 will be committed.
1962
1962
1963 If you are committing the result of a merge, do not provide any
1963 If you are committing the result of a merge, do not provide any
1964 filenames or -I/-X filters.
1964 filenames or -I/-X filters.
1965
1965
1966 If no commit message is specified, Mercurial starts your
1966 If no commit message is specified, Mercurial starts your
1967 configured editor where you can enter a message. In case your
1967 configured editor where you can enter a message. In case your
1968 commit fails, you will find a backup of your message in
1968 commit fails, you will find a backup of your message in
1969 ``.hg/last-message.txt``.
1969 ``.hg/last-message.txt``.
1970
1970
1971 The --close-branch flag can be used to mark the current branch
1971 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
1972 head closed. When all heads of a branch are closed, the branch
1973 will be considered closed and no longer listed.
1973 will be considered closed and no longer listed.
1974
1974
1975 The --amend flag can be used to amend the parent of the
1975 The --amend flag can be used to amend the parent of the
1976 working directory with a new commit that contains the changes
1976 working directory with a new commit that contains the changes
1977 in the parent in addition to those currently reported by :hg:`status`,
1977 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
1978 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`
1979 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1980 on how to restore it).
1980 on how to restore it).
1981
1981
1982 Message, user and date are taken from the amended commit unless
1982 Message, user and date are taken from the amended commit unless
1983 specified. When a message isn't specified on the command line,
1983 specified. When a message isn't specified on the command line,
1984 the editor will open with the message of the amended commit.
1984 the editor will open with the message of the amended commit.
1985
1985
1986 It is not possible to amend public changesets (see :hg:`help phases`)
1986 It is not possible to amend public changesets (see :hg:`help phases`)
1987 or changesets that have children.
1987 or changesets that have children.
1988
1988
1989 See :hg:`help dates` for a list of formats valid for -d/--date.
1989 See :hg:`help dates` for a list of formats valid for -d/--date.
1990
1990
1991 Returns 0 on success, 1 if nothing changed.
1991 Returns 0 on success, 1 if nothing changed.
1992
1992
1993 .. container:: verbose
1993 .. container:: verbose
1994
1994
1995 Examples:
1995 Examples:
1996
1996
1997 - commit all files ending in .py::
1997 - commit all files ending in .py::
1998
1998
1999 hg commit --include "set:**.py"
1999 hg commit --include "set:**.py"
2000
2000
2001 - commit all non-binary files::
2001 - commit all non-binary files::
2002
2002
2003 hg commit --exclude "set:binary()"
2003 hg commit --exclude "set:binary()"
2004
2004
2005 - amend the current commit and set the date to now::
2005 - amend the current commit and set the date to now::
2006
2006
2007 hg commit --amend --date now
2007 hg commit --amend --date now
2008 """
2008 """
2009 with repo.wlock(), repo.lock():
2009 with repo.wlock(), repo.lock():
2010 return _docommit(ui, repo, *pats, **opts)
2010 return _docommit(ui, repo, *pats, **opts)
2011
2011
2012
2012
2013 def _docommit(ui, repo, *pats, **opts):
2013 def _docommit(ui, repo, *pats, **opts):
2014 if opts.get('interactive'):
2014 if opts.get('interactive'):
2015 opts.pop('interactive')
2015 opts.pop('interactive')
2016 ret = cmdutil.dorecord(
2016 ret = cmdutil.dorecord(
2017 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2017 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2018 )
2018 )
2019 # ret can be 0 (no changes to record) or the value returned by
2019 # ret can be 0 (no changes to record) or the value returned by
2020 # commit(), 1 if nothing changed or None on success.
2020 # commit(), 1 if nothing changed or None on success.
2021 return 1 if ret == 0 else ret
2021 return 1 if ret == 0 else ret
2022
2022
2023 opts = pycompat.byteskwargs(opts)
2023 opts = pycompat.byteskwargs(opts)
2024 if opts.get(b'subrepos'):
2024 if opts.get(b'subrepos'):
2025 if opts.get(b'amend'):
2025 if opts.get(b'amend'):
2026 raise error.Abort(_(b'cannot amend with --subrepos'))
2026 raise error.Abort(_(b'cannot amend with --subrepos'))
2027 # Let --subrepos on the command line override config setting.
2027 # Let --subrepos on the command line override config setting.
2028 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2028 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2029
2029
2030 cmdutil.checkunfinished(repo, commit=True)
2030 cmdutil.checkunfinished(repo, commit=True)
2031
2031
2032 branch = repo[None].branch()
2032 branch = repo[None].branch()
2033 bheads = repo.branchheads(branch)
2033 bheads = repo.branchheads(branch)
2034
2034
2035 extra = {}
2035 extra = {}
2036 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2036 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2037 extra[b'close'] = b'1'
2037 extra[b'close'] = b'1'
2038
2038
2039 if repo[b'.'].closesbranch():
2039 if repo[b'.'].closesbranch():
2040 raise error.Abort(
2040 raise error.Abort(
2041 _(b'current revision is already a branch closing head')
2041 _(b'current revision is already a branch closing head')
2042 )
2042 )
2043 elif not bheads:
2043 elif not bheads:
2044 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2044 raise error.Abort(_(b'branch "%s" has no heads to close') % branch)
2045 elif (
2045 elif (
2046 branch == repo[b'.'].branch()
2046 branch == repo[b'.'].branch()
2047 and repo[b'.'].node() not in bheads
2047 and repo[b'.'].node() not in bheads
2048 and not opts.get(b'force_close_branch')
2048 and not opts.get(b'force_close_branch')
2049 ):
2049 ):
2050 hint = _(
2050 hint = _(
2051 b'use --force-close-branch to close branch from a non-head'
2051 b'use --force-close-branch to close branch from a non-head'
2052 b' changeset'
2052 b' changeset'
2053 )
2053 )
2054 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2054 raise error.Abort(_(b'can only close branch heads'), hint=hint)
2055 elif opts.get(b'amend'):
2055 elif opts.get(b'amend'):
2056 if (
2056 if (
2057 repo[b'.'].p1().branch() != branch
2057 repo[b'.'].p1().branch() != branch
2058 and repo[b'.'].p2().branch() != branch
2058 and repo[b'.'].p2().branch() != branch
2059 ):
2059 ):
2060 raise error.Abort(_(b'can only close branch heads'))
2060 raise error.Abort(_(b'can only close branch heads'))
2061
2061
2062 if opts.get(b'amend'):
2062 if opts.get(b'amend'):
2063 if ui.configbool(b'ui', b'commitsubrepos'):
2063 if ui.configbool(b'ui', b'commitsubrepos'):
2064 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2064 raise error.Abort(_(b'cannot amend with ui.commitsubrepos enabled'))
2065
2065
2066 old = repo[b'.']
2066 old = repo[b'.']
2067 rewriteutil.precheck(repo, [old.rev()], b'amend')
2067 rewriteutil.precheck(repo, [old.rev()], b'amend')
2068
2068
2069 # Currently histedit gets confused if an amend happens while histedit
2069 # Currently histedit gets confused if an amend happens while histedit
2070 # is in progress. Since we have a checkunfinished command, we are
2070 # is in progress. Since we have a checkunfinished command, we are
2071 # temporarily honoring it.
2071 # temporarily honoring it.
2072 #
2072 #
2073 # Note: eventually this guard will be removed. Please do not expect
2073 # Note: eventually this guard will be removed. Please do not expect
2074 # this behavior to remain.
2074 # this behavior to remain.
2075 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2075 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2076 cmdutil.checkunfinished(repo)
2076 cmdutil.checkunfinished(repo)
2077
2077
2078 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2078 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2079 if node == old.node():
2079 if node == old.node():
2080 ui.status(_(b"nothing changed\n"))
2080 ui.status(_(b"nothing changed\n"))
2081 return 1
2081 return 1
2082 else:
2082 else:
2083
2083
2084 def commitfunc(ui, repo, message, match, opts):
2084 def commitfunc(ui, repo, message, match, opts):
2085 overrides = {}
2085 overrides = {}
2086 if opts.get(b'secret'):
2086 if opts.get(b'secret'):
2087 overrides[(b'phases', b'new-commit')] = b'secret'
2087 overrides[(b'phases', b'new-commit')] = b'secret'
2088
2088
2089 baseui = repo.baseui
2089 baseui = repo.baseui
2090 with baseui.configoverride(overrides, b'commit'):
2090 with baseui.configoverride(overrides, b'commit'):
2091 with ui.configoverride(overrides, b'commit'):
2091 with ui.configoverride(overrides, b'commit'):
2092 editform = cmdutil.mergeeditform(
2092 editform = cmdutil.mergeeditform(
2093 repo[None], b'commit.normal'
2093 repo[None], b'commit.normal'
2094 )
2094 )
2095 editor = cmdutil.getcommiteditor(
2095 editor = cmdutil.getcommiteditor(
2096 editform=editform, **pycompat.strkwargs(opts)
2096 editform=editform, **pycompat.strkwargs(opts)
2097 )
2097 )
2098 return repo.commit(
2098 return repo.commit(
2099 message,
2099 message,
2100 opts.get(b'user'),
2100 opts.get(b'user'),
2101 opts.get(b'date'),
2101 opts.get(b'date'),
2102 match,
2102 match,
2103 editor=editor,
2103 editor=editor,
2104 extra=extra,
2104 extra=extra,
2105 )
2105 )
2106
2106
2107 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2107 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2108
2108
2109 if not node:
2109 if not node:
2110 stat = cmdutil.postcommitstatus(repo, pats, opts)
2110 stat = cmdutil.postcommitstatus(repo, pats, opts)
2111 if stat.deleted:
2111 if stat.deleted:
2112 ui.status(
2112 ui.status(
2113 _(
2113 _(
2114 b"nothing changed (%d missing files, see "
2114 b"nothing changed (%d missing files, see "
2115 b"'hg status')\n"
2115 b"'hg status')\n"
2116 )
2116 )
2117 % len(stat.deleted)
2117 % len(stat.deleted)
2118 )
2118 )
2119 else:
2119 else:
2120 ui.status(_(b"nothing changed\n"))
2120 ui.status(_(b"nothing changed\n"))
2121 return 1
2121 return 1
2122
2122
2123 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2123 cmdutil.commitstatus(repo, node, branch, bheads, opts)
2124
2124
2125 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2125 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2126 status(
2126 status(
2127 ui,
2127 ui,
2128 repo,
2128 repo,
2129 modified=True,
2129 modified=True,
2130 added=True,
2130 added=True,
2131 removed=True,
2131 removed=True,
2132 deleted=True,
2132 deleted=True,
2133 unknown=True,
2133 unknown=True,
2134 subrepos=opts.get(b'subrepos'),
2134 subrepos=opts.get(b'subrepos'),
2135 )
2135 )
2136
2136
2137
2137
2138 @command(
2138 @command(
2139 b'config|showconfig|debugconfig',
2139 b'config|showconfig|debugconfig',
2140 [
2140 [
2141 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2141 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2142 (b'e', b'edit', None, _(b'edit user config')),
2142 (b'e', b'edit', None, _(b'edit user config')),
2143 (b'l', b'local', None, _(b'edit repository config')),
2143 (b'l', b'local', None, _(b'edit repository config')),
2144 (b'g', b'global', None, _(b'edit global config')),
2144 (b'g', b'global', None, _(b'edit global config')),
2145 ]
2145 ]
2146 + formatteropts,
2146 + formatteropts,
2147 _(b'[-u] [NAME]...'),
2147 _(b'[-u] [NAME]...'),
2148 helpcategory=command.CATEGORY_HELP,
2148 helpcategory=command.CATEGORY_HELP,
2149 optionalrepo=True,
2149 optionalrepo=True,
2150 intents={INTENT_READONLY},
2150 intents={INTENT_READONLY},
2151 )
2151 )
2152 def config(ui, repo, *values, **opts):
2152 def config(ui, repo, *values, **opts):
2153 """show combined config settings from all hgrc files
2153 """show combined config settings from all hgrc files
2154
2154
2155 With no arguments, print names and values of all config items.
2155 With no arguments, print names and values of all config items.
2156
2156
2157 With one argument of the form section.name, print just the value
2157 With one argument of the form section.name, print just the value
2158 of that config item.
2158 of that config item.
2159
2159
2160 With multiple arguments, print names and values of all config
2160 With multiple arguments, print names and values of all config
2161 items with matching section names or section.names.
2161 items with matching section names or section.names.
2162
2162
2163 With --edit, start an editor on the user-level config file. With
2163 With --edit, start an editor on the user-level config file. With
2164 --global, edit the system-wide config file. With --local, edit the
2164 --global, edit the system-wide config file. With --local, edit the
2165 repository-level config file.
2165 repository-level config file.
2166
2166
2167 With --debug, the source (filename and line number) is printed
2167 With --debug, the source (filename and line number) is printed
2168 for each config item.
2168 for each config item.
2169
2169
2170 See :hg:`help config` for more information about config files.
2170 See :hg:`help config` for more information about config files.
2171
2171
2172 .. container:: verbose
2172 .. container:: verbose
2173
2173
2174 Template:
2174 Template:
2175
2175
2176 The following keywords are supported. See also :hg:`help templates`.
2176 The following keywords are supported. See also :hg:`help templates`.
2177
2177
2178 :name: String. Config name.
2178 :name: String. Config name.
2179 :source: String. Filename and line number where the item is defined.
2179 :source: String. Filename and line number where the item is defined.
2180 :value: String. Config value.
2180 :value: String. Config value.
2181
2181
2182 Returns 0 on success, 1 if NAME does not exist.
2182 Returns 0 on success, 1 if NAME does not exist.
2183
2183
2184 """
2184 """
2185
2185
2186 opts = pycompat.byteskwargs(opts)
2186 opts = pycompat.byteskwargs(opts)
2187 if opts.get(b'edit') or opts.get(b'local') or opts.get(b'global'):
2187 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'):
2188 if opts.get(b'local') and opts.get(b'global'):
2189 raise error.Abort(_(b"can't use --local and --global together"))
2189 raise error.Abort(_(b"can't use --local and --global together"))
2190
2190
2191 if opts.get(b'local'):
2191 if opts.get(b'local'):
2192 if not repo:
2192 if not repo:
2193 raise error.Abort(_(b"can't use --local outside a repository"))
2193 raise error.Abort(_(b"can't use --local outside a repository"))
2194 paths = [repo.vfs.join(b'hgrc')]
2194 paths = [repo.vfs.join(b'hgrc')]
2195 elif opts.get(b'global'):
2195 elif opts.get(b'global'):
2196 paths = rcutil.systemrcpath()
2196 paths = rcutil.systemrcpath()
2197 else:
2197 else:
2198 paths = rcutil.userrcpath()
2198 paths = rcutil.userrcpath()
2199
2199
2200 for f in paths:
2200 for f in paths:
2201 if os.path.exists(f):
2201 if os.path.exists(f):
2202 break
2202 break
2203 else:
2203 else:
2204 if opts.get(b'global'):
2204 if opts.get(b'global'):
2205 samplehgrc = uimod.samplehgrcs[b'global']
2205 samplehgrc = uimod.samplehgrcs[b'global']
2206 elif opts.get(b'local'):
2206 elif opts.get(b'local'):
2207 samplehgrc = uimod.samplehgrcs[b'local']
2207 samplehgrc = uimod.samplehgrcs[b'local']
2208 else:
2208 else:
2209 samplehgrc = uimod.samplehgrcs[b'user']
2209 samplehgrc = uimod.samplehgrcs[b'user']
2210
2210
2211 f = paths[0]
2211 f = paths[0]
2212 fp = open(f, b"wb")
2212 fp = open(f, b"wb")
2213 fp.write(util.tonativeeol(samplehgrc))
2213 fp.write(util.tonativeeol(samplehgrc))
2214 fp.close()
2214 fp.close()
2215
2215
2216 editor = ui.geteditor()
2216 editor = ui.geteditor()
2217 ui.system(
2217 ui.system(
2218 b"%s \"%s\"" % (editor, f),
2218 b"%s \"%s\"" % (editor, f),
2219 onerr=error.Abort,
2219 onerr=error.Abort,
2220 errprefix=_(b"edit failed"),
2220 errprefix=_(b"edit failed"),
2221 blockedtag=b'config_edit',
2221 blockedtag=b'config_edit',
2222 )
2222 )
2223 return
2223 return
2224 ui.pager(b'config')
2224 ui.pager(b'config')
2225 fm = ui.formatter(b'config', opts)
2225 fm = ui.formatter(b'config', opts)
2226 for t, f in rcutil.rccomponents():
2226 for t, f in rcutil.rccomponents():
2227 if t == b'path':
2227 if t == b'path':
2228 ui.debug(b'read config from: %s\n' % f)
2228 ui.debug(b'read config from: %s\n' % f)
2229 elif t == b'resource':
2229 elif t == b'resource':
2230 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2230 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2231 elif t == b'items':
2231 elif t == b'items':
2232 # Don't print anything for 'items'.
2232 # Don't print anything for 'items'.
2233 pass
2233 pass
2234 else:
2234 else:
2235 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2235 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2236 untrusted = bool(opts.get(b'untrusted'))
2236 untrusted = bool(opts.get(b'untrusted'))
2237
2237
2238 selsections = selentries = []
2238 selsections = selentries = []
2239 if values:
2239 if values:
2240 selsections = [v for v in values if b'.' not in v]
2240 selsections = [v for v in values if b'.' not in v]
2241 selentries = [v for v in values if b'.' in v]
2241 selentries = [v for v in values if b'.' in v]
2242 uniquesel = len(selentries) == 1 and not selsections
2242 uniquesel = len(selentries) == 1 and not selsections
2243 selsections = set(selsections)
2243 selsections = set(selsections)
2244 selentries = set(selentries)
2244 selentries = set(selentries)
2245
2245
2246 matched = False
2246 matched = False
2247 for section, name, value in ui.walkconfig(untrusted=untrusted):
2247 for section, name, value in ui.walkconfig(untrusted=untrusted):
2248 source = ui.configsource(section, name, untrusted)
2248 source = ui.configsource(section, name, untrusted)
2249 value = pycompat.bytestr(value)
2249 value = pycompat.bytestr(value)
2250 defaultvalue = ui.configdefault(section, name)
2250 defaultvalue = ui.configdefault(section, name)
2251 if fm.isplain():
2251 if fm.isplain():
2252 source = source or b'none'
2252 source = source or b'none'
2253 value = value.replace(b'\n', b'\\n')
2253 value = value.replace(b'\n', b'\\n')
2254 entryname = section + b'.' + name
2254 entryname = section + b'.' + name
2255 if values and not (section in selsections or entryname in selentries):
2255 if values and not (section in selsections or entryname in selentries):
2256 continue
2256 continue
2257 fm.startitem()
2257 fm.startitem()
2258 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2258 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2259 if uniquesel:
2259 if uniquesel:
2260 fm.data(name=entryname)
2260 fm.data(name=entryname)
2261 fm.write(b'value', b'%s\n', value)
2261 fm.write(b'value', b'%s\n', value)
2262 else:
2262 else:
2263 fm.write(b'name value', b'%s=%s\n', entryname, value)
2263 fm.write(b'name value', b'%s=%s\n', entryname, value)
2264 if formatter.isprintable(defaultvalue):
2264 if formatter.isprintable(defaultvalue):
2265 fm.data(defaultvalue=defaultvalue)
2265 fm.data(defaultvalue=defaultvalue)
2266 elif isinstance(defaultvalue, list) and all(
2266 elif isinstance(defaultvalue, list) and all(
2267 formatter.isprintable(e) for e in defaultvalue
2267 formatter.isprintable(e) for e in defaultvalue
2268 ):
2268 ):
2269 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2269 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2270 # TODO: no idea how to process unsupported defaultvalue types
2270 # TODO: no idea how to process unsupported defaultvalue types
2271 matched = True
2271 matched = True
2272 fm.end()
2272 fm.end()
2273 if matched:
2273 if matched:
2274 return 0
2274 return 0
2275 return 1
2275 return 1
2276
2276
2277
2277
2278 @command(
2278 @command(
2279 b'continue',
2279 b'continue',
2280 dryrunopts,
2280 dryrunopts,
2281 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2281 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2282 helpbasic=True,
2282 helpbasic=True,
2283 )
2283 )
2284 def continuecmd(ui, repo, **opts):
2284 def continuecmd(ui, repo, **opts):
2285 """resumes an interrupted operation (EXPERIMENTAL)
2285 """resumes an interrupted operation (EXPERIMENTAL)
2286
2286
2287 Finishes a multistep operation like graft, histedit, rebase, merge,
2287 Finishes a multistep operation like graft, histedit, rebase, merge,
2288 and unshelve if they are in an interrupted state.
2288 and unshelve if they are in an interrupted state.
2289
2289
2290 use --dry-run/-n to dry run the command.
2290 use --dry-run/-n to dry run the command.
2291 """
2291 """
2292 dryrun = opts.get('dry_run')
2292 dryrun = opts.get('dry_run')
2293 contstate = cmdutil.getunfinishedstate(repo)
2293 contstate = cmdutil.getunfinishedstate(repo)
2294 if not contstate:
2294 if not contstate:
2295 raise error.Abort(_(b'no operation in progress'))
2295 raise error.Abort(_(b'no operation in progress'))
2296 if not contstate.continuefunc:
2296 if not contstate.continuefunc:
2297 raise error.Abort(
2297 raise error.Abort(
2298 (
2298 (
2299 _(b"%s in progress but does not support 'hg continue'")
2299 _(b"%s in progress but does not support 'hg continue'")
2300 % (contstate._opname)
2300 % (contstate._opname)
2301 ),
2301 ),
2302 hint=contstate.continuemsg(),
2302 hint=contstate.continuemsg(),
2303 )
2303 )
2304 if dryrun:
2304 if dryrun:
2305 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2305 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2306 return
2306 return
2307 return contstate.continuefunc(ui, repo)
2307 return contstate.continuefunc(ui, repo)
2308
2308
2309
2309
2310 @command(
2310 @command(
2311 b'copy|cp',
2311 b'copy|cp',
2312 [
2312 [
2313 (b'', b'forget', None, _(b'unmark a file as copied')),
2313 (b'', b'forget', None, _(b'unmark a file as copied')),
2314 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2314 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2315 (
2315 (
2316 b'',
2316 b'',
2317 b'at-rev',
2317 b'at-rev',
2318 b'',
2318 b'',
2319 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2319 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2320 _(b'REV'),
2320 _(b'REV'),
2321 ),
2321 ),
2322 (
2322 (
2323 b'f',
2323 b'f',
2324 b'force',
2324 b'force',
2325 None,
2325 None,
2326 _(b'forcibly copy over an existing managed file'),
2326 _(b'forcibly copy over an existing managed file'),
2327 ),
2327 ),
2328 ]
2328 ]
2329 + walkopts
2329 + walkopts
2330 + dryrunopts,
2330 + dryrunopts,
2331 _(b'[OPTION]... SOURCE... DEST'),
2331 _(b'[OPTION]... SOURCE... DEST'),
2332 helpcategory=command.CATEGORY_FILE_CONTENTS,
2332 helpcategory=command.CATEGORY_FILE_CONTENTS,
2333 )
2333 )
2334 def copy(ui, repo, *pats, **opts):
2334 def copy(ui, repo, *pats, **opts):
2335 """mark files as copied for the next commit
2335 """mark files as copied for the next commit
2336
2336
2337 Mark dest as having copies of source files. If dest is a
2337 Mark dest as having copies of source files. If dest is a
2338 directory, copies are put in that directory. If dest is a file,
2338 directory, copies are put in that directory. If dest is a file,
2339 the source must be a single file.
2339 the source must be a single file.
2340
2340
2341 By default, this command copies the contents of files as they
2341 By default, this command copies the contents of files as they
2342 exist in the working directory. If invoked with -A/--after, the
2342 exist in the working directory. If invoked with -A/--after, the
2343 operation is recorded, but no copying is performed.
2343 operation is recorded, but no copying is performed.
2344
2344
2345 To undo marking a file as copied, use --forget. With that option,
2345 To undo marking a file as copied, use --forget. With that option,
2346 all given (positional) arguments are unmarked as copies. The destination
2346 all given (positional) arguments are unmarked as copies. The destination
2347 file(s) will be left in place (still tracked).
2347 file(s) will be left in place (still tracked).
2348
2348
2349 This command takes effect with the next commit by default.
2349 This command takes effect with the next commit by default.
2350
2350
2351 Returns 0 on success, 1 if errors are encountered.
2351 Returns 0 on success, 1 if errors are encountered.
2352 """
2352 """
2353 opts = pycompat.byteskwargs(opts)
2353 opts = pycompat.byteskwargs(opts)
2354 with repo.wlock():
2354 with repo.wlock():
2355 return cmdutil.copy(ui, repo, pats, opts)
2355 return cmdutil.copy(ui, repo, pats, opts)
2356
2356
2357
2357
2358 @command(
2358 @command(
2359 b'debugcommands',
2359 b'debugcommands',
2360 [],
2360 [],
2361 _(b'[COMMAND]'),
2361 _(b'[COMMAND]'),
2362 helpcategory=command.CATEGORY_HELP,
2362 helpcategory=command.CATEGORY_HELP,
2363 norepo=True,
2363 norepo=True,
2364 )
2364 )
2365 def debugcommands(ui, cmd=b'', *args):
2365 def debugcommands(ui, cmd=b'', *args):
2366 """list all available commands and options"""
2366 """list all available commands and options"""
2367 for cmd, vals in sorted(pycompat.iteritems(table)):
2367 for cmd, vals in sorted(pycompat.iteritems(table)):
2368 cmd = cmd.split(b'|')[0]
2368 cmd = cmd.split(b'|')[0]
2369 opts = b', '.join([i[1] for i in vals[1]])
2369 opts = b', '.join([i[1] for i in vals[1]])
2370 ui.write(b'%s: %s\n' % (cmd, opts))
2370 ui.write(b'%s: %s\n' % (cmd, opts))
2371
2371
2372
2372
2373 @command(
2373 @command(
2374 b'debugcomplete',
2374 b'debugcomplete',
2375 [(b'o', b'options', None, _(b'show the command options'))],
2375 [(b'o', b'options', None, _(b'show the command options'))],
2376 _(b'[-o] CMD'),
2376 _(b'[-o] CMD'),
2377 helpcategory=command.CATEGORY_HELP,
2377 helpcategory=command.CATEGORY_HELP,
2378 norepo=True,
2378 norepo=True,
2379 )
2379 )
2380 def debugcomplete(ui, cmd=b'', **opts):
2380 def debugcomplete(ui, cmd=b'', **opts):
2381 """returns the completion list associated with the given command"""
2381 """returns the completion list associated with the given command"""
2382
2382
2383 if opts.get('options'):
2383 if opts.get('options'):
2384 options = []
2384 options = []
2385 otables = [globalopts]
2385 otables = [globalopts]
2386 if cmd:
2386 if cmd:
2387 aliases, entry = cmdutil.findcmd(cmd, table, False)
2387 aliases, entry = cmdutil.findcmd(cmd, table, False)
2388 otables.append(entry[1])
2388 otables.append(entry[1])
2389 for t in otables:
2389 for t in otables:
2390 for o in t:
2390 for o in t:
2391 if b"(DEPRECATED)" in o[3]:
2391 if b"(DEPRECATED)" in o[3]:
2392 continue
2392 continue
2393 if o[0]:
2393 if o[0]:
2394 options.append(b'-%s' % o[0])
2394 options.append(b'-%s' % o[0])
2395 options.append(b'--%s' % o[1])
2395 options.append(b'--%s' % o[1])
2396 ui.write(b"%s\n" % b"\n".join(options))
2396 ui.write(b"%s\n" % b"\n".join(options))
2397 return
2397 return
2398
2398
2399 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2399 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2400 if ui.verbose:
2400 if ui.verbose:
2401 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2401 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2402 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2402 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2403
2403
2404
2404
2405 @command(
2405 @command(
2406 b'diff',
2406 b'diff',
2407 [
2407 [
2408 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2408 (b'r', b'rev', [], _(b'revision'), _(b'REV')),
2409 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2409 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2410 ]
2410 ]
2411 + diffopts
2411 + diffopts
2412 + diffopts2
2412 + diffopts2
2413 + walkopts
2413 + walkopts
2414 + subrepoopts,
2414 + subrepoopts,
2415 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2415 _(b'[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2416 helpcategory=command.CATEGORY_FILE_CONTENTS,
2416 helpcategory=command.CATEGORY_FILE_CONTENTS,
2417 helpbasic=True,
2417 helpbasic=True,
2418 inferrepo=True,
2418 inferrepo=True,
2419 intents={INTENT_READONLY},
2419 intents={INTENT_READONLY},
2420 )
2420 )
2421 def diff(ui, repo, *pats, **opts):
2421 def diff(ui, repo, *pats, **opts):
2422 """diff repository (or selected files)
2422 """diff repository (or selected files)
2423
2423
2424 Show differences between revisions for the specified files.
2424 Show differences between revisions for the specified files.
2425
2425
2426 Differences between files are shown using the unified diff format.
2426 Differences between files are shown using the unified diff format.
2427
2427
2428 .. note::
2428 .. note::
2429
2429
2430 :hg:`diff` may generate unexpected results for merges, as it will
2430 :hg:`diff` may generate unexpected results for merges, as it will
2431 default to comparing against the working directory's first
2431 default to comparing against the working directory's first
2432 parent changeset if no revisions are specified.
2432 parent changeset if no revisions are specified.
2433
2433
2434 When two revision arguments are given, then changes are shown
2434 When two revision arguments are given, then changes are shown
2435 between those revisions. If only one revision is specified then
2435 between those revisions. If only one revision is specified then
2436 that revision is compared to the working directory, and, when no
2436 that revision is compared to the working directory, and, when no
2437 revisions are specified, the working directory files are compared
2437 revisions are specified, the working directory files are compared
2438 to its first parent.
2438 to its first parent.
2439
2439
2440 Alternatively you can specify -c/--change with a revision to see
2440 Alternatively you can specify -c/--change with a revision to see
2441 the changes in that changeset relative to its first parent.
2441 the changes in that changeset relative to its first parent.
2442
2442
2443 Without the -a/--text option, diff will avoid generating diffs of
2443 Without the -a/--text option, diff will avoid generating diffs of
2444 files it detects as binary. With -a, diff will generate a diff
2444 files it detects as binary. With -a, diff will generate a diff
2445 anyway, probably with undesirable results.
2445 anyway, probably with undesirable results.
2446
2446
2447 Use the -g/--git option to generate diffs in the git extended diff
2447 Use the -g/--git option to generate diffs in the git extended diff
2448 format. For more information, read :hg:`help diffs`.
2448 format. For more information, read :hg:`help diffs`.
2449
2449
2450 .. container:: verbose
2450 .. container:: verbose
2451
2451
2452 Examples:
2452 Examples:
2453
2453
2454 - compare a file in the current working directory to its parent::
2454 - compare a file in the current working directory to its parent::
2455
2455
2456 hg diff foo.c
2456 hg diff foo.c
2457
2457
2458 - compare two historical versions of a directory, with rename info::
2458 - compare two historical versions of a directory, with rename info::
2459
2459
2460 hg diff --git -r 1.0:1.2 lib/
2460 hg diff --git -r 1.0:1.2 lib/
2461
2461
2462 - get change stats relative to the last change on some date::
2462 - get change stats relative to the last change on some date::
2463
2463
2464 hg diff --stat -r "date('may 2')"
2464 hg diff --stat -r "date('may 2')"
2465
2465
2466 - diff all newly-added files that contain a keyword::
2466 - diff all newly-added files that contain a keyword::
2467
2467
2468 hg diff "set:added() and grep(GNU)"
2468 hg diff "set:added() and grep(GNU)"
2469
2469
2470 - compare a revision and its parents::
2470 - compare a revision and its parents::
2471
2471
2472 hg diff -c 9353 # compare against first parent
2472 hg diff -c 9353 # compare against first parent
2473 hg diff -r 9353^:9353 # same using revset syntax
2473 hg diff -r 9353^:9353 # same using revset syntax
2474 hg diff -r 9353^2:9353 # compare against the second parent
2474 hg diff -r 9353^2:9353 # compare against the second parent
2475
2475
2476 Returns 0 on success.
2476 Returns 0 on success.
2477 """
2477 """
2478
2478
2479 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2479 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2480 opts = pycompat.byteskwargs(opts)
2480 opts = pycompat.byteskwargs(opts)
2481 revs = opts.get(b'rev')
2481 revs = opts.get(b'rev')
2482 change = opts.get(b'change')
2482 change = opts.get(b'change')
2483 stat = opts.get(b'stat')
2483 stat = opts.get(b'stat')
2484 reverse = opts.get(b'reverse')
2484 reverse = opts.get(b'reverse')
2485
2485
2486 if change:
2486 if change:
2487 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2487 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2488 ctx2 = scmutil.revsingle(repo, change, None)
2488 ctx2 = scmutil.revsingle(repo, change, None)
2489 ctx1 = ctx2.p1()
2489 ctx1 = ctx2.p1()
2490 else:
2490 else:
2491 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2491 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2492 ctx1, ctx2 = scmutil.revpair(repo, revs)
2492 ctx1, ctx2 = scmutil.revpair(repo, revs)
2493
2493
2494 if reverse:
2494 if reverse:
2495 ctxleft = ctx2
2495 ctxleft = ctx2
2496 ctxright = ctx1
2496 ctxright = ctx1
2497 else:
2497 else:
2498 ctxleft = ctx1
2498 ctxleft = ctx1
2499 ctxright = ctx2
2499 ctxright = ctx2
2500
2500
2501 diffopts = patch.diffallopts(ui, opts)
2501 diffopts = patch.diffallopts(ui, opts)
2502 m = scmutil.match(ctx2, pats, opts)
2502 m = scmutil.match(ctx2, pats, opts)
2503 m = repo.narrowmatch(m)
2503 m = repo.narrowmatch(m)
2504 ui.pager(b'diff')
2504 ui.pager(b'diff')
2505 logcmdutil.diffordiffstat(
2505 logcmdutil.diffordiffstat(
2506 ui,
2506 ui,
2507 repo,
2507 repo,
2508 diffopts,
2508 diffopts,
2509 ctxleft,
2509 ctxleft,
2510 ctxright,
2510 ctxright,
2511 m,
2511 m,
2512 stat=stat,
2512 stat=stat,
2513 listsubrepos=opts.get(b'subrepos'),
2513 listsubrepos=opts.get(b'subrepos'),
2514 root=opts.get(b'root'),
2514 root=opts.get(b'root'),
2515 )
2515 )
2516
2516
2517
2517
2518 @command(
2518 @command(
2519 b'export',
2519 b'export',
2520 [
2520 [
2521 (
2521 (
2522 b'B',
2522 b'B',
2523 b'bookmark',
2523 b'bookmark',
2524 b'',
2524 b'',
2525 _(b'export changes only reachable by given bookmark'),
2525 _(b'export changes only reachable by given bookmark'),
2526 _(b'BOOKMARK'),
2526 _(b'BOOKMARK'),
2527 ),
2527 ),
2528 (
2528 (
2529 b'o',
2529 b'o',
2530 b'output',
2530 b'output',
2531 b'',
2531 b'',
2532 _(b'print output to file with formatted name'),
2532 _(b'print output to file with formatted name'),
2533 _(b'FORMAT'),
2533 _(b'FORMAT'),
2534 ),
2534 ),
2535 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2535 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2536 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2536 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2537 ]
2537 ]
2538 + diffopts
2538 + diffopts
2539 + formatteropts,
2539 + formatteropts,
2540 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2540 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2541 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2541 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2542 helpbasic=True,
2542 helpbasic=True,
2543 intents={INTENT_READONLY},
2543 intents={INTENT_READONLY},
2544 )
2544 )
2545 def export(ui, repo, *changesets, **opts):
2545 def export(ui, repo, *changesets, **opts):
2546 """dump the header and diffs for one or more changesets
2546 """dump the header and diffs for one or more changesets
2547
2547
2548 Print the changeset header and diffs for one or more revisions.
2548 Print the changeset header and diffs for one or more revisions.
2549 If no revision is given, the parent of the working directory is used.
2549 If no revision is given, the parent of the working directory is used.
2550
2550
2551 The information shown in the changeset header is: author, date,
2551 The information shown in the changeset header is: author, date,
2552 branch name (if non-default), changeset hash, parent(s) and commit
2552 branch name (if non-default), changeset hash, parent(s) and commit
2553 comment.
2553 comment.
2554
2554
2555 .. note::
2555 .. note::
2556
2556
2557 :hg:`export` may generate unexpected diff output for merge
2557 :hg:`export` may generate unexpected diff output for merge
2558 changesets, as it will compare the merge changeset against its
2558 changesets, as it will compare the merge changeset against its
2559 first parent only.
2559 first parent only.
2560
2560
2561 Output may be to a file, in which case the name of the file is
2561 Output may be to a file, in which case the name of the file is
2562 given using a template string. See :hg:`help templates`. In addition
2562 given using a template string. See :hg:`help templates`. In addition
2563 to the common template keywords, the following formatting rules are
2563 to the common template keywords, the following formatting rules are
2564 supported:
2564 supported:
2565
2565
2566 :``%%``: literal "%" character
2566 :``%%``: literal "%" character
2567 :``%H``: changeset hash (40 hexadecimal digits)
2567 :``%H``: changeset hash (40 hexadecimal digits)
2568 :``%N``: number of patches being generated
2568 :``%N``: number of patches being generated
2569 :``%R``: changeset revision number
2569 :``%R``: changeset revision number
2570 :``%b``: basename of the exporting repository
2570 :``%b``: basename of the exporting repository
2571 :``%h``: short-form changeset hash (12 hexadecimal digits)
2571 :``%h``: short-form changeset hash (12 hexadecimal digits)
2572 :``%m``: first line of the commit message (only alphanumeric characters)
2572 :``%m``: first line of the commit message (only alphanumeric characters)
2573 :``%n``: zero-padded sequence number, starting at 1
2573 :``%n``: zero-padded sequence number, starting at 1
2574 :``%r``: zero-padded changeset revision number
2574 :``%r``: zero-padded changeset revision number
2575 :``\\``: literal "\\" character
2575 :``\\``: literal "\\" character
2576
2576
2577 Without the -a/--text option, export will avoid generating diffs
2577 Without the -a/--text option, export will avoid generating diffs
2578 of files it detects as binary. With -a, export will generate a
2578 of files it detects as binary. With -a, export will generate a
2579 diff anyway, probably with undesirable results.
2579 diff anyway, probably with undesirable results.
2580
2580
2581 With -B/--bookmark changesets reachable by the given bookmark are
2581 With -B/--bookmark changesets reachable by the given bookmark are
2582 selected.
2582 selected.
2583
2583
2584 Use the -g/--git option to generate diffs in the git extended diff
2584 Use the -g/--git option to generate diffs in the git extended diff
2585 format. See :hg:`help diffs` for more information.
2585 format. See :hg:`help diffs` for more information.
2586
2586
2587 With the --switch-parent option, the diff will be against the
2587 With the --switch-parent option, the diff will be against the
2588 second parent. It can be useful to review a merge.
2588 second parent. It can be useful to review a merge.
2589
2589
2590 .. container:: verbose
2590 .. container:: verbose
2591
2591
2592 Template:
2592 Template:
2593
2593
2594 The following keywords are supported in addition to the common template
2594 The following keywords are supported in addition to the common template
2595 keywords and functions. See also :hg:`help templates`.
2595 keywords and functions. See also :hg:`help templates`.
2596
2596
2597 :diff: String. Diff content.
2597 :diff: String. Diff content.
2598 :parents: List of strings. Parent nodes of the changeset.
2598 :parents: List of strings. Parent nodes of the changeset.
2599
2599
2600 Examples:
2600 Examples:
2601
2601
2602 - use export and import to transplant a bugfix to the current
2602 - use export and import to transplant a bugfix to the current
2603 branch::
2603 branch::
2604
2604
2605 hg export -r 9353 | hg import -
2605 hg export -r 9353 | hg import -
2606
2606
2607 - export all the changesets between two revisions to a file with
2607 - export all the changesets between two revisions to a file with
2608 rename information::
2608 rename information::
2609
2609
2610 hg export --git -r 123:150 > changes.txt
2610 hg export --git -r 123:150 > changes.txt
2611
2611
2612 - split outgoing changes into a series of patches with
2612 - split outgoing changes into a series of patches with
2613 descriptive names::
2613 descriptive names::
2614
2614
2615 hg export -r "outgoing()" -o "%n-%m.patch"
2615 hg export -r "outgoing()" -o "%n-%m.patch"
2616
2616
2617 Returns 0 on success.
2617 Returns 0 on success.
2618 """
2618 """
2619 opts = pycompat.byteskwargs(opts)
2619 opts = pycompat.byteskwargs(opts)
2620 bookmark = opts.get(b'bookmark')
2620 bookmark = opts.get(b'bookmark')
2621 changesets += tuple(opts.get(b'rev', []))
2621 changesets += tuple(opts.get(b'rev', []))
2622
2622
2623 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2623 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2624
2624
2625 if bookmark:
2625 if bookmark:
2626 if bookmark not in repo._bookmarks:
2626 if bookmark not in repo._bookmarks:
2627 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2627 raise error.Abort(_(b"bookmark '%s' not found") % bookmark)
2628
2628
2629 revs = scmutil.bookmarkrevs(repo, bookmark)
2629 revs = scmutil.bookmarkrevs(repo, bookmark)
2630 else:
2630 else:
2631 if not changesets:
2631 if not changesets:
2632 changesets = [b'.']
2632 changesets = [b'.']
2633
2633
2634 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2634 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2635 revs = scmutil.revrange(repo, changesets)
2635 revs = scmutil.revrange(repo, changesets)
2636
2636
2637 if not revs:
2637 if not revs:
2638 raise error.Abort(_(b"export requires at least one changeset"))
2638 raise error.Abort(_(b"export requires at least one changeset"))
2639 if len(revs) > 1:
2639 if len(revs) > 1:
2640 ui.note(_(b'exporting patches:\n'))
2640 ui.note(_(b'exporting patches:\n'))
2641 else:
2641 else:
2642 ui.note(_(b'exporting patch:\n'))
2642 ui.note(_(b'exporting patch:\n'))
2643
2643
2644 fntemplate = opts.get(b'output')
2644 fntemplate = opts.get(b'output')
2645 if cmdutil.isstdiofilename(fntemplate):
2645 if cmdutil.isstdiofilename(fntemplate):
2646 fntemplate = b''
2646 fntemplate = b''
2647
2647
2648 if fntemplate:
2648 if fntemplate:
2649 fm = formatter.nullformatter(ui, b'export', opts)
2649 fm = formatter.nullformatter(ui, b'export', opts)
2650 else:
2650 else:
2651 ui.pager(b'export')
2651 ui.pager(b'export')
2652 fm = ui.formatter(b'export', opts)
2652 fm = ui.formatter(b'export', opts)
2653 with fm:
2653 with fm:
2654 cmdutil.export(
2654 cmdutil.export(
2655 repo,
2655 repo,
2656 revs,
2656 revs,
2657 fm,
2657 fm,
2658 fntemplate=fntemplate,
2658 fntemplate=fntemplate,
2659 switch_parent=opts.get(b'switch_parent'),
2659 switch_parent=opts.get(b'switch_parent'),
2660 opts=patch.diffallopts(ui, opts),
2660 opts=patch.diffallopts(ui, opts),
2661 )
2661 )
2662
2662
2663
2663
2664 @command(
2664 @command(
2665 b'files',
2665 b'files',
2666 [
2666 [
2667 (
2667 (
2668 b'r',
2668 b'r',
2669 b'rev',
2669 b'rev',
2670 b'',
2670 b'',
2671 _(b'search the repository as it is in REV'),
2671 _(b'search the repository as it is in REV'),
2672 _(b'REV'),
2672 _(b'REV'),
2673 ),
2673 ),
2674 (
2674 (
2675 b'0',
2675 b'0',
2676 b'print0',
2676 b'print0',
2677 None,
2677 None,
2678 _(b'end filenames with NUL, for use with xargs'),
2678 _(b'end filenames with NUL, for use with xargs'),
2679 ),
2679 ),
2680 ]
2680 ]
2681 + walkopts
2681 + walkopts
2682 + formatteropts
2682 + formatteropts
2683 + subrepoopts,
2683 + subrepoopts,
2684 _(b'[OPTION]... [FILE]...'),
2684 _(b'[OPTION]... [FILE]...'),
2685 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2685 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2686 intents={INTENT_READONLY},
2686 intents={INTENT_READONLY},
2687 )
2687 )
2688 def files(ui, repo, *pats, **opts):
2688 def files(ui, repo, *pats, **opts):
2689 """list tracked files
2689 """list tracked files
2690
2690
2691 Print files under Mercurial control in the working directory or
2691 Print files under Mercurial control in the working directory or
2692 specified revision for given files (excluding removed files).
2692 specified revision for given files (excluding removed files).
2693 Files can be specified as filenames or filesets.
2693 Files can be specified as filenames or filesets.
2694
2694
2695 If no files are given to match, this command prints the names
2695 If no files are given to match, this command prints the names
2696 of all files under Mercurial control.
2696 of all files under Mercurial control.
2697
2697
2698 .. container:: verbose
2698 .. container:: verbose
2699
2699
2700 Template:
2700 Template:
2701
2701
2702 The following keywords are supported in addition to the common template
2702 The following keywords are supported in addition to the common template
2703 keywords and functions. See also :hg:`help templates`.
2703 keywords and functions. See also :hg:`help templates`.
2704
2704
2705 :flags: String. Character denoting file's symlink and executable bits.
2705 :flags: String. Character denoting file's symlink and executable bits.
2706 :path: String. Repository-absolute path of the file.
2706 :path: String. Repository-absolute path of the file.
2707 :size: Integer. Size of the file in bytes.
2707 :size: Integer. Size of the file in bytes.
2708
2708
2709 Examples:
2709 Examples:
2710
2710
2711 - list all files under the current directory::
2711 - list all files under the current directory::
2712
2712
2713 hg files .
2713 hg files .
2714
2714
2715 - shows sizes and flags for current revision::
2715 - shows sizes and flags for current revision::
2716
2716
2717 hg files -vr .
2717 hg files -vr .
2718
2718
2719 - list all files named README::
2719 - list all files named README::
2720
2720
2721 hg files -I "**/README"
2721 hg files -I "**/README"
2722
2722
2723 - list all binary files::
2723 - list all binary files::
2724
2724
2725 hg files "set:binary()"
2725 hg files "set:binary()"
2726
2726
2727 - find files containing a regular expression::
2727 - find files containing a regular expression::
2728
2728
2729 hg files "set:grep('bob')"
2729 hg files "set:grep('bob')"
2730
2730
2731 - search tracked file contents with xargs and grep::
2731 - search tracked file contents with xargs and grep::
2732
2732
2733 hg files -0 | xargs -0 grep foo
2733 hg files -0 | xargs -0 grep foo
2734
2734
2735 See :hg:`help patterns` and :hg:`help filesets` for more information
2735 See :hg:`help patterns` and :hg:`help filesets` for more information
2736 on specifying file patterns.
2736 on specifying file patterns.
2737
2737
2738 Returns 0 if a match is found, 1 otherwise.
2738 Returns 0 if a match is found, 1 otherwise.
2739
2739
2740 """
2740 """
2741
2741
2742 opts = pycompat.byteskwargs(opts)
2742 opts = pycompat.byteskwargs(opts)
2743 rev = opts.get(b'rev')
2743 rev = opts.get(b'rev')
2744 if rev:
2744 if rev:
2745 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2745 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2746 ctx = scmutil.revsingle(repo, rev, None)
2746 ctx = scmutil.revsingle(repo, rev, None)
2747
2747
2748 end = b'\n'
2748 end = b'\n'
2749 if opts.get(b'print0'):
2749 if opts.get(b'print0'):
2750 end = b'\0'
2750 end = b'\0'
2751 fmt = b'%s' + end
2751 fmt = b'%s' + end
2752
2752
2753 m = scmutil.match(ctx, pats, opts)
2753 m = scmutil.match(ctx, pats, opts)
2754 ui.pager(b'files')
2754 ui.pager(b'files')
2755 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2755 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2756 with ui.formatter(b'files', opts) as fm:
2756 with ui.formatter(b'files', opts) as fm:
2757 return cmdutil.files(
2757 return cmdutil.files(
2758 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2758 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2759 )
2759 )
2760
2760
2761
2761
2762 @command(
2762 @command(
2763 b'forget',
2763 b'forget',
2764 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2764 [(b'i', b'interactive', None, _(b'use interactive mode')),]
2765 + walkopts
2765 + walkopts
2766 + dryrunopts,
2766 + dryrunopts,
2767 _(b'[OPTION]... FILE...'),
2767 _(b'[OPTION]... FILE...'),
2768 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2768 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2769 helpbasic=True,
2769 helpbasic=True,
2770 inferrepo=True,
2770 inferrepo=True,
2771 )
2771 )
2772 def forget(ui, repo, *pats, **opts):
2772 def forget(ui, repo, *pats, **opts):
2773 """forget the specified files on the next commit
2773 """forget the specified files on the next commit
2774
2774
2775 Mark the specified files so they will no longer be tracked
2775 Mark the specified files so they will no longer be tracked
2776 after the next commit.
2776 after the next commit.
2777
2777
2778 This only removes files from the current branch, not from the
2778 This only removes files from the current branch, not from the
2779 entire project history, and it does not delete them from the
2779 entire project history, and it does not delete them from the
2780 working directory.
2780 working directory.
2781
2781
2782 To delete the file from the working directory, see :hg:`remove`.
2782 To delete the file from the working directory, see :hg:`remove`.
2783
2783
2784 To undo a forget before the next commit, see :hg:`add`.
2784 To undo a forget before the next commit, see :hg:`add`.
2785
2785
2786 .. container:: verbose
2786 .. container:: verbose
2787
2787
2788 Examples:
2788 Examples:
2789
2789
2790 - forget newly-added binary files::
2790 - forget newly-added binary files::
2791
2791
2792 hg forget "set:added() and binary()"
2792 hg forget "set:added() and binary()"
2793
2793
2794 - forget files that would be excluded by .hgignore::
2794 - forget files that would be excluded by .hgignore::
2795
2795
2796 hg forget "set:hgignore()"
2796 hg forget "set:hgignore()"
2797
2797
2798 Returns 0 on success.
2798 Returns 0 on success.
2799 """
2799 """
2800
2800
2801 opts = pycompat.byteskwargs(opts)
2801 opts = pycompat.byteskwargs(opts)
2802 if not pats:
2802 if not pats:
2803 raise error.Abort(_(b'no files specified'))
2803 raise error.Abort(_(b'no files specified'))
2804
2804
2805 m = scmutil.match(repo[None], pats, opts)
2805 m = scmutil.match(repo[None], pats, opts)
2806 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2806 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2807 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2807 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2808 rejected = cmdutil.forget(
2808 rejected = cmdutil.forget(
2809 ui,
2809 ui,
2810 repo,
2810 repo,
2811 m,
2811 m,
2812 prefix=b"",
2812 prefix=b"",
2813 uipathfn=uipathfn,
2813 uipathfn=uipathfn,
2814 explicitonly=False,
2814 explicitonly=False,
2815 dryrun=dryrun,
2815 dryrun=dryrun,
2816 interactive=interactive,
2816 interactive=interactive,
2817 )[0]
2817 )[0]
2818 return rejected and 1 or 0
2818 return rejected and 1 or 0
2819
2819
2820
2820
2821 @command(
2821 @command(
2822 b'graft',
2822 b'graft',
2823 [
2823 [
2824 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2824 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2825 (
2825 (
2826 b'',
2826 b'',
2827 b'base',
2827 b'base',
2828 b'',
2828 b'',
2829 _(b'base revision when doing the graft merge (ADVANCED)'),
2829 _(b'base revision when doing the graft merge (ADVANCED)'),
2830 _(b'REV'),
2830 _(b'REV'),
2831 ),
2831 ),
2832 (b'c', b'continue', False, _(b'resume interrupted graft')),
2832 (b'c', b'continue', False, _(b'resume interrupted graft')),
2833 (b'', b'stop', False, _(b'stop interrupted graft')),
2833 (b'', b'stop', False, _(b'stop interrupted graft')),
2834 (b'', b'abort', False, _(b'abort interrupted graft')),
2834 (b'', b'abort', False, _(b'abort interrupted graft')),
2835 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2835 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2836 (b'', b'log', None, _(b'append graft info to log message')),
2836 (b'', b'log', None, _(b'append graft info to log message')),
2837 (
2837 (
2838 b'',
2838 b'',
2839 b'no-commit',
2839 b'no-commit',
2840 None,
2840 None,
2841 _(b"don't commit, just apply the changes in working directory"),
2841 _(b"don't commit, just apply the changes in working directory"),
2842 ),
2842 ),
2843 (b'f', b'force', False, _(b'force graft')),
2843 (b'f', b'force', False, _(b'force graft')),
2844 (
2844 (
2845 b'D',
2845 b'D',
2846 b'currentdate',
2846 b'currentdate',
2847 False,
2847 False,
2848 _(b'record the current date as commit date'),
2848 _(b'record the current date as commit date'),
2849 ),
2849 ),
2850 (
2850 (
2851 b'U',
2851 b'U',
2852 b'currentuser',
2852 b'currentuser',
2853 False,
2853 False,
2854 _(b'record the current user as committer'),
2854 _(b'record the current user as committer'),
2855 ),
2855 ),
2856 ]
2856 ]
2857 + commitopts2
2857 + commitopts2
2858 + mergetoolopts
2858 + mergetoolopts
2859 + dryrunopts,
2859 + dryrunopts,
2860 _(b'[OPTION]... [-r REV]... REV...'),
2860 _(b'[OPTION]... [-r REV]... REV...'),
2861 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2861 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2862 )
2862 )
2863 def graft(ui, repo, *revs, **opts):
2863 def graft(ui, repo, *revs, **opts):
2864 '''copy changes from other branches onto the current branch
2864 '''copy changes from other branches onto the current branch
2865
2865
2866 This command uses Mercurial's merge logic to copy individual
2866 This command uses Mercurial's merge logic to copy individual
2867 changes from other branches without merging branches in the
2867 changes from other branches without merging branches in the
2868 history graph. This is sometimes known as 'backporting' or
2868 history graph. This is sometimes known as 'backporting' or
2869 'cherry-picking'. By default, graft will copy user, date, and
2869 'cherry-picking'. By default, graft will copy user, date, and
2870 description from the source changesets.
2870 description from the source changesets.
2871
2871
2872 Changesets that are ancestors of the current revision, that have
2872 Changesets that are ancestors of the current revision, that have
2873 already been grafted, or that are merges will be skipped.
2873 already been grafted, or that are merges will be skipped.
2874
2874
2875 If --log is specified, log messages will have a comment appended
2875 If --log is specified, log messages will have a comment appended
2876 of the form::
2876 of the form::
2877
2877
2878 (grafted from CHANGESETHASH)
2878 (grafted from CHANGESETHASH)
2879
2879
2880 If --force is specified, revisions will be grafted even if they
2880 If --force is specified, revisions will be grafted even if they
2881 are already ancestors of, or have been grafted to, the destination.
2881 are already ancestors of, or have been grafted to, the destination.
2882 This is useful when the revisions have since been backed out.
2882 This is useful when the revisions have since been backed out.
2883
2883
2884 If a graft merge results in conflicts, the graft process is
2884 If a graft merge results in conflicts, the graft process is
2885 interrupted so that the current merge can be manually resolved.
2885 interrupted so that the current merge can be manually resolved.
2886 Once all conflicts are addressed, the graft process can be
2886 Once all conflicts are addressed, the graft process can be
2887 continued with the -c/--continue option.
2887 continued with the -c/--continue option.
2888
2888
2889 The -c/--continue option reapplies all the earlier options.
2889 The -c/--continue option reapplies all the earlier options.
2890
2890
2891 .. container:: verbose
2891 .. container:: verbose
2892
2892
2893 The --base option exposes more of how graft internally uses merge with a
2893 The --base option exposes more of how graft internally uses merge with a
2894 custom base revision. --base can be used to specify another ancestor than
2894 custom base revision. --base can be used to specify another ancestor than
2895 the first and only parent.
2895 the first and only parent.
2896
2896
2897 The command::
2897 The command::
2898
2898
2899 hg graft -r 345 --base 234
2899 hg graft -r 345 --base 234
2900
2900
2901 is thus pretty much the same as::
2901 is thus pretty much the same as::
2902
2902
2903 hg diff -r 234 -r 345 | hg import
2903 hg diff -r 234 -r 345 | hg import
2904
2904
2905 but using merge to resolve conflicts and track moved files.
2905 but using merge to resolve conflicts and track moved files.
2906
2906
2907 The result of a merge can thus be backported as a single commit by
2907 The result of a merge can thus be backported as a single commit by
2908 specifying one of the merge parents as base, and thus effectively
2908 specifying one of the merge parents as base, and thus effectively
2909 grafting the changes from the other side.
2909 grafting the changes from the other side.
2910
2910
2911 It is also possible to collapse multiple changesets and clean up history
2911 It is also possible to collapse multiple changesets and clean up history
2912 by specifying another ancestor as base, much like rebase --collapse
2912 by specifying another ancestor as base, much like rebase --collapse
2913 --keep.
2913 --keep.
2914
2914
2915 The commit message can be tweaked after the fact using commit --amend .
2915 The commit message can be tweaked after the fact using commit --amend .
2916
2916
2917 For using non-ancestors as the base to backout changes, see the backout
2917 For using non-ancestors as the base to backout changes, see the backout
2918 command and the hidden --parent option.
2918 command and the hidden --parent option.
2919
2919
2920 .. container:: verbose
2920 .. container:: verbose
2921
2921
2922 Examples:
2922 Examples:
2923
2923
2924 - copy a single change to the stable branch and edit its description::
2924 - copy a single change to the stable branch and edit its description::
2925
2925
2926 hg update stable
2926 hg update stable
2927 hg graft --edit 9393
2927 hg graft --edit 9393
2928
2928
2929 - graft a range of changesets with one exception, updating dates::
2929 - graft a range of changesets with one exception, updating dates::
2930
2930
2931 hg graft -D "2085::2093 and not 2091"
2931 hg graft -D "2085::2093 and not 2091"
2932
2932
2933 - continue a graft after resolving conflicts::
2933 - continue a graft after resolving conflicts::
2934
2934
2935 hg graft -c
2935 hg graft -c
2936
2936
2937 - show the source of a grafted changeset::
2937 - show the source of a grafted changeset::
2938
2938
2939 hg log --debug -r .
2939 hg log --debug -r .
2940
2940
2941 - show revisions sorted by date::
2941 - show revisions sorted by date::
2942
2942
2943 hg log -r "sort(all(), date)"
2943 hg log -r "sort(all(), date)"
2944
2944
2945 - backport the result of a merge as a single commit::
2945 - backport the result of a merge as a single commit::
2946
2946
2947 hg graft -r 123 --base 123^
2947 hg graft -r 123 --base 123^
2948
2948
2949 - land a feature branch as one changeset::
2949 - land a feature branch as one changeset::
2950
2950
2951 hg up -cr default
2951 hg up -cr default
2952 hg graft -r featureX --base "ancestor('featureX', 'default')"
2952 hg graft -r featureX --base "ancestor('featureX', 'default')"
2953
2953
2954 See :hg:`help revisions` for more about specifying revisions.
2954 See :hg:`help revisions` for more about specifying revisions.
2955
2955
2956 Returns 0 on successful completion, 1 if there are unresolved files.
2956 Returns 0 on successful completion, 1 if there are unresolved files.
2957 '''
2957 '''
2958 with repo.wlock():
2958 with repo.wlock():
2959 return _dograft(ui, repo, *revs, **opts)
2959 return _dograft(ui, repo, *revs, **opts)
2960
2960
2961
2961
2962 def _dograft(ui, repo, *revs, **opts):
2962 def _dograft(ui, repo, *revs, **opts):
2963 opts = pycompat.byteskwargs(opts)
2963 opts = pycompat.byteskwargs(opts)
2964 if revs and opts.get(b'rev'):
2964 if revs and opts.get(b'rev'):
2965 ui.warn(
2965 ui.warn(
2966 _(
2966 _(
2967 b'warning: inconsistent use of --rev might give unexpected '
2967 b'warning: inconsistent use of --rev might give unexpected '
2968 b'revision ordering!\n'
2968 b'revision ordering!\n'
2969 )
2969 )
2970 )
2970 )
2971
2971
2972 revs = list(revs)
2972 revs = list(revs)
2973 revs.extend(opts.get(b'rev'))
2973 revs.extend(opts.get(b'rev'))
2974 # a dict of data to be stored in state file
2974 # a dict of data to be stored in state file
2975 statedata = {}
2975 statedata = {}
2976 # list of new nodes created by ongoing graft
2976 # list of new nodes created by ongoing graft
2977 statedata[b'newnodes'] = []
2977 statedata[b'newnodes'] = []
2978
2978
2979 cmdutil.resolvecommitoptions(ui, opts)
2979 cmdutil.resolvecommitoptions(ui, opts)
2980
2980
2981 editor = cmdutil.getcommiteditor(
2981 editor = cmdutil.getcommiteditor(
2982 editform=b'graft', **pycompat.strkwargs(opts)
2982 editform=b'graft', **pycompat.strkwargs(opts)
2983 )
2983 )
2984
2984
2985 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
2986
2985 cont = False
2987 cont = False
2986 if opts.get(b'no_commit'):
2988 if opts.get(b'no_commit'):
2987 if opts.get(b'edit'):
2989 if opts.get(b'edit'):
2988 raise error.Abort(
2990 raise error.Abort(
2989 _(b"cannot specify --no-commit and --edit together")
2991 _(b"cannot specify --no-commit and --edit together")
2990 )
2992 )
2991 if opts.get(b'currentuser'):
2993 if opts.get(b'currentuser'):
2992 raise error.Abort(
2994 raise error.Abort(
2993 _(b"cannot specify --no-commit and --currentuser together")
2995 _(b"cannot specify --no-commit and --currentuser together")
2994 )
2996 )
2995 if opts.get(b'currentdate'):
2997 if opts.get(b'currentdate'):
2996 raise error.Abort(
2998 raise error.Abort(
2997 _(b"cannot specify --no-commit and --currentdate together")
2999 _(b"cannot specify --no-commit and --currentdate together")
2998 )
3000 )
2999 if opts.get(b'log'):
3001 if opts.get(b'log'):
3000 raise error.Abort(
3002 raise error.Abort(
3001 _(b"cannot specify --no-commit and --log together")
3003 _(b"cannot specify --no-commit and --log together")
3002 )
3004 )
3003
3005
3004 graftstate = statemod.cmdstate(repo, b'graftstate')
3006 graftstate = statemod.cmdstate(repo, b'graftstate')
3005
3007
3006 if opts.get(b'stop'):
3008 if opts.get(b'stop'):
3007 if opts.get(b'continue'):
3008 raise error.Abort(
3009 _(b"cannot use '--continue' and '--stop' together")
3010 )
3011 if opts.get(b'abort'):
3012 raise error.Abort(_(b"cannot use '--abort' and '--stop' together"))
3013
3014 if any(
3009 if any(
3015 (
3010 (
3016 opts.get(b'edit'),
3011 opts.get(b'edit'),
3017 opts.get(b'log'),
3012 opts.get(b'log'),
3018 opts.get(b'user'),
3013 opts.get(b'user'),
3019 opts.get(b'date'),
3014 opts.get(b'date'),
3020 opts.get(b'currentdate'),
3015 opts.get(b'currentdate'),
3021 opts.get(b'currentuser'),
3016 opts.get(b'currentuser'),
3022 opts.get(b'rev'),
3017 opts.get(b'rev'),
3023 )
3018 )
3024 ):
3019 ):
3025 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3020 raise error.Abort(_(b"cannot specify any other flag with '--stop'"))
3026 return _stopgraft(ui, repo, graftstate)
3021 return _stopgraft(ui, repo, graftstate)
3027 elif opts.get(b'abort'):
3022 elif opts.get(b'abort'):
3028 if opts.get(b'continue'):
3029 raise error.Abort(
3030 _(b"cannot use '--continue' and '--abort' together")
3031 )
3032 if any(
3023 if any(
3033 (
3024 (
3034 opts.get(b'edit'),
3025 opts.get(b'edit'),
3035 opts.get(b'log'),
3026 opts.get(b'log'),
3036 opts.get(b'user'),
3027 opts.get(b'user'),
3037 opts.get(b'date'),
3028 opts.get(b'date'),
3038 opts.get(b'currentdate'),
3029 opts.get(b'currentdate'),
3039 opts.get(b'currentuser'),
3030 opts.get(b'currentuser'),
3040 opts.get(b'rev'),
3031 opts.get(b'rev'),
3041 )
3032 )
3042 ):
3033 ):
3043 raise error.Abort(
3034 raise error.Abort(
3044 _(b"cannot specify any other flag with '--abort'")
3035 _(b"cannot specify any other flag with '--abort'")
3045 )
3036 )
3046
3037
3047 return cmdutil.abortgraft(ui, repo, graftstate)
3038 return cmdutil.abortgraft(ui, repo, graftstate)
3048 elif opts.get(b'continue'):
3039 elif opts.get(b'continue'):
3049 cont = True
3040 cont = True
3050 if revs:
3041 if revs:
3051 raise error.Abort(_(b"can't specify --continue and revisions"))
3042 raise error.Abort(_(b"can't specify --continue and revisions"))
3052 # read in unfinished revisions
3043 # read in unfinished revisions
3053 if graftstate.exists():
3044 if graftstate.exists():
3054 statedata = cmdutil.readgraftstate(repo, graftstate)
3045 statedata = cmdutil.readgraftstate(repo, graftstate)
3055 if statedata.get(b'date'):
3046 if statedata.get(b'date'):
3056 opts[b'date'] = statedata[b'date']
3047 opts[b'date'] = statedata[b'date']
3057 if statedata.get(b'user'):
3048 if statedata.get(b'user'):
3058 opts[b'user'] = statedata[b'user']
3049 opts[b'user'] = statedata[b'user']
3059 if statedata.get(b'log'):
3050 if statedata.get(b'log'):
3060 opts[b'log'] = True
3051 opts[b'log'] = True
3061 if statedata.get(b'no_commit'):
3052 if statedata.get(b'no_commit'):
3062 opts[b'no_commit'] = statedata.get(b'no_commit')
3053 opts[b'no_commit'] = statedata.get(b'no_commit')
3063 if statedata.get(b'base'):
3054 if statedata.get(b'base'):
3064 opts[b'base'] = statedata.get(b'base')
3055 opts[b'base'] = statedata.get(b'base')
3065 nodes = statedata[b'nodes']
3056 nodes = statedata[b'nodes']
3066 revs = [repo[node].rev() for node in nodes]
3057 revs = [repo[node].rev() for node in nodes]
3067 else:
3058 else:
3068 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3059 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3069 else:
3060 else:
3070 if not revs:
3061 if not revs:
3071 raise error.Abort(_(b'no revisions specified'))
3062 raise error.Abort(_(b'no revisions specified'))
3072 cmdutil.checkunfinished(repo)
3063 cmdutil.checkunfinished(repo)
3073 cmdutil.bailifchanged(repo)
3064 cmdutil.bailifchanged(repo)
3074 revs = scmutil.revrange(repo, revs)
3065 revs = scmutil.revrange(repo, revs)
3075
3066
3076 skipped = set()
3067 skipped = set()
3077 basectx = None
3068 basectx = None
3078 if opts.get(b'base'):
3069 if opts.get(b'base'):
3079 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3070 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3080 if basectx is None:
3071 if basectx is None:
3081 # check for merges
3072 # check for merges
3082 for rev in repo.revs(b'%ld and merge()', revs):
3073 for rev in repo.revs(b'%ld and merge()', revs):
3083 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3074 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3084 skipped.add(rev)
3075 skipped.add(rev)
3085 revs = [r for r in revs if r not in skipped]
3076 revs = [r for r in revs if r not in skipped]
3086 if not revs:
3077 if not revs:
3087 return -1
3078 return -1
3088 if basectx is not None and len(revs) != 1:
3079 if basectx is not None and len(revs) != 1:
3089 raise error.Abort(_(b'only one revision allowed with --base '))
3080 raise error.Abort(_(b'only one revision allowed with --base '))
3090
3081
3091 # Don't check in the --continue case, in effect retaining --force across
3082 # Don't check in the --continue case, in effect retaining --force across
3092 # --continues. That's because without --force, any revisions we decided to
3083 # --continues. That's because without --force, any revisions we decided to
3093 # skip would have been filtered out here, so they wouldn't have made their
3084 # skip would have been filtered out here, so they wouldn't have made their
3094 # way to the graftstate. With --force, any revisions we would have otherwise
3085 # way to the graftstate. With --force, any revisions we would have otherwise
3095 # skipped would not have been filtered out, and if they hadn't been applied
3086 # skipped would not have been filtered out, and if they hadn't been applied
3096 # already, they'd have been in the graftstate.
3087 # already, they'd have been in the graftstate.
3097 if not (cont or opts.get(b'force')) and basectx is None:
3088 if not (cont or opts.get(b'force')) and basectx is None:
3098 # check for ancestors of dest branch
3089 # check for ancestors of dest branch
3099 ancestors = repo.revs(b'%ld & (::.)', revs)
3090 ancestors = repo.revs(b'%ld & (::.)', revs)
3100 for rev in ancestors:
3091 for rev in ancestors:
3101 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3092 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3102
3093
3103 revs = [r for r in revs if r not in ancestors]
3094 revs = [r for r in revs if r not in ancestors]
3104
3095
3105 if not revs:
3096 if not revs:
3106 return -1
3097 return -1
3107
3098
3108 # analyze revs for earlier grafts
3099 # analyze revs for earlier grafts
3109 ids = {}
3100 ids = {}
3110 for ctx in repo.set(b"%ld", revs):
3101 for ctx in repo.set(b"%ld", revs):
3111 ids[ctx.hex()] = ctx.rev()
3102 ids[ctx.hex()] = ctx.rev()
3112 n = ctx.extra().get(b'source')
3103 n = ctx.extra().get(b'source')
3113 if n:
3104 if n:
3114 ids[n] = ctx.rev()
3105 ids[n] = ctx.rev()
3115
3106
3116 # check ancestors for earlier grafts
3107 # check ancestors for earlier grafts
3117 ui.debug(b'scanning for duplicate grafts\n')
3108 ui.debug(b'scanning for duplicate grafts\n')
3118
3109
3119 # The only changesets we can be sure doesn't contain grafts of any
3110 # The only changesets we can be sure doesn't contain grafts of any
3120 # revs, are the ones that are common ancestors of *all* revs:
3111 # revs, are the ones that are common ancestors of *all* revs:
3121 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3112 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3122 ctx = repo[rev]
3113 ctx = repo[rev]
3123 n = ctx.extra().get(b'source')
3114 n = ctx.extra().get(b'source')
3124 if n in ids:
3115 if n in ids:
3125 try:
3116 try:
3126 r = repo[n].rev()
3117 r = repo[n].rev()
3127 except error.RepoLookupError:
3118 except error.RepoLookupError:
3128 r = None
3119 r = None
3129 if r in revs:
3120 if r in revs:
3130 ui.warn(
3121 ui.warn(
3131 _(
3122 _(
3132 b'skipping revision %d:%s '
3123 b'skipping revision %d:%s '
3133 b'(already grafted to %d:%s)\n'
3124 b'(already grafted to %d:%s)\n'
3134 )
3125 )
3135 % (r, repo[r], rev, ctx)
3126 % (r, repo[r], rev, ctx)
3136 )
3127 )
3137 revs.remove(r)
3128 revs.remove(r)
3138 elif ids[n] in revs:
3129 elif ids[n] in revs:
3139 if r is None:
3130 if r is None:
3140 ui.warn(
3131 ui.warn(
3141 _(
3132 _(
3142 b'skipping already grafted revision %d:%s '
3133 b'skipping already grafted revision %d:%s '
3143 b'(%d:%s also has unknown origin %s)\n'
3134 b'(%d:%s also has unknown origin %s)\n'
3144 )
3135 )
3145 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3136 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3146 )
3137 )
3147 else:
3138 else:
3148 ui.warn(
3139 ui.warn(
3149 _(
3140 _(
3150 b'skipping already grafted revision %d:%s '
3141 b'skipping already grafted revision %d:%s '
3151 b'(%d:%s also has origin %d:%s)\n'
3142 b'(%d:%s also has origin %d:%s)\n'
3152 )
3143 )
3153 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3144 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3154 )
3145 )
3155 revs.remove(ids[n])
3146 revs.remove(ids[n])
3156 elif ctx.hex() in ids:
3147 elif ctx.hex() in ids:
3157 r = ids[ctx.hex()]
3148 r = ids[ctx.hex()]
3158 if r in revs:
3149 if r in revs:
3159 ui.warn(
3150 ui.warn(
3160 _(
3151 _(
3161 b'skipping already grafted revision %d:%s '
3152 b'skipping already grafted revision %d:%s '
3162 b'(was grafted from %d:%s)\n'
3153 b'(was grafted from %d:%s)\n'
3163 )
3154 )
3164 % (r, repo[r], rev, ctx)
3155 % (r, repo[r], rev, ctx)
3165 )
3156 )
3166 revs.remove(r)
3157 revs.remove(r)
3167 if not revs:
3158 if not revs:
3168 return -1
3159 return -1
3169
3160
3170 if opts.get(b'no_commit'):
3161 if opts.get(b'no_commit'):
3171 statedata[b'no_commit'] = True
3162 statedata[b'no_commit'] = True
3172 if opts.get(b'base'):
3163 if opts.get(b'base'):
3173 statedata[b'base'] = opts[b'base']
3164 statedata[b'base'] = opts[b'base']
3174 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3165 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3175 desc = b'%d:%s "%s"' % (
3166 desc = b'%d:%s "%s"' % (
3176 ctx.rev(),
3167 ctx.rev(),
3177 ctx,
3168 ctx,
3178 ctx.description().split(b'\n', 1)[0],
3169 ctx.description().split(b'\n', 1)[0],
3179 )
3170 )
3180 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3171 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3181 if names:
3172 if names:
3182 desc += b' (%s)' % b' '.join(names)
3173 desc += b' (%s)' % b' '.join(names)
3183 ui.status(_(b'grafting %s\n') % desc)
3174 ui.status(_(b'grafting %s\n') % desc)
3184 if opts.get(b'dry_run'):
3175 if opts.get(b'dry_run'):
3185 continue
3176 continue
3186
3177
3187 source = ctx.extra().get(b'source')
3178 source = ctx.extra().get(b'source')
3188 extra = {}
3179 extra = {}
3189 if source:
3180 if source:
3190 extra[b'source'] = source
3181 extra[b'source'] = source
3191 extra[b'intermediate-source'] = ctx.hex()
3182 extra[b'intermediate-source'] = ctx.hex()
3192 else:
3183 else:
3193 extra[b'source'] = ctx.hex()
3184 extra[b'source'] = ctx.hex()
3194 user = ctx.user()
3185 user = ctx.user()
3195 if opts.get(b'user'):
3186 if opts.get(b'user'):
3196 user = opts[b'user']
3187 user = opts[b'user']
3197 statedata[b'user'] = user
3188 statedata[b'user'] = user
3198 date = ctx.date()
3189 date = ctx.date()
3199 if opts.get(b'date'):
3190 if opts.get(b'date'):
3200 date = opts[b'date']
3191 date = opts[b'date']
3201 statedata[b'date'] = date
3192 statedata[b'date'] = date
3202 message = ctx.description()
3193 message = ctx.description()
3203 if opts.get(b'log'):
3194 if opts.get(b'log'):
3204 message += b'\n(grafted from %s)' % ctx.hex()
3195 message += b'\n(grafted from %s)' % ctx.hex()
3205 statedata[b'log'] = True
3196 statedata[b'log'] = True
3206
3197
3207 # we don't merge the first commit when continuing
3198 # we don't merge the first commit when continuing
3208 if not cont:
3199 if not cont:
3209 # perform the graft merge with p1(rev) as 'ancestor'
3200 # perform the graft merge with p1(rev) as 'ancestor'
3210 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3201 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3211 base = ctx.p1() if basectx is None else basectx
3202 base = ctx.p1() if basectx is None else basectx
3212 with ui.configoverride(overrides, b'graft'):
3203 with ui.configoverride(overrides, b'graft'):
3213 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3204 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3214 # report any conflicts
3205 # report any conflicts
3215 if stats.unresolvedcount > 0:
3206 if stats.unresolvedcount > 0:
3216 # write out state for --continue
3207 # write out state for --continue
3217 nodes = [repo[rev].hex() for rev in revs[pos:]]
3208 nodes = [repo[rev].hex() for rev in revs[pos:]]
3218 statedata[b'nodes'] = nodes
3209 statedata[b'nodes'] = nodes
3219 stateversion = 1
3210 stateversion = 1
3220 graftstate.save(stateversion, statedata)
3211 graftstate.save(stateversion, statedata)
3221 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3212 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3222 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3213 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3223 return 1
3214 return 1
3224 else:
3215 else:
3225 cont = False
3216 cont = False
3226
3217
3227 # commit if --no-commit is false
3218 # commit if --no-commit is false
3228 if not opts.get(b'no_commit'):
3219 if not opts.get(b'no_commit'):
3229 node = repo.commit(
3220 node = repo.commit(
3230 text=message, user=user, date=date, extra=extra, editor=editor
3221 text=message, user=user, date=date, extra=extra, editor=editor
3231 )
3222 )
3232 if node is None:
3223 if node is None:
3233 ui.warn(
3224 ui.warn(
3234 _(b'note: graft of %d:%s created no changes to commit\n')
3225 _(b'note: graft of %d:%s created no changes to commit\n')
3235 % (ctx.rev(), ctx)
3226 % (ctx.rev(), ctx)
3236 )
3227 )
3237 # checking that newnodes exist because old state files won't have it
3228 # checking that newnodes exist because old state files won't have it
3238 elif statedata.get(b'newnodes') is not None:
3229 elif statedata.get(b'newnodes') is not None:
3239 statedata[b'newnodes'].append(node)
3230 statedata[b'newnodes'].append(node)
3240
3231
3241 # remove state when we complete successfully
3232 # remove state when we complete successfully
3242 if not opts.get(b'dry_run'):
3233 if not opts.get(b'dry_run'):
3243 graftstate.delete()
3234 graftstate.delete()
3244
3235
3245 return 0
3236 return 0
3246
3237
3247
3238
3248 def _stopgraft(ui, repo, graftstate):
3239 def _stopgraft(ui, repo, graftstate):
3249 """stop the interrupted graft"""
3240 """stop the interrupted graft"""
3250 if not graftstate.exists():
3241 if not graftstate.exists():
3251 raise error.Abort(_(b"no interrupted graft found"))
3242 raise error.Abort(_(b"no interrupted graft found"))
3252 pctx = repo[b'.']
3243 pctx = repo[b'.']
3253 hg.updaterepo(repo, pctx.node(), overwrite=True)
3244 hg.updaterepo(repo, pctx.node(), overwrite=True)
3254 graftstate.delete()
3245 graftstate.delete()
3255 ui.status(_(b"stopped the interrupted graft\n"))
3246 ui.status(_(b"stopped the interrupted graft\n"))
3256 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3247 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3257 return 0
3248 return 0
3258
3249
3259
3250
3260 statemod.addunfinished(
3251 statemod.addunfinished(
3261 b'graft',
3252 b'graft',
3262 fname=b'graftstate',
3253 fname=b'graftstate',
3263 clearable=True,
3254 clearable=True,
3264 stopflag=True,
3255 stopflag=True,
3265 continueflag=True,
3256 continueflag=True,
3266 abortfunc=cmdutil.hgabortgraft,
3257 abortfunc=cmdutil.hgabortgraft,
3267 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3258 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3268 )
3259 )
3269
3260
3270
3261
3271 @command(
3262 @command(
3272 b'grep',
3263 b'grep',
3273 [
3264 [
3274 (b'0', b'print0', None, _(b'end fields with NUL')),
3265 (b'0', b'print0', None, _(b'end fields with NUL')),
3275 (b'', b'all', None, _(b'print all revisions that match (DEPRECATED) ')),
3266 (b'', b'all', None, _(b'print all revisions that match (DEPRECATED) ')),
3276 (
3267 (
3277 b'',
3268 b'',
3278 b'diff',
3269 b'diff',
3279 None,
3270 None,
3280 _(
3271 _(
3281 b'search revision differences for when the pattern was added '
3272 b'search revision differences for when the pattern was added '
3282 b'or removed'
3273 b'or removed'
3283 ),
3274 ),
3284 ),
3275 ),
3285 (b'a', b'text', None, _(b'treat all files as text')),
3276 (b'a', b'text', None, _(b'treat all files as text')),
3286 (
3277 (
3287 b'f',
3278 b'f',
3288 b'follow',
3279 b'follow',
3289 None,
3280 None,
3290 _(
3281 _(
3291 b'follow changeset history,'
3282 b'follow changeset history,'
3292 b' or file history across copies and renames'
3283 b' or file history across copies and renames'
3293 ),
3284 ),
3294 ),
3285 ),
3295 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3286 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3296 (
3287 (
3297 b'l',
3288 b'l',
3298 b'files-with-matches',
3289 b'files-with-matches',
3299 None,
3290 None,
3300 _(b'print only filenames and revisions that match'),
3291 _(b'print only filenames and revisions that match'),
3301 ),
3292 ),
3302 (b'n', b'line-number', None, _(b'print matching line numbers')),
3293 (b'n', b'line-number', None, _(b'print matching line numbers')),
3303 (
3294 (
3304 b'r',
3295 b'r',
3305 b'rev',
3296 b'rev',
3306 [],
3297 [],
3307 _(b'search files changed within revision range'),
3298 _(b'search files changed within revision range'),
3308 _(b'REV'),
3299 _(b'REV'),
3309 ),
3300 ),
3310 (
3301 (
3311 b'',
3302 b'',
3312 b'all-files',
3303 b'all-files',
3313 None,
3304 None,
3314 _(
3305 _(
3315 b'include all files in the changeset while grepping (DEPRECATED)'
3306 b'include all files in the changeset while grepping (DEPRECATED)'
3316 ),
3307 ),
3317 ),
3308 ),
3318 (b'u', b'user', None, _(b'list the author (long with -v)')),
3309 (b'u', b'user', None, _(b'list the author (long with -v)')),
3319 (b'd', b'date', None, _(b'list the date (short with -q)')),
3310 (b'd', b'date', None, _(b'list the date (short with -q)')),
3320 ]
3311 ]
3321 + formatteropts
3312 + formatteropts
3322 + walkopts,
3313 + walkopts,
3323 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3314 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3324 helpcategory=command.CATEGORY_FILE_CONTENTS,
3315 helpcategory=command.CATEGORY_FILE_CONTENTS,
3325 inferrepo=True,
3316 inferrepo=True,
3326 intents={INTENT_READONLY},
3317 intents={INTENT_READONLY},
3327 )
3318 )
3328 def grep(ui, repo, pattern, *pats, **opts):
3319 def grep(ui, repo, pattern, *pats, **opts):
3329 """search for a pattern in specified files
3320 """search for a pattern in specified files
3330
3321
3331 Search the working directory or revision history for a regular
3322 Search the working directory or revision history for a regular
3332 expression in the specified files for the entire repository.
3323 expression in the specified files for the entire repository.
3333
3324
3334 By default, grep searches the repository files in the working
3325 By default, grep searches the repository files in the working
3335 directory and prints the files where it finds a match. To specify
3326 directory and prints the files where it finds a match. To specify
3336 historical revisions instead of the working directory, use the
3327 historical revisions instead of the working directory, use the
3337 --rev flag.
3328 --rev flag.
3338
3329
3339 To search instead historical revision differences that contains a
3330 To search instead historical revision differences that contains a
3340 change in match status ("-" for a match that becomes a non-match,
3331 change in match status ("-" for a match that becomes a non-match,
3341 or "+" for a non-match that becomes a match), use the --diff flag.
3332 or "+" for a non-match that becomes a match), use the --diff flag.
3342
3333
3343 PATTERN can be any Python (roughly Perl-compatible) regular
3334 PATTERN can be any Python (roughly Perl-compatible) regular
3344 expression.
3335 expression.
3345
3336
3346 If no FILEs are specified and the --rev flag isn't supplied, all
3337 If no FILEs are specified and the --rev flag isn't supplied, all
3347 files in the working directory are searched. When using the --rev
3338 files in the working directory are searched. When using the --rev
3348 flag and specifying FILEs, use the --follow argument to also
3339 flag and specifying FILEs, use the --follow argument to also
3349 follow the specified FILEs across renames and copies.
3340 follow the specified FILEs across renames and copies.
3350
3341
3351 .. container:: verbose
3342 .. container:: verbose
3352
3343
3353 Template:
3344 Template:
3354
3345
3355 The following keywords are supported in addition to the common template
3346 The following keywords are supported in addition to the common template
3356 keywords and functions. See also :hg:`help templates`.
3347 keywords and functions. See also :hg:`help templates`.
3357
3348
3358 :change: String. Character denoting insertion ``+`` or removal ``-``.
3349 :change: String. Character denoting insertion ``+`` or removal ``-``.
3359 Available if ``--diff`` is specified.
3350 Available if ``--diff`` is specified.
3360 :lineno: Integer. Line number of the match.
3351 :lineno: Integer. Line number of the match.
3361 :path: String. Repository-absolute path of the file.
3352 :path: String. Repository-absolute path of the file.
3362 :texts: List of text chunks.
3353 :texts: List of text chunks.
3363
3354
3364 And each entry of ``{texts}`` provides the following sub-keywords.
3355 And each entry of ``{texts}`` provides the following sub-keywords.
3365
3356
3366 :matched: Boolean. True if the chunk matches the specified pattern.
3357 :matched: Boolean. True if the chunk matches the specified pattern.
3367 :text: String. Chunk content.
3358 :text: String. Chunk content.
3368
3359
3369 See :hg:`help templates.operators` for the list expansion syntax.
3360 See :hg:`help templates.operators` for the list expansion syntax.
3370
3361
3371 Returns 0 if a match is found, 1 otherwise.
3362 Returns 0 if a match is found, 1 otherwise.
3372
3363
3373 """
3364 """
3374 opts = pycompat.byteskwargs(opts)
3365 opts = pycompat.byteskwargs(opts)
3375 diff = opts.get(b'all') or opts.get(b'diff')
3366 diff = opts.get(b'all') or opts.get(b'diff')
3376 if diff and opts.get(b'all_files'):
3367 if diff and opts.get(b'all_files'):
3377 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3368 raise error.Abort(_(b'--diff and --all-files are mutually exclusive'))
3378 if opts.get(b'all_files') is None and not diff:
3369 if opts.get(b'all_files') is None and not diff:
3379 opts[b'all_files'] = True
3370 opts[b'all_files'] = True
3380 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3371 plaingrep = opts.get(b'all_files') and not opts.get(b'rev')
3381 all_files = opts.get(b'all_files')
3372 all_files = opts.get(b'all_files')
3382 if plaingrep:
3373 if plaingrep:
3383 opts[b'rev'] = [b'wdir()']
3374 opts[b'rev'] = [b'wdir()']
3384
3375
3385 reflags = re.M
3376 reflags = re.M
3386 if opts.get(b'ignore_case'):
3377 if opts.get(b'ignore_case'):
3387 reflags |= re.I
3378 reflags |= re.I
3388 try:
3379 try:
3389 regexp = util.re.compile(pattern, reflags)
3380 regexp = util.re.compile(pattern, reflags)
3390 except re.error as inst:
3381 except re.error as inst:
3391 ui.warn(
3382 ui.warn(
3392 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3383 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3393 )
3384 )
3394 return 1
3385 return 1
3395 sep, eol = b':', b'\n'
3386 sep, eol = b':', b'\n'
3396 if opts.get(b'print0'):
3387 if opts.get(b'print0'):
3397 sep = eol = b'\0'
3388 sep = eol = b'\0'
3398
3389
3399 getfile = util.lrucachefunc(repo.file)
3390 getfile = util.lrucachefunc(repo.file)
3400
3391
3401 def matchlines(body):
3392 def matchlines(body):
3402 begin = 0
3393 begin = 0
3403 linenum = 0
3394 linenum = 0
3404 while begin < len(body):
3395 while begin < len(body):
3405 match = regexp.search(body, begin)
3396 match = regexp.search(body, begin)
3406 if not match:
3397 if not match:
3407 break
3398 break
3408 mstart, mend = match.span()
3399 mstart, mend = match.span()
3409 linenum += body.count(b'\n', begin, mstart) + 1
3400 linenum += body.count(b'\n', begin, mstart) + 1
3410 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3401 lstart = body.rfind(b'\n', begin, mstart) + 1 or begin
3411 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3402 begin = body.find(b'\n', mend) + 1 or len(body) + 1
3412 lend = begin - 1
3403 lend = begin - 1
3413 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3404 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3414
3405
3415 class linestate(object):
3406 class linestate(object):
3416 def __init__(self, line, linenum, colstart, colend):
3407 def __init__(self, line, linenum, colstart, colend):
3417 self.line = line
3408 self.line = line
3418 self.linenum = linenum
3409 self.linenum = linenum
3419 self.colstart = colstart
3410 self.colstart = colstart
3420 self.colend = colend
3411 self.colend = colend
3421
3412
3422 def __hash__(self):
3413 def __hash__(self):
3423 return hash((self.linenum, self.line))
3414 return hash((self.linenum, self.line))
3424
3415
3425 def __eq__(self, other):
3416 def __eq__(self, other):
3426 return self.line == other.line
3417 return self.line == other.line
3427
3418
3428 def findpos(self):
3419 def findpos(self):
3429 """Iterate all (start, end) indices of matches"""
3420 """Iterate all (start, end) indices of matches"""
3430 yield self.colstart, self.colend
3421 yield self.colstart, self.colend
3431 p = self.colend
3422 p = self.colend
3432 while p < len(self.line):
3423 while p < len(self.line):
3433 m = regexp.search(self.line, p)
3424 m = regexp.search(self.line, p)
3434 if not m:
3425 if not m:
3435 break
3426 break
3436 if m.end() == p:
3427 if m.end() == p:
3437 p += 1
3428 p += 1
3438 else:
3429 else:
3439 yield m.span()
3430 yield m.span()
3440 p = m.end()
3431 p = m.end()
3441
3432
3442 matches = {}
3433 matches = {}
3443 copies = {}
3434 copies = {}
3444
3435
3445 def grepbody(fn, rev, body):
3436 def grepbody(fn, rev, body):
3446 matches[rev].setdefault(fn, [])
3437 matches[rev].setdefault(fn, [])
3447 m = matches[rev][fn]
3438 m = matches[rev][fn]
3448 if body is None:
3439 if body is None:
3449 return
3440 return
3450
3441
3451 for lnum, cstart, cend, line in matchlines(body):
3442 for lnum, cstart, cend, line in matchlines(body):
3452 s = linestate(line, lnum, cstart, cend)
3443 s = linestate(line, lnum, cstart, cend)
3453 m.append(s)
3444 m.append(s)
3454
3445
3455 def difflinestates(a, b):
3446 def difflinestates(a, b):
3456 sm = difflib.SequenceMatcher(None, a, b)
3447 sm = difflib.SequenceMatcher(None, a, b)
3457 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3448 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3458 if tag == 'insert':
3449 if tag == 'insert':
3459 for i in pycompat.xrange(blo, bhi):
3450 for i in pycompat.xrange(blo, bhi):
3460 yield (b'+', b[i])
3451 yield (b'+', b[i])
3461 elif tag == 'delete':
3452 elif tag == 'delete':
3462 for i in pycompat.xrange(alo, ahi):
3453 for i in pycompat.xrange(alo, ahi):
3463 yield (b'-', a[i])
3454 yield (b'-', a[i])
3464 elif tag == 'replace':
3455 elif tag == 'replace':
3465 for i in pycompat.xrange(alo, ahi):
3456 for i in pycompat.xrange(alo, ahi):
3466 yield (b'-', a[i])
3457 yield (b'-', a[i])
3467 for i in pycompat.xrange(blo, bhi):
3458 for i in pycompat.xrange(blo, bhi):
3468 yield (b'+', b[i])
3459 yield (b'+', b[i])
3469
3460
3470 uipathfn = scmutil.getuipathfn(repo)
3461 uipathfn = scmutil.getuipathfn(repo)
3471
3462
3472 def display(fm, fn, ctx, pstates, states):
3463 def display(fm, fn, ctx, pstates, states):
3473 rev = scmutil.intrev(ctx)
3464 rev = scmutil.intrev(ctx)
3474 if fm.isplain():
3465 if fm.isplain():
3475 formatuser = ui.shortuser
3466 formatuser = ui.shortuser
3476 else:
3467 else:
3477 formatuser = pycompat.bytestr
3468 formatuser = pycompat.bytestr
3478 if ui.quiet:
3469 if ui.quiet:
3479 datefmt = b'%Y-%m-%d'
3470 datefmt = b'%Y-%m-%d'
3480 else:
3471 else:
3481 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3472 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3482 found = False
3473 found = False
3483
3474
3484 @util.cachefunc
3475 @util.cachefunc
3485 def binary():
3476 def binary():
3486 flog = getfile(fn)
3477 flog = getfile(fn)
3487 try:
3478 try:
3488 return stringutil.binary(flog.read(ctx.filenode(fn)))
3479 return stringutil.binary(flog.read(ctx.filenode(fn)))
3489 except error.WdirUnsupported:
3480 except error.WdirUnsupported:
3490 return ctx[fn].isbinary()
3481 return ctx[fn].isbinary()
3491
3482
3492 fieldnamemap = {b'linenumber': b'lineno'}
3483 fieldnamemap = {b'linenumber': b'lineno'}
3493 if diff:
3484 if diff:
3494 iter = difflinestates(pstates, states)
3485 iter = difflinestates(pstates, states)
3495 else:
3486 else:
3496 iter = [(b'', l) for l in states]
3487 iter = [(b'', l) for l in states]
3497 for change, l in iter:
3488 for change, l in iter:
3498 fm.startitem()
3489 fm.startitem()
3499 fm.context(ctx=ctx)
3490 fm.context(ctx=ctx)
3500 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3491 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3501 fm.plain(uipathfn(fn), label=b'grep.filename')
3492 fm.plain(uipathfn(fn), label=b'grep.filename')
3502
3493
3503 cols = [
3494 cols = [
3504 (b'rev', b'%d', rev, not plaingrep, b''),
3495 (b'rev', b'%d', rev, not plaingrep, b''),
3505 (
3496 (
3506 b'linenumber',
3497 b'linenumber',
3507 b'%d',
3498 b'%d',
3508 l.linenum,
3499 l.linenum,
3509 opts.get(b'line_number'),
3500 opts.get(b'line_number'),
3510 b'',
3501 b'',
3511 ),
3502 ),
3512 ]
3503 ]
3513 if diff:
3504 if diff:
3514 cols.append(
3505 cols.append(
3515 (
3506 (
3516 b'change',
3507 b'change',
3517 b'%s',
3508 b'%s',
3518 change,
3509 change,
3519 True,
3510 True,
3520 b'grep.inserted '
3511 b'grep.inserted '
3521 if change == b'+'
3512 if change == b'+'
3522 else b'grep.deleted ',
3513 else b'grep.deleted ',
3523 )
3514 )
3524 )
3515 )
3525 cols.extend(
3516 cols.extend(
3526 [
3517 [
3527 (
3518 (
3528 b'user',
3519 b'user',
3529 b'%s',
3520 b'%s',
3530 formatuser(ctx.user()),
3521 formatuser(ctx.user()),
3531 opts.get(b'user'),
3522 opts.get(b'user'),
3532 b'',
3523 b'',
3533 ),
3524 ),
3534 (
3525 (
3535 b'date',
3526 b'date',
3536 b'%s',
3527 b'%s',
3537 fm.formatdate(ctx.date(), datefmt),
3528 fm.formatdate(ctx.date(), datefmt),
3538 opts.get(b'date'),
3529 opts.get(b'date'),
3539 b'',
3530 b'',
3540 ),
3531 ),
3541 ]
3532 ]
3542 )
3533 )
3543 for name, fmt, data, cond, extra_label in cols:
3534 for name, fmt, data, cond, extra_label in cols:
3544 if cond:
3535 if cond:
3545 fm.plain(sep, label=b'grep.sep')
3536 fm.plain(sep, label=b'grep.sep')
3546 field = fieldnamemap.get(name, name)
3537 field = fieldnamemap.get(name, name)
3547 label = extra_label + (b'grep.%s' % name)
3538 label = extra_label + (b'grep.%s' % name)
3548 fm.condwrite(cond, field, fmt, data, label=label)
3539 fm.condwrite(cond, field, fmt, data, label=label)
3549 if not opts.get(b'files_with_matches'):
3540 if not opts.get(b'files_with_matches'):
3550 fm.plain(sep, label=b'grep.sep')
3541 fm.plain(sep, label=b'grep.sep')
3551 if not opts.get(b'text') and binary():
3542 if not opts.get(b'text') and binary():
3552 fm.plain(_(b" Binary file matches"))
3543 fm.plain(_(b" Binary file matches"))
3553 else:
3544 else:
3554 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3545 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3555 fm.plain(eol)
3546 fm.plain(eol)
3556 found = True
3547 found = True
3557 if opts.get(b'files_with_matches'):
3548 if opts.get(b'files_with_matches'):
3558 break
3549 break
3559 return found
3550 return found
3560
3551
3561 def displaymatches(fm, l):
3552 def displaymatches(fm, l):
3562 p = 0
3553 p = 0
3563 for s, e in l.findpos():
3554 for s, e in l.findpos():
3564 if p < s:
3555 if p < s:
3565 fm.startitem()
3556 fm.startitem()
3566 fm.write(b'text', b'%s', l.line[p:s])
3557 fm.write(b'text', b'%s', l.line[p:s])
3567 fm.data(matched=False)
3558 fm.data(matched=False)
3568 fm.startitem()
3559 fm.startitem()
3569 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3560 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3570 fm.data(matched=True)
3561 fm.data(matched=True)
3571 p = e
3562 p = e
3572 if p < len(l.line):
3563 if p < len(l.line):
3573 fm.startitem()
3564 fm.startitem()
3574 fm.write(b'text', b'%s', l.line[p:])
3565 fm.write(b'text', b'%s', l.line[p:])
3575 fm.data(matched=False)
3566 fm.data(matched=False)
3576 fm.end()
3567 fm.end()
3577
3568
3578 skip = set()
3569 skip = set()
3579 revfiles = {}
3570 revfiles = {}
3580 match = scmutil.match(repo[None], pats, opts)
3571 match = scmutil.match(repo[None], pats, opts)
3581 found = False
3572 found = False
3582 follow = opts.get(b'follow')
3573 follow = opts.get(b'follow')
3583
3574
3584 getrenamed = scmutil.getrenamedfn(repo)
3575 getrenamed = scmutil.getrenamedfn(repo)
3585
3576
3586 def readfile(ctx, fn):
3577 def readfile(ctx, fn):
3587 rev = ctx.rev()
3578 rev = ctx.rev()
3588 if rev is None:
3579 if rev is None:
3589 fctx = ctx[fn]
3580 fctx = ctx[fn]
3590 try:
3581 try:
3591 return fctx.data()
3582 return fctx.data()
3592 except IOError as e:
3583 except IOError as e:
3593 if e.errno != errno.ENOENT:
3584 if e.errno != errno.ENOENT:
3594 raise
3585 raise
3595 else:
3586 else:
3596 flog = getfile(fn)
3587 flog = getfile(fn)
3597 fnode = ctx.filenode(fn)
3588 fnode = ctx.filenode(fn)
3598 try:
3589 try:
3599 return flog.read(fnode)
3590 return flog.read(fnode)
3600 except error.CensoredNodeError:
3591 except error.CensoredNodeError:
3601 ui.warn(
3592 ui.warn(
3602 _(
3593 _(
3603 b'cannot search in censored file: %(filename)s:%(revnum)s\n'
3594 b'cannot search in censored file: %(filename)s:%(revnum)s\n'
3604 )
3595 )
3605 % {b'filename': fn, b'revnum': pycompat.bytestr(rev),}
3596 % {b'filename': fn, b'revnum': pycompat.bytestr(rev),}
3606 )
3597 )
3607
3598
3608 def prep(ctx, fns):
3599 def prep(ctx, fns):
3609 rev = ctx.rev()
3600 rev = ctx.rev()
3610 pctx = ctx.p1()
3601 pctx = ctx.p1()
3611 matches.setdefault(rev, {})
3602 matches.setdefault(rev, {})
3612 if diff:
3603 if diff:
3613 parent = pctx.rev()
3604 parent = pctx.rev()
3614 matches.setdefault(parent, {})
3605 matches.setdefault(parent, {})
3615 files = revfiles.setdefault(rev, [])
3606 files = revfiles.setdefault(rev, [])
3616 if rev is None:
3607 if rev is None:
3617 # in `hg grep pattern`, 2/3 of the time is spent is spent in
3608 # in `hg grep pattern`, 2/3 of the time is spent is spent in
3618 # pathauditor checks without this in mozilla-central
3609 # pathauditor checks without this in mozilla-central
3619 contextmanager = repo.wvfs.audit.cached
3610 contextmanager = repo.wvfs.audit.cached
3620 else:
3611 else:
3621 contextmanager = util.nullcontextmanager
3612 contextmanager = util.nullcontextmanager
3622 with contextmanager():
3613 with contextmanager():
3623 for fn in fns:
3614 for fn in fns:
3624 # fn might not exist in the revision (could be a file removed by
3615 # fn might not exist in the revision (could be a file removed by
3625 # the revision). We could check `fn not in ctx` even when rev is
3616 # the revision). We could check `fn not in ctx` even when rev is
3626 # None, but it's less racy to protect againt that in readfile.
3617 # None, but it's less racy to protect againt that in readfile.
3627 if rev is not None and fn not in ctx:
3618 if rev is not None and fn not in ctx:
3628 continue
3619 continue
3629
3620
3630 copy = None
3621 copy = None
3631 if follow:
3622 if follow:
3632 copy = getrenamed(fn, rev)
3623 copy = getrenamed(fn, rev)
3633 if copy:
3624 if copy:
3634 copies.setdefault(rev, {})[fn] = copy
3625 copies.setdefault(rev, {})[fn] = copy
3635 if fn in skip:
3626 if fn in skip:
3636 skip.add(copy)
3627 skip.add(copy)
3637 if fn in skip:
3628 if fn in skip:
3638 continue
3629 continue
3639 files.append(fn)
3630 files.append(fn)
3640
3631
3641 if fn not in matches[rev]:
3632 if fn not in matches[rev]:
3642 grepbody(fn, rev, readfile(ctx, fn))
3633 grepbody(fn, rev, readfile(ctx, fn))
3643
3634
3644 if diff:
3635 if diff:
3645 pfn = copy or fn
3636 pfn = copy or fn
3646 if pfn not in matches[parent] and pfn in pctx:
3637 if pfn not in matches[parent] and pfn in pctx:
3647 grepbody(pfn, parent, readfile(pctx, pfn))
3638 grepbody(pfn, parent, readfile(pctx, pfn))
3648
3639
3649 ui.pager(b'grep')
3640 ui.pager(b'grep')
3650 fm = ui.formatter(b'grep', opts)
3641 fm = ui.formatter(b'grep', opts)
3651 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3642 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3652 rev = ctx.rev()
3643 rev = ctx.rev()
3653 parent = ctx.p1().rev()
3644 parent = ctx.p1().rev()
3654 for fn in sorted(revfiles.get(rev, [])):
3645 for fn in sorted(revfiles.get(rev, [])):
3655 states = matches[rev][fn]
3646 states = matches[rev][fn]
3656 copy = copies.get(rev, {}).get(fn)
3647 copy = copies.get(rev, {}).get(fn)
3657 if fn in skip:
3648 if fn in skip:
3658 if copy:
3649 if copy:
3659 skip.add(copy)
3650 skip.add(copy)
3660 continue
3651 continue
3661 pstates = matches.get(parent, {}).get(copy or fn, [])
3652 pstates = matches.get(parent, {}).get(copy or fn, [])
3662 if pstates or states:
3653 if pstates or states:
3663 r = display(fm, fn, ctx, pstates, states)
3654 r = display(fm, fn, ctx, pstates, states)
3664 found = found or r
3655 found = found or r
3665 if r and not diff and not all_files:
3656 if r and not diff and not all_files:
3666 skip.add(fn)
3657 skip.add(fn)
3667 if copy:
3658 if copy:
3668 skip.add(copy)
3659 skip.add(copy)
3669 del revfiles[rev]
3660 del revfiles[rev]
3670 # We will keep the matches dict for the duration of the window
3661 # We will keep the matches dict for the duration of the window
3671 # clear the matches dict once the window is over
3662 # clear the matches dict once the window is over
3672 if not revfiles:
3663 if not revfiles:
3673 matches.clear()
3664 matches.clear()
3674 fm.end()
3665 fm.end()
3675
3666
3676 return not found
3667 return not found
3677
3668
3678
3669
3679 @command(
3670 @command(
3680 b'heads',
3671 b'heads',
3681 [
3672 [
3682 (
3673 (
3683 b'r',
3674 b'r',
3684 b'rev',
3675 b'rev',
3685 b'',
3676 b'',
3686 _(b'show only heads which are descendants of STARTREV'),
3677 _(b'show only heads which are descendants of STARTREV'),
3687 _(b'STARTREV'),
3678 _(b'STARTREV'),
3688 ),
3679 ),
3689 (b't', b'topo', False, _(b'show topological heads only')),
3680 (b't', b'topo', False, _(b'show topological heads only')),
3690 (
3681 (
3691 b'a',
3682 b'a',
3692 b'active',
3683 b'active',
3693 False,
3684 False,
3694 _(b'show active branchheads only (DEPRECATED)'),
3685 _(b'show active branchheads only (DEPRECATED)'),
3695 ),
3686 ),
3696 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3687 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3697 ]
3688 ]
3698 + templateopts,
3689 + templateopts,
3699 _(b'[-ct] [-r STARTREV] [REV]...'),
3690 _(b'[-ct] [-r STARTREV] [REV]...'),
3700 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3691 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3701 intents={INTENT_READONLY},
3692 intents={INTENT_READONLY},
3702 )
3693 )
3703 def heads(ui, repo, *branchrevs, **opts):
3694 def heads(ui, repo, *branchrevs, **opts):
3704 """show branch heads
3695 """show branch heads
3705
3696
3706 With no arguments, show all open branch heads in the repository.
3697 With no arguments, show all open branch heads in the repository.
3707 Branch heads are changesets that have no descendants on the
3698 Branch heads are changesets that have no descendants on the
3708 same branch. They are where development generally takes place and
3699 same branch. They are where development generally takes place and
3709 are the usual targets for update and merge operations.
3700 are the usual targets for update and merge operations.
3710
3701
3711 If one or more REVs are given, only open branch heads on the
3702 If one or more REVs are given, only open branch heads on the
3712 branches associated with the specified changesets are shown. This
3703 branches associated with the specified changesets are shown. This
3713 means that you can use :hg:`heads .` to see the heads on the
3704 means that you can use :hg:`heads .` to see the heads on the
3714 currently checked-out branch.
3705 currently checked-out branch.
3715
3706
3716 If -c/--closed is specified, also show branch heads marked closed
3707 If -c/--closed is specified, also show branch heads marked closed
3717 (see :hg:`commit --close-branch`).
3708 (see :hg:`commit --close-branch`).
3718
3709
3719 If STARTREV is specified, only those heads that are descendants of
3710 If STARTREV is specified, only those heads that are descendants of
3720 STARTREV will be displayed.
3711 STARTREV will be displayed.
3721
3712
3722 If -t/--topo is specified, named branch mechanics will be ignored and only
3713 If -t/--topo is specified, named branch mechanics will be ignored and only
3723 topological heads (changesets with no children) will be shown.
3714 topological heads (changesets with no children) will be shown.
3724
3715
3725 Returns 0 if matching heads are found, 1 if not.
3716 Returns 0 if matching heads are found, 1 if not.
3726 """
3717 """
3727
3718
3728 opts = pycompat.byteskwargs(opts)
3719 opts = pycompat.byteskwargs(opts)
3729 start = None
3720 start = None
3730 rev = opts.get(b'rev')
3721 rev = opts.get(b'rev')
3731 if rev:
3722 if rev:
3732 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3723 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3733 start = scmutil.revsingle(repo, rev, None).node()
3724 start = scmutil.revsingle(repo, rev, None).node()
3734
3725
3735 if opts.get(b'topo'):
3726 if opts.get(b'topo'):
3736 heads = [repo[h] for h in repo.heads(start)]
3727 heads = [repo[h] for h in repo.heads(start)]
3737 else:
3728 else:
3738 heads = []
3729 heads = []
3739 for branch in repo.branchmap():
3730 for branch in repo.branchmap():
3740 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3731 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3741 heads = [repo[h] for h in heads]
3732 heads = [repo[h] for h in heads]
3742
3733
3743 if branchrevs:
3734 if branchrevs:
3744 branches = {
3735 branches = {
3745 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3736 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3746 }
3737 }
3747 heads = [h for h in heads if h.branch() in branches]
3738 heads = [h for h in heads if h.branch() in branches]
3748
3739
3749 if opts.get(b'active') and branchrevs:
3740 if opts.get(b'active') and branchrevs:
3750 dagheads = repo.heads(start)
3741 dagheads = repo.heads(start)
3751 heads = [h for h in heads if h.node() in dagheads]
3742 heads = [h for h in heads if h.node() in dagheads]
3752
3743
3753 if branchrevs:
3744 if branchrevs:
3754 haveheads = {h.branch() for h in heads}
3745 haveheads = {h.branch() for h in heads}
3755 if branches - haveheads:
3746 if branches - haveheads:
3756 headless = b', '.join(b for b in branches - haveheads)
3747 headless = b', '.join(b for b in branches - haveheads)
3757 msg = _(b'no open branch heads found on branches %s')
3748 msg = _(b'no open branch heads found on branches %s')
3758 if opts.get(b'rev'):
3749 if opts.get(b'rev'):
3759 msg += _(b' (started at %s)') % opts[b'rev']
3750 msg += _(b' (started at %s)') % opts[b'rev']
3760 ui.warn((msg + b'\n') % headless)
3751 ui.warn((msg + b'\n') % headless)
3761
3752
3762 if not heads:
3753 if not heads:
3763 return 1
3754 return 1
3764
3755
3765 ui.pager(b'heads')
3756 ui.pager(b'heads')
3766 heads = sorted(heads, key=lambda x: -(x.rev()))
3757 heads = sorted(heads, key=lambda x: -(x.rev()))
3767 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3758 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3768 for ctx in heads:
3759 for ctx in heads:
3769 displayer.show(ctx)
3760 displayer.show(ctx)
3770 displayer.close()
3761 displayer.close()
3771
3762
3772
3763
3773 @command(
3764 @command(
3774 b'help',
3765 b'help',
3775 [
3766 [
3776 (b'e', b'extension', None, _(b'show only help for extensions')),
3767 (b'e', b'extension', None, _(b'show only help for extensions')),
3777 (b'c', b'command', None, _(b'show only help for commands')),
3768 (b'c', b'command', None, _(b'show only help for commands')),
3778 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3769 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3779 (
3770 (
3780 b's',
3771 b's',
3781 b'system',
3772 b'system',
3782 [],
3773 [],
3783 _(b'show help for specific platform(s)'),
3774 _(b'show help for specific platform(s)'),
3784 _(b'PLATFORM'),
3775 _(b'PLATFORM'),
3785 ),
3776 ),
3786 ],
3777 ],
3787 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3778 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3788 helpcategory=command.CATEGORY_HELP,
3779 helpcategory=command.CATEGORY_HELP,
3789 norepo=True,
3780 norepo=True,
3790 intents={INTENT_READONLY},
3781 intents={INTENT_READONLY},
3791 )
3782 )
3792 def help_(ui, name=None, **opts):
3783 def help_(ui, name=None, **opts):
3793 """show help for a given topic or a help overview
3784 """show help for a given topic or a help overview
3794
3785
3795 With no arguments, print a list of commands with short help messages.
3786 With no arguments, print a list of commands with short help messages.
3796
3787
3797 Given a topic, extension, or command name, print help for that
3788 Given a topic, extension, or command name, print help for that
3798 topic.
3789 topic.
3799
3790
3800 Returns 0 if successful.
3791 Returns 0 if successful.
3801 """
3792 """
3802
3793
3803 keep = opts.get('system') or []
3794 keep = opts.get('system') or []
3804 if len(keep) == 0:
3795 if len(keep) == 0:
3805 if pycompat.sysplatform.startswith(b'win'):
3796 if pycompat.sysplatform.startswith(b'win'):
3806 keep.append(b'windows')
3797 keep.append(b'windows')
3807 elif pycompat.sysplatform == b'OpenVMS':
3798 elif pycompat.sysplatform == b'OpenVMS':
3808 keep.append(b'vms')
3799 keep.append(b'vms')
3809 elif pycompat.sysplatform == b'plan9':
3800 elif pycompat.sysplatform == b'plan9':
3810 keep.append(b'plan9')
3801 keep.append(b'plan9')
3811 else:
3802 else:
3812 keep.append(b'unix')
3803 keep.append(b'unix')
3813 keep.append(pycompat.sysplatform.lower())
3804 keep.append(pycompat.sysplatform.lower())
3814 if ui.verbose:
3805 if ui.verbose:
3815 keep.append(b'verbose')
3806 keep.append(b'verbose')
3816
3807
3817 commands = sys.modules[__name__]
3808 commands = sys.modules[__name__]
3818 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3809 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3819 ui.pager(b'help')
3810 ui.pager(b'help')
3820 ui.write(formatted)
3811 ui.write(formatted)
3821
3812
3822
3813
3823 @command(
3814 @command(
3824 b'identify|id',
3815 b'identify|id',
3825 [
3816 [
3826 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3817 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3827 (b'n', b'num', None, _(b'show local revision number')),
3818 (b'n', b'num', None, _(b'show local revision number')),
3828 (b'i', b'id', None, _(b'show global revision id')),
3819 (b'i', b'id', None, _(b'show global revision id')),
3829 (b'b', b'branch', None, _(b'show branch')),
3820 (b'b', b'branch', None, _(b'show branch')),
3830 (b't', b'tags', None, _(b'show tags')),
3821 (b't', b'tags', None, _(b'show tags')),
3831 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3822 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3832 ]
3823 ]
3833 + remoteopts
3824 + remoteopts
3834 + formatteropts,
3825 + formatteropts,
3835 _(b'[-nibtB] [-r REV] [SOURCE]'),
3826 _(b'[-nibtB] [-r REV] [SOURCE]'),
3836 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3827 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3837 optionalrepo=True,
3828 optionalrepo=True,
3838 intents={INTENT_READONLY},
3829 intents={INTENT_READONLY},
3839 )
3830 )
3840 def identify(
3831 def identify(
3841 ui,
3832 ui,
3842 repo,
3833 repo,
3843 source=None,
3834 source=None,
3844 rev=None,
3835 rev=None,
3845 num=None,
3836 num=None,
3846 id=None,
3837 id=None,
3847 branch=None,
3838 branch=None,
3848 tags=None,
3839 tags=None,
3849 bookmarks=None,
3840 bookmarks=None,
3850 **opts
3841 **opts
3851 ):
3842 ):
3852 """identify the working directory or specified revision
3843 """identify the working directory or specified revision
3853
3844
3854 Print a summary identifying the repository state at REV using one or
3845 Print a summary identifying the repository state at REV using one or
3855 two parent hash identifiers, followed by a "+" if the working
3846 two parent hash identifiers, followed by a "+" if the working
3856 directory has uncommitted changes, the branch name (if not default),
3847 directory has uncommitted changes, the branch name (if not default),
3857 a list of tags, and a list of bookmarks.
3848 a list of tags, and a list of bookmarks.
3858
3849
3859 When REV is not given, print a summary of the current state of the
3850 When REV is not given, print a summary of the current state of the
3860 repository including the working directory. Specify -r. to get information
3851 repository including the working directory. Specify -r. to get information
3861 of the working directory parent without scanning uncommitted changes.
3852 of the working directory parent without scanning uncommitted changes.
3862
3853
3863 Specifying a path to a repository root or Mercurial bundle will
3854 Specifying a path to a repository root or Mercurial bundle will
3864 cause lookup to operate on that repository/bundle.
3855 cause lookup to operate on that repository/bundle.
3865
3856
3866 .. container:: verbose
3857 .. container:: verbose
3867
3858
3868 Template:
3859 Template:
3869
3860
3870 The following keywords are supported in addition to the common template
3861 The following keywords are supported in addition to the common template
3871 keywords and functions. See also :hg:`help templates`.
3862 keywords and functions. See also :hg:`help templates`.
3872
3863
3873 :dirty: String. Character ``+`` denoting if the working directory has
3864 :dirty: String. Character ``+`` denoting if the working directory has
3874 uncommitted changes.
3865 uncommitted changes.
3875 :id: String. One or two nodes, optionally followed by ``+``.
3866 :id: String. One or two nodes, optionally followed by ``+``.
3876 :parents: List of strings. Parent nodes of the changeset.
3867 :parents: List of strings. Parent nodes of the changeset.
3877
3868
3878 Examples:
3869 Examples:
3879
3870
3880 - generate a build identifier for the working directory::
3871 - generate a build identifier for the working directory::
3881
3872
3882 hg id --id > build-id.dat
3873 hg id --id > build-id.dat
3883
3874
3884 - find the revision corresponding to a tag::
3875 - find the revision corresponding to a tag::
3885
3876
3886 hg id -n -r 1.3
3877 hg id -n -r 1.3
3887
3878
3888 - check the most recent revision of a remote repository::
3879 - check the most recent revision of a remote repository::
3889
3880
3890 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3881 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3891
3882
3892 See :hg:`log` for generating more information about specific revisions,
3883 See :hg:`log` for generating more information about specific revisions,
3893 including full hash identifiers.
3884 including full hash identifiers.
3894
3885
3895 Returns 0 if successful.
3886 Returns 0 if successful.
3896 """
3887 """
3897
3888
3898 opts = pycompat.byteskwargs(opts)
3889 opts = pycompat.byteskwargs(opts)
3899 if not repo and not source:
3890 if not repo and not source:
3900 raise error.Abort(
3891 raise error.Abort(
3901 _(b"there is no Mercurial repository here (.hg not found)")
3892 _(b"there is no Mercurial repository here (.hg not found)")
3902 )
3893 )
3903
3894
3904 default = not (num or id or branch or tags or bookmarks)
3895 default = not (num or id or branch or tags or bookmarks)
3905 output = []
3896 output = []
3906 revs = []
3897 revs = []
3907
3898
3908 if source:
3899 if source:
3909 source, branches = hg.parseurl(ui.expandpath(source))
3900 source, branches = hg.parseurl(ui.expandpath(source))
3910 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3901 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3911 repo = peer.local()
3902 repo = peer.local()
3912 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3903 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3913
3904
3914 fm = ui.formatter(b'identify', opts)
3905 fm = ui.formatter(b'identify', opts)
3915 fm.startitem()
3906 fm.startitem()
3916
3907
3917 if not repo:
3908 if not repo:
3918 if num or branch or tags:
3909 if num or branch or tags:
3919 raise error.Abort(
3910 raise error.Abort(
3920 _(b"can't query remote revision number, branch, or tags")
3911 _(b"can't query remote revision number, branch, or tags")
3921 )
3912 )
3922 if not rev and revs:
3913 if not rev and revs:
3923 rev = revs[0]
3914 rev = revs[0]
3924 if not rev:
3915 if not rev:
3925 rev = b"tip"
3916 rev = b"tip"
3926
3917
3927 remoterev = peer.lookup(rev)
3918 remoterev = peer.lookup(rev)
3928 hexrev = fm.hexfunc(remoterev)
3919 hexrev = fm.hexfunc(remoterev)
3929 if default or id:
3920 if default or id:
3930 output = [hexrev]
3921 output = [hexrev]
3931 fm.data(id=hexrev)
3922 fm.data(id=hexrev)
3932
3923
3933 @util.cachefunc
3924 @util.cachefunc
3934 def getbms():
3925 def getbms():
3935 bms = []
3926 bms = []
3936
3927
3937 if b'bookmarks' in peer.listkeys(b'namespaces'):
3928 if b'bookmarks' in peer.listkeys(b'namespaces'):
3938 hexremoterev = hex(remoterev)
3929 hexremoterev = hex(remoterev)
3939 bms = [
3930 bms = [
3940 bm
3931 bm
3941 for bm, bmr in pycompat.iteritems(
3932 for bm, bmr in pycompat.iteritems(
3942 peer.listkeys(b'bookmarks')
3933 peer.listkeys(b'bookmarks')
3943 )
3934 )
3944 if bmr == hexremoterev
3935 if bmr == hexremoterev
3945 ]
3936 ]
3946
3937
3947 return sorted(bms)
3938 return sorted(bms)
3948
3939
3949 if fm.isplain():
3940 if fm.isplain():
3950 if bookmarks:
3941 if bookmarks:
3951 output.extend(getbms())
3942 output.extend(getbms())
3952 elif default and not ui.quiet:
3943 elif default and not ui.quiet:
3953 # multiple bookmarks for a single parent separated by '/'
3944 # multiple bookmarks for a single parent separated by '/'
3954 bm = b'/'.join(getbms())
3945 bm = b'/'.join(getbms())
3955 if bm:
3946 if bm:
3956 output.append(bm)
3947 output.append(bm)
3957 else:
3948 else:
3958 fm.data(node=hex(remoterev))
3949 fm.data(node=hex(remoterev))
3959 if bookmarks or b'bookmarks' in fm.datahint():
3950 if bookmarks or b'bookmarks' in fm.datahint():
3960 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3951 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3961 else:
3952 else:
3962 if rev:
3953 if rev:
3963 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3954 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3964 ctx = scmutil.revsingle(repo, rev, None)
3955 ctx = scmutil.revsingle(repo, rev, None)
3965
3956
3966 if ctx.rev() is None:
3957 if ctx.rev() is None:
3967 ctx = repo[None]
3958 ctx = repo[None]
3968 parents = ctx.parents()
3959 parents = ctx.parents()
3969 taglist = []
3960 taglist = []
3970 for p in parents:
3961 for p in parents:
3971 taglist.extend(p.tags())
3962 taglist.extend(p.tags())
3972
3963
3973 dirty = b""
3964 dirty = b""
3974 if ctx.dirty(missing=True, merge=False, branch=False):
3965 if ctx.dirty(missing=True, merge=False, branch=False):
3975 dirty = b'+'
3966 dirty = b'+'
3976 fm.data(dirty=dirty)
3967 fm.data(dirty=dirty)
3977
3968
3978 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3969 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3979 if default or id:
3970 if default or id:
3980 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3971 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3981 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3972 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3982
3973
3983 if num:
3974 if num:
3984 numoutput = [b"%d" % p.rev() for p in parents]
3975 numoutput = [b"%d" % p.rev() for p in parents]
3985 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3976 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3986
3977
3987 fm.data(
3978 fm.data(
3988 parents=fm.formatlist(
3979 parents=fm.formatlist(
3989 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3980 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3990 )
3981 )
3991 )
3982 )
3992 else:
3983 else:
3993 hexoutput = fm.hexfunc(ctx.node())
3984 hexoutput = fm.hexfunc(ctx.node())
3994 if default or id:
3985 if default or id:
3995 output = [hexoutput]
3986 output = [hexoutput]
3996 fm.data(id=hexoutput)
3987 fm.data(id=hexoutput)
3997
3988
3998 if num:
3989 if num:
3999 output.append(pycompat.bytestr(ctx.rev()))
3990 output.append(pycompat.bytestr(ctx.rev()))
4000 taglist = ctx.tags()
3991 taglist = ctx.tags()
4001
3992
4002 if default and not ui.quiet:
3993 if default and not ui.quiet:
4003 b = ctx.branch()
3994 b = ctx.branch()
4004 if b != b'default':
3995 if b != b'default':
4005 output.append(b"(%s)" % b)
3996 output.append(b"(%s)" % b)
4006
3997
4007 # multiple tags for a single parent separated by '/'
3998 # multiple tags for a single parent separated by '/'
4008 t = b'/'.join(taglist)
3999 t = b'/'.join(taglist)
4009 if t:
4000 if t:
4010 output.append(t)
4001 output.append(t)
4011
4002
4012 # multiple bookmarks for a single parent separated by '/'
4003 # multiple bookmarks for a single parent separated by '/'
4013 bm = b'/'.join(ctx.bookmarks())
4004 bm = b'/'.join(ctx.bookmarks())
4014 if bm:
4005 if bm:
4015 output.append(bm)
4006 output.append(bm)
4016 else:
4007 else:
4017 if branch:
4008 if branch:
4018 output.append(ctx.branch())
4009 output.append(ctx.branch())
4019
4010
4020 if tags:
4011 if tags:
4021 output.extend(taglist)
4012 output.extend(taglist)
4022
4013
4023 if bookmarks:
4014 if bookmarks:
4024 output.extend(ctx.bookmarks())
4015 output.extend(ctx.bookmarks())
4025
4016
4026 fm.data(node=ctx.hex())
4017 fm.data(node=ctx.hex())
4027 fm.data(branch=ctx.branch())
4018 fm.data(branch=ctx.branch())
4028 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4019 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
4029 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4020 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
4030 fm.context(ctx=ctx)
4021 fm.context(ctx=ctx)
4031
4022
4032 fm.plain(b"%s\n" % b' '.join(output))
4023 fm.plain(b"%s\n" % b' '.join(output))
4033 fm.end()
4024 fm.end()
4034
4025
4035
4026
4036 @command(
4027 @command(
4037 b'import|patch',
4028 b'import|patch',
4038 [
4029 [
4039 (
4030 (
4040 b'p',
4031 b'p',
4041 b'strip',
4032 b'strip',
4042 1,
4033 1,
4043 _(
4034 _(
4044 b'directory strip option for patch. This has the same '
4035 b'directory strip option for patch. This has the same '
4045 b'meaning as the corresponding patch option'
4036 b'meaning as the corresponding patch option'
4046 ),
4037 ),
4047 _(b'NUM'),
4038 _(b'NUM'),
4048 ),
4039 ),
4049 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4040 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
4050 (b'', b'secret', None, _(b'use the secret phase for committing')),
4041 (b'', b'secret', None, _(b'use the secret phase for committing')),
4051 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4042 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
4052 (
4043 (
4053 b'f',
4044 b'f',
4054 b'force',
4045 b'force',
4055 None,
4046 None,
4056 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4047 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
4057 ),
4048 ),
4058 (
4049 (
4059 b'',
4050 b'',
4060 b'no-commit',
4051 b'no-commit',
4061 None,
4052 None,
4062 _(b"don't commit, just update the working directory"),
4053 _(b"don't commit, just update the working directory"),
4063 ),
4054 ),
4064 (
4055 (
4065 b'',
4056 b'',
4066 b'bypass',
4057 b'bypass',
4067 None,
4058 None,
4068 _(b"apply patch without touching the working directory"),
4059 _(b"apply patch without touching the working directory"),
4069 ),
4060 ),
4070 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4061 (b'', b'partial', None, _(b'commit even if some hunks fail')),
4071 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4062 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
4072 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4063 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
4073 (
4064 (
4074 b'',
4065 b'',
4075 b'import-branch',
4066 b'import-branch',
4076 None,
4067 None,
4077 _(b'use any branch information in patch (implied by --exact)'),
4068 _(b'use any branch information in patch (implied by --exact)'),
4078 ),
4069 ),
4079 ]
4070 ]
4080 + commitopts
4071 + commitopts
4081 + commitopts2
4072 + commitopts2
4082 + similarityopts,
4073 + similarityopts,
4083 _(b'[OPTION]... PATCH...'),
4074 _(b'[OPTION]... PATCH...'),
4084 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4075 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4085 )
4076 )
4086 def import_(ui, repo, patch1=None, *patches, **opts):
4077 def import_(ui, repo, patch1=None, *patches, **opts):
4087 """import an ordered set of patches
4078 """import an ordered set of patches
4088
4079
4089 Import a list of patches and commit them individually (unless
4080 Import a list of patches and commit them individually (unless
4090 --no-commit is specified).
4081 --no-commit is specified).
4091
4082
4092 To read a patch from standard input (stdin), use "-" as the patch
4083 To read a patch from standard input (stdin), use "-" as the patch
4093 name. If a URL is specified, the patch will be downloaded from
4084 name. If a URL is specified, the patch will be downloaded from
4094 there.
4085 there.
4095
4086
4096 Import first applies changes to the working directory (unless
4087 Import first applies changes to the working directory (unless
4097 --bypass is specified), import will abort if there are outstanding
4088 --bypass is specified), import will abort if there are outstanding
4098 changes.
4089 changes.
4099
4090
4100 Use --bypass to apply and commit patches directly to the
4091 Use --bypass to apply and commit patches directly to the
4101 repository, without affecting the working directory. Without
4092 repository, without affecting the working directory. Without
4102 --exact, patches will be applied on top of the working directory
4093 --exact, patches will be applied on top of the working directory
4103 parent revision.
4094 parent revision.
4104
4095
4105 You can import a patch straight from a mail message. Even patches
4096 You can import a patch straight from a mail message. Even patches
4106 as attachments work (to use the body part, it must have type
4097 as attachments work (to use the body part, it must have type
4107 text/plain or text/x-patch). From and Subject headers of email
4098 text/plain or text/x-patch). From and Subject headers of email
4108 message are used as default committer and commit message. All
4099 message are used as default committer and commit message. All
4109 text/plain body parts before first diff are added to the commit
4100 text/plain body parts before first diff are added to the commit
4110 message.
4101 message.
4111
4102
4112 If the imported patch was generated by :hg:`export`, user and
4103 If the imported patch was generated by :hg:`export`, user and
4113 description from patch override values from message headers and
4104 description from patch override values from message headers and
4114 body. Values given on command line with -m/--message and -u/--user
4105 body. Values given on command line with -m/--message and -u/--user
4115 override these.
4106 override these.
4116
4107
4117 If --exact is specified, import will set the working directory to
4108 If --exact is specified, import will set the working directory to
4118 the parent of each patch before applying it, and will abort if the
4109 the parent of each patch before applying it, and will abort if the
4119 resulting changeset has a different ID than the one recorded in
4110 resulting changeset has a different ID than the one recorded in
4120 the patch. This will guard against various ways that portable
4111 the patch. This will guard against various ways that portable
4121 patch formats and mail systems might fail to transfer Mercurial
4112 patch formats and mail systems might fail to transfer Mercurial
4122 data or metadata. See :hg:`bundle` for lossless transmission.
4113 data or metadata. See :hg:`bundle` for lossless transmission.
4123
4114
4124 Use --partial to ensure a changeset will be created from the patch
4115 Use --partial to ensure a changeset will be created from the patch
4125 even if some hunks fail to apply. Hunks that fail to apply will be
4116 even if some hunks fail to apply. Hunks that fail to apply will be
4126 written to a <target-file>.rej file. Conflicts can then be resolved
4117 written to a <target-file>.rej file. Conflicts can then be resolved
4127 by hand before :hg:`commit --amend` is run to update the created
4118 by hand before :hg:`commit --amend` is run to update the created
4128 changeset. This flag exists to let people import patches that
4119 changeset. This flag exists to let people import patches that
4129 partially apply without losing the associated metadata (author,
4120 partially apply without losing the associated metadata (author,
4130 date, description, ...).
4121 date, description, ...).
4131
4122
4132 .. note::
4123 .. note::
4133
4124
4134 When no hunks apply cleanly, :hg:`import --partial` will create
4125 When no hunks apply cleanly, :hg:`import --partial` will create
4135 an empty changeset, importing only the patch metadata.
4126 an empty changeset, importing only the patch metadata.
4136
4127
4137 With -s/--similarity, hg will attempt to discover renames and
4128 With -s/--similarity, hg will attempt to discover renames and
4138 copies in the patch in the same way as :hg:`addremove`.
4129 copies in the patch in the same way as :hg:`addremove`.
4139
4130
4140 It is possible to use external patch programs to perform the patch
4131 It is possible to use external patch programs to perform the patch
4141 by setting the ``ui.patch`` configuration option. For the default
4132 by setting the ``ui.patch`` configuration option. For the default
4142 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4133 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4143 See :hg:`help config` for more information about configuration
4134 See :hg:`help config` for more information about configuration
4144 files and how to use these options.
4135 files and how to use these options.
4145
4136
4146 See :hg:`help dates` for a list of formats valid for -d/--date.
4137 See :hg:`help dates` for a list of formats valid for -d/--date.
4147
4138
4148 .. container:: verbose
4139 .. container:: verbose
4149
4140
4150 Examples:
4141 Examples:
4151
4142
4152 - import a traditional patch from a website and detect renames::
4143 - import a traditional patch from a website and detect renames::
4153
4144
4154 hg import -s 80 http://example.com/bugfix.patch
4145 hg import -s 80 http://example.com/bugfix.patch
4155
4146
4156 - import a changeset from an hgweb server::
4147 - import a changeset from an hgweb server::
4157
4148
4158 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4149 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4159
4150
4160 - import all the patches in an Unix-style mbox::
4151 - import all the patches in an Unix-style mbox::
4161
4152
4162 hg import incoming-patches.mbox
4153 hg import incoming-patches.mbox
4163
4154
4164 - import patches from stdin::
4155 - import patches from stdin::
4165
4156
4166 hg import -
4157 hg import -
4167
4158
4168 - attempt to exactly restore an exported changeset (not always
4159 - attempt to exactly restore an exported changeset (not always
4169 possible)::
4160 possible)::
4170
4161
4171 hg import --exact proposed-fix.patch
4162 hg import --exact proposed-fix.patch
4172
4163
4173 - use an external tool to apply a patch which is too fuzzy for
4164 - use an external tool to apply a patch which is too fuzzy for
4174 the default internal tool.
4165 the default internal tool.
4175
4166
4176 hg import --config ui.patch="patch --merge" fuzzy.patch
4167 hg import --config ui.patch="patch --merge" fuzzy.patch
4177
4168
4178 - change the default fuzzing from 2 to a less strict 7
4169 - change the default fuzzing from 2 to a less strict 7
4179
4170
4180 hg import --config ui.fuzz=7 fuzz.patch
4171 hg import --config ui.fuzz=7 fuzz.patch
4181
4172
4182 Returns 0 on success, 1 on partial success (see --partial).
4173 Returns 0 on success, 1 on partial success (see --partial).
4183 """
4174 """
4184
4175
4185 opts = pycompat.byteskwargs(opts)
4176 opts = pycompat.byteskwargs(opts)
4186 if not patch1:
4177 if not patch1:
4187 raise error.Abort(_(b'need at least one patch to import'))
4178 raise error.Abort(_(b'need at least one patch to import'))
4188
4179
4189 patches = (patch1,) + patches
4180 patches = (patch1,) + patches
4190
4181
4191 date = opts.get(b'date')
4182 date = opts.get(b'date')
4192 if date:
4183 if date:
4193 opts[b'date'] = dateutil.parsedate(date)
4184 opts[b'date'] = dateutil.parsedate(date)
4194
4185
4195 exact = opts.get(b'exact')
4186 exact = opts.get(b'exact')
4196 update = not opts.get(b'bypass')
4187 update = not opts.get(b'bypass')
4197 if not update and opts.get(b'no_commit'):
4188 if not update and opts.get(b'no_commit'):
4198 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4189 raise error.Abort(_(b'cannot use --no-commit with --bypass'))
4199 if opts.get(b'secret') and opts.get(b'no_commit'):
4190 if opts.get(b'secret') and opts.get(b'no_commit'):
4200 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4191 raise error.Abort(_(b'cannot use --no-commit with --secret'))
4201 try:
4192 try:
4202 sim = float(opts.get(b'similarity') or 0)
4193 sim = float(opts.get(b'similarity') or 0)
4203 except ValueError:
4194 except ValueError:
4204 raise error.Abort(_(b'similarity must be a number'))
4195 raise error.Abort(_(b'similarity must be a number'))
4205 if sim < 0 or sim > 100:
4196 if sim < 0 or sim > 100:
4206 raise error.Abort(_(b'similarity must be between 0 and 100'))
4197 raise error.Abort(_(b'similarity must be between 0 and 100'))
4207 if sim and not update:
4198 if sim and not update:
4208 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4199 raise error.Abort(_(b'cannot use --similarity with --bypass'))
4209 if exact:
4200 if exact:
4210 if opts.get(b'edit'):
4201 if opts.get(b'edit'):
4211 raise error.Abort(_(b'cannot use --exact with --edit'))
4202 raise error.Abort(_(b'cannot use --exact with --edit'))
4212 if opts.get(b'prefix'):
4203 if opts.get(b'prefix'):
4213 raise error.Abort(_(b'cannot use --exact with --prefix'))
4204 raise error.Abort(_(b'cannot use --exact with --prefix'))
4214
4205
4215 base = opts[b"base"]
4206 base = opts[b"base"]
4216 msgs = []
4207 msgs = []
4217 ret = 0
4208 ret = 0
4218
4209
4219 with repo.wlock():
4210 with repo.wlock():
4220 if update:
4211 if update:
4221 cmdutil.checkunfinished(repo)
4212 cmdutil.checkunfinished(repo)
4222 if exact or not opts.get(b'force'):
4213 if exact or not opts.get(b'force'):
4223 cmdutil.bailifchanged(repo)
4214 cmdutil.bailifchanged(repo)
4224
4215
4225 if not opts.get(b'no_commit'):
4216 if not opts.get(b'no_commit'):
4226 lock = repo.lock
4217 lock = repo.lock
4227 tr = lambda: repo.transaction(b'import')
4218 tr = lambda: repo.transaction(b'import')
4228 dsguard = util.nullcontextmanager
4219 dsguard = util.nullcontextmanager
4229 else:
4220 else:
4230 lock = util.nullcontextmanager
4221 lock = util.nullcontextmanager
4231 tr = util.nullcontextmanager
4222 tr = util.nullcontextmanager
4232 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4223 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4233 with lock(), tr(), dsguard():
4224 with lock(), tr(), dsguard():
4234 parents = repo[None].parents()
4225 parents = repo[None].parents()
4235 for patchurl in patches:
4226 for patchurl in patches:
4236 if patchurl == b'-':
4227 if patchurl == b'-':
4237 ui.status(_(b'applying patch from stdin\n'))
4228 ui.status(_(b'applying patch from stdin\n'))
4238 patchfile = ui.fin
4229 patchfile = ui.fin
4239 patchurl = b'stdin' # for error message
4230 patchurl = b'stdin' # for error message
4240 else:
4231 else:
4241 patchurl = os.path.join(base, patchurl)
4232 patchurl = os.path.join(base, patchurl)
4242 ui.status(_(b'applying %s\n') % patchurl)
4233 ui.status(_(b'applying %s\n') % patchurl)
4243 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4234 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4244
4235
4245 haspatch = False
4236 haspatch = False
4246 for hunk in patch.split(patchfile):
4237 for hunk in patch.split(patchfile):
4247 with patch.extract(ui, hunk) as patchdata:
4238 with patch.extract(ui, hunk) as patchdata:
4248 msg, node, rej = cmdutil.tryimportone(
4239 msg, node, rej = cmdutil.tryimportone(
4249 ui, repo, patchdata, parents, opts, msgs, hg.clean
4240 ui, repo, patchdata, parents, opts, msgs, hg.clean
4250 )
4241 )
4251 if msg:
4242 if msg:
4252 haspatch = True
4243 haspatch = True
4253 ui.note(msg + b'\n')
4244 ui.note(msg + b'\n')
4254 if update or exact:
4245 if update or exact:
4255 parents = repo[None].parents()
4246 parents = repo[None].parents()
4256 else:
4247 else:
4257 parents = [repo[node]]
4248 parents = [repo[node]]
4258 if rej:
4249 if rej:
4259 ui.write_err(_(b"patch applied partially\n"))
4250 ui.write_err(_(b"patch applied partially\n"))
4260 ui.write_err(
4251 ui.write_err(
4261 _(
4252 _(
4262 b"(fix the .rej files and run "
4253 b"(fix the .rej files and run "
4263 b"`hg commit --amend`)\n"
4254 b"`hg commit --amend`)\n"
4264 )
4255 )
4265 )
4256 )
4266 ret = 1
4257 ret = 1
4267 break
4258 break
4268
4259
4269 if not haspatch:
4260 if not haspatch:
4270 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4261 raise error.Abort(_(b'%s: no diffs found') % patchurl)
4271
4262
4272 if msgs:
4263 if msgs:
4273 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4264 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4274 return ret
4265 return ret
4275
4266
4276
4267
4277 @command(
4268 @command(
4278 b'incoming|in',
4269 b'incoming|in',
4279 [
4270 [
4280 (
4271 (
4281 b'f',
4272 b'f',
4282 b'force',
4273 b'force',
4283 None,
4274 None,
4284 _(b'run even if remote repository is unrelated'),
4275 _(b'run even if remote repository is unrelated'),
4285 ),
4276 ),
4286 (b'n', b'newest-first', None, _(b'show newest record first')),
4277 (b'n', b'newest-first', None, _(b'show newest record first')),
4287 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4278 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4288 (
4279 (
4289 b'r',
4280 b'r',
4290 b'rev',
4281 b'rev',
4291 [],
4282 [],
4292 _(b'a remote changeset intended to be added'),
4283 _(b'a remote changeset intended to be added'),
4293 _(b'REV'),
4284 _(b'REV'),
4294 ),
4285 ),
4295 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4286 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4296 (
4287 (
4297 b'b',
4288 b'b',
4298 b'branch',
4289 b'branch',
4299 [],
4290 [],
4300 _(b'a specific branch you would like to pull'),
4291 _(b'a specific branch you would like to pull'),
4301 _(b'BRANCH'),
4292 _(b'BRANCH'),
4302 ),
4293 ),
4303 ]
4294 ]
4304 + logopts
4295 + logopts
4305 + remoteopts
4296 + remoteopts
4306 + subrepoopts,
4297 + subrepoopts,
4307 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4298 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4308 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4299 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4309 )
4300 )
4310 def incoming(ui, repo, source=b"default", **opts):
4301 def incoming(ui, repo, source=b"default", **opts):
4311 """show new changesets found in source
4302 """show new changesets found in source
4312
4303
4313 Show new changesets found in the specified path/URL or the default
4304 Show new changesets found in the specified path/URL or the default
4314 pull location. These are the changesets that would have been pulled
4305 pull location. These are the changesets that would have been pulled
4315 by :hg:`pull` at the time you issued this command.
4306 by :hg:`pull` at the time you issued this command.
4316
4307
4317 See pull for valid source format details.
4308 See pull for valid source format details.
4318
4309
4319 .. container:: verbose
4310 .. container:: verbose
4320
4311
4321 With -B/--bookmarks, the result of bookmark comparison between
4312 With -B/--bookmarks, the result of bookmark comparison between
4322 local and remote repositories is displayed. With -v/--verbose,
4313 local and remote repositories is displayed. With -v/--verbose,
4323 status is also displayed for each bookmark like below::
4314 status is also displayed for each bookmark like below::
4324
4315
4325 BM1 01234567890a added
4316 BM1 01234567890a added
4326 BM2 1234567890ab advanced
4317 BM2 1234567890ab advanced
4327 BM3 234567890abc diverged
4318 BM3 234567890abc diverged
4328 BM4 34567890abcd changed
4319 BM4 34567890abcd changed
4329
4320
4330 The action taken locally when pulling depends on the
4321 The action taken locally when pulling depends on the
4331 status of each bookmark:
4322 status of each bookmark:
4332
4323
4333 :``added``: pull will create it
4324 :``added``: pull will create it
4334 :``advanced``: pull will update it
4325 :``advanced``: pull will update it
4335 :``diverged``: pull will create a divergent bookmark
4326 :``diverged``: pull will create a divergent bookmark
4336 :``changed``: result depends on remote changesets
4327 :``changed``: result depends on remote changesets
4337
4328
4338 From the point of view of pulling behavior, bookmark
4329 From the point of view of pulling behavior, bookmark
4339 existing only in the remote repository are treated as ``added``,
4330 existing only in the remote repository are treated as ``added``,
4340 even if it is in fact locally deleted.
4331 even if it is in fact locally deleted.
4341
4332
4342 .. container:: verbose
4333 .. container:: verbose
4343
4334
4344 For remote repository, using --bundle avoids downloading the
4335 For remote repository, using --bundle avoids downloading the
4345 changesets twice if the incoming is followed by a pull.
4336 changesets twice if the incoming is followed by a pull.
4346
4337
4347 Examples:
4338 Examples:
4348
4339
4349 - show incoming changes with patches and full description::
4340 - show incoming changes with patches and full description::
4350
4341
4351 hg incoming -vp
4342 hg incoming -vp
4352
4343
4353 - show incoming changes excluding merges, store a bundle::
4344 - show incoming changes excluding merges, store a bundle::
4354
4345
4355 hg in -vpM --bundle incoming.hg
4346 hg in -vpM --bundle incoming.hg
4356 hg pull incoming.hg
4347 hg pull incoming.hg
4357
4348
4358 - briefly list changes inside a bundle::
4349 - briefly list changes inside a bundle::
4359
4350
4360 hg in changes.hg -T "{desc|firstline}\\n"
4351 hg in changes.hg -T "{desc|firstline}\\n"
4361
4352
4362 Returns 0 if there are incoming changes, 1 otherwise.
4353 Returns 0 if there are incoming changes, 1 otherwise.
4363 """
4354 """
4364 opts = pycompat.byteskwargs(opts)
4355 opts = pycompat.byteskwargs(opts)
4365 if opts.get(b'graph'):
4356 if opts.get(b'graph'):
4366 logcmdutil.checkunsupportedgraphflags([], opts)
4357 logcmdutil.checkunsupportedgraphflags([], opts)
4367
4358
4368 def display(other, chlist, displayer):
4359 def display(other, chlist, displayer):
4369 revdag = logcmdutil.graphrevs(other, chlist, opts)
4360 revdag = logcmdutil.graphrevs(other, chlist, opts)
4370 logcmdutil.displaygraph(
4361 logcmdutil.displaygraph(
4371 ui, repo, revdag, displayer, graphmod.asciiedges
4362 ui, repo, revdag, displayer, graphmod.asciiedges
4372 )
4363 )
4373
4364
4374 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4365 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4375 return 0
4366 return 0
4376
4367
4377 if opts.get(b'bundle') and opts.get(b'subrepos'):
4368 if opts.get(b'bundle') and opts.get(b'subrepos'):
4378 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4369 raise error.Abort(_(b'cannot combine --bundle and --subrepos'))
4379
4370
4380 if opts.get(b'bookmarks'):
4371 if opts.get(b'bookmarks'):
4381 source, branches = hg.parseurl(
4372 source, branches = hg.parseurl(
4382 ui.expandpath(source), opts.get(b'branch')
4373 ui.expandpath(source), opts.get(b'branch')
4383 )
4374 )
4384 other = hg.peer(repo, opts, source)
4375 other = hg.peer(repo, opts, source)
4385 if b'bookmarks' not in other.listkeys(b'namespaces'):
4376 if b'bookmarks' not in other.listkeys(b'namespaces'):
4386 ui.warn(_(b"remote doesn't support bookmarks\n"))
4377 ui.warn(_(b"remote doesn't support bookmarks\n"))
4387 return 0
4378 return 0
4388 ui.pager(b'incoming')
4379 ui.pager(b'incoming')
4389 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4380 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4390 return bookmarks.incoming(ui, repo, other)
4381 return bookmarks.incoming(ui, repo, other)
4391
4382
4392 repo._subtoppath = ui.expandpath(source)
4383 repo._subtoppath = ui.expandpath(source)
4393 try:
4384 try:
4394 return hg.incoming(ui, repo, source, opts)
4385 return hg.incoming(ui, repo, source, opts)
4395 finally:
4386 finally:
4396 del repo._subtoppath
4387 del repo._subtoppath
4397
4388
4398
4389
4399 @command(
4390 @command(
4400 b'init',
4391 b'init',
4401 remoteopts,
4392 remoteopts,
4402 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4393 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4403 helpcategory=command.CATEGORY_REPO_CREATION,
4394 helpcategory=command.CATEGORY_REPO_CREATION,
4404 helpbasic=True,
4395 helpbasic=True,
4405 norepo=True,
4396 norepo=True,
4406 )
4397 )
4407 def init(ui, dest=b".", **opts):
4398 def init(ui, dest=b".", **opts):
4408 """create a new repository in the given directory
4399 """create a new repository in the given directory
4409
4400
4410 Initialize a new repository in the given directory. If the given
4401 Initialize a new repository in the given directory. If the given
4411 directory does not exist, it will be created.
4402 directory does not exist, it will be created.
4412
4403
4413 If no directory is given, the current directory is used.
4404 If no directory is given, the current directory is used.
4414
4405
4415 It is possible to specify an ``ssh://`` URL as the destination.
4406 It is possible to specify an ``ssh://`` URL as the destination.
4416 See :hg:`help urls` for more information.
4407 See :hg:`help urls` for more information.
4417
4408
4418 Returns 0 on success.
4409 Returns 0 on success.
4419 """
4410 """
4420 opts = pycompat.byteskwargs(opts)
4411 opts = pycompat.byteskwargs(opts)
4421 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4412 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4422
4413
4423
4414
4424 @command(
4415 @command(
4425 b'locate',
4416 b'locate',
4426 [
4417 [
4427 (
4418 (
4428 b'r',
4419 b'r',
4429 b'rev',
4420 b'rev',
4430 b'',
4421 b'',
4431 _(b'search the repository as it is in REV'),
4422 _(b'search the repository as it is in REV'),
4432 _(b'REV'),
4423 _(b'REV'),
4433 ),
4424 ),
4434 (
4425 (
4435 b'0',
4426 b'0',
4436 b'print0',
4427 b'print0',
4437 None,
4428 None,
4438 _(b'end filenames with NUL, for use with xargs'),
4429 _(b'end filenames with NUL, for use with xargs'),
4439 ),
4430 ),
4440 (
4431 (
4441 b'f',
4432 b'f',
4442 b'fullpath',
4433 b'fullpath',
4443 None,
4434 None,
4444 _(b'print complete paths from the filesystem root'),
4435 _(b'print complete paths from the filesystem root'),
4445 ),
4436 ),
4446 ]
4437 ]
4447 + walkopts,
4438 + walkopts,
4448 _(b'[OPTION]... [PATTERN]...'),
4439 _(b'[OPTION]... [PATTERN]...'),
4449 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4440 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4450 )
4441 )
4451 def locate(ui, repo, *pats, **opts):
4442 def locate(ui, repo, *pats, **opts):
4452 """locate files matching specific patterns (DEPRECATED)
4443 """locate files matching specific patterns (DEPRECATED)
4453
4444
4454 Print files under Mercurial control in the working directory whose
4445 Print files under Mercurial control in the working directory whose
4455 names match the given patterns.
4446 names match the given patterns.
4456
4447
4457 By default, this command searches all directories in the working
4448 By default, this command searches all directories in the working
4458 directory. To search just the current directory and its
4449 directory. To search just the current directory and its
4459 subdirectories, use "--include .".
4450 subdirectories, use "--include .".
4460
4451
4461 If no patterns are given to match, this command prints the names
4452 If no patterns are given to match, this command prints the names
4462 of all files under Mercurial control in the working directory.
4453 of all files under Mercurial control in the working directory.
4463
4454
4464 If you want to feed the output of this command into the "xargs"
4455 If you want to feed the output of this command into the "xargs"
4465 command, use the -0 option to both this command and "xargs". This
4456 command, use the -0 option to both this command and "xargs". This
4466 will avoid the problem of "xargs" treating single filenames that
4457 will avoid the problem of "xargs" treating single filenames that
4467 contain whitespace as multiple filenames.
4458 contain whitespace as multiple filenames.
4468
4459
4469 See :hg:`help files` for a more versatile command.
4460 See :hg:`help files` for a more versatile command.
4470
4461
4471 Returns 0 if a match is found, 1 otherwise.
4462 Returns 0 if a match is found, 1 otherwise.
4472 """
4463 """
4473 opts = pycompat.byteskwargs(opts)
4464 opts = pycompat.byteskwargs(opts)
4474 if opts.get(b'print0'):
4465 if opts.get(b'print0'):
4475 end = b'\0'
4466 end = b'\0'
4476 else:
4467 else:
4477 end = b'\n'
4468 end = b'\n'
4478 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4469 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4479
4470
4480 ret = 1
4471 ret = 1
4481 m = scmutil.match(
4472 m = scmutil.match(
4482 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4473 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4483 )
4474 )
4484
4475
4485 ui.pager(b'locate')
4476 ui.pager(b'locate')
4486 if ctx.rev() is None:
4477 if ctx.rev() is None:
4487 # When run on the working copy, "locate" includes removed files, so
4478 # When run on the working copy, "locate" includes removed files, so
4488 # we get the list of files from the dirstate.
4479 # we get the list of files from the dirstate.
4489 filesgen = sorted(repo.dirstate.matches(m))
4480 filesgen = sorted(repo.dirstate.matches(m))
4490 else:
4481 else:
4491 filesgen = ctx.matches(m)
4482 filesgen = ctx.matches(m)
4492 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4483 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4493 for abs in filesgen:
4484 for abs in filesgen:
4494 if opts.get(b'fullpath'):
4485 if opts.get(b'fullpath'):
4495 ui.write(repo.wjoin(abs), end)
4486 ui.write(repo.wjoin(abs), end)
4496 else:
4487 else:
4497 ui.write(uipathfn(abs), end)
4488 ui.write(uipathfn(abs), end)
4498 ret = 0
4489 ret = 0
4499
4490
4500 return ret
4491 return ret
4501
4492
4502
4493
4503 @command(
4494 @command(
4504 b'log|history',
4495 b'log|history',
4505 [
4496 [
4506 (
4497 (
4507 b'f',
4498 b'f',
4508 b'follow',
4499 b'follow',
4509 None,
4500 None,
4510 _(
4501 _(
4511 b'follow changeset history, or file history across copies and renames'
4502 b'follow changeset history, or file history across copies and renames'
4512 ),
4503 ),
4513 ),
4504 ),
4514 (
4505 (
4515 b'',
4506 b'',
4516 b'follow-first',
4507 b'follow-first',
4517 None,
4508 None,
4518 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4509 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4519 ),
4510 ),
4520 (
4511 (
4521 b'd',
4512 b'd',
4522 b'date',
4513 b'date',
4523 b'',
4514 b'',
4524 _(b'show revisions matching date spec'),
4515 _(b'show revisions matching date spec'),
4525 _(b'DATE'),
4516 _(b'DATE'),
4526 ),
4517 ),
4527 (b'C', b'copies', None, _(b'show copied files')),
4518 (b'C', b'copies', None, _(b'show copied files')),
4528 (
4519 (
4529 b'k',
4520 b'k',
4530 b'keyword',
4521 b'keyword',
4531 [],
4522 [],
4532 _(b'do case-insensitive search for a given text'),
4523 _(b'do case-insensitive search for a given text'),
4533 _(b'TEXT'),
4524 _(b'TEXT'),
4534 ),
4525 ),
4535 (
4526 (
4536 b'r',
4527 b'r',
4537 b'rev',
4528 b'rev',
4538 [],
4529 [],
4539 _(b'show the specified revision or revset'),
4530 _(b'show the specified revision or revset'),
4540 _(b'REV'),
4531 _(b'REV'),
4541 ),
4532 ),
4542 (
4533 (
4543 b'L',
4534 b'L',
4544 b'line-range',
4535 b'line-range',
4545 [],
4536 [],
4546 _(b'follow line range of specified file (EXPERIMENTAL)'),
4537 _(b'follow line range of specified file (EXPERIMENTAL)'),
4547 _(b'FILE,RANGE'),
4538 _(b'FILE,RANGE'),
4548 ),
4539 ),
4549 (
4540 (
4550 b'',
4541 b'',
4551 b'removed',
4542 b'removed',
4552 None,
4543 None,
4553 _(b'include revisions where files were removed'),
4544 _(b'include revisions where files were removed'),
4554 ),
4545 ),
4555 (
4546 (
4556 b'm',
4547 b'm',
4557 b'only-merges',
4548 b'only-merges',
4558 None,
4549 None,
4559 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4550 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4560 ),
4551 ),
4561 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4552 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4562 (
4553 (
4563 b'',
4554 b'',
4564 b'only-branch',
4555 b'only-branch',
4565 [],
4556 [],
4566 _(
4557 _(
4567 b'show only changesets within the given named branch (DEPRECATED)'
4558 b'show only changesets within the given named branch (DEPRECATED)'
4568 ),
4559 ),
4569 _(b'BRANCH'),
4560 _(b'BRANCH'),
4570 ),
4561 ),
4571 (
4562 (
4572 b'b',
4563 b'b',
4573 b'branch',
4564 b'branch',
4574 [],
4565 [],
4575 _(b'show changesets within the given named branch'),
4566 _(b'show changesets within the given named branch'),
4576 _(b'BRANCH'),
4567 _(b'BRANCH'),
4577 ),
4568 ),
4578 (
4569 (
4579 b'P',
4570 b'P',
4580 b'prune',
4571 b'prune',
4581 [],
4572 [],
4582 _(b'do not display revision or any of its ancestors'),
4573 _(b'do not display revision or any of its ancestors'),
4583 _(b'REV'),
4574 _(b'REV'),
4584 ),
4575 ),
4585 ]
4576 ]
4586 + logopts
4577 + logopts
4587 + walkopts,
4578 + walkopts,
4588 _(b'[OPTION]... [FILE]'),
4579 _(b'[OPTION]... [FILE]'),
4589 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4580 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4590 helpbasic=True,
4581 helpbasic=True,
4591 inferrepo=True,
4582 inferrepo=True,
4592 intents={INTENT_READONLY},
4583 intents={INTENT_READONLY},
4593 )
4584 )
4594 def log(ui, repo, *pats, **opts):
4585 def log(ui, repo, *pats, **opts):
4595 """show revision history of entire repository or files
4586 """show revision history of entire repository or files
4596
4587
4597 Print the revision history of the specified files or the entire
4588 Print the revision history of the specified files or the entire
4598 project.
4589 project.
4599
4590
4600 If no revision range is specified, the default is ``tip:0`` unless
4591 If no revision range is specified, the default is ``tip:0`` unless
4601 --follow is set, in which case the working directory parent is
4592 --follow is set, in which case the working directory parent is
4602 used as the starting revision.
4593 used as the starting revision.
4603
4594
4604 File history is shown without following rename or copy history of
4595 File history is shown without following rename or copy history of
4605 files. Use -f/--follow with a filename to follow history across
4596 files. Use -f/--follow with a filename to follow history across
4606 renames and copies. --follow without a filename will only show
4597 renames and copies. --follow without a filename will only show
4607 ancestors of the starting revision.
4598 ancestors of the starting revision.
4608
4599
4609 By default this command prints revision number and changeset id,
4600 By default this command prints revision number and changeset id,
4610 tags, non-trivial parents, user, date and time, and a summary for
4601 tags, non-trivial parents, user, date and time, and a summary for
4611 each commit. When the -v/--verbose switch is used, the list of
4602 each commit. When the -v/--verbose switch is used, the list of
4612 changed files and full commit message are shown.
4603 changed files and full commit message are shown.
4613
4604
4614 With --graph the revisions are shown as an ASCII art DAG with the most
4605 With --graph the revisions are shown as an ASCII art DAG with the most
4615 recent changeset at the top.
4606 recent changeset at the top.
4616 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4607 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4617 involved in an unresolved merge conflict, '_' closes a branch,
4608 involved in an unresolved merge conflict, '_' closes a branch,
4618 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4609 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4619 changeset from the lines below is a parent of the 'o' merge on the same
4610 changeset from the lines below is a parent of the 'o' merge on the same
4620 line.
4611 line.
4621 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4612 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4622 of a '|' indicates one or more revisions in a path are omitted.
4613 of a '|' indicates one or more revisions in a path are omitted.
4623
4614
4624 .. container:: verbose
4615 .. container:: verbose
4625
4616
4626 Use -L/--line-range FILE,M:N options to follow the history of lines
4617 Use -L/--line-range FILE,M:N options to follow the history of lines
4627 from M to N in FILE. With -p/--patch only diff hunks affecting
4618 from M to N in FILE. With -p/--patch only diff hunks affecting
4628 specified line range will be shown. This option requires --follow;
4619 specified line range will be shown. This option requires --follow;
4629 it can be specified multiple times. Currently, this option is not
4620 it can be specified multiple times. Currently, this option is not
4630 compatible with --graph. This option is experimental.
4621 compatible with --graph. This option is experimental.
4631
4622
4632 .. note::
4623 .. note::
4633
4624
4634 :hg:`log --patch` may generate unexpected diff output for merge
4625 :hg:`log --patch` may generate unexpected diff output for merge
4635 changesets, as it will only compare the merge changeset against
4626 changesets, as it will only compare the merge changeset against
4636 its first parent. Also, only files different from BOTH parents
4627 its first parent. Also, only files different from BOTH parents
4637 will appear in files:.
4628 will appear in files:.
4638
4629
4639 .. note::
4630 .. note::
4640
4631
4641 For performance reasons, :hg:`log FILE` may omit duplicate changes
4632 For performance reasons, :hg:`log FILE` may omit duplicate changes
4642 made on branches and will not show removals or mode changes. To
4633 made on branches and will not show removals or mode changes. To
4643 see all such changes, use the --removed switch.
4634 see all such changes, use the --removed switch.
4644
4635
4645 .. container:: verbose
4636 .. container:: verbose
4646
4637
4647 .. note::
4638 .. note::
4648
4639
4649 The history resulting from -L/--line-range options depends on diff
4640 The history resulting from -L/--line-range options depends on diff
4650 options; for instance if white-spaces are ignored, respective changes
4641 options; for instance if white-spaces are ignored, respective changes
4651 with only white-spaces in specified line range will not be listed.
4642 with only white-spaces in specified line range will not be listed.
4652
4643
4653 .. container:: verbose
4644 .. container:: verbose
4654
4645
4655 Some examples:
4646 Some examples:
4656
4647
4657 - changesets with full descriptions and file lists::
4648 - changesets with full descriptions and file lists::
4658
4649
4659 hg log -v
4650 hg log -v
4660
4651
4661 - changesets ancestral to the working directory::
4652 - changesets ancestral to the working directory::
4662
4653
4663 hg log -f
4654 hg log -f
4664
4655
4665 - last 10 commits on the current branch::
4656 - last 10 commits on the current branch::
4666
4657
4667 hg log -l 10 -b .
4658 hg log -l 10 -b .
4668
4659
4669 - changesets showing all modifications of a file, including removals::
4660 - changesets showing all modifications of a file, including removals::
4670
4661
4671 hg log --removed file.c
4662 hg log --removed file.c
4672
4663
4673 - all changesets that touch a directory, with diffs, excluding merges::
4664 - all changesets that touch a directory, with diffs, excluding merges::
4674
4665
4675 hg log -Mp lib/
4666 hg log -Mp lib/
4676
4667
4677 - all revision numbers that match a keyword::
4668 - all revision numbers that match a keyword::
4678
4669
4679 hg log -k bug --template "{rev}\\n"
4670 hg log -k bug --template "{rev}\\n"
4680
4671
4681 - the full hash identifier of the working directory parent::
4672 - the full hash identifier of the working directory parent::
4682
4673
4683 hg log -r . --template "{node}\\n"
4674 hg log -r . --template "{node}\\n"
4684
4675
4685 - list available log templates::
4676 - list available log templates::
4686
4677
4687 hg log -T list
4678 hg log -T list
4688
4679
4689 - check if a given changeset is included in a tagged release::
4680 - check if a given changeset is included in a tagged release::
4690
4681
4691 hg log -r "a21ccf and ancestor(1.9)"
4682 hg log -r "a21ccf and ancestor(1.9)"
4692
4683
4693 - find all changesets by some user in a date range::
4684 - find all changesets by some user in a date range::
4694
4685
4695 hg log -k alice -d "may 2008 to jul 2008"
4686 hg log -k alice -d "may 2008 to jul 2008"
4696
4687
4697 - summary of all changesets after the last tag::
4688 - summary of all changesets after the last tag::
4698
4689
4699 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4690 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4700
4691
4701 - changesets touching lines 13 to 23 for file.c::
4692 - changesets touching lines 13 to 23 for file.c::
4702
4693
4703 hg log -L file.c,13:23
4694 hg log -L file.c,13:23
4704
4695
4705 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4696 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4706 main.c with patch::
4697 main.c with patch::
4707
4698
4708 hg log -L file.c,13:23 -L main.c,2:6 -p
4699 hg log -L file.c,13:23 -L main.c,2:6 -p
4709
4700
4710 See :hg:`help dates` for a list of formats valid for -d/--date.
4701 See :hg:`help dates` for a list of formats valid for -d/--date.
4711
4702
4712 See :hg:`help revisions` for more about specifying and ordering
4703 See :hg:`help revisions` for more about specifying and ordering
4713 revisions.
4704 revisions.
4714
4705
4715 See :hg:`help templates` for more about pre-packaged styles and
4706 See :hg:`help templates` for more about pre-packaged styles and
4716 specifying custom templates. The default template used by the log
4707 specifying custom templates. The default template used by the log
4717 command can be customized via the ``ui.logtemplate`` configuration
4708 command can be customized via the ``ui.logtemplate`` configuration
4718 setting.
4709 setting.
4719
4710
4720 Returns 0 on success.
4711 Returns 0 on success.
4721
4712
4722 """
4713 """
4723 opts = pycompat.byteskwargs(opts)
4714 opts = pycompat.byteskwargs(opts)
4724 linerange = opts.get(b'line_range')
4715 linerange = opts.get(b'line_range')
4725
4716
4726 if linerange and not opts.get(b'follow'):
4717 if linerange and not opts.get(b'follow'):
4727 raise error.Abort(_(b'--line-range requires --follow'))
4718 raise error.Abort(_(b'--line-range requires --follow'))
4728
4719
4729 if linerange and pats:
4720 if linerange and pats:
4730 # TODO: take pats as patterns with no line-range filter
4721 # TODO: take pats as patterns with no line-range filter
4731 raise error.Abort(
4722 raise error.Abort(
4732 _(b'FILE arguments are not compatible with --line-range option')
4723 _(b'FILE arguments are not compatible with --line-range option')
4733 )
4724 )
4734
4725
4735 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4726 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4736 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4727 revs, differ = logcmdutil.getrevs(repo, pats, opts)
4737 if linerange:
4728 if linerange:
4738 # TODO: should follow file history from logcmdutil._initialrevs(),
4729 # TODO: should follow file history from logcmdutil._initialrevs(),
4739 # then filter the result by logcmdutil._makerevset() and --limit
4730 # then filter the result by logcmdutil._makerevset() and --limit
4740 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4731 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4741
4732
4742 getcopies = None
4733 getcopies = None
4743 if opts.get(b'copies'):
4734 if opts.get(b'copies'):
4744 endrev = None
4735 endrev = None
4745 if revs:
4736 if revs:
4746 endrev = revs.max() + 1
4737 endrev = revs.max() + 1
4747 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4738 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4748
4739
4749 ui.pager(b'log')
4740 ui.pager(b'log')
4750 displayer = logcmdutil.changesetdisplayer(
4741 displayer = logcmdutil.changesetdisplayer(
4751 ui, repo, opts, differ, buffered=True
4742 ui, repo, opts, differ, buffered=True
4752 )
4743 )
4753 if opts.get(b'graph'):
4744 if opts.get(b'graph'):
4754 displayfn = logcmdutil.displaygraphrevs
4745 displayfn = logcmdutil.displaygraphrevs
4755 else:
4746 else:
4756 displayfn = logcmdutil.displayrevs
4747 displayfn = logcmdutil.displayrevs
4757 displayfn(ui, repo, revs, displayer, getcopies)
4748 displayfn(ui, repo, revs, displayer, getcopies)
4758
4749
4759
4750
4760 @command(
4751 @command(
4761 b'manifest',
4752 b'manifest',
4762 [
4753 [
4763 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4754 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4764 (b'', b'all', False, _(b"list files from all revisions")),
4755 (b'', b'all', False, _(b"list files from all revisions")),
4765 ]
4756 ]
4766 + formatteropts,
4757 + formatteropts,
4767 _(b'[-r REV]'),
4758 _(b'[-r REV]'),
4768 helpcategory=command.CATEGORY_MAINTENANCE,
4759 helpcategory=command.CATEGORY_MAINTENANCE,
4769 intents={INTENT_READONLY},
4760 intents={INTENT_READONLY},
4770 )
4761 )
4771 def manifest(ui, repo, node=None, rev=None, **opts):
4762 def manifest(ui, repo, node=None, rev=None, **opts):
4772 """output the current or given revision of the project manifest
4763 """output the current or given revision of the project manifest
4773
4764
4774 Print a list of version controlled files for the given revision.
4765 Print a list of version controlled files for the given revision.
4775 If no revision is given, the first parent of the working directory
4766 If no revision is given, the first parent of the working directory
4776 is used, or the null revision if no revision is checked out.
4767 is used, or the null revision if no revision is checked out.
4777
4768
4778 With -v, print file permissions, symlink and executable bits.
4769 With -v, print file permissions, symlink and executable bits.
4779 With --debug, print file revision hashes.
4770 With --debug, print file revision hashes.
4780
4771
4781 If option --all is specified, the list of all files from all revisions
4772 If option --all is specified, the list of all files from all revisions
4782 is printed. This includes deleted and renamed files.
4773 is printed. This includes deleted and renamed files.
4783
4774
4784 Returns 0 on success.
4775 Returns 0 on success.
4785 """
4776 """
4786 opts = pycompat.byteskwargs(opts)
4777 opts = pycompat.byteskwargs(opts)
4787 fm = ui.formatter(b'manifest', opts)
4778 fm = ui.formatter(b'manifest', opts)
4788
4779
4789 if opts.get(b'all'):
4780 if opts.get(b'all'):
4790 if rev or node:
4781 if rev or node:
4791 raise error.Abort(_(b"can't specify a revision with --all"))
4782 raise error.Abort(_(b"can't specify a revision with --all"))
4792
4783
4793 res = set()
4784 res = set()
4794 for rev in repo:
4785 for rev in repo:
4795 ctx = repo[rev]
4786 ctx = repo[rev]
4796 res |= set(ctx.files())
4787 res |= set(ctx.files())
4797
4788
4798 ui.pager(b'manifest')
4789 ui.pager(b'manifest')
4799 for f in sorted(res):
4790 for f in sorted(res):
4800 fm.startitem()
4791 fm.startitem()
4801 fm.write(b"path", b'%s\n', f)
4792 fm.write(b"path", b'%s\n', f)
4802 fm.end()
4793 fm.end()
4803 return
4794 return
4804
4795
4805 if rev and node:
4796 if rev and node:
4806 raise error.Abort(_(b"please specify just one revision"))
4797 raise error.Abort(_(b"please specify just one revision"))
4807
4798
4808 if not node:
4799 if not node:
4809 node = rev
4800 node = rev
4810
4801
4811 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4802 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4812 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4803 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4813 if node:
4804 if node:
4814 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4805 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4815 ctx = scmutil.revsingle(repo, node)
4806 ctx = scmutil.revsingle(repo, node)
4816 mf = ctx.manifest()
4807 mf = ctx.manifest()
4817 ui.pager(b'manifest')
4808 ui.pager(b'manifest')
4818 for f in ctx:
4809 for f in ctx:
4819 fm.startitem()
4810 fm.startitem()
4820 fm.context(ctx=ctx)
4811 fm.context(ctx=ctx)
4821 fl = ctx[f].flags()
4812 fl = ctx[f].flags()
4822 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4813 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4823 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4814 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4824 fm.write(b'path', b'%s\n', f)
4815 fm.write(b'path', b'%s\n', f)
4825 fm.end()
4816 fm.end()
4826
4817
4827
4818
4828 @command(
4819 @command(
4829 b'merge',
4820 b'merge',
4830 [
4821 [
4831 (
4822 (
4832 b'f',
4823 b'f',
4833 b'force',
4824 b'force',
4834 None,
4825 None,
4835 _(b'force a merge including outstanding changes (DEPRECATED)'),
4826 _(b'force a merge including outstanding changes (DEPRECATED)'),
4836 ),
4827 ),
4837 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4828 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4838 (
4829 (
4839 b'P',
4830 b'P',
4840 b'preview',
4831 b'preview',
4841 None,
4832 None,
4842 _(b'review revisions to merge (no merge is performed)'),
4833 _(b'review revisions to merge (no merge is performed)'),
4843 ),
4834 ),
4844 (b'', b'abort', None, _(b'abort the ongoing merge')),
4835 (b'', b'abort', None, _(b'abort the ongoing merge')),
4845 ]
4836 ]
4846 + mergetoolopts,
4837 + mergetoolopts,
4847 _(b'[-P] [[-r] REV]'),
4838 _(b'[-P] [[-r] REV]'),
4848 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4839 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4849 helpbasic=True,
4840 helpbasic=True,
4850 )
4841 )
4851 def merge(ui, repo, node=None, **opts):
4842 def merge(ui, repo, node=None, **opts):
4852 """merge another revision into working directory
4843 """merge another revision into working directory
4853
4844
4854 The current working directory is updated with all changes made in
4845 The current working directory is updated with all changes made in
4855 the requested revision since the last common predecessor revision.
4846 the requested revision since the last common predecessor revision.
4856
4847
4857 Files that changed between either parent are marked as changed for
4848 Files that changed between either parent are marked as changed for
4858 the next commit and a commit must be performed before any further
4849 the next commit and a commit must be performed before any further
4859 updates to the repository are allowed. The next commit will have
4850 updates to the repository are allowed. The next commit will have
4860 two parents.
4851 two parents.
4861
4852
4862 ``--tool`` can be used to specify the merge tool used for file
4853 ``--tool`` can be used to specify the merge tool used for file
4863 merges. It overrides the HGMERGE environment variable and your
4854 merges. It overrides the HGMERGE environment variable and your
4864 configuration files. See :hg:`help merge-tools` for options.
4855 configuration files. See :hg:`help merge-tools` for options.
4865
4856
4866 If no revision is specified, the working directory's parent is a
4857 If no revision is specified, the working directory's parent is a
4867 head revision, and the current branch contains exactly one other
4858 head revision, and the current branch contains exactly one other
4868 head, the other head is merged with by default. Otherwise, an
4859 head, the other head is merged with by default. Otherwise, an
4869 explicit revision with which to merge must be provided.
4860 explicit revision with which to merge must be provided.
4870
4861
4871 See :hg:`help resolve` for information on handling file conflicts.
4862 See :hg:`help resolve` for information on handling file conflicts.
4872
4863
4873 To undo an uncommitted merge, use :hg:`merge --abort` which
4864 To undo an uncommitted merge, use :hg:`merge --abort` which
4874 will check out a clean copy of the original merge parent, losing
4865 will check out a clean copy of the original merge parent, losing
4875 all changes.
4866 all changes.
4876
4867
4877 Returns 0 on success, 1 if there are unresolved files.
4868 Returns 0 on success, 1 if there are unresolved files.
4878 """
4869 """
4879
4870
4880 opts = pycompat.byteskwargs(opts)
4871 opts = pycompat.byteskwargs(opts)
4881 abort = opts.get(b'abort')
4872 abort = opts.get(b'abort')
4882 if abort and repo.dirstate.p2() == nullid:
4873 if abort and repo.dirstate.p2() == nullid:
4883 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4874 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4884 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4875 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4885 if abort:
4876 if abort:
4886 state = cmdutil.getunfinishedstate(repo)
4877 state = cmdutil.getunfinishedstate(repo)
4887 if state and state._opname != b'merge':
4878 if state and state._opname != b'merge':
4888 raise error.Abort(
4879 raise error.Abort(
4889 _(b'cannot abort merge with %s in progress') % (state._opname),
4880 _(b'cannot abort merge with %s in progress') % (state._opname),
4890 hint=state.hint(),
4881 hint=state.hint(),
4891 )
4882 )
4892 if node:
4883 if node:
4893 raise error.Abort(_(b"cannot specify a node with --abort"))
4884 raise error.Abort(_(b"cannot specify a node with --abort"))
4894 return hg.abortmerge(repo.ui, repo)
4885 return hg.abortmerge(repo.ui, repo)
4895
4886
4896 if opts.get(b'rev') and node:
4887 if opts.get(b'rev') and node:
4897 raise error.Abort(_(b"please specify just one revision"))
4888 raise error.Abort(_(b"please specify just one revision"))
4898 if not node:
4889 if not node:
4899 node = opts.get(b'rev')
4890 node = opts.get(b'rev')
4900
4891
4901 if node:
4892 if node:
4902 ctx = scmutil.revsingle(repo, node)
4893 ctx = scmutil.revsingle(repo, node)
4903 else:
4894 else:
4904 if ui.configbool(b'commands', b'merge.require-rev'):
4895 if ui.configbool(b'commands', b'merge.require-rev'):
4905 raise error.Abort(
4896 raise error.Abort(
4906 _(
4897 _(
4907 b'configuration requires specifying revision to merge '
4898 b'configuration requires specifying revision to merge '
4908 b'with'
4899 b'with'
4909 )
4900 )
4910 )
4901 )
4911 ctx = repo[destutil.destmerge(repo)]
4902 ctx = repo[destutil.destmerge(repo)]
4912
4903
4913 if ctx.node() is None:
4904 if ctx.node() is None:
4914 raise error.Abort(_(b'merging with the working copy has no effect'))
4905 raise error.Abort(_(b'merging with the working copy has no effect'))
4915
4906
4916 if opts.get(b'preview'):
4907 if opts.get(b'preview'):
4917 # find nodes that are ancestors of p2 but not of p1
4908 # find nodes that are ancestors of p2 but not of p1
4918 p1 = repo[b'.'].node()
4909 p1 = repo[b'.'].node()
4919 p2 = ctx.node()
4910 p2 = ctx.node()
4920 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4911 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4921
4912
4922 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4913 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4923 for node in nodes:
4914 for node in nodes:
4924 displayer.show(repo[node])
4915 displayer.show(repo[node])
4925 displayer.close()
4916 displayer.close()
4926 return 0
4917 return 0
4927
4918
4928 # ui.forcemerge is an internal variable, do not document
4919 # ui.forcemerge is an internal variable, do not document
4929 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4920 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4930 with ui.configoverride(overrides, b'merge'):
4921 with ui.configoverride(overrides, b'merge'):
4931 force = opts.get(b'force')
4922 force = opts.get(b'force')
4932 labels = [b'working copy', b'merge rev']
4923 labels = [b'working copy', b'merge rev']
4933 return hg.merge(ctx, force=force, labels=labels)
4924 return hg.merge(ctx, force=force, labels=labels)
4934
4925
4935
4926
4936 statemod.addunfinished(
4927 statemod.addunfinished(
4937 b'merge',
4928 b'merge',
4938 fname=None,
4929 fname=None,
4939 clearable=True,
4930 clearable=True,
4940 allowcommit=True,
4931 allowcommit=True,
4941 cmdmsg=_(b'outstanding uncommitted merge'),
4932 cmdmsg=_(b'outstanding uncommitted merge'),
4942 abortfunc=hg.abortmerge,
4933 abortfunc=hg.abortmerge,
4943 statushint=_(
4934 statushint=_(
4944 b'To continue: hg commit\nTo abort: hg merge --abort'
4935 b'To continue: hg commit\nTo abort: hg merge --abort'
4945 ),
4936 ),
4946 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4937 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4947 )
4938 )
4948
4939
4949
4940
4950 @command(
4941 @command(
4951 b'outgoing|out',
4942 b'outgoing|out',
4952 [
4943 [
4953 (
4944 (
4954 b'f',
4945 b'f',
4955 b'force',
4946 b'force',
4956 None,
4947 None,
4957 _(b'run even when the destination is unrelated'),
4948 _(b'run even when the destination is unrelated'),
4958 ),
4949 ),
4959 (
4950 (
4960 b'r',
4951 b'r',
4961 b'rev',
4952 b'rev',
4962 [],
4953 [],
4963 _(b'a changeset intended to be included in the destination'),
4954 _(b'a changeset intended to be included in the destination'),
4964 _(b'REV'),
4955 _(b'REV'),
4965 ),
4956 ),
4966 (b'n', b'newest-first', None, _(b'show newest record first')),
4957 (b'n', b'newest-first', None, _(b'show newest record first')),
4967 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4958 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4968 (
4959 (
4969 b'b',
4960 b'b',
4970 b'branch',
4961 b'branch',
4971 [],
4962 [],
4972 _(b'a specific branch you would like to push'),
4963 _(b'a specific branch you would like to push'),
4973 _(b'BRANCH'),
4964 _(b'BRANCH'),
4974 ),
4965 ),
4975 ]
4966 ]
4976 + logopts
4967 + logopts
4977 + remoteopts
4968 + remoteopts
4978 + subrepoopts,
4969 + subrepoopts,
4979 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4970 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4980 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4971 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4981 )
4972 )
4982 def outgoing(ui, repo, dest=None, **opts):
4973 def outgoing(ui, repo, dest=None, **opts):
4983 """show changesets not found in the destination
4974 """show changesets not found in the destination
4984
4975
4985 Show changesets not found in the specified destination repository
4976 Show changesets not found in the specified destination repository
4986 or the default push location. These are the changesets that would
4977 or the default push location. These are the changesets that would
4987 be pushed if a push was requested.
4978 be pushed if a push was requested.
4988
4979
4989 See pull for details of valid destination formats.
4980 See pull for details of valid destination formats.
4990
4981
4991 .. container:: verbose
4982 .. container:: verbose
4992
4983
4993 With -B/--bookmarks, the result of bookmark comparison between
4984 With -B/--bookmarks, the result of bookmark comparison between
4994 local and remote repositories is displayed. With -v/--verbose,
4985 local and remote repositories is displayed. With -v/--verbose,
4995 status is also displayed for each bookmark like below::
4986 status is also displayed for each bookmark like below::
4996
4987
4997 BM1 01234567890a added
4988 BM1 01234567890a added
4998 BM2 deleted
4989 BM2 deleted
4999 BM3 234567890abc advanced
4990 BM3 234567890abc advanced
5000 BM4 34567890abcd diverged
4991 BM4 34567890abcd diverged
5001 BM5 4567890abcde changed
4992 BM5 4567890abcde changed
5002
4993
5003 The action taken when pushing depends on the
4994 The action taken when pushing depends on the
5004 status of each bookmark:
4995 status of each bookmark:
5005
4996
5006 :``added``: push with ``-B`` will create it
4997 :``added``: push with ``-B`` will create it
5007 :``deleted``: push with ``-B`` will delete it
4998 :``deleted``: push with ``-B`` will delete it
5008 :``advanced``: push will update it
4999 :``advanced``: push will update it
5009 :``diverged``: push with ``-B`` will update it
5000 :``diverged``: push with ``-B`` will update it
5010 :``changed``: push with ``-B`` will update it
5001 :``changed``: push with ``-B`` will update it
5011
5002
5012 From the point of view of pushing behavior, bookmarks
5003 From the point of view of pushing behavior, bookmarks
5013 existing only in the remote repository are treated as
5004 existing only in the remote repository are treated as
5014 ``deleted``, even if it is in fact added remotely.
5005 ``deleted``, even if it is in fact added remotely.
5015
5006
5016 Returns 0 if there are outgoing changes, 1 otherwise.
5007 Returns 0 if there are outgoing changes, 1 otherwise.
5017 """
5008 """
5018 # hg._outgoing() needs to re-resolve the path in order to handle #branch
5009 # hg._outgoing() needs to re-resolve the path in order to handle #branch
5019 # style URLs, so don't overwrite dest.
5010 # style URLs, so don't overwrite dest.
5020 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5011 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5021 if not path:
5012 if not path:
5022 raise error.Abort(
5013 raise error.Abort(
5023 _(b'default repository not configured!'),
5014 _(b'default repository not configured!'),
5024 hint=_(b"see 'hg help config.paths'"),
5015 hint=_(b"see 'hg help config.paths'"),
5025 )
5016 )
5026
5017
5027 opts = pycompat.byteskwargs(opts)
5018 opts = pycompat.byteskwargs(opts)
5028 if opts.get(b'graph'):
5019 if opts.get(b'graph'):
5029 logcmdutil.checkunsupportedgraphflags([], opts)
5020 logcmdutil.checkunsupportedgraphflags([], opts)
5030 o, other = hg._outgoing(ui, repo, dest, opts)
5021 o, other = hg._outgoing(ui, repo, dest, opts)
5031 if not o:
5022 if not o:
5032 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5023 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5033 return
5024 return
5034
5025
5035 revdag = logcmdutil.graphrevs(repo, o, opts)
5026 revdag = logcmdutil.graphrevs(repo, o, opts)
5036 ui.pager(b'outgoing')
5027 ui.pager(b'outgoing')
5037 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5028 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
5038 logcmdutil.displaygraph(
5029 logcmdutil.displaygraph(
5039 ui, repo, revdag, displayer, graphmod.asciiedges
5030 ui, repo, revdag, displayer, graphmod.asciiedges
5040 )
5031 )
5041 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5032 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5042 return 0
5033 return 0
5043
5034
5044 if opts.get(b'bookmarks'):
5035 if opts.get(b'bookmarks'):
5045 dest = path.pushloc or path.loc
5036 dest = path.pushloc or path.loc
5046 other = hg.peer(repo, opts, dest)
5037 other = hg.peer(repo, opts, dest)
5047 if b'bookmarks' not in other.listkeys(b'namespaces'):
5038 if b'bookmarks' not in other.listkeys(b'namespaces'):
5048 ui.warn(_(b"remote doesn't support bookmarks\n"))
5039 ui.warn(_(b"remote doesn't support bookmarks\n"))
5049 return 0
5040 return 0
5050 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5041 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
5051 ui.pager(b'outgoing')
5042 ui.pager(b'outgoing')
5052 return bookmarks.outgoing(ui, repo, other)
5043 return bookmarks.outgoing(ui, repo, other)
5053
5044
5054 repo._subtoppath = path.pushloc or path.loc
5045 repo._subtoppath = path.pushloc or path.loc
5055 try:
5046 try:
5056 return hg.outgoing(ui, repo, dest, opts)
5047 return hg.outgoing(ui, repo, dest, opts)
5057 finally:
5048 finally:
5058 del repo._subtoppath
5049 del repo._subtoppath
5059
5050
5060
5051
5061 @command(
5052 @command(
5062 b'parents',
5053 b'parents',
5063 [
5054 [
5064 (
5055 (
5065 b'r',
5056 b'r',
5066 b'rev',
5057 b'rev',
5067 b'',
5058 b'',
5068 _(b'show parents of the specified revision'),
5059 _(b'show parents of the specified revision'),
5069 _(b'REV'),
5060 _(b'REV'),
5070 ),
5061 ),
5071 ]
5062 ]
5072 + templateopts,
5063 + templateopts,
5073 _(b'[-r REV] [FILE]'),
5064 _(b'[-r REV] [FILE]'),
5074 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5065 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5075 inferrepo=True,
5066 inferrepo=True,
5076 )
5067 )
5077 def parents(ui, repo, file_=None, **opts):
5068 def parents(ui, repo, file_=None, **opts):
5078 """show the parents of the working directory or revision (DEPRECATED)
5069 """show the parents of the working directory or revision (DEPRECATED)
5079
5070
5080 Print the working directory's parent revisions. If a revision is
5071 Print the working directory's parent revisions. If a revision is
5081 given via -r/--rev, the parent of that revision will be printed.
5072 given via -r/--rev, the parent of that revision will be printed.
5082 If a file argument is given, the revision in which the file was
5073 If a file argument is given, the revision in which the file was
5083 last changed (before the working directory revision or the
5074 last changed (before the working directory revision or the
5084 argument to --rev if given) is printed.
5075 argument to --rev if given) is printed.
5085
5076
5086 This command is equivalent to::
5077 This command is equivalent to::
5087
5078
5088 hg log -r "p1()+p2()" or
5079 hg log -r "p1()+p2()" or
5089 hg log -r "p1(REV)+p2(REV)" or
5080 hg log -r "p1(REV)+p2(REV)" or
5090 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5081 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5091 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5082 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5092
5083
5093 See :hg:`summary` and :hg:`help revsets` for related information.
5084 See :hg:`summary` and :hg:`help revsets` for related information.
5094
5085
5095 Returns 0 on success.
5086 Returns 0 on success.
5096 """
5087 """
5097
5088
5098 opts = pycompat.byteskwargs(opts)
5089 opts = pycompat.byteskwargs(opts)
5099 rev = opts.get(b'rev')
5090 rev = opts.get(b'rev')
5100 if rev:
5091 if rev:
5101 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5092 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5102 ctx = scmutil.revsingle(repo, rev, None)
5093 ctx = scmutil.revsingle(repo, rev, None)
5103
5094
5104 if file_:
5095 if file_:
5105 m = scmutil.match(ctx, (file_,), opts)
5096 m = scmutil.match(ctx, (file_,), opts)
5106 if m.anypats() or len(m.files()) != 1:
5097 if m.anypats() or len(m.files()) != 1:
5107 raise error.Abort(_(b'can only specify an explicit filename'))
5098 raise error.Abort(_(b'can only specify an explicit filename'))
5108 file_ = m.files()[0]
5099 file_ = m.files()[0]
5109 filenodes = []
5100 filenodes = []
5110 for cp in ctx.parents():
5101 for cp in ctx.parents():
5111 if not cp:
5102 if not cp:
5112 continue
5103 continue
5113 try:
5104 try:
5114 filenodes.append(cp.filenode(file_))
5105 filenodes.append(cp.filenode(file_))
5115 except error.LookupError:
5106 except error.LookupError:
5116 pass
5107 pass
5117 if not filenodes:
5108 if not filenodes:
5118 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5109 raise error.Abort(_(b"'%s' not found in manifest!") % file_)
5119 p = []
5110 p = []
5120 for fn in filenodes:
5111 for fn in filenodes:
5121 fctx = repo.filectx(file_, fileid=fn)
5112 fctx = repo.filectx(file_, fileid=fn)
5122 p.append(fctx.node())
5113 p.append(fctx.node())
5123 else:
5114 else:
5124 p = [cp.node() for cp in ctx.parents()]
5115 p = [cp.node() for cp in ctx.parents()]
5125
5116
5126 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5117 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5127 for n in p:
5118 for n in p:
5128 if n != nullid:
5119 if n != nullid:
5129 displayer.show(repo[n])
5120 displayer.show(repo[n])
5130 displayer.close()
5121 displayer.close()
5131
5122
5132
5123
5133 @command(
5124 @command(
5134 b'paths',
5125 b'paths',
5135 formatteropts,
5126 formatteropts,
5136 _(b'[NAME]'),
5127 _(b'[NAME]'),
5137 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5128 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5138 optionalrepo=True,
5129 optionalrepo=True,
5139 intents={INTENT_READONLY},
5130 intents={INTENT_READONLY},
5140 )
5131 )
5141 def paths(ui, repo, search=None, **opts):
5132 def paths(ui, repo, search=None, **opts):
5142 """show aliases for remote repositories
5133 """show aliases for remote repositories
5143
5134
5144 Show definition of symbolic path name NAME. If no name is given,
5135 Show definition of symbolic path name NAME. If no name is given,
5145 show definition of all available names.
5136 show definition of all available names.
5146
5137
5147 Option -q/--quiet suppresses all output when searching for NAME
5138 Option -q/--quiet suppresses all output when searching for NAME
5148 and shows only the path names when listing all definitions.
5139 and shows only the path names when listing all definitions.
5149
5140
5150 Path names are defined in the [paths] section of your
5141 Path names are defined in the [paths] section of your
5151 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5142 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5152 repository, ``.hg/hgrc`` is used, too.
5143 repository, ``.hg/hgrc`` is used, too.
5153
5144
5154 The path names ``default`` and ``default-push`` have a special
5145 The path names ``default`` and ``default-push`` have a special
5155 meaning. When performing a push or pull operation, they are used
5146 meaning. When performing a push or pull operation, they are used
5156 as fallbacks if no location is specified on the command-line.
5147 as fallbacks if no location is specified on the command-line.
5157 When ``default-push`` is set, it will be used for push and
5148 When ``default-push`` is set, it will be used for push and
5158 ``default`` will be used for pull; otherwise ``default`` is used
5149 ``default`` will be used for pull; otherwise ``default`` is used
5159 as the fallback for both. When cloning a repository, the clone
5150 as the fallback for both. When cloning a repository, the clone
5160 source is written as ``default`` in ``.hg/hgrc``.
5151 source is written as ``default`` in ``.hg/hgrc``.
5161
5152
5162 .. note::
5153 .. note::
5163
5154
5164 ``default`` and ``default-push`` apply to all inbound (e.g.
5155 ``default`` and ``default-push`` apply to all inbound (e.g.
5165 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5156 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5166 and :hg:`bundle`) operations.
5157 and :hg:`bundle`) operations.
5167
5158
5168 See :hg:`help urls` for more information.
5159 See :hg:`help urls` for more information.
5169
5160
5170 .. container:: verbose
5161 .. container:: verbose
5171
5162
5172 Template:
5163 Template:
5173
5164
5174 The following keywords are supported. See also :hg:`help templates`.
5165 The following keywords are supported. See also :hg:`help templates`.
5175
5166
5176 :name: String. Symbolic name of the path alias.
5167 :name: String. Symbolic name of the path alias.
5177 :pushurl: String. URL for push operations.
5168 :pushurl: String. URL for push operations.
5178 :url: String. URL or directory path for the other operations.
5169 :url: String. URL or directory path for the other operations.
5179
5170
5180 Returns 0 on success.
5171 Returns 0 on success.
5181 """
5172 """
5182
5173
5183 opts = pycompat.byteskwargs(opts)
5174 opts = pycompat.byteskwargs(opts)
5184 ui.pager(b'paths')
5175 ui.pager(b'paths')
5185 if search:
5176 if search:
5186 pathitems = [
5177 pathitems = [
5187 (name, path)
5178 (name, path)
5188 for name, path in pycompat.iteritems(ui.paths)
5179 for name, path in pycompat.iteritems(ui.paths)
5189 if name == search
5180 if name == search
5190 ]
5181 ]
5191 else:
5182 else:
5192 pathitems = sorted(pycompat.iteritems(ui.paths))
5183 pathitems = sorted(pycompat.iteritems(ui.paths))
5193
5184
5194 fm = ui.formatter(b'paths', opts)
5185 fm = ui.formatter(b'paths', opts)
5195 if fm.isplain():
5186 if fm.isplain():
5196 hidepassword = util.hidepassword
5187 hidepassword = util.hidepassword
5197 else:
5188 else:
5198 hidepassword = bytes
5189 hidepassword = bytes
5199 if ui.quiet:
5190 if ui.quiet:
5200 namefmt = b'%s\n'
5191 namefmt = b'%s\n'
5201 else:
5192 else:
5202 namefmt = b'%s = '
5193 namefmt = b'%s = '
5203 showsubopts = not search and not ui.quiet
5194 showsubopts = not search and not ui.quiet
5204
5195
5205 for name, path in pathitems:
5196 for name, path in pathitems:
5206 fm.startitem()
5197 fm.startitem()
5207 fm.condwrite(not search, b'name', namefmt, name)
5198 fm.condwrite(not search, b'name', namefmt, name)
5208 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5199 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5209 for subopt, value in sorted(path.suboptions.items()):
5200 for subopt, value in sorted(path.suboptions.items()):
5210 assert subopt not in (b'name', b'url')
5201 assert subopt not in (b'name', b'url')
5211 if showsubopts:
5202 if showsubopts:
5212 fm.plain(b'%s:%s = ' % (name, subopt))
5203 fm.plain(b'%s:%s = ' % (name, subopt))
5213 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5204 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5214
5205
5215 fm.end()
5206 fm.end()
5216
5207
5217 if search and not pathitems:
5208 if search and not pathitems:
5218 if not ui.quiet:
5209 if not ui.quiet:
5219 ui.warn(_(b"not found!\n"))
5210 ui.warn(_(b"not found!\n"))
5220 return 1
5211 return 1
5221 else:
5212 else:
5222 return 0
5213 return 0
5223
5214
5224
5215
5225 @command(
5216 @command(
5226 b'phase',
5217 b'phase',
5227 [
5218 [
5228 (b'p', b'public', False, _(b'set changeset phase to public')),
5219 (b'p', b'public', False, _(b'set changeset phase to public')),
5229 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5220 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5230 (b's', b'secret', False, _(b'set changeset phase to secret')),
5221 (b's', b'secret', False, _(b'set changeset phase to secret')),
5231 (b'f', b'force', False, _(b'allow to move boundary backward')),
5222 (b'f', b'force', False, _(b'allow to move boundary backward')),
5232 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5223 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5233 ],
5224 ],
5234 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5225 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5235 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5226 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5236 )
5227 )
5237 def phase(ui, repo, *revs, **opts):
5228 def phase(ui, repo, *revs, **opts):
5238 """set or show the current phase name
5229 """set or show the current phase name
5239
5230
5240 With no argument, show the phase name of the current revision(s).
5231 With no argument, show the phase name of the current revision(s).
5241
5232
5242 With one of -p/--public, -d/--draft or -s/--secret, change the
5233 With one of -p/--public, -d/--draft or -s/--secret, change the
5243 phase value of the specified revisions.
5234 phase value of the specified revisions.
5244
5235
5245 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5236 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5246 lower phase to a higher phase. Phases are ordered as follows::
5237 lower phase to a higher phase. Phases are ordered as follows::
5247
5238
5248 public < draft < secret
5239 public < draft < secret
5249
5240
5250 Returns 0 on success, 1 if some phases could not be changed.
5241 Returns 0 on success, 1 if some phases could not be changed.
5251
5242
5252 (For more information about the phases concept, see :hg:`help phases`.)
5243 (For more information about the phases concept, see :hg:`help phases`.)
5253 """
5244 """
5254 opts = pycompat.byteskwargs(opts)
5245 opts = pycompat.byteskwargs(opts)
5255 # search for a unique phase argument
5246 # search for a unique phase argument
5256 targetphase = None
5247 targetphase = None
5257 for idx, name in enumerate(phases.cmdphasenames):
5248 for idx, name in enumerate(phases.cmdphasenames):
5258 if opts[name]:
5249 if opts[name]:
5259 if targetphase is not None:
5250 if targetphase is not None:
5260 raise error.Abort(_(b'only one phase can be specified'))
5251 raise error.Abort(_(b'only one phase can be specified'))
5261 targetphase = idx
5252 targetphase = idx
5262
5253
5263 # look for specified revision
5254 # look for specified revision
5264 revs = list(revs)
5255 revs = list(revs)
5265 revs.extend(opts[b'rev'])
5256 revs.extend(opts[b'rev'])
5266 if not revs:
5257 if not revs:
5267 # display both parents as the second parent phase can influence
5258 # display both parents as the second parent phase can influence
5268 # the phase of a merge commit
5259 # the phase of a merge commit
5269 revs = [c.rev() for c in repo[None].parents()]
5260 revs = [c.rev() for c in repo[None].parents()]
5270
5261
5271 revs = scmutil.revrange(repo, revs)
5262 revs = scmutil.revrange(repo, revs)
5272
5263
5273 ret = 0
5264 ret = 0
5274 if targetphase is None:
5265 if targetphase is None:
5275 # display
5266 # display
5276 for r in revs:
5267 for r in revs:
5277 ctx = repo[r]
5268 ctx = repo[r]
5278 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5269 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5279 else:
5270 else:
5280 with repo.lock(), repo.transaction(b"phase") as tr:
5271 with repo.lock(), repo.transaction(b"phase") as tr:
5281 # set phase
5272 # set phase
5282 if not revs:
5273 if not revs:
5283 raise error.Abort(_(b'empty revision set'))
5274 raise error.Abort(_(b'empty revision set'))
5284 nodes = [repo[r].node() for r in revs]
5275 nodes = [repo[r].node() for r in revs]
5285 # moving revision from public to draft may hide them
5276 # moving revision from public to draft may hide them
5286 # We have to check result on an unfiltered repository
5277 # We have to check result on an unfiltered repository
5287 unfi = repo.unfiltered()
5278 unfi = repo.unfiltered()
5288 getphase = unfi._phasecache.phase
5279 getphase = unfi._phasecache.phase
5289 olddata = [getphase(unfi, r) for r in unfi]
5280 olddata = [getphase(unfi, r) for r in unfi]
5290 phases.advanceboundary(repo, tr, targetphase, nodes)
5281 phases.advanceboundary(repo, tr, targetphase, nodes)
5291 if opts[b'force']:
5282 if opts[b'force']:
5292 phases.retractboundary(repo, tr, targetphase, nodes)
5283 phases.retractboundary(repo, tr, targetphase, nodes)
5293 getphase = unfi._phasecache.phase
5284 getphase = unfi._phasecache.phase
5294 newdata = [getphase(unfi, r) for r in unfi]
5285 newdata = [getphase(unfi, r) for r in unfi]
5295 changes = sum(newdata[r] != olddata[r] for r in unfi)
5286 changes = sum(newdata[r] != olddata[r] for r in unfi)
5296 cl = unfi.changelog
5287 cl = unfi.changelog
5297 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5288 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5298 if rejected:
5289 if rejected:
5299 ui.warn(
5290 ui.warn(
5300 _(
5291 _(
5301 b'cannot move %i changesets to a higher '
5292 b'cannot move %i changesets to a higher '
5302 b'phase, use --force\n'
5293 b'phase, use --force\n'
5303 )
5294 )
5304 % len(rejected)
5295 % len(rejected)
5305 )
5296 )
5306 ret = 1
5297 ret = 1
5307 if changes:
5298 if changes:
5308 msg = _(b'phase changed for %i changesets\n') % changes
5299 msg = _(b'phase changed for %i changesets\n') % changes
5309 if ret:
5300 if ret:
5310 ui.status(msg)
5301 ui.status(msg)
5311 else:
5302 else:
5312 ui.note(msg)
5303 ui.note(msg)
5313 else:
5304 else:
5314 ui.warn(_(b'no phases changed\n'))
5305 ui.warn(_(b'no phases changed\n'))
5315 return ret
5306 return ret
5316
5307
5317
5308
5318 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5309 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5319 """Run after a changegroup has been added via pull/unbundle
5310 """Run after a changegroup has been added via pull/unbundle
5320
5311
5321 This takes arguments below:
5312 This takes arguments below:
5322
5313
5323 :modheads: change of heads by pull/unbundle
5314 :modheads: change of heads by pull/unbundle
5324 :optupdate: updating working directory is needed or not
5315 :optupdate: updating working directory is needed or not
5325 :checkout: update destination revision (or None to default destination)
5316 :checkout: update destination revision (or None to default destination)
5326 :brev: a name, which might be a bookmark to be activated after updating
5317 :brev: a name, which might be a bookmark to be activated after updating
5327 """
5318 """
5328 if modheads == 0:
5319 if modheads == 0:
5329 return
5320 return
5330 if optupdate:
5321 if optupdate:
5331 try:
5322 try:
5332 return hg.updatetotally(ui, repo, checkout, brev)
5323 return hg.updatetotally(ui, repo, checkout, brev)
5333 except error.UpdateAbort as inst:
5324 except error.UpdateAbort as inst:
5334 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5325 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5335 hint = inst.hint
5326 hint = inst.hint
5336 raise error.UpdateAbort(msg, hint=hint)
5327 raise error.UpdateAbort(msg, hint=hint)
5337 if modheads is not None and modheads > 1:
5328 if modheads is not None and modheads > 1:
5338 currentbranchheads = len(repo.branchheads())
5329 currentbranchheads = len(repo.branchheads())
5339 if currentbranchheads == modheads:
5330 if currentbranchheads == modheads:
5340 ui.status(
5331 ui.status(
5341 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5332 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5342 )
5333 )
5343 elif currentbranchheads > 1:
5334 elif currentbranchheads > 1:
5344 ui.status(
5335 ui.status(
5345 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5336 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5346 )
5337 )
5347 else:
5338 else:
5348 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5339 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5349 elif not ui.configbool(b'commands', b'update.requiredest'):
5340 elif not ui.configbool(b'commands', b'update.requiredest'):
5350 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5341 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5351
5342
5352
5343
5353 @command(
5344 @command(
5354 b'pull',
5345 b'pull',
5355 [
5346 [
5356 (
5347 (
5357 b'u',
5348 b'u',
5358 b'update',
5349 b'update',
5359 None,
5350 None,
5360 _(b'update to new branch head if new descendants were pulled'),
5351 _(b'update to new branch head if new descendants were pulled'),
5361 ),
5352 ),
5362 (
5353 (
5363 b'f',
5354 b'f',
5364 b'force',
5355 b'force',
5365 None,
5356 None,
5366 _(b'run even when remote repository is unrelated'),
5357 _(b'run even when remote repository is unrelated'),
5367 ),
5358 ),
5368 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5359 (b'', b'confirm', None, _(b'confirm pull before applying changes'),),
5369 (
5360 (
5370 b'r',
5361 b'r',
5371 b'rev',
5362 b'rev',
5372 [],
5363 [],
5373 _(b'a remote changeset intended to be added'),
5364 _(b'a remote changeset intended to be added'),
5374 _(b'REV'),
5365 _(b'REV'),
5375 ),
5366 ),
5376 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5367 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5377 (
5368 (
5378 b'b',
5369 b'b',
5379 b'branch',
5370 b'branch',
5380 [],
5371 [],
5381 _(b'a specific branch you would like to pull'),
5372 _(b'a specific branch you would like to pull'),
5382 _(b'BRANCH'),
5373 _(b'BRANCH'),
5383 ),
5374 ),
5384 ]
5375 ]
5385 + remoteopts,
5376 + remoteopts,
5386 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5377 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5387 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5378 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5388 helpbasic=True,
5379 helpbasic=True,
5389 )
5380 )
5390 def pull(ui, repo, source=b"default", **opts):
5381 def pull(ui, repo, source=b"default", **opts):
5391 """pull changes from the specified source
5382 """pull changes from the specified source
5392
5383
5393 Pull changes from a remote repository to a local one.
5384 Pull changes from a remote repository to a local one.
5394
5385
5395 This finds all changes from the repository at the specified path
5386 This finds all changes from the repository at the specified path
5396 or URL and adds them to a local repository (the current one unless
5387 or URL and adds them to a local repository (the current one unless
5397 -R is specified). By default, this does not update the copy of the
5388 -R is specified). By default, this does not update the copy of the
5398 project in the working directory.
5389 project in the working directory.
5399
5390
5400 When cloning from servers that support it, Mercurial may fetch
5391 When cloning from servers that support it, Mercurial may fetch
5401 pre-generated data. When this is done, hooks operating on incoming
5392 pre-generated data. When this is done, hooks operating on incoming
5402 changesets and changegroups may fire more than once, once for each
5393 changesets and changegroups may fire more than once, once for each
5403 pre-generated bundle and as well as for any additional remaining
5394 pre-generated bundle and as well as for any additional remaining
5404 data. See :hg:`help -e clonebundles` for more.
5395 data. See :hg:`help -e clonebundles` for more.
5405
5396
5406 Use :hg:`incoming` if you want to see what would have been added
5397 Use :hg:`incoming` if you want to see what would have been added
5407 by a pull at the time you issued this command. If you then decide
5398 by a pull at the time you issued this command. If you then decide
5408 to add those changes to the repository, you should use :hg:`pull
5399 to add those changes to the repository, you should use :hg:`pull
5409 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5400 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5410
5401
5411 If SOURCE is omitted, the 'default' path will be used.
5402 If SOURCE is omitted, the 'default' path will be used.
5412 See :hg:`help urls` for more information.
5403 See :hg:`help urls` for more information.
5413
5404
5414 Specifying bookmark as ``.`` is equivalent to specifying the active
5405 Specifying bookmark as ``.`` is equivalent to specifying the active
5415 bookmark's name.
5406 bookmark's name.
5416
5407
5417 Returns 0 on success, 1 if an update had unresolved files.
5408 Returns 0 on success, 1 if an update had unresolved files.
5418 """
5409 """
5419
5410
5420 opts = pycompat.byteskwargs(opts)
5411 opts = pycompat.byteskwargs(opts)
5421 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5412 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5422 b'update'
5413 b'update'
5423 ):
5414 ):
5424 msg = _(b'update destination required by configuration')
5415 msg = _(b'update destination required by configuration')
5425 hint = _(b'use hg pull followed by hg update DEST')
5416 hint = _(b'use hg pull followed by hg update DEST')
5426 raise error.Abort(msg, hint=hint)
5417 raise error.Abort(msg, hint=hint)
5427
5418
5428 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5419 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5429 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5420 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5430 other = hg.peer(repo, opts, source)
5421 other = hg.peer(repo, opts, source)
5431 try:
5422 try:
5432 revs, checkout = hg.addbranchrevs(
5423 revs, checkout = hg.addbranchrevs(
5433 repo, other, branches, opts.get(b'rev')
5424 repo, other, branches, opts.get(b'rev')
5434 )
5425 )
5435
5426
5436 pullopargs = {}
5427 pullopargs = {}
5437
5428
5438 nodes = None
5429 nodes = None
5439 if opts.get(b'bookmark') or revs:
5430 if opts.get(b'bookmark') or revs:
5440 # The list of bookmark used here is the same used to actually update
5431 # The list of bookmark used here is the same used to actually update
5441 # the bookmark names, to avoid the race from issue 4689 and we do
5432 # the bookmark names, to avoid the race from issue 4689 and we do
5442 # all lookup and bookmark queries in one go so they see the same
5433 # all lookup and bookmark queries in one go so they see the same
5443 # version of the server state (issue 4700).
5434 # version of the server state (issue 4700).
5444 nodes = []
5435 nodes = []
5445 fnodes = []
5436 fnodes = []
5446 revs = revs or []
5437 revs = revs or []
5447 if revs and not other.capable(b'lookup'):
5438 if revs and not other.capable(b'lookup'):
5448 err = _(
5439 err = _(
5449 b"other repository doesn't support revision lookup, "
5440 b"other repository doesn't support revision lookup, "
5450 b"so a rev cannot be specified."
5441 b"so a rev cannot be specified."
5451 )
5442 )
5452 raise error.Abort(err)
5443 raise error.Abort(err)
5453 with other.commandexecutor() as e:
5444 with other.commandexecutor() as e:
5454 fremotebookmarks = e.callcommand(
5445 fremotebookmarks = e.callcommand(
5455 b'listkeys', {b'namespace': b'bookmarks'}
5446 b'listkeys', {b'namespace': b'bookmarks'}
5456 )
5447 )
5457 for r in revs:
5448 for r in revs:
5458 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5449 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5459 remotebookmarks = fremotebookmarks.result()
5450 remotebookmarks = fremotebookmarks.result()
5460 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5451 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5461 pullopargs[b'remotebookmarks'] = remotebookmarks
5452 pullopargs[b'remotebookmarks'] = remotebookmarks
5462 for b in opts.get(b'bookmark', []):
5453 for b in opts.get(b'bookmark', []):
5463 b = repo._bookmarks.expandname(b)
5454 b = repo._bookmarks.expandname(b)
5464 if b not in remotebookmarks:
5455 if b not in remotebookmarks:
5465 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5456 raise error.Abort(_(b'remote bookmark %s not found!') % b)
5466 nodes.append(remotebookmarks[b])
5457 nodes.append(remotebookmarks[b])
5467 for i, rev in enumerate(revs):
5458 for i, rev in enumerate(revs):
5468 node = fnodes[i].result()
5459 node = fnodes[i].result()
5469 nodes.append(node)
5460 nodes.append(node)
5470 if rev == checkout:
5461 if rev == checkout:
5471 checkout = node
5462 checkout = node
5472
5463
5473 wlock = util.nullcontextmanager()
5464 wlock = util.nullcontextmanager()
5474 if opts.get(b'update'):
5465 if opts.get(b'update'):
5475 wlock = repo.wlock()
5466 wlock = repo.wlock()
5476 with wlock:
5467 with wlock:
5477 pullopargs.update(opts.get(b'opargs', {}))
5468 pullopargs.update(opts.get(b'opargs', {}))
5478 modheads = exchange.pull(
5469 modheads = exchange.pull(
5479 repo,
5470 repo,
5480 other,
5471 other,
5481 heads=nodes,
5472 heads=nodes,
5482 force=opts.get(b'force'),
5473 force=opts.get(b'force'),
5483 bookmarks=opts.get(b'bookmark', ()),
5474 bookmarks=opts.get(b'bookmark', ()),
5484 opargs=pullopargs,
5475 opargs=pullopargs,
5485 confirm=opts.get(b'confirm'),
5476 confirm=opts.get(b'confirm'),
5486 ).cgresult
5477 ).cgresult
5487
5478
5488 # brev is a name, which might be a bookmark to be activated at
5479 # brev is a name, which might be a bookmark to be activated at
5489 # the end of the update. In other words, it is an explicit
5480 # the end of the update. In other words, it is an explicit
5490 # destination of the update
5481 # destination of the update
5491 brev = None
5482 brev = None
5492
5483
5493 if checkout:
5484 if checkout:
5494 checkout = repo.unfiltered().changelog.rev(checkout)
5485 checkout = repo.unfiltered().changelog.rev(checkout)
5495
5486
5496 # order below depends on implementation of
5487 # order below depends on implementation of
5497 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5488 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5498 # because 'checkout' is determined without it.
5489 # because 'checkout' is determined without it.
5499 if opts.get(b'rev'):
5490 if opts.get(b'rev'):
5500 brev = opts[b'rev'][0]
5491 brev = opts[b'rev'][0]
5501 elif opts.get(b'branch'):
5492 elif opts.get(b'branch'):
5502 brev = opts[b'branch'][0]
5493 brev = opts[b'branch'][0]
5503 else:
5494 else:
5504 brev = branches[0]
5495 brev = branches[0]
5505 repo._subtoppath = source
5496 repo._subtoppath = source
5506 try:
5497 try:
5507 ret = postincoming(
5498 ret = postincoming(
5508 ui, repo, modheads, opts.get(b'update'), checkout, brev
5499 ui, repo, modheads, opts.get(b'update'), checkout, brev
5509 )
5500 )
5510 except error.FilteredRepoLookupError as exc:
5501 except error.FilteredRepoLookupError as exc:
5511 msg = _(b'cannot update to target: %s') % exc.args[0]
5502 msg = _(b'cannot update to target: %s') % exc.args[0]
5512 exc.args = (msg,) + exc.args[1:]
5503 exc.args = (msg,) + exc.args[1:]
5513 raise
5504 raise
5514 finally:
5505 finally:
5515 del repo._subtoppath
5506 del repo._subtoppath
5516
5507
5517 finally:
5508 finally:
5518 other.close()
5509 other.close()
5519 return ret
5510 return ret
5520
5511
5521
5512
5522 @command(
5513 @command(
5523 b'push',
5514 b'push',
5524 [
5515 [
5525 (b'f', b'force', None, _(b'force push')),
5516 (b'f', b'force', None, _(b'force push')),
5526 (
5517 (
5527 b'r',
5518 b'r',
5528 b'rev',
5519 b'rev',
5529 [],
5520 [],
5530 _(b'a changeset intended to be included in the destination'),
5521 _(b'a changeset intended to be included in the destination'),
5531 _(b'REV'),
5522 _(b'REV'),
5532 ),
5523 ),
5533 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5524 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5534 (
5525 (
5535 b'b',
5526 b'b',
5536 b'branch',
5527 b'branch',
5537 [],
5528 [],
5538 _(b'a specific branch you would like to push'),
5529 _(b'a specific branch you would like to push'),
5539 _(b'BRANCH'),
5530 _(b'BRANCH'),
5540 ),
5531 ),
5541 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5532 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5542 (
5533 (
5543 b'',
5534 b'',
5544 b'pushvars',
5535 b'pushvars',
5545 [],
5536 [],
5546 _(b'variables that can be sent to server (ADVANCED)'),
5537 _(b'variables that can be sent to server (ADVANCED)'),
5547 ),
5538 ),
5548 (
5539 (
5549 b'',
5540 b'',
5550 b'publish',
5541 b'publish',
5551 False,
5542 False,
5552 _(b'push the changeset as public (EXPERIMENTAL)'),
5543 _(b'push the changeset as public (EXPERIMENTAL)'),
5553 ),
5544 ),
5554 ]
5545 ]
5555 + remoteopts,
5546 + remoteopts,
5556 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5547 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5557 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5548 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5558 helpbasic=True,
5549 helpbasic=True,
5559 )
5550 )
5560 def push(ui, repo, dest=None, **opts):
5551 def push(ui, repo, dest=None, **opts):
5561 """push changes to the specified destination
5552 """push changes to the specified destination
5562
5553
5563 Push changesets from the local repository to the specified
5554 Push changesets from the local repository to the specified
5564 destination.
5555 destination.
5565
5556
5566 This operation is symmetrical to pull: it is identical to a pull
5557 This operation is symmetrical to pull: it is identical to a pull
5567 in the destination repository from the current one.
5558 in the destination repository from the current one.
5568
5559
5569 By default, push will not allow creation of new heads at the
5560 By default, push will not allow creation of new heads at the
5570 destination, since multiple heads would make it unclear which head
5561 destination, since multiple heads would make it unclear which head
5571 to use. In this situation, it is recommended to pull and merge
5562 to use. In this situation, it is recommended to pull and merge
5572 before pushing.
5563 before pushing.
5573
5564
5574 Use --new-branch if you want to allow push to create a new named
5565 Use --new-branch if you want to allow push to create a new named
5575 branch that is not present at the destination. This allows you to
5566 branch that is not present at the destination. This allows you to
5576 only create a new branch without forcing other changes.
5567 only create a new branch without forcing other changes.
5577
5568
5578 .. note::
5569 .. note::
5579
5570
5580 Extra care should be taken with the -f/--force option,
5571 Extra care should be taken with the -f/--force option,
5581 which will push all new heads on all branches, an action which will
5572 which will push all new heads on all branches, an action which will
5582 almost always cause confusion for collaborators.
5573 almost always cause confusion for collaborators.
5583
5574
5584 If -r/--rev is used, the specified revision and all its ancestors
5575 If -r/--rev is used, the specified revision and all its ancestors
5585 will be pushed to the remote repository.
5576 will be pushed to the remote repository.
5586
5577
5587 If -B/--bookmark is used, the specified bookmarked revision, its
5578 If -B/--bookmark is used, the specified bookmarked revision, its
5588 ancestors, and the bookmark will be pushed to the remote
5579 ancestors, and the bookmark will be pushed to the remote
5589 repository. Specifying ``.`` is equivalent to specifying the active
5580 repository. Specifying ``.`` is equivalent to specifying the active
5590 bookmark's name.
5581 bookmark's name.
5591
5582
5592 Please see :hg:`help urls` for important details about ``ssh://``
5583 Please see :hg:`help urls` for important details about ``ssh://``
5593 URLs. If DESTINATION is omitted, a default path will be used.
5584 URLs. If DESTINATION is omitted, a default path will be used.
5594
5585
5595 .. container:: verbose
5586 .. container:: verbose
5596
5587
5597 The --pushvars option sends strings to the server that become
5588 The --pushvars option sends strings to the server that become
5598 environment variables prepended with ``HG_USERVAR_``. For example,
5589 environment variables prepended with ``HG_USERVAR_``. For example,
5599 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5590 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5600 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5591 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5601
5592
5602 pushvars can provide for user-overridable hooks as well as set debug
5593 pushvars can provide for user-overridable hooks as well as set debug
5603 levels. One example is having a hook that blocks commits containing
5594 levels. One example is having a hook that blocks commits containing
5604 conflict markers, but enables the user to override the hook if the file
5595 conflict markers, but enables the user to override the hook if the file
5605 is using conflict markers for testing purposes or the file format has
5596 is using conflict markers for testing purposes or the file format has
5606 strings that look like conflict markers.
5597 strings that look like conflict markers.
5607
5598
5608 By default, servers will ignore `--pushvars`. To enable it add the
5599 By default, servers will ignore `--pushvars`. To enable it add the
5609 following to your configuration file::
5600 following to your configuration file::
5610
5601
5611 [push]
5602 [push]
5612 pushvars.server = true
5603 pushvars.server = true
5613
5604
5614 Returns 0 if push was successful, 1 if nothing to push.
5605 Returns 0 if push was successful, 1 if nothing to push.
5615 """
5606 """
5616
5607
5617 opts = pycompat.byteskwargs(opts)
5608 opts = pycompat.byteskwargs(opts)
5618 if opts.get(b'bookmark'):
5609 if opts.get(b'bookmark'):
5619 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5610 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5620 for b in opts[b'bookmark']:
5611 for b in opts[b'bookmark']:
5621 # translate -B options to -r so changesets get pushed
5612 # translate -B options to -r so changesets get pushed
5622 b = repo._bookmarks.expandname(b)
5613 b = repo._bookmarks.expandname(b)
5623 if b in repo._bookmarks:
5614 if b in repo._bookmarks:
5624 opts.setdefault(b'rev', []).append(b)
5615 opts.setdefault(b'rev', []).append(b)
5625 else:
5616 else:
5626 # if we try to push a deleted bookmark, translate it to null
5617 # if we try to push a deleted bookmark, translate it to null
5627 # this lets simultaneous -r, -b options continue working
5618 # this lets simultaneous -r, -b options continue working
5628 opts.setdefault(b'rev', []).append(b"null")
5619 opts.setdefault(b'rev', []).append(b"null")
5629
5620
5630 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5621 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5631 if not path:
5622 if not path:
5632 raise error.Abort(
5623 raise error.Abort(
5633 _(b'default repository not configured!'),
5624 _(b'default repository not configured!'),
5634 hint=_(b"see 'hg help config.paths'"),
5625 hint=_(b"see 'hg help config.paths'"),
5635 )
5626 )
5636 dest = path.pushloc or path.loc
5627 dest = path.pushloc or path.loc
5637 branches = (path.branch, opts.get(b'branch') or [])
5628 branches = (path.branch, opts.get(b'branch') or [])
5638 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5629 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5639 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5630 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5640 other = hg.peer(repo, opts, dest)
5631 other = hg.peer(repo, opts, dest)
5641
5632
5642 if revs:
5633 if revs:
5643 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5634 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5644 if not revs:
5635 if not revs:
5645 raise error.Abort(
5636 raise error.Abort(
5646 _(b"specified revisions evaluate to an empty set"),
5637 _(b"specified revisions evaluate to an empty set"),
5647 hint=_(b"use different revision arguments"),
5638 hint=_(b"use different revision arguments"),
5648 )
5639 )
5649 elif path.pushrev:
5640 elif path.pushrev:
5650 # It doesn't make any sense to specify ancestor revisions. So limit
5641 # It doesn't make any sense to specify ancestor revisions. So limit
5651 # to DAG heads to make discovery simpler.
5642 # to DAG heads to make discovery simpler.
5652 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5643 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5653 revs = scmutil.revrange(repo, [expr])
5644 revs = scmutil.revrange(repo, [expr])
5654 revs = [repo[rev].node() for rev in revs]
5645 revs = [repo[rev].node() for rev in revs]
5655 if not revs:
5646 if not revs:
5656 raise error.Abort(
5647 raise error.Abort(
5657 _(b'default push revset for path evaluates to an empty set')
5648 _(b'default push revset for path evaluates to an empty set')
5658 )
5649 )
5659 elif ui.configbool(b'commands', b'push.require-revs'):
5650 elif ui.configbool(b'commands', b'push.require-revs'):
5660 raise error.Abort(
5651 raise error.Abort(
5661 _(b'no revisions specified to push'),
5652 _(b'no revisions specified to push'),
5662 hint=_(b'did you mean "hg push -r ."?'),
5653 hint=_(b'did you mean "hg push -r ."?'),
5663 )
5654 )
5664
5655
5665 repo._subtoppath = dest
5656 repo._subtoppath = dest
5666 try:
5657 try:
5667 # push subrepos depth-first for coherent ordering
5658 # push subrepos depth-first for coherent ordering
5668 c = repo[b'.']
5659 c = repo[b'.']
5669 subs = c.substate # only repos that are committed
5660 subs = c.substate # only repos that are committed
5670 for s in sorted(subs):
5661 for s in sorted(subs):
5671 result = c.sub(s).push(opts)
5662 result = c.sub(s).push(opts)
5672 if result == 0:
5663 if result == 0:
5673 return not result
5664 return not result
5674 finally:
5665 finally:
5675 del repo._subtoppath
5666 del repo._subtoppath
5676
5667
5677 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5668 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5678 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5669 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5679
5670
5680 pushop = exchange.push(
5671 pushop = exchange.push(
5681 repo,
5672 repo,
5682 other,
5673 other,
5683 opts.get(b'force'),
5674 opts.get(b'force'),
5684 revs=revs,
5675 revs=revs,
5685 newbranch=opts.get(b'new_branch'),
5676 newbranch=opts.get(b'new_branch'),
5686 bookmarks=opts.get(b'bookmark', ()),
5677 bookmarks=opts.get(b'bookmark', ()),
5687 publish=opts.get(b'publish'),
5678 publish=opts.get(b'publish'),
5688 opargs=opargs,
5679 opargs=opargs,
5689 )
5680 )
5690
5681
5691 result = not pushop.cgresult
5682 result = not pushop.cgresult
5692
5683
5693 if pushop.bkresult is not None:
5684 if pushop.bkresult is not None:
5694 if pushop.bkresult == 2:
5685 if pushop.bkresult == 2:
5695 result = 2
5686 result = 2
5696 elif not result and pushop.bkresult:
5687 elif not result and pushop.bkresult:
5697 result = 2
5688 result = 2
5698
5689
5699 return result
5690 return result
5700
5691
5701
5692
5702 @command(
5693 @command(
5703 b'recover',
5694 b'recover',
5704 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5695 [(b'', b'verify', False, b"run `hg verify` after successful recover"),],
5705 helpcategory=command.CATEGORY_MAINTENANCE,
5696 helpcategory=command.CATEGORY_MAINTENANCE,
5706 )
5697 )
5707 def recover(ui, repo, **opts):
5698 def recover(ui, repo, **opts):
5708 """roll back an interrupted transaction
5699 """roll back an interrupted transaction
5709
5700
5710 Recover from an interrupted commit or pull.
5701 Recover from an interrupted commit or pull.
5711
5702
5712 This command tries to fix the repository status after an
5703 This command tries to fix the repository status after an
5713 interrupted operation. It should only be necessary when Mercurial
5704 interrupted operation. It should only be necessary when Mercurial
5714 suggests it.
5705 suggests it.
5715
5706
5716 Returns 0 if successful, 1 if nothing to recover or verify fails.
5707 Returns 0 if successful, 1 if nothing to recover or verify fails.
5717 """
5708 """
5718 ret = repo.recover()
5709 ret = repo.recover()
5719 if ret:
5710 if ret:
5720 if opts['verify']:
5711 if opts['verify']:
5721 return hg.verify(repo)
5712 return hg.verify(repo)
5722 else:
5713 else:
5723 msg = _(
5714 msg = _(
5724 b"(verify step skipped, run `hg verify` to check your "
5715 b"(verify step skipped, run `hg verify` to check your "
5725 b"repository content)\n"
5716 b"repository content)\n"
5726 )
5717 )
5727 ui.warn(msg)
5718 ui.warn(msg)
5728 return 0
5719 return 0
5729 return 1
5720 return 1
5730
5721
5731
5722
5732 @command(
5723 @command(
5733 b'remove|rm',
5724 b'remove|rm',
5734 [
5725 [
5735 (b'A', b'after', None, _(b'record delete for missing files')),
5726 (b'A', b'after', None, _(b'record delete for missing files')),
5736 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5727 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5737 ]
5728 ]
5738 + subrepoopts
5729 + subrepoopts
5739 + walkopts
5730 + walkopts
5740 + dryrunopts,
5731 + dryrunopts,
5741 _(b'[OPTION]... FILE...'),
5732 _(b'[OPTION]... FILE...'),
5742 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5733 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5743 helpbasic=True,
5734 helpbasic=True,
5744 inferrepo=True,
5735 inferrepo=True,
5745 )
5736 )
5746 def remove(ui, repo, *pats, **opts):
5737 def remove(ui, repo, *pats, **opts):
5747 """remove the specified files on the next commit
5738 """remove the specified files on the next commit
5748
5739
5749 Schedule the indicated files for removal from the current branch.
5740 Schedule the indicated files for removal from the current branch.
5750
5741
5751 This command schedules the files to be removed at the next commit.
5742 This command schedules the files to be removed at the next commit.
5752 To undo a remove before that, see :hg:`revert`. To undo added
5743 To undo a remove before that, see :hg:`revert`. To undo added
5753 files, see :hg:`forget`.
5744 files, see :hg:`forget`.
5754
5745
5755 .. container:: verbose
5746 .. container:: verbose
5756
5747
5757 -A/--after can be used to remove only files that have already
5748 -A/--after can be used to remove only files that have already
5758 been deleted, -f/--force can be used to force deletion, and -Af
5749 been deleted, -f/--force can be used to force deletion, and -Af
5759 can be used to remove files from the next revision without
5750 can be used to remove files from the next revision without
5760 deleting them from the working directory.
5751 deleting them from the working directory.
5761
5752
5762 The following table details the behavior of remove for different
5753 The following table details the behavior of remove for different
5763 file states (columns) and option combinations (rows). The file
5754 file states (columns) and option combinations (rows). The file
5764 states are Added [A], Clean [C], Modified [M] and Missing [!]
5755 states are Added [A], Clean [C], Modified [M] and Missing [!]
5765 (as reported by :hg:`status`). The actions are Warn, Remove
5756 (as reported by :hg:`status`). The actions are Warn, Remove
5766 (from branch) and Delete (from disk):
5757 (from branch) and Delete (from disk):
5767
5758
5768 ========= == == == ==
5759 ========= == == == ==
5769 opt/state A C M !
5760 opt/state A C M !
5770 ========= == == == ==
5761 ========= == == == ==
5771 none W RD W R
5762 none W RD W R
5772 -f R RD RD R
5763 -f R RD RD R
5773 -A W W W R
5764 -A W W W R
5774 -Af R R R R
5765 -Af R R R R
5775 ========= == == == ==
5766 ========= == == == ==
5776
5767
5777 .. note::
5768 .. note::
5778
5769
5779 :hg:`remove` never deletes files in Added [A] state from the
5770 :hg:`remove` never deletes files in Added [A] state from the
5780 working directory, not even if ``--force`` is specified.
5771 working directory, not even if ``--force`` is specified.
5781
5772
5782 Returns 0 on success, 1 if any warnings encountered.
5773 Returns 0 on success, 1 if any warnings encountered.
5783 """
5774 """
5784
5775
5785 opts = pycompat.byteskwargs(opts)
5776 opts = pycompat.byteskwargs(opts)
5786 after, force = opts.get(b'after'), opts.get(b'force')
5777 after, force = opts.get(b'after'), opts.get(b'force')
5787 dryrun = opts.get(b'dry_run')
5778 dryrun = opts.get(b'dry_run')
5788 if not pats and not after:
5779 if not pats and not after:
5789 raise error.Abort(_(b'no files specified'))
5780 raise error.Abort(_(b'no files specified'))
5790
5781
5791 m = scmutil.match(repo[None], pats, opts)
5782 m = scmutil.match(repo[None], pats, opts)
5792 subrepos = opts.get(b'subrepos')
5783 subrepos = opts.get(b'subrepos')
5793 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5784 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5794 return cmdutil.remove(
5785 return cmdutil.remove(
5795 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5786 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5796 )
5787 )
5797
5788
5798
5789
5799 @command(
5790 @command(
5800 b'rename|move|mv',
5791 b'rename|move|mv',
5801 [
5792 [
5802 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5793 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5803 (
5794 (
5804 b'f',
5795 b'f',
5805 b'force',
5796 b'force',
5806 None,
5797 None,
5807 _(b'forcibly move over an existing managed file'),
5798 _(b'forcibly move over an existing managed file'),
5808 ),
5799 ),
5809 ]
5800 ]
5810 + walkopts
5801 + walkopts
5811 + dryrunopts,
5802 + dryrunopts,
5812 _(b'[OPTION]... SOURCE... DEST'),
5803 _(b'[OPTION]... SOURCE... DEST'),
5813 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5804 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5814 )
5805 )
5815 def rename(ui, repo, *pats, **opts):
5806 def rename(ui, repo, *pats, **opts):
5816 """rename files; equivalent of copy + remove
5807 """rename files; equivalent of copy + remove
5817
5808
5818 Mark dest as copies of sources; mark sources for deletion. If dest
5809 Mark dest as copies of sources; mark sources for deletion. If dest
5819 is a directory, copies are put in that directory. If dest is a
5810 is a directory, copies are put in that directory. If dest is a
5820 file, there can only be one source.
5811 file, there can only be one source.
5821
5812
5822 By default, this command copies the contents of files as they
5813 By default, this command copies the contents of files as they
5823 exist in the working directory. If invoked with -A/--after, the
5814 exist in the working directory. If invoked with -A/--after, the
5824 operation is recorded, but no copying is performed.
5815 operation is recorded, but no copying is performed.
5825
5816
5826 This command takes effect at the next commit. To undo a rename
5817 This command takes effect at the next commit. To undo a rename
5827 before that, see :hg:`revert`.
5818 before that, see :hg:`revert`.
5828
5819
5829 Returns 0 on success, 1 if errors are encountered.
5820 Returns 0 on success, 1 if errors are encountered.
5830 """
5821 """
5831 opts = pycompat.byteskwargs(opts)
5822 opts = pycompat.byteskwargs(opts)
5832 with repo.wlock():
5823 with repo.wlock():
5833 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5824 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5834
5825
5835
5826
5836 @command(
5827 @command(
5837 b'resolve',
5828 b'resolve',
5838 [
5829 [
5839 (b'a', b'all', None, _(b'select all unresolved files')),
5830 (b'a', b'all', None, _(b'select all unresolved files')),
5840 (b'l', b'list', None, _(b'list state of files needing merge')),
5831 (b'l', b'list', None, _(b'list state of files needing merge')),
5841 (b'm', b'mark', None, _(b'mark files as resolved')),
5832 (b'm', b'mark', None, _(b'mark files as resolved')),
5842 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5833 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5843 (b'n', b'no-status', None, _(b'hide status prefix')),
5834 (b'n', b'no-status', None, _(b'hide status prefix')),
5844 (b'', b're-merge', None, _(b're-merge files')),
5835 (b'', b're-merge', None, _(b're-merge files')),
5845 ]
5836 ]
5846 + mergetoolopts
5837 + mergetoolopts
5847 + walkopts
5838 + walkopts
5848 + formatteropts,
5839 + formatteropts,
5849 _(b'[OPTION]... [FILE]...'),
5840 _(b'[OPTION]... [FILE]...'),
5850 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5841 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5851 inferrepo=True,
5842 inferrepo=True,
5852 )
5843 )
5853 def resolve(ui, repo, *pats, **opts):
5844 def resolve(ui, repo, *pats, **opts):
5854 """redo merges or set/view the merge status of files
5845 """redo merges or set/view the merge status of files
5855
5846
5856 Merges with unresolved conflicts are often the result of
5847 Merges with unresolved conflicts are often the result of
5857 non-interactive merging using the ``internal:merge`` configuration
5848 non-interactive merging using the ``internal:merge`` configuration
5858 setting, or a command-line merge tool like ``diff3``. The resolve
5849 setting, or a command-line merge tool like ``diff3``. The resolve
5859 command is used to manage the files involved in a merge, after
5850 command is used to manage the files involved in a merge, after
5860 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5851 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5861 working directory must have two parents). See :hg:`help
5852 working directory must have two parents). See :hg:`help
5862 merge-tools` for information on configuring merge tools.
5853 merge-tools` for information on configuring merge tools.
5863
5854
5864 The resolve command can be used in the following ways:
5855 The resolve command can be used in the following ways:
5865
5856
5866 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5857 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5867 the specified files, discarding any previous merge attempts. Re-merging
5858 the specified files, discarding any previous merge attempts. Re-merging
5868 is not performed for files already marked as resolved. Use ``--all/-a``
5859 is not performed for files already marked as resolved. Use ``--all/-a``
5869 to select all unresolved files. ``--tool`` can be used to specify
5860 to select all unresolved files. ``--tool`` can be used to specify
5870 the merge tool used for the given files. It overrides the HGMERGE
5861 the merge tool used for the given files. It overrides the HGMERGE
5871 environment variable and your configuration files. Previous file
5862 environment variable and your configuration files. Previous file
5872 contents are saved with a ``.orig`` suffix.
5863 contents are saved with a ``.orig`` suffix.
5873
5864
5874 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5865 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5875 (e.g. after having manually fixed-up the files). The default is
5866 (e.g. after having manually fixed-up the files). The default is
5876 to mark all unresolved files.
5867 to mark all unresolved files.
5877
5868
5878 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5869 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5879 default is to mark all resolved files.
5870 default is to mark all resolved files.
5880
5871
5881 - :hg:`resolve -l`: list files which had or still have conflicts.
5872 - :hg:`resolve -l`: list files which had or still have conflicts.
5882 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5873 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5883 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5874 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5884 the list. See :hg:`help filesets` for details.
5875 the list. See :hg:`help filesets` for details.
5885
5876
5886 .. note::
5877 .. note::
5887
5878
5888 Mercurial will not let you commit files with unresolved merge
5879 Mercurial will not let you commit files with unresolved merge
5889 conflicts. You must use :hg:`resolve -m ...` before you can
5880 conflicts. You must use :hg:`resolve -m ...` before you can
5890 commit after a conflicting merge.
5881 commit after a conflicting merge.
5891
5882
5892 .. container:: verbose
5883 .. container:: verbose
5893
5884
5894 Template:
5885 Template:
5895
5886
5896 The following keywords are supported in addition to the common template
5887 The following keywords are supported in addition to the common template
5897 keywords and functions. See also :hg:`help templates`.
5888 keywords and functions. See also :hg:`help templates`.
5898
5889
5899 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5890 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5900 :path: String. Repository-absolute path of the file.
5891 :path: String. Repository-absolute path of the file.
5901
5892
5902 Returns 0 on success, 1 if any files fail a resolve attempt.
5893 Returns 0 on success, 1 if any files fail a resolve attempt.
5903 """
5894 """
5904
5895
5905 opts = pycompat.byteskwargs(opts)
5896 opts = pycompat.byteskwargs(opts)
5906 confirm = ui.configbool(b'commands', b'resolve.confirm')
5897 confirm = ui.configbool(b'commands', b'resolve.confirm')
5907 flaglist = b'all mark unmark list no_status re_merge'.split()
5898 flaglist = b'all mark unmark list no_status re_merge'.split()
5908 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5899 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5909
5900
5910 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5901 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5911 if actioncount > 1:
5902 if actioncount > 1:
5912 raise error.Abort(_(b"too many actions specified"))
5903 raise error.Abort(_(b"too many actions specified"))
5913 elif actioncount == 0 and ui.configbool(
5904 elif actioncount == 0 and ui.configbool(
5914 b'commands', b'resolve.explicit-re-merge'
5905 b'commands', b'resolve.explicit-re-merge'
5915 ):
5906 ):
5916 hint = _(b'use --mark, --unmark, --list or --re-merge')
5907 hint = _(b'use --mark, --unmark, --list or --re-merge')
5917 raise error.Abort(_(b'no action specified'), hint=hint)
5908 raise error.Abort(_(b'no action specified'), hint=hint)
5918 if pats and all:
5909 if pats and all:
5919 raise error.Abort(_(b"can't specify --all and patterns"))
5910 raise error.Abort(_(b"can't specify --all and patterns"))
5920 if not (all or pats or show or mark or unmark):
5911 if not (all or pats or show or mark or unmark):
5921 raise error.Abort(
5912 raise error.Abort(
5922 _(b'no files or directories specified'),
5913 _(b'no files or directories specified'),
5923 hint=b'use --all to re-merge all unresolved files',
5914 hint=b'use --all to re-merge all unresolved files',
5924 )
5915 )
5925
5916
5926 if confirm:
5917 if confirm:
5927 if all:
5918 if all:
5928 if ui.promptchoice(
5919 if ui.promptchoice(
5929 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5920 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5930 ):
5921 ):
5931 raise error.Abort(_(b'user quit'))
5922 raise error.Abort(_(b'user quit'))
5932 if mark and not pats:
5923 if mark and not pats:
5933 if ui.promptchoice(
5924 if ui.promptchoice(
5934 _(
5925 _(
5935 b'mark all unresolved files as resolved (yn)?'
5926 b'mark all unresolved files as resolved (yn)?'
5936 b'$$ &Yes $$ &No'
5927 b'$$ &Yes $$ &No'
5937 )
5928 )
5938 ):
5929 ):
5939 raise error.Abort(_(b'user quit'))
5930 raise error.Abort(_(b'user quit'))
5940 if unmark and not pats:
5931 if unmark and not pats:
5941 if ui.promptchoice(
5932 if ui.promptchoice(
5942 _(
5933 _(
5943 b'mark all resolved files as unresolved (yn)?'
5934 b'mark all resolved files as unresolved (yn)?'
5944 b'$$ &Yes $$ &No'
5935 b'$$ &Yes $$ &No'
5945 )
5936 )
5946 ):
5937 ):
5947 raise error.Abort(_(b'user quit'))
5938 raise error.Abort(_(b'user quit'))
5948
5939
5949 uipathfn = scmutil.getuipathfn(repo)
5940 uipathfn = scmutil.getuipathfn(repo)
5950
5941
5951 if show:
5942 if show:
5952 ui.pager(b'resolve')
5943 ui.pager(b'resolve')
5953 fm = ui.formatter(b'resolve', opts)
5944 fm = ui.formatter(b'resolve', opts)
5954 ms = mergestatemod.mergestate.read(repo)
5945 ms = mergestatemod.mergestate.read(repo)
5955 wctx = repo[None]
5946 wctx = repo[None]
5956 m = scmutil.match(wctx, pats, opts)
5947 m = scmutil.match(wctx, pats, opts)
5957
5948
5958 # Labels and keys based on merge state. Unresolved path conflicts show
5949 # Labels and keys based on merge state. Unresolved path conflicts show
5959 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5950 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5960 # resolved conflicts.
5951 # resolved conflicts.
5961 mergestateinfo = {
5952 mergestateinfo = {
5962 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5953 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5963 b'resolve.unresolved',
5954 b'resolve.unresolved',
5964 b'U',
5955 b'U',
5965 ),
5956 ),
5966 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5957 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5967 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5958 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5968 b'resolve.unresolved',
5959 b'resolve.unresolved',
5969 b'P',
5960 b'P',
5970 ),
5961 ),
5971 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5962 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5972 b'resolve.resolved',
5963 b'resolve.resolved',
5973 b'R',
5964 b'R',
5974 ),
5965 ),
5975 mergestatemod.MERGE_RECORD_DRIVER_RESOLVED: (
5966 mergestatemod.MERGE_RECORD_DRIVER_RESOLVED: (
5976 b'resolve.driverresolved',
5967 b'resolve.driverresolved',
5977 b'D',
5968 b'D',
5978 ),
5969 ),
5979 }
5970 }
5980
5971
5981 for f in ms:
5972 for f in ms:
5982 if not m(f):
5973 if not m(f):
5983 continue
5974 continue
5984
5975
5985 if ms[f] == mergestatemod.MERGE_RECORD_MERGED_OTHER:
5976 if ms[f] == mergestatemod.MERGE_RECORD_MERGED_OTHER:
5986 continue
5977 continue
5987 label, key = mergestateinfo[ms[f]]
5978 label, key = mergestateinfo[ms[f]]
5988 fm.startitem()
5979 fm.startitem()
5989 fm.context(ctx=wctx)
5980 fm.context(ctx=wctx)
5990 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5981 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5991 fm.data(path=f)
5982 fm.data(path=f)
5992 fm.plain(b'%s\n' % uipathfn(f), label=label)
5983 fm.plain(b'%s\n' % uipathfn(f), label=label)
5993 fm.end()
5984 fm.end()
5994 return 0
5985 return 0
5995
5986
5996 with repo.wlock():
5987 with repo.wlock():
5997 ms = mergestatemod.mergestate.read(repo)
5988 ms = mergestatemod.mergestate.read(repo)
5998
5989
5999 if not (ms.active() or repo.dirstate.p2() != nullid):
5990 if not (ms.active() or repo.dirstate.p2() != nullid):
6000 raise error.Abort(
5991 raise error.Abort(
6001 _(b'resolve command not applicable when not merging')
5992 _(b'resolve command not applicable when not merging')
6002 )
5993 )
6003
5994
6004 wctx = repo[None]
5995 wctx = repo[None]
6005
5996
6006 if (
5997 if (
6007 ms.mergedriver
5998 ms.mergedriver
6008 and ms.mdstate() == mergestatemod.MERGE_DRIVER_STATE_UNMARKED
5999 and ms.mdstate() == mergestatemod.MERGE_DRIVER_STATE_UNMARKED
6009 ):
6000 ):
6010 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6001 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6011 ms.commit()
6002 ms.commit()
6012 # allow mark and unmark to go through
6003 # allow mark and unmark to go through
6013 if not mark and not unmark and not proceed:
6004 if not mark and not unmark and not proceed:
6014 return 1
6005 return 1
6015
6006
6016 m = scmutil.match(wctx, pats, opts)
6007 m = scmutil.match(wctx, pats, opts)
6017 ret = 0
6008 ret = 0
6018 didwork = False
6009 didwork = False
6019 runconclude = False
6010 runconclude = False
6020
6011
6021 tocomplete = []
6012 tocomplete = []
6022 hasconflictmarkers = []
6013 hasconflictmarkers = []
6023 if mark:
6014 if mark:
6024 markcheck = ui.config(b'commands', b'resolve.mark-check')
6015 markcheck = ui.config(b'commands', b'resolve.mark-check')
6025 if markcheck not in [b'warn', b'abort']:
6016 if markcheck not in [b'warn', b'abort']:
6026 # Treat all invalid / unrecognized values as 'none'.
6017 # Treat all invalid / unrecognized values as 'none'.
6027 markcheck = False
6018 markcheck = False
6028 for f in ms:
6019 for f in ms:
6029 if not m(f):
6020 if not m(f):
6030 continue
6021 continue
6031
6022
6032 didwork = True
6023 didwork = True
6033
6024
6034 if ms[f] == mergestatemod.MERGE_RECORD_MERGED_OTHER:
6025 if ms[f] == mergestatemod.MERGE_RECORD_MERGED_OTHER:
6035 continue
6026 continue
6036
6027
6037 # don't let driver-resolved files be marked, and run the conclude
6028 # don't let driver-resolved files be marked, and run the conclude
6038 # step if asked to resolve
6029 # step if asked to resolve
6039 if ms[f] == mergestatemod.MERGE_RECORD_DRIVER_RESOLVED:
6030 if ms[f] == mergestatemod.MERGE_RECORD_DRIVER_RESOLVED:
6040 exact = m.exact(f)
6031 exact = m.exact(f)
6041 if mark:
6032 if mark:
6042 if exact:
6033 if exact:
6043 ui.warn(
6034 ui.warn(
6044 _(b'not marking %s as it is driver-resolved\n')
6035 _(b'not marking %s as it is driver-resolved\n')
6045 % uipathfn(f)
6036 % uipathfn(f)
6046 )
6037 )
6047 elif unmark:
6038 elif unmark:
6048 if exact:
6039 if exact:
6049 ui.warn(
6040 ui.warn(
6050 _(b'not unmarking %s as it is driver-resolved\n')
6041 _(b'not unmarking %s as it is driver-resolved\n')
6051 % uipathfn(f)
6042 % uipathfn(f)
6052 )
6043 )
6053 else:
6044 else:
6054 runconclude = True
6045 runconclude = True
6055 continue
6046 continue
6056
6047
6057 # path conflicts must be resolved manually
6048 # path conflicts must be resolved manually
6058 if ms[f] in (
6049 if ms[f] in (
6059 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6050 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6060 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6051 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6061 ):
6052 ):
6062 if mark:
6053 if mark:
6063 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6054 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6064 elif unmark:
6055 elif unmark:
6065 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6056 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6066 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6057 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6067 ui.warn(
6058 ui.warn(
6068 _(b'%s: path conflict must be resolved manually\n')
6059 _(b'%s: path conflict must be resolved manually\n')
6069 % uipathfn(f)
6060 % uipathfn(f)
6070 )
6061 )
6071 continue
6062 continue
6072
6063
6073 if mark:
6064 if mark:
6074 if markcheck:
6065 if markcheck:
6075 fdata = repo.wvfs.tryread(f)
6066 fdata = repo.wvfs.tryread(f)
6076 if (
6067 if (
6077 filemerge.hasconflictmarkers(fdata)
6068 filemerge.hasconflictmarkers(fdata)
6078 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6069 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6079 ):
6070 ):
6080 hasconflictmarkers.append(f)
6071 hasconflictmarkers.append(f)
6081 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6072 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6082 elif unmark:
6073 elif unmark:
6083 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6074 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6084 else:
6075 else:
6085 # backup pre-resolve (merge uses .orig for its own purposes)
6076 # backup pre-resolve (merge uses .orig for its own purposes)
6086 a = repo.wjoin(f)
6077 a = repo.wjoin(f)
6087 try:
6078 try:
6088 util.copyfile(a, a + b".resolve")
6079 util.copyfile(a, a + b".resolve")
6089 except (IOError, OSError) as inst:
6080 except (IOError, OSError) as inst:
6090 if inst.errno != errno.ENOENT:
6081 if inst.errno != errno.ENOENT:
6091 raise
6082 raise
6092
6083
6093 try:
6084 try:
6094 # preresolve file
6085 # preresolve file
6095 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6086 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6096 with ui.configoverride(overrides, b'resolve'):
6087 with ui.configoverride(overrides, b'resolve'):
6097 complete, r = ms.preresolve(f, wctx)
6088 complete, r = ms.preresolve(f, wctx)
6098 if not complete:
6089 if not complete:
6099 tocomplete.append(f)
6090 tocomplete.append(f)
6100 elif r:
6091 elif r:
6101 ret = 1
6092 ret = 1
6102 finally:
6093 finally:
6103 ms.commit()
6094 ms.commit()
6104
6095
6105 # replace filemerge's .orig file with our resolve file, but only
6096 # replace filemerge's .orig file with our resolve file, but only
6106 # for merges that are complete
6097 # for merges that are complete
6107 if complete:
6098 if complete:
6108 try:
6099 try:
6109 util.rename(
6100 util.rename(
6110 a + b".resolve", scmutil.backuppath(ui, repo, f)
6101 a + b".resolve", scmutil.backuppath(ui, repo, f)
6111 )
6102 )
6112 except OSError as inst:
6103 except OSError as inst:
6113 if inst.errno != errno.ENOENT:
6104 if inst.errno != errno.ENOENT:
6114 raise
6105 raise
6115
6106
6116 if hasconflictmarkers:
6107 if hasconflictmarkers:
6117 ui.warn(
6108 ui.warn(
6118 _(
6109 _(
6119 b'warning: the following files still have conflict '
6110 b'warning: the following files still have conflict '
6120 b'markers:\n'
6111 b'markers:\n'
6121 )
6112 )
6122 + b''.join(
6113 + b''.join(
6123 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6114 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6124 )
6115 )
6125 )
6116 )
6126 if markcheck == b'abort' and not all and not pats:
6117 if markcheck == b'abort' and not all and not pats:
6127 raise error.Abort(
6118 raise error.Abort(
6128 _(b'conflict markers detected'),
6119 _(b'conflict markers detected'),
6129 hint=_(b'use --all to mark anyway'),
6120 hint=_(b'use --all to mark anyway'),
6130 )
6121 )
6131
6122
6132 for f in tocomplete:
6123 for f in tocomplete:
6133 try:
6124 try:
6134 # resolve file
6125 # resolve file
6135 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6126 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6136 with ui.configoverride(overrides, b'resolve'):
6127 with ui.configoverride(overrides, b'resolve'):
6137 r = ms.resolve(f, wctx)
6128 r = ms.resolve(f, wctx)
6138 if r:
6129 if r:
6139 ret = 1
6130 ret = 1
6140 finally:
6131 finally:
6141 ms.commit()
6132 ms.commit()
6142
6133
6143 # replace filemerge's .orig file with our resolve file
6134 # replace filemerge's .orig file with our resolve file
6144 a = repo.wjoin(f)
6135 a = repo.wjoin(f)
6145 try:
6136 try:
6146 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6137 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6147 except OSError as inst:
6138 except OSError as inst:
6148 if inst.errno != errno.ENOENT:
6139 if inst.errno != errno.ENOENT:
6149 raise
6140 raise
6150
6141
6151 ms.commit()
6142 ms.commit()
6152 ms.recordactions()
6143 ms.recordactions()
6153
6144
6154 if not didwork and pats:
6145 if not didwork and pats:
6155 hint = None
6146 hint = None
6156 if not any([p for p in pats if p.find(b':') >= 0]):
6147 if not any([p for p in pats if p.find(b':') >= 0]):
6157 pats = [b'path:%s' % p for p in pats]
6148 pats = [b'path:%s' % p for p in pats]
6158 m = scmutil.match(wctx, pats, opts)
6149 m = scmutil.match(wctx, pats, opts)
6159 for f in ms:
6150 for f in ms:
6160 if not m(f):
6151 if not m(f):
6161 continue
6152 continue
6162
6153
6163 def flag(o):
6154 def flag(o):
6164 if o == b're_merge':
6155 if o == b're_merge':
6165 return b'--re-merge '
6156 return b'--re-merge '
6166 return b'-%s ' % o[0:1]
6157 return b'-%s ' % o[0:1]
6167
6158
6168 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6159 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6169 hint = _(b"(try: hg resolve %s%s)\n") % (
6160 hint = _(b"(try: hg resolve %s%s)\n") % (
6170 flags,
6161 flags,
6171 b' '.join(pats),
6162 b' '.join(pats),
6172 )
6163 )
6173 break
6164 break
6174 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6165 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6175 if hint:
6166 if hint:
6176 ui.warn(hint)
6167 ui.warn(hint)
6177 elif ms.mergedriver and ms.mdstate() != b's':
6168 elif ms.mergedriver and ms.mdstate() != b's':
6178 # run conclude step when either a driver-resolved file is requested
6169 # run conclude step when either a driver-resolved file is requested
6179 # or there are no driver-resolved files
6170 # or there are no driver-resolved files
6180 # we can't use 'ret' to determine whether any files are unresolved
6171 # we can't use 'ret' to determine whether any files are unresolved
6181 # because we might not have tried to resolve some
6172 # because we might not have tried to resolve some
6182 if (runconclude or not list(ms.driverresolved())) and not list(
6173 if (runconclude or not list(ms.driverresolved())) and not list(
6183 ms.unresolved()
6174 ms.unresolved()
6184 ):
6175 ):
6185 proceed = mergemod.driverconclude(repo, ms, wctx)
6176 proceed = mergemod.driverconclude(repo, ms, wctx)
6186 ms.commit()
6177 ms.commit()
6187 if not proceed:
6178 if not proceed:
6188 return 1
6179 return 1
6189
6180
6190 # Nudge users into finishing an unfinished operation
6181 # Nudge users into finishing an unfinished operation
6191 unresolvedf = list(ms.unresolved())
6182 unresolvedf = list(ms.unresolved())
6192 driverresolvedf = list(ms.driverresolved())
6183 driverresolvedf = list(ms.driverresolved())
6193 if not unresolvedf and not driverresolvedf:
6184 if not unresolvedf and not driverresolvedf:
6194 ui.status(_(b'(no more unresolved files)\n'))
6185 ui.status(_(b'(no more unresolved files)\n'))
6195 cmdutil.checkafterresolved(repo)
6186 cmdutil.checkafterresolved(repo)
6196 elif not unresolvedf:
6187 elif not unresolvedf:
6197 ui.status(
6188 ui.status(
6198 _(
6189 _(
6199 b'(no more unresolved files -- '
6190 b'(no more unresolved files -- '
6200 b'run "hg resolve --all" to conclude)\n'
6191 b'run "hg resolve --all" to conclude)\n'
6201 )
6192 )
6202 )
6193 )
6203
6194
6204 return ret
6195 return ret
6205
6196
6206
6197
6207 @command(
6198 @command(
6208 b'revert',
6199 b'revert',
6209 [
6200 [
6210 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6201 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6211 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6202 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6212 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6203 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6213 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6204 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6214 (b'i', b'interactive', None, _(b'interactively select the changes')),
6205 (b'i', b'interactive', None, _(b'interactively select the changes')),
6215 ]
6206 ]
6216 + walkopts
6207 + walkopts
6217 + dryrunopts,
6208 + dryrunopts,
6218 _(b'[OPTION]... [-r REV] [NAME]...'),
6209 _(b'[OPTION]... [-r REV] [NAME]...'),
6219 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6210 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6220 )
6211 )
6221 def revert(ui, repo, *pats, **opts):
6212 def revert(ui, repo, *pats, **opts):
6222 """restore files to their checkout state
6213 """restore files to their checkout state
6223
6214
6224 .. note::
6215 .. note::
6225
6216
6226 To check out earlier revisions, you should use :hg:`update REV`.
6217 To check out earlier revisions, you should use :hg:`update REV`.
6227 To cancel an uncommitted merge (and lose your changes),
6218 To cancel an uncommitted merge (and lose your changes),
6228 use :hg:`merge --abort`.
6219 use :hg:`merge --abort`.
6229
6220
6230 With no revision specified, revert the specified files or directories
6221 With no revision specified, revert the specified files or directories
6231 to the contents they had in the parent of the working directory.
6222 to the contents they had in the parent of the working directory.
6232 This restores the contents of files to an unmodified
6223 This restores the contents of files to an unmodified
6233 state and unschedules adds, removes, copies, and renames. If the
6224 state and unschedules adds, removes, copies, and renames. If the
6234 working directory has two parents, you must explicitly specify a
6225 working directory has two parents, you must explicitly specify a
6235 revision.
6226 revision.
6236
6227
6237 Using the -r/--rev or -d/--date options, revert the given files or
6228 Using the -r/--rev or -d/--date options, revert the given files or
6238 directories to their states as of a specific revision. Because
6229 directories to their states as of a specific revision. Because
6239 revert does not change the working directory parents, this will
6230 revert does not change the working directory parents, this will
6240 cause these files to appear modified. This can be helpful to "back
6231 cause these files to appear modified. This can be helpful to "back
6241 out" some or all of an earlier change. See :hg:`backout` for a
6232 out" some or all of an earlier change. See :hg:`backout` for a
6242 related method.
6233 related method.
6243
6234
6244 Modified files are saved with a .orig suffix before reverting.
6235 Modified files are saved with a .orig suffix before reverting.
6245 To disable these backups, use --no-backup. It is possible to store
6236 To disable these backups, use --no-backup. It is possible to store
6246 the backup files in a custom directory relative to the root of the
6237 the backup files in a custom directory relative to the root of the
6247 repository by setting the ``ui.origbackuppath`` configuration
6238 repository by setting the ``ui.origbackuppath`` configuration
6248 option.
6239 option.
6249
6240
6250 See :hg:`help dates` for a list of formats valid for -d/--date.
6241 See :hg:`help dates` for a list of formats valid for -d/--date.
6251
6242
6252 See :hg:`help backout` for a way to reverse the effect of an
6243 See :hg:`help backout` for a way to reverse the effect of an
6253 earlier changeset.
6244 earlier changeset.
6254
6245
6255 Returns 0 on success.
6246 Returns 0 on success.
6256 """
6247 """
6257
6248
6258 opts = pycompat.byteskwargs(opts)
6249 opts = pycompat.byteskwargs(opts)
6259 if opts.get(b"date"):
6250 if opts.get(b"date"):
6260 if opts.get(b"rev"):
6251 if opts.get(b"rev"):
6261 raise error.Abort(_(b"you can't specify a revision and a date"))
6252 raise error.Abort(_(b"you can't specify a revision and a date"))
6262 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6253 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6263
6254
6264 parent, p2 = repo.dirstate.parents()
6255 parent, p2 = repo.dirstate.parents()
6265 if not opts.get(b'rev') and p2 != nullid:
6256 if not opts.get(b'rev') and p2 != nullid:
6266 # revert after merge is a trap for new users (issue2915)
6257 # revert after merge is a trap for new users (issue2915)
6267 raise error.Abort(
6258 raise error.Abort(
6268 _(b'uncommitted merge with no revision specified'),
6259 _(b'uncommitted merge with no revision specified'),
6269 hint=_(b"use 'hg update' or see 'hg help revert'"),
6260 hint=_(b"use 'hg update' or see 'hg help revert'"),
6270 )
6261 )
6271
6262
6272 rev = opts.get(b'rev')
6263 rev = opts.get(b'rev')
6273 if rev:
6264 if rev:
6274 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6265 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6275 ctx = scmutil.revsingle(repo, rev)
6266 ctx = scmutil.revsingle(repo, rev)
6276
6267
6277 if not (
6268 if not (
6278 pats
6269 pats
6279 or opts.get(b'include')
6270 or opts.get(b'include')
6280 or opts.get(b'exclude')
6271 or opts.get(b'exclude')
6281 or opts.get(b'all')
6272 or opts.get(b'all')
6282 or opts.get(b'interactive')
6273 or opts.get(b'interactive')
6283 ):
6274 ):
6284 msg = _(b"no files or directories specified")
6275 msg = _(b"no files or directories specified")
6285 if p2 != nullid:
6276 if p2 != nullid:
6286 hint = _(
6277 hint = _(
6287 b"uncommitted merge, use --all to discard all changes,"
6278 b"uncommitted merge, use --all to discard all changes,"
6288 b" or 'hg update -C .' to abort the merge"
6279 b" or 'hg update -C .' to abort the merge"
6289 )
6280 )
6290 raise error.Abort(msg, hint=hint)
6281 raise error.Abort(msg, hint=hint)
6291 dirty = any(repo.status())
6282 dirty = any(repo.status())
6292 node = ctx.node()
6283 node = ctx.node()
6293 if node != parent:
6284 if node != parent:
6294 if dirty:
6285 if dirty:
6295 hint = (
6286 hint = (
6296 _(
6287 _(
6297 b"uncommitted changes, use --all to discard all"
6288 b"uncommitted changes, use --all to discard all"
6298 b" changes, or 'hg update %d' to update"
6289 b" changes, or 'hg update %d' to update"
6299 )
6290 )
6300 % ctx.rev()
6291 % ctx.rev()
6301 )
6292 )
6302 else:
6293 else:
6303 hint = (
6294 hint = (
6304 _(
6295 _(
6305 b"use --all to revert all files,"
6296 b"use --all to revert all files,"
6306 b" or 'hg update %d' to update"
6297 b" or 'hg update %d' to update"
6307 )
6298 )
6308 % ctx.rev()
6299 % ctx.rev()
6309 )
6300 )
6310 elif dirty:
6301 elif dirty:
6311 hint = _(b"uncommitted changes, use --all to discard all changes")
6302 hint = _(b"uncommitted changes, use --all to discard all changes")
6312 else:
6303 else:
6313 hint = _(b"use --all to revert all files")
6304 hint = _(b"use --all to revert all files")
6314 raise error.Abort(msg, hint=hint)
6305 raise error.Abort(msg, hint=hint)
6315
6306
6316 return cmdutil.revert(
6307 return cmdutil.revert(
6317 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6308 ui, repo, ctx, (parent, p2), *pats, **pycompat.strkwargs(opts)
6318 )
6309 )
6319
6310
6320
6311
6321 @command(
6312 @command(
6322 b'rollback',
6313 b'rollback',
6323 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6314 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6324 helpcategory=command.CATEGORY_MAINTENANCE,
6315 helpcategory=command.CATEGORY_MAINTENANCE,
6325 )
6316 )
6326 def rollback(ui, repo, **opts):
6317 def rollback(ui, repo, **opts):
6327 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6318 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6328
6319
6329 Please use :hg:`commit --amend` instead of rollback to correct
6320 Please use :hg:`commit --amend` instead of rollback to correct
6330 mistakes in the last commit.
6321 mistakes in the last commit.
6331
6322
6332 This command should be used with care. There is only one level of
6323 This command should be used with care. There is only one level of
6333 rollback, and there is no way to undo a rollback. It will also
6324 rollback, and there is no way to undo a rollback. It will also
6334 restore the dirstate at the time of the last transaction, losing
6325 restore the dirstate at the time of the last transaction, losing
6335 any dirstate changes since that time. This command does not alter
6326 any dirstate changes since that time. This command does not alter
6336 the working directory.
6327 the working directory.
6337
6328
6338 Transactions are used to encapsulate the effects of all commands
6329 Transactions are used to encapsulate the effects of all commands
6339 that create new changesets or propagate existing changesets into a
6330 that create new changesets or propagate existing changesets into a
6340 repository.
6331 repository.
6341
6332
6342 .. container:: verbose
6333 .. container:: verbose
6343
6334
6344 For example, the following commands are transactional, and their
6335 For example, the following commands are transactional, and their
6345 effects can be rolled back:
6336 effects can be rolled back:
6346
6337
6347 - commit
6338 - commit
6348 - import
6339 - import
6349 - pull
6340 - pull
6350 - push (with this repository as the destination)
6341 - push (with this repository as the destination)
6351 - unbundle
6342 - unbundle
6352
6343
6353 To avoid permanent data loss, rollback will refuse to rollback a
6344 To avoid permanent data loss, rollback will refuse to rollback a
6354 commit transaction if it isn't checked out. Use --force to
6345 commit transaction if it isn't checked out. Use --force to
6355 override this protection.
6346 override this protection.
6356
6347
6357 The rollback command can be entirely disabled by setting the
6348 The rollback command can be entirely disabled by setting the
6358 ``ui.rollback`` configuration setting to false. If you're here
6349 ``ui.rollback`` configuration setting to false. If you're here
6359 because you want to use rollback and it's disabled, you can
6350 because you want to use rollback and it's disabled, you can
6360 re-enable the command by setting ``ui.rollback`` to true.
6351 re-enable the command by setting ``ui.rollback`` to true.
6361
6352
6362 This command is not intended for use on public repositories. Once
6353 This command is not intended for use on public repositories. Once
6363 changes are visible for pull by other users, rolling a transaction
6354 changes are visible for pull by other users, rolling a transaction
6364 back locally is ineffective (someone else may already have pulled
6355 back locally is ineffective (someone else may already have pulled
6365 the changes). Furthermore, a race is possible with readers of the
6356 the changes). Furthermore, a race is possible with readers of the
6366 repository; for example an in-progress pull from the repository
6357 repository; for example an in-progress pull from the repository
6367 may fail if a rollback is performed.
6358 may fail if a rollback is performed.
6368
6359
6369 Returns 0 on success, 1 if no rollback data is available.
6360 Returns 0 on success, 1 if no rollback data is available.
6370 """
6361 """
6371 if not ui.configbool(b'ui', b'rollback'):
6362 if not ui.configbool(b'ui', b'rollback'):
6372 raise error.Abort(
6363 raise error.Abort(
6373 _(b'rollback is disabled because it is unsafe'),
6364 _(b'rollback is disabled because it is unsafe'),
6374 hint=b'see `hg help -v rollback` for information',
6365 hint=b'see `hg help -v rollback` for information',
6375 )
6366 )
6376 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6367 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6377
6368
6378
6369
6379 @command(
6370 @command(
6380 b'root',
6371 b'root',
6381 [] + formatteropts,
6372 [] + formatteropts,
6382 intents={INTENT_READONLY},
6373 intents={INTENT_READONLY},
6383 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6374 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6384 )
6375 )
6385 def root(ui, repo, **opts):
6376 def root(ui, repo, **opts):
6386 """print the root (top) of the current working directory
6377 """print the root (top) of the current working directory
6387
6378
6388 Print the root directory of the current repository.
6379 Print the root directory of the current repository.
6389
6380
6390 .. container:: verbose
6381 .. container:: verbose
6391
6382
6392 Template:
6383 Template:
6393
6384
6394 The following keywords are supported in addition to the common template
6385 The following keywords are supported in addition to the common template
6395 keywords and functions. See also :hg:`help templates`.
6386 keywords and functions. See also :hg:`help templates`.
6396
6387
6397 :hgpath: String. Path to the .hg directory.
6388 :hgpath: String. Path to the .hg directory.
6398 :storepath: String. Path to the directory holding versioned data.
6389 :storepath: String. Path to the directory holding versioned data.
6399
6390
6400 Returns 0 on success.
6391 Returns 0 on success.
6401 """
6392 """
6402 opts = pycompat.byteskwargs(opts)
6393 opts = pycompat.byteskwargs(opts)
6403 with ui.formatter(b'root', opts) as fm:
6394 with ui.formatter(b'root', opts) as fm:
6404 fm.startitem()
6395 fm.startitem()
6405 fm.write(b'reporoot', b'%s\n', repo.root)
6396 fm.write(b'reporoot', b'%s\n', repo.root)
6406 fm.data(hgpath=repo.path, storepath=repo.spath)
6397 fm.data(hgpath=repo.path, storepath=repo.spath)
6407
6398
6408
6399
6409 @command(
6400 @command(
6410 b'serve',
6401 b'serve',
6411 [
6402 [
6412 (
6403 (
6413 b'A',
6404 b'A',
6414 b'accesslog',
6405 b'accesslog',
6415 b'',
6406 b'',
6416 _(b'name of access log file to write to'),
6407 _(b'name of access log file to write to'),
6417 _(b'FILE'),
6408 _(b'FILE'),
6418 ),
6409 ),
6419 (b'd', b'daemon', None, _(b'run server in background')),
6410 (b'd', b'daemon', None, _(b'run server in background')),
6420 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6411 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6421 (
6412 (
6422 b'E',
6413 b'E',
6423 b'errorlog',
6414 b'errorlog',
6424 b'',
6415 b'',
6425 _(b'name of error log file to write to'),
6416 _(b'name of error log file to write to'),
6426 _(b'FILE'),
6417 _(b'FILE'),
6427 ),
6418 ),
6428 # use string type, then we can check if something was passed
6419 # use string type, then we can check if something was passed
6429 (
6420 (
6430 b'p',
6421 b'p',
6431 b'port',
6422 b'port',
6432 b'',
6423 b'',
6433 _(b'port to listen on (default: 8000)'),
6424 _(b'port to listen on (default: 8000)'),
6434 _(b'PORT'),
6425 _(b'PORT'),
6435 ),
6426 ),
6436 (
6427 (
6437 b'a',
6428 b'a',
6438 b'address',
6429 b'address',
6439 b'',
6430 b'',
6440 _(b'address to listen on (default: all interfaces)'),
6431 _(b'address to listen on (default: all interfaces)'),
6441 _(b'ADDR'),
6432 _(b'ADDR'),
6442 ),
6433 ),
6443 (
6434 (
6444 b'',
6435 b'',
6445 b'prefix',
6436 b'prefix',
6446 b'',
6437 b'',
6447 _(b'prefix path to serve from (default: server root)'),
6438 _(b'prefix path to serve from (default: server root)'),
6448 _(b'PREFIX'),
6439 _(b'PREFIX'),
6449 ),
6440 ),
6450 (
6441 (
6451 b'n',
6442 b'n',
6452 b'name',
6443 b'name',
6453 b'',
6444 b'',
6454 _(b'name to show in web pages (default: working directory)'),
6445 _(b'name to show in web pages (default: working directory)'),
6455 _(b'NAME'),
6446 _(b'NAME'),
6456 ),
6447 ),
6457 (
6448 (
6458 b'',
6449 b'',
6459 b'web-conf',
6450 b'web-conf',
6460 b'',
6451 b'',
6461 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6452 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6462 _(b'FILE'),
6453 _(b'FILE'),
6463 ),
6454 ),
6464 (
6455 (
6465 b'',
6456 b'',
6466 b'webdir-conf',
6457 b'webdir-conf',
6467 b'',
6458 b'',
6468 _(b'name of the hgweb config file (DEPRECATED)'),
6459 _(b'name of the hgweb config file (DEPRECATED)'),
6469 _(b'FILE'),
6460 _(b'FILE'),
6470 ),
6461 ),
6471 (
6462 (
6472 b'',
6463 b'',
6473 b'pid-file',
6464 b'pid-file',
6474 b'',
6465 b'',
6475 _(b'name of file to write process ID to'),
6466 _(b'name of file to write process ID to'),
6476 _(b'FILE'),
6467 _(b'FILE'),
6477 ),
6468 ),
6478 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6469 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6479 (
6470 (
6480 b'',
6471 b'',
6481 b'cmdserver',
6472 b'cmdserver',
6482 b'',
6473 b'',
6483 _(b'for remote clients (ADVANCED)'),
6474 _(b'for remote clients (ADVANCED)'),
6484 _(b'MODE'),
6475 _(b'MODE'),
6485 ),
6476 ),
6486 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6477 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6487 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6478 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6488 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6479 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6489 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6480 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6490 (b'', b'print-url', None, _(b'start and print only the URL')),
6481 (b'', b'print-url', None, _(b'start and print only the URL')),
6491 ]
6482 ]
6492 + subrepoopts,
6483 + subrepoopts,
6493 _(b'[OPTION]...'),
6484 _(b'[OPTION]...'),
6494 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6485 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6495 helpbasic=True,
6486 helpbasic=True,
6496 optionalrepo=True,
6487 optionalrepo=True,
6497 )
6488 )
6498 def serve(ui, repo, **opts):
6489 def serve(ui, repo, **opts):
6499 """start stand-alone webserver
6490 """start stand-alone webserver
6500
6491
6501 Start a local HTTP repository browser and pull server. You can use
6492 Start a local HTTP repository browser and pull server. You can use
6502 this for ad-hoc sharing and browsing of repositories. It is
6493 this for ad-hoc sharing and browsing of repositories. It is
6503 recommended to use a real web server to serve a repository for
6494 recommended to use a real web server to serve a repository for
6504 longer periods of time.
6495 longer periods of time.
6505
6496
6506 Please note that the server does not implement access control.
6497 Please note that the server does not implement access control.
6507 This means that, by default, anybody can read from the server and
6498 This means that, by default, anybody can read from the server and
6508 nobody can write to it by default. Set the ``web.allow-push``
6499 nobody can write to it by default. Set the ``web.allow-push``
6509 option to ``*`` to allow everybody to push to the server. You
6500 option to ``*`` to allow everybody to push to the server. You
6510 should use a real web server if you need to authenticate users.
6501 should use a real web server if you need to authenticate users.
6511
6502
6512 By default, the server logs accesses to stdout and errors to
6503 By default, the server logs accesses to stdout and errors to
6513 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6504 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6514 files.
6505 files.
6515
6506
6516 To have the server choose a free port number to listen on, specify
6507 To have the server choose a free port number to listen on, specify
6517 a port number of 0; in this case, the server will print the port
6508 a port number of 0; in this case, the server will print the port
6518 number it uses.
6509 number it uses.
6519
6510
6520 Returns 0 on success.
6511 Returns 0 on success.
6521 """
6512 """
6522
6513
6523 opts = pycompat.byteskwargs(opts)
6514 opts = pycompat.byteskwargs(opts)
6524 if opts[b"stdio"] and opts[b"cmdserver"]:
6515 if opts[b"stdio"] and opts[b"cmdserver"]:
6525 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6516 raise error.Abort(_(b"cannot use --stdio with --cmdserver"))
6526 if opts[b"print_url"] and ui.verbose:
6517 if opts[b"print_url"] and ui.verbose:
6527 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6518 raise error.Abort(_(b"cannot use --print-url with --verbose"))
6528
6519
6529 if opts[b"stdio"]:
6520 if opts[b"stdio"]:
6530 if repo is None:
6521 if repo is None:
6531 raise error.RepoError(
6522 raise error.RepoError(
6532 _(b"there is no Mercurial repository here (.hg not found)")
6523 _(b"there is no Mercurial repository here (.hg not found)")
6533 )
6524 )
6534 s = wireprotoserver.sshserver(ui, repo)
6525 s = wireprotoserver.sshserver(ui, repo)
6535 s.serve_forever()
6526 s.serve_forever()
6536
6527
6537 service = server.createservice(ui, repo, opts)
6528 service = server.createservice(ui, repo, opts)
6538 return server.runservice(opts, initfn=service.init, runfn=service.run)
6529 return server.runservice(opts, initfn=service.init, runfn=service.run)
6539
6530
6540
6531
6541 @command(
6532 @command(
6542 b'shelve',
6533 b'shelve',
6543 [
6534 [
6544 (
6535 (
6545 b'A',
6536 b'A',
6546 b'addremove',
6537 b'addremove',
6547 None,
6538 None,
6548 _(b'mark new/missing files as added/removed before shelving'),
6539 _(b'mark new/missing files as added/removed before shelving'),
6549 ),
6540 ),
6550 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6541 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6551 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6542 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6552 (
6543 (
6553 b'',
6544 b'',
6554 b'date',
6545 b'date',
6555 b'',
6546 b'',
6556 _(b'shelve with the specified commit date'),
6547 _(b'shelve with the specified commit date'),
6557 _(b'DATE'),
6548 _(b'DATE'),
6558 ),
6549 ),
6559 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6550 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6560 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6551 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6561 (
6552 (
6562 b'k',
6553 b'k',
6563 b'keep',
6554 b'keep',
6564 False,
6555 False,
6565 _(b'shelve, but keep changes in the working directory'),
6556 _(b'shelve, but keep changes in the working directory'),
6566 ),
6557 ),
6567 (b'l', b'list', None, _(b'list current shelves')),
6558 (b'l', b'list', None, _(b'list current shelves')),
6568 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6559 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6569 (
6560 (
6570 b'n',
6561 b'n',
6571 b'name',
6562 b'name',
6572 b'',
6563 b'',
6573 _(b'use the given name for the shelved commit'),
6564 _(b'use the given name for the shelved commit'),
6574 _(b'NAME'),
6565 _(b'NAME'),
6575 ),
6566 ),
6576 (
6567 (
6577 b'p',
6568 b'p',
6578 b'patch',
6569 b'patch',
6579 None,
6570 None,
6580 _(
6571 _(
6581 b'output patches for changes (provide the names of the shelved '
6572 b'output patches for changes (provide the names of the shelved '
6582 b'changes as positional arguments)'
6573 b'changes as positional arguments)'
6583 ),
6574 ),
6584 ),
6575 ),
6585 (b'i', b'interactive', None, _(b'interactive mode')),
6576 (b'i', b'interactive', None, _(b'interactive mode')),
6586 (
6577 (
6587 b'',
6578 b'',
6588 b'stat',
6579 b'stat',
6589 None,
6580 None,
6590 _(
6581 _(
6591 b'output diffstat-style summary of changes (provide the names of '
6582 b'output diffstat-style summary of changes (provide the names of '
6592 b'the shelved changes as positional arguments)'
6583 b'the shelved changes as positional arguments)'
6593 ),
6584 ),
6594 ),
6585 ),
6595 ]
6586 ]
6596 + cmdutil.walkopts,
6587 + cmdutil.walkopts,
6597 _(b'hg shelve [OPTION]... [FILE]...'),
6588 _(b'hg shelve [OPTION]... [FILE]...'),
6598 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6589 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6599 )
6590 )
6600 def shelve(ui, repo, *pats, **opts):
6591 def shelve(ui, repo, *pats, **opts):
6601 '''save and set aside changes from the working directory
6592 '''save and set aside changes from the working directory
6602
6593
6603 Shelving takes files that "hg status" reports as not clean, saves
6594 Shelving takes files that "hg status" reports as not clean, saves
6604 the modifications to a bundle (a shelved change), and reverts the
6595 the modifications to a bundle (a shelved change), and reverts the
6605 files so that their state in the working directory becomes clean.
6596 files so that their state in the working directory becomes clean.
6606
6597
6607 To restore these changes to the working directory, using "hg
6598 To restore these changes to the working directory, using "hg
6608 unshelve"; this will work even if you switch to a different
6599 unshelve"; this will work even if you switch to a different
6609 commit.
6600 commit.
6610
6601
6611 When no files are specified, "hg shelve" saves all not-clean
6602 When no files are specified, "hg shelve" saves all not-clean
6612 files. If specific files or directories are named, only changes to
6603 files. If specific files or directories are named, only changes to
6613 those files are shelved.
6604 those files are shelved.
6614
6605
6615 In bare shelve (when no files are specified, without interactive,
6606 In bare shelve (when no files are specified, without interactive,
6616 include and exclude option), shelving remembers information if the
6607 include and exclude option), shelving remembers information if the
6617 working directory was on newly created branch, in other words working
6608 working directory was on newly created branch, in other words working
6618 directory was on different branch than its first parent. In this
6609 directory was on different branch than its first parent. In this
6619 situation unshelving restores branch information to the working directory.
6610 situation unshelving restores branch information to the working directory.
6620
6611
6621 Each shelved change has a name that makes it easier to find later.
6612 Each shelved change has a name that makes it easier to find later.
6622 The name of a shelved change defaults to being based on the active
6613 The name of a shelved change defaults to being based on the active
6623 bookmark, or if there is no active bookmark, the current named
6614 bookmark, or if there is no active bookmark, the current named
6624 branch. To specify a different name, use ``--name``.
6615 branch. To specify a different name, use ``--name``.
6625
6616
6626 To see a list of existing shelved changes, use the ``--list``
6617 To see a list of existing shelved changes, use the ``--list``
6627 option. For each shelved change, this will print its name, age,
6618 option. For each shelved change, this will print its name, age,
6628 and description; use ``--patch`` or ``--stat`` for more details.
6619 and description; use ``--patch`` or ``--stat`` for more details.
6629
6620
6630 To delete specific shelved changes, use ``--delete``. To delete
6621 To delete specific shelved changes, use ``--delete``. To delete
6631 all shelved changes, use ``--cleanup``.
6622 all shelved changes, use ``--cleanup``.
6632 '''
6623 '''
6633 opts = pycompat.byteskwargs(opts)
6624 opts = pycompat.byteskwargs(opts)
6634 allowables = [
6625 allowables = [
6635 (b'addremove', {b'create'}), # 'create' is pseudo action
6626 (b'addremove', {b'create'}), # 'create' is pseudo action
6636 (b'unknown', {b'create'}),
6627 (b'unknown', {b'create'}),
6637 (b'cleanup', {b'cleanup'}),
6628 (b'cleanup', {b'cleanup'}),
6638 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6629 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6639 (b'delete', {b'delete'}),
6630 (b'delete', {b'delete'}),
6640 (b'edit', {b'create'}),
6631 (b'edit', {b'create'}),
6641 (b'keep', {b'create'}),
6632 (b'keep', {b'create'}),
6642 (b'list', {b'list'}),
6633 (b'list', {b'list'}),
6643 (b'message', {b'create'}),
6634 (b'message', {b'create'}),
6644 (b'name', {b'create'}),
6635 (b'name', {b'create'}),
6645 (b'patch', {b'patch', b'list'}),
6636 (b'patch', {b'patch', b'list'}),
6646 (b'stat', {b'stat', b'list'}),
6637 (b'stat', {b'stat', b'list'}),
6647 ]
6638 ]
6648
6639
6649 def checkopt(opt):
6640 def checkopt(opt):
6650 if opts.get(opt):
6641 if opts.get(opt):
6651 for i, allowable in allowables:
6642 for i, allowable in allowables:
6652 if opts[i] and opt not in allowable:
6643 if opts[i] and opt not in allowable:
6653 raise error.Abort(
6644 raise error.Abort(
6654 _(
6645 _(
6655 b"options '--%s' and '--%s' may not be "
6646 b"options '--%s' and '--%s' may not be "
6656 b"used together"
6647 b"used together"
6657 )
6648 )
6658 % (opt, i)
6649 % (opt, i)
6659 )
6650 )
6660 return True
6651 return True
6661
6652
6662 if checkopt(b'cleanup'):
6653 if checkopt(b'cleanup'):
6663 if pats:
6654 if pats:
6664 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6655 raise error.Abort(_(b"cannot specify names when using '--cleanup'"))
6665 return shelvemod.cleanupcmd(ui, repo)
6656 return shelvemod.cleanupcmd(ui, repo)
6666 elif checkopt(b'delete'):
6657 elif checkopt(b'delete'):
6667 return shelvemod.deletecmd(ui, repo, pats)
6658 return shelvemod.deletecmd(ui, repo, pats)
6668 elif checkopt(b'list'):
6659 elif checkopt(b'list'):
6669 return shelvemod.listcmd(ui, repo, pats, opts)
6660 return shelvemod.listcmd(ui, repo, pats, opts)
6670 elif checkopt(b'patch') or checkopt(b'stat'):
6661 elif checkopt(b'patch') or checkopt(b'stat'):
6671 return shelvemod.patchcmds(ui, repo, pats, opts)
6662 return shelvemod.patchcmds(ui, repo, pats, opts)
6672 else:
6663 else:
6673 return shelvemod.createcmd(ui, repo, pats, opts)
6664 return shelvemod.createcmd(ui, repo, pats, opts)
6674
6665
6675
6666
6676 _NOTTERSE = b'nothing'
6667 _NOTTERSE = b'nothing'
6677
6668
6678
6669
6679 @command(
6670 @command(
6680 b'status|st',
6671 b'status|st',
6681 [
6672 [
6682 (b'A', b'all', None, _(b'show status of all files')),
6673 (b'A', b'all', None, _(b'show status of all files')),
6683 (b'm', b'modified', None, _(b'show only modified files')),
6674 (b'm', b'modified', None, _(b'show only modified files')),
6684 (b'a', b'added', None, _(b'show only added files')),
6675 (b'a', b'added', None, _(b'show only added files')),
6685 (b'r', b'removed', None, _(b'show only removed files')),
6676 (b'r', b'removed', None, _(b'show only removed files')),
6686 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6677 (b'd', b'deleted', None, _(b'show only deleted (but tracked) files')),
6687 (b'c', b'clean', None, _(b'show only files without changes')),
6678 (b'c', b'clean', None, _(b'show only files without changes')),
6688 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6679 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6689 (b'i', b'ignored', None, _(b'show only ignored files')),
6680 (b'i', b'ignored', None, _(b'show only ignored files')),
6690 (b'n', b'no-status', None, _(b'hide status prefix')),
6681 (b'n', b'no-status', None, _(b'hide status prefix')),
6691 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6682 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6692 (
6683 (
6693 b'C',
6684 b'C',
6694 b'copies',
6685 b'copies',
6695 None,
6686 None,
6696 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6687 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6697 ),
6688 ),
6698 (
6689 (
6699 b'0',
6690 b'0',
6700 b'print0',
6691 b'print0',
6701 None,
6692 None,
6702 _(b'end filenames with NUL, for use with xargs'),
6693 _(b'end filenames with NUL, for use with xargs'),
6703 ),
6694 ),
6704 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6695 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6705 (
6696 (
6706 b'',
6697 b'',
6707 b'change',
6698 b'change',
6708 b'',
6699 b'',
6709 _(b'list the changed files of a revision'),
6700 _(b'list the changed files of a revision'),
6710 _(b'REV'),
6701 _(b'REV'),
6711 ),
6702 ),
6712 ]
6703 ]
6713 + walkopts
6704 + walkopts
6714 + subrepoopts
6705 + subrepoopts
6715 + formatteropts,
6706 + formatteropts,
6716 _(b'[OPTION]... [FILE]...'),
6707 _(b'[OPTION]... [FILE]...'),
6717 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6708 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6718 helpbasic=True,
6709 helpbasic=True,
6719 inferrepo=True,
6710 inferrepo=True,
6720 intents={INTENT_READONLY},
6711 intents={INTENT_READONLY},
6721 )
6712 )
6722 def status(ui, repo, *pats, **opts):
6713 def status(ui, repo, *pats, **opts):
6723 """show changed files in the working directory
6714 """show changed files in the working directory
6724
6715
6725 Show status of files in the repository. If names are given, only
6716 Show status of files in the repository. If names are given, only
6726 files that match are shown. Files that are clean or ignored or
6717 files that match are shown. Files that are clean or ignored or
6727 the source of a copy/move operation, are not listed unless
6718 the source of a copy/move operation, are not listed unless
6728 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6719 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6729 Unless options described with "show only ..." are given, the
6720 Unless options described with "show only ..." are given, the
6730 options -mardu are used.
6721 options -mardu are used.
6731
6722
6732 Option -q/--quiet hides untracked (unknown and ignored) files
6723 Option -q/--quiet hides untracked (unknown and ignored) files
6733 unless explicitly requested with -u/--unknown or -i/--ignored.
6724 unless explicitly requested with -u/--unknown or -i/--ignored.
6734
6725
6735 .. note::
6726 .. note::
6736
6727
6737 :hg:`status` may appear to disagree with diff if permissions have
6728 :hg:`status` may appear to disagree with diff if permissions have
6738 changed or a merge has occurred. The standard diff format does
6729 changed or a merge has occurred. The standard diff format does
6739 not report permission changes and diff only reports changes
6730 not report permission changes and diff only reports changes
6740 relative to one merge parent.
6731 relative to one merge parent.
6741
6732
6742 If one revision is given, it is used as the base revision.
6733 If one revision is given, it is used as the base revision.
6743 If two revisions are given, the differences between them are
6734 If two revisions are given, the differences between them are
6744 shown. The --change option can also be used as a shortcut to list
6735 shown. The --change option can also be used as a shortcut to list
6745 the changed files of a revision from its first parent.
6736 the changed files of a revision from its first parent.
6746
6737
6747 The codes used to show the status of files are::
6738 The codes used to show the status of files are::
6748
6739
6749 M = modified
6740 M = modified
6750 A = added
6741 A = added
6751 R = removed
6742 R = removed
6752 C = clean
6743 C = clean
6753 ! = missing (deleted by non-hg command, but still tracked)
6744 ! = missing (deleted by non-hg command, but still tracked)
6754 ? = not tracked
6745 ? = not tracked
6755 I = ignored
6746 I = ignored
6756 = origin of the previous file (with --copies)
6747 = origin of the previous file (with --copies)
6757
6748
6758 .. container:: verbose
6749 .. container:: verbose
6759
6750
6760 The -t/--terse option abbreviates the output by showing only the directory
6751 The -t/--terse option abbreviates the output by showing only the directory
6761 name if all the files in it share the same status. The option takes an
6752 name if all the files in it share the same status. The option takes an
6762 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6753 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6763 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6754 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6764 for 'ignored' and 'c' for clean.
6755 for 'ignored' and 'c' for clean.
6765
6756
6766 It abbreviates only those statuses which are passed. Note that clean and
6757 It abbreviates only those statuses which are passed. Note that clean and
6767 ignored files are not displayed with '--terse ic' unless the -c/--clean
6758 ignored files are not displayed with '--terse ic' unless the -c/--clean
6768 and -i/--ignored options are also used.
6759 and -i/--ignored options are also used.
6769
6760
6770 The -v/--verbose option shows information when the repository is in an
6761 The -v/--verbose option shows information when the repository is in an
6771 unfinished merge, shelve, rebase state etc. You can have this behavior
6762 unfinished merge, shelve, rebase state etc. You can have this behavior
6772 turned on by default by enabling the ``commands.status.verbose`` option.
6763 turned on by default by enabling the ``commands.status.verbose`` option.
6773
6764
6774 You can skip displaying some of these states by setting
6765 You can skip displaying some of these states by setting
6775 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6766 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6776 'histedit', 'merge', 'rebase', or 'unshelve'.
6767 'histedit', 'merge', 'rebase', or 'unshelve'.
6777
6768
6778 Template:
6769 Template:
6779
6770
6780 The following keywords are supported in addition to the common template
6771 The following keywords are supported in addition to the common template
6781 keywords and functions. See also :hg:`help templates`.
6772 keywords and functions. See also :hg:`help templates`.
6782
6773
6783 :path: String. Repository-absolute path of the file.
6774 :path: String. Repository-absolute path of the file.
6784 :source: String. Repository-absolute path of the file originated from.
6775 :source: String. Repository-absolute path of the file originated from.
6785 Available if ``--copies`` is specified.
6776 Available if ``--copies`` is specified.
6786 :status: String. Character denoting file's status.
6777 :status: String. Character denoting file's status.
6787
6778
6788 Examples:
6779 Examples:
6789
6780
6790 - show changes in the working directory relative to a
6781 - show changes in the working directory relative to a
6791 changeset::
6782 changeset::
6792
6783
6793 hg status --rev 9353
6784 hg status --rev 9353
6794
6785
6795 - show changes in the working directory relative to the
6786 - show changes in the working directory relative to the
6796 current directory (see :hg:`help patterns` for more information)::
6787 current directory (see :hg:`help patterns` for more information)::
6797
6788
6798 hg status re:
6789 hg status re:
6799
6790
6800 - show all changes including copies in an existing changeset::
6791 - show all changes including copies in an existing changeset::
6801
6792
6802 hg status --copies --change 9353
6793 hg status --copies --change 9353
6803
6794
6804 - get a NUL separated list of added files, suitable for xargs::
6795 - get a NUL separated list of added files, suitable for xargs::
6805
6796
6806 hg status -an0
6797 hg status -an0
6807
6798
6808 - show more information about the repository status, abbreviating
6799 - show more information about the repository status, abbreviating
6809 added, removed, modified, deleted, and untracked paths::
6800 added, removed, modified, deleted, and untracked paths::
6810
6801
6811 hg status -v -t mardu
6802 hg status -v -t mardu
6812
6803
6813 Returns 0 on success.
6804 Returns 0 on success.
6814
6805
6815 """
6806 """
6816
6807
6817 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6808 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6818 opts = pycompat.byteskwargs(opts)
6809 opts = pycompat.byteskwargs(opts)
6819 revs = opts.get(b'rev')
6810 revs = opts.get(b'rev')
6820 change = opts.get(b'change')
6811 change = opts.get(b'change')
6821 terse = opts.get(b'terse')
6812 terse = opts.get(b'terse')
6822 if terse is _NOTTERSE:
6813 if terse is _NOTTERSE:
6823 if revs:
6814 if revs:
6824 terse = b''
6815 terse = b''
6825 else:
6816 else:
6826 terse = ui.config(b'commands', b'status.terse')
6817 terse = ui.config(b'commands', b'status.terse')
6827
6818
6828 if revs and terse:
6819 if revs and terse:
6829 msg = _(b'cannot use --terse with --rev')
6820 msg = _(b'cannot use --terse with --rev')
6830 raise error.Abort(msg)
6821 raise error.Abort(msg)
6831 elif change:
6822 elif change:
6832 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6823 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6833 ctx2 = scmutil.revsingle(repo, change, None)
6824 ctx2 = scmutil.revsingle(repo, change, None)
6834 ctx1 = ctx2.p1()
6825 ctx1 = ctx2.p1()
6835 else:
6826 else:
6836 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6827 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6837 ctx1, ctx2 = scmutil.revpair(repo, revs)
6828 ctx1, ctx2 = scmutil.revpair(repo, revs)
6838
6829
6839 forcerelativevalue = None
6830 forcerelativevalue = None
6840 if ui.hasconfig(b'commands', b'status.relative'):
6831 if ui.hasconfig(b'commands', b'status.relative'):
6841 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6832 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6842 uipathfn = scmutil.getuipathfn(
6833 uipathfn = scmutil.getuipathfn(
6843 repo,
6834 repo,
6844 legacyrelativevalue=bool(pats),
6835 legacyrelativevalue=bool(pats),
6845 forcerelativevalue=forcerelativevalue,
6836 forcerelativevalue=forcerelativevalue,
6846 )
6837 )
6847
6838
6848 if opts.get(b'print0'):
6839 if opts.get(b'print0'):
6849 end = b'\0'
6840 end = b'\0'
6850 else:
6841 else:
6851 end = b'\n'
6842 end = b'\n'
6852 states = b'modified added removed deleted unknown ignored clean'.split()
6843 states = b'modified added removed deleted unknown ignored clean'.split()
6853 show = [k for k in states if opts.get(k)]
6844 show = [k for k in states if opts.get(k)]
6854 if opts.get(b'all'):
6845 if opts.get(b'all'):
6855 show += ui.quiet and (states[:4] + [b'clean']) or states
6846 show += ui.quiet and (states[:4] + [b'clean']) or states
6856
6847
6857 if not show:
6848 if not show:
6858 if ui.quiet:
6849 if ui.quiet:
6859 show = states[:4]
6850 show = states[:4]
6860 else:
6851 else:
6861 show = states[:5]
6852 show = states[:5]
6862
6853
6863 m = scmutil.match(ctx2, pats, opts)
6854 m = scmutil.match(ctx2, pats, opts)
6864 if terse:
6855 if terse:
6865 # we need to compute clean and unknown to terse
6856 # we need to compute clean and unknown to terse
6866 stat = repo.status(
6857 stat = repo.status(
6867 ctx1.node(),
6858 ctx1.node(),
6868 ctx2.node(),
6859 ctx2.node(),
6869 m,
6860 m,
6870 b'ignored' in show or b'i' in terse,
6861 b'ignored' in show or b'i' in terse,
6871 clean=True,
6862 clean=True,
6872 unknown=True,
6863 unknown=True,
6873 listsubrepos=opts.get(b'subrepos'),
6864 listsubrepos=opts.get(b'subrepos'),
6874 )
6865 )
6875
6866
6876 stat = cmdutil.tersedir(stat, terse)
6867 stat = cmdutil.tersedir(stat, terse)
6877 else:
6868 else:
6878 stat = repo.status(
6869 stat = repo.status(
6879 ctx1.node(),
6870 ctx1.node(),
6880 ctx2.node(),
6871 ctx2.node(),
6881 m,
6872 m,
6882 b'ignored' in show,
6873 b'ignored' in show,
6883 b'clean' in show,
6874 b'clean' in show,
6884 b'unknown' in show,
6875 b'unknown' in show,
6885 opts.get(b'subrepos'),
6876 opts.get(b'subrepos'),
6886 )
6877 )
6887
6878
6888 changestates = zip(
6879 changestates = zip(
6889 states,
6880 states,
6890 pycompat.iterbytestr(b'MAR!?IC'),
6881 pycompat.iterbytestr(b'MAR!?IC'),
6891 [getattr(stat, s.decode('utf8')) for s in states],
6882 [getattr(stat, s.decode('utf8')) for s in states],
6892 )
6883 )
6893
6884
6894 copy = {}
6885 copy = {}
6895 if (
6886 if (
6896 opts.get(b'all')
6887 opts.get(b'all')
6897 or opts.get(b'copies')
6888 or opts.get(b'copies')
6898 or ui.configbool(b'ui', b'statuscopies')
6889 or ui.configbool(b'ui', b'statuscopies')
6899 ) and not opts.get(b'no_status'):
6890 ) and not opts.get(b'no_status'):
6900 copy = copies.pathcopies(ctx1, ctx2, m)
6891 copy = copies.pathcopies(ctx1, ctx2, m)
6901
6892
6902 morestatus = None
6893 morestatus = None
6903 if (
6894 if (
6904 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6895 ui.verbose or ui.configbool(b'commands', b'status.verbose')
6905 ) and not ui.plain():
6896 ) and not ui.plain():
6906 morestatus = cmdutil.readmorestatus(repo)
6897 morestatus = cmdutil.readmorestatus(repo)
6907
6898
6908 ui.pager(b'status')
6899 ui.pager(b'status')
6909 fm = ui.formatter(b'status', opts)
6900 fm = ui.formatter(b'status', opts)
6910 fmt = b'%s' + end
6901 fmt = b'%s' + end
6911 showchar = not opts.get(b'no_status')
6902 showchar = not opts.get(b'no_status')
6912
6903
6913 for state, char, files in changestates:
6904 for state, char, files in changestates:
6914 if state in show:
6905 if state in show:
6915 label = b'status.' + state
6906 label = b'status.' + state
6916 for f in files:
6907 for f in files:
6917 fm.startitem()
6908 fm.startitem()
6918 fm.context(ctx=ctx2)
6909 fm.context(ctx=ctx2)
6919 fm.data(itemtype=b'file', path=f)
6910 fm.data(itemtype=b'file', path=f)
6920 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6911 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6921 fm.plain(fmt % uipathfn(f), label=label)
6912 fm.plain(fmt % uipathfn(f), label=label)
6922 if f in copy:
6913 if f in copy:
6923 fm.data(source=copy[f])
6914 fm.data(source=copy[f])
6924 fm.plain(
6915 fm.plain(
6925 (b' %s' + end) % uipathfn(copy[f]),
6916 (b' %s' + end) % uipathfn(copy[f]),
6926 label=b'status.copied',
6917 label=b'status.copied',
6927 )
6918 )
6928 if morestatus:
6919 if morestatus:
6929 morestatus.formatfile(f, fm)
6920 morestatus.formatfile(f, fm)
6930
6921
6931 if morestatus:
6922 if morestatus:
6932 morestatus.formatfooter(fm)
6923 morestatus.formatfooter(fm)
6933 fm.end()
6924 fm.end()
6934
6925
6935
6926
6936 @command(
6927 @command(
6937 b'summary|sum',
6928 b'summary|sum',
6938 [(b'', b'remote', None, _(b'check for push and pull'))],
6929 [(b'', b'remote', None, _(b'check for push and pull'))],
6939 b'[--remote]',
6930 b'[--remote]',
6940 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6931 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6941 helpbasic=True,
6932 helpbasic=True,
6942 intents={INTENT_READONLY},
6933 intents={INTENT_READONLY},
6943 )
6934 )
6944 def summary(ui, repo, **opts):
6935 def summary(ui, repo, **opts):
6945 """summarize working directory state
6936 """summarize working directory state
6946
6937
6947 This generates a brief summary of the working directory state,
6938 This generates a brief summary of the working directory state,
6948 including parents, branch, commit status, phase and available updates.
6939 including parents, branch, commit status, phase and available updates.
6949
6940
6950 With the --remote option, this will check the default paths for
6941 With the --remote option, this will check the default paths for
6951 incoming and outgoing changes. This can be time-consuming.
6942 incoming and outgoing changes. This can be time-consuming.
6952
6943
6953 Returns 0 on success.
6944 Returns 0 on success.
6954 """
6945 """
6955
6946
6956 opts = pycompat.byteskwargs(opts)
6947 opts = pycompat.byteskwargs(opts)
6957 ui.pager(b'summary')
6948 ui.pager(b'summary')
6958 ctx = repo[None]
6949 ctx = repo[None]
6959 parents = ctx.parents()
6950 parents = ctx.parents()
6960 pnode = parents[0].node()
6951 pnode = parents[0].node()
6961 marks = []
6952 marks = []
6962
6953
6963 try:
6954 try:
6964 ms = mergestatemod.mergestate.read(repo)
6955 ms = mergestatemod.mergestate.read(repo)
6965 except error.UnsupportedMergeRecords as e:
6956 except error.UnsupportedMergeRecords as e:
6966 s = b' '.join(e.recordtypes)
6957 s = b' '.join(e.recordtypes)
6967 ui.warn(
6958 ui.warn(
6968 _(b'warning: merge state has unsupported record types: %s\n') % s
6959 _(b'warning: merge state has unsupported record types: %s\n') % s
6969 )
6960 )
6970 unresolved = []
6961 unresolved = []
6971 else:
6962 else:
6972 unresolved = list(ms.unresolved())
6963 unresolved = list(ms.unresolved())
6973
6964
6974 for p in parents:
6965 for p in parents:
6975 # label with log.changeset (instead of log.parent) since this
6966 # label with log.changeset (instead of log.parent) since this
6976 # shows a working directory parent *changeset*:
6967 # shows a working directory parent *changeset*:
6977 # i18n: column positioning for "hg summary"
6968 # i18n: column positioning for "hg summary"
6978 ui.write(
6969 ui.write(
6979 _(b'parent: %d:%s ') % (p.rev(), p),
6970 _(b'parent: %d:%s ') % (p.rev(), p),
6980 label=logcmdutil.changesetlabels(p),
6971 label=logcmdutil.changesetlabels(p),
6981 )
6972 )
6982 ui.write(b' '.join(p.tags()), label=b'log.tag')
6973 ui.write(b' '.join(p.tags()), label=b'log.tag')
6983 if p.bookmarks():
6974 if p.bookmarks():
6984 marks.extend(p.bookmarks())
6975 marks.extend(p.bookmarks())
6985 if p.rev() == -1:
6976 if p.rev() == -1:
6986 if not len(repo):
6977 if not len(repo):
6987 ui.write(_(b' (empty repository)'))
6978 ui.write(_(b' (empty repository)'))
6988 else:
6979 else:
6989 ui.write(_(b' (no revision checked out)'))
6980 ui.write(_(b' (no revision checked out)'))
6990 if p.obsolete():
6981 if p.obsolete():
6991 ui.write(_(b' (obsolete)'))
6982 ui.write(_(b' (obsolete)'))
6992 if p.isunstable():
6983 if p.isunstable():
6993 instabilities = (
6984 instabilities = (
6994 ui.label(instability, b'trouble.%s' % instability)
6985 ui.label(instability, b'trouble.%s' % instability)
6995 for instability in p.instabilities()
6986 for instability in p.instabilities()
6996 )
6987 )
6997 ui.write(b' (' + b', '.join(instabilities) + b')')
6988 ui.write(b' (' + b', '.join(instabilities) + b')')
6998 ui.write(b'\n')
6989 ui.write(b'\n')
6999 if p.description():
6990 if p.description():
7000 ui.status(
6991 ui.status(
7001 b' ' + p.description().splitlines()[0].strip() + b'\n',
6992 b' ' + p.description().splitlines()[0].strip() + b'\n',
7002 label=b'log.summary',
6993 label=b'log.summary',
7003 )
6994 )
7004
6995
7005 branch = ctx.branch()
6996 branch = ctx.branch()
7006 bheads = repo.branchheads(branch)
6997 bheads = repo.branchheads(branch)
7007 # i18n: column positioning for "hg summary"
6998 # i18n: column positioning for "hg summary"
7008 m = _(b'branch: %s\n') % branch
6999 m = _(b'branch: %s\n') % branch
7009 if branch != b'default':
7000 if branch != b'default':
7010 ui.write(m, label=b'log.branch')
7001 ui.write(m, label=b'log.branch')
7011 else:
7002 else:
7012 ui.status(m, label=b'log.branch')
7003 ui.status(m, label=b'log.branch')
7013
7004
7014 if marks:
7005 if marks:
7015 active = repo._activebookmark
7006 active = repo._activebookmark
7016 # i18n: column positioning for "hg summary"
7007 # i18n: column positioning for "hg summary"
7017 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7008 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7018 if active is not None:
7009 if active is not None:
7019 if active in marks:
7010 if active in marks:
7020 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7011 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7021 marks.remove(active)
7012 marks.remove(active)
7022 else:
7013 else:
7023 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7014 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7024 for m in marks:
7015 for m in marks:
7025 ui.write(b' ' + m, label=b'log.bookmark')
7016 ui.write(b' ' + m, label=b'log.bookmark')
7026 ui.write(b'\n', label=b'log.bookmark')
7017 ui.write(b'\n', label=b'log.bookmark')
7027
7018
7028 status = repo.status(unknown=True)
7019 status = repo.status(unknown=True)
7029
7020
7030 c = repo.dirstate.copies()
7021 c = repo.dirstate.copies()
7031 copied, renamed = [], []
7022 copied, renamed = [], []
7032 for d, s in pycompat.iteritems(c):
7023 for d, s in pycompat.iteritems(c):
7033 if s in status.removed:
7024 if s in status.removed:
7034 status.removed.remove(s)
7025 status.removed.remove(s)
7035 renamed.append(d)
7026 renamed.append(d)
7036 else:
7027 else:
7037 copied.append(d)
7028 copied.append(d)
7038 if d in status.added:
7029 if d in status.added:
7039 status.added.remove(d)
7030 status.added.remove(d)
7040
7031
7041 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7032 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7042
7033
7043 labels = [
7034 labels = [
7044 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7035 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7045 (ui.label(_(b'%d added'), b'status.added'), status.added),
7036 (ui.label(_(b'%d added'), b'status.added'), status.added),
7046 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7037 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7047 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7038 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7048 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7039 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7049 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7040 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7050 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7041 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7051 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7042 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7052 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7043 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7053 ]
7044 ]
7054 t = []
7045 t = []
7055 for l, s in labels:
7046 for l, s in labels:
7056 if s:
7047 if s:
7057 t.append(l % len(s))
7048 t.append(l % len(s))
7058
7049
7059 t = b', '.join(t)
7050 t = b', '.join(t)
7060 cleanworkdir = False
7051 cleanworkdir = False
7061
7052
7062 if repo.vfs.exists(b'graftstate'):
7053 if repo.vfs.exists(b'graftstate'):
7063 t += _(b' (graft in progress)')
7054 t += _(b' (graft in progress)')
7064 if repo.vfs.exists(b'updatestate'):
7055 if repo.vfs.exists(b'updatestate'):
7065 t += _(b' (interrupted update)')
7056 t += _(b' (interrupted update)')
7066 elif len(parents) > 1:
7057 elif len(parents) > 1:
7067 t += _(b' (merge)')
7058 t += _(b' (merge)')
7068 elif branch != parents[0].branch():
7059 elif branch != parents[0].branch():
7069 t += _(b' (new branch)')
7060 t += _(b' (new branch)')
7070 elif parents[0].closesbranch() and pnode in repo.branchheads(
7061 elif parents[0].closesbranch() and pnode in repo.branchheads(
7071 branch, closed=True
7062 branch, closed=True
7072 ):
7063 ):
7073 t += _(b' (head closed)')
7064 t += _(b' (head closed)')
7074 elif not (
7065 elif not (
7075 status.modified
7066 status.modified
7076 or status.added
7067 or status.added
7077 or status.removed
7068 or status.removed
7078 or renamed
7069 or renamed
7079 or copied
7070 or copied
7080 or subs
7071 or subs
7081 ):
7072 ):
7082 t += _(b' (clean)')
7073 t += _(b' (clean)')
7083 cleanworkdir = True
7074 cleanworkdir = True
7084 elif pnode not in bheads:
7075 elif pnode not in bheads:
7085 t += _(b' (new branch head)')
7076 t += _(b' (new branch head)')
7086
7077
7087 if parents:
7078 if parents:
7088 pendingphase = max(p.phase() for p in parents)
7079 pendingphase = max(p.phase() for p in parents)
7089 else:
7080 else:
7090 pendingphase = phases.public
7081 pendingphase = phases.public
7091
7082
7092 if pendingphase > phases.newcommitphase(ui):
7083 if pendingphase > phases.newcommitphase(ui):
7093 t += b' (%s)' % phases.phasenames[pendingphase]
7084 t += b' (%s)' % phases.phasenames[pendingphase]
7094
7085
7095 if cleanworkdir:
7086 if cleanworkdir:
7096 # i18n: column positioning for "hg summary"
7087 # i18n: column positioning for "hg summary"
7097 ui.status(_(b'commit: %s\n') % t.strip())
7088 ui.status(_(b'commit: %s\n') % t.strip())
7098 else:
7089 else:
7099 # i18n: column positioning for "hg summary"
7090 # i18n: column positioning for "hg summary"
7100 ui.write(_(b'commit: %s\n') % t.strip())
7091 ui.write(_(b'commit: %s\n') % t.strip())
7101
7092
7102 # all ancestors of branch heads - all ancestors of parent = new csets
7093 # all ancestors of branch heads - all ancestors of parent = new csets
7103 new = len(
7094 new = len(
7104 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7095 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7105 )
7096 )
7106
7097
7107 if new == 0:
7098 if new == 0:
7108 # i18n: column positioning for "hg summary"
7099 # i18n: column positioning for "hg summary"
7109 ui.status(_(b'update: (current)\n'))
7100 ui.status(_(b'update: (current)\n'))
7110 elif pnode not in bheads:
7101 elif pnode not in bheads:
7111 # i18n: column positioning for "hg summary"
7102 # i18n: column positioning for "hg summary"
7112 ui.write(_(b'update: %d new changesets (update)\n') % new)
7103 ui.write(_(b'update: %d new changesets (update)\n') % new)
7113 else:
7104 else:
7114 # i18n: column positioning for "hg summary"
7105 # i18n: column positioning for "hg summary"
7115 ui.write(
7106 ui.write(
7116 _(b'update: %d new changesets, %d branch heads (merge)\n')
7107 _(b'update: %d new changesets, %d branch heads (merge)\n')
7117 % (new, len(bheads))
7108 % (new, len(bheads))
7118 )
7109 )
7119
7110
7120 t = []
7111 t = []
7121 draft = len(repo.revs(b'draft()'))
7112 draft = len(repo.revs(b'draft()'))
7122 if draft:
7113 if draft:
7123 t.append(_(b'%d draft') % draft)
7114 t.append(_(b'%d draft') % draft)
7124 secret = len(repo.revs(b'secret()'))
7115 secret = len(repo.revs(b'secret()'))
7125 if secret:
7116 if secret:
7126 t.append(_(b'%d secret') % secret)
7117 t.append(_(b'%d secret') % secret)
7127
7118
7128 if draft or secret:
7119 if draft or secret:
7129 ui.status(_(b'phases: %s\n') % b', '.join(t))
7120 ui.status(_(b'phases: %s\n') % b', '.join(t))
7130
7121
7131 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7122 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7132 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7123 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7133 numtrouble = len(repo.revs(trouble + b"()"))
7124 numtrouble = len(repo.revs(trouble + b"()"))
7134 # We write all the possibilities to ease translation
7125 # We write all the possibilities to ease translation
7135 troublemsg = {
7126 troublemsg = {
7136 b"orphan": _(b"orphan: %d changesets"),
7127 b"orphan": _(b"orphan: %d changesets"),
7137 b"contentdivergent": _(b"content-divergent: %d changesets"),
7128 b"contentdivergent": _(b"content-divergent: %d changesets"),
7138 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7129 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7139 }
7130 }
7140 if numtrouble > 0:
7131 if numtrouble > 0:
7141 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7132 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7142
7133
7143 cmdutil.summaryhooks(ui, repo)
7134 cmdutil.summaryhooks(ui, repo)
7144
7135
7145 if opts.get(b'remote'):
7136 if opts.get(b'remote'):
7146 needsincoming, needsoutgoing = True, True
7137 needsincoming, needsoutgoing = True, True
7147 else:
7138 else:
7148 needsincoming, needsoutgoing = False, False
7139 needsincoming, needsoutgoing = False, False
7149 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7140 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7150 if i:
7141 if i:
7151 needsincoming = True
7142 needsincoming = True
7152 if o:
7143 if o:
7153 needsoutgoing = True
7144 needsoutgoing = True
7154 if not needsincoming and not needsoutgoing:
7145 if not needsincoming and not needsoutgoing:
7155 return
7146 return
7156
7147
7157 def getincoming():
7148 def getincoming():
7158 source, branches = hg.parseurl(ui.expandpath(b'default'))
7149 source, branches = hg.parseurl(ui.expandpath(b'default'))
7159 sbranch = branches[0]
7150 sbranch = branches[0]
7160 try:
7151 try:
7161 other = hg.peer(repo, {}, source)
7152 other = hg.peer(repo, {}, source)
7162 except error.RepoError:
7153 except error.RepoError:
7163 if opts.get(b'remote'):
7154 if opts.get(b'remote'):
7164 raise
7155 raise
7165 return source, sbranch, None, None, None
7156 return source, sbranch, None, None, None
7166 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7157 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7167 if revs:
7158 if revs:
7168 revs = [other.lookup(rev) for rev in revs]
7159 revs = [other.lookup(rev) for rev in revs]
7169 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7160 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7170 repo.ui.pushbuffer()
7161 repo.ui.pushbuffer()
7171 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7162 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7172 repo.ui.popbuffer()
7163 repo.ui.popbuffer()
7173 return source, sbranch, other, commoninc, commoninc[1]
7164 return source, sbranch, other, commoninc, commoninc[1]
7174
7165
7175 if needsincoming:
7166 if needsincoming:
7176 source, sbranch, sother, commoninc, incoming = getincoming()
7167 source, sbranch, sother, commoninc, incoming = getincoming()
7177 else:
7168 else:
7178 source = sbranch = sother = commoninc = incoming = None
7169 source = sbranch = sother = commoninc = incoming = None
7179
7170
7180 def getoutgoing():
7171 def getoutgoing():
7181 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7172 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7182 dbranch = branches[0]
7173 dbranch = branches[0]
7183 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7174 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7184 if source != dest:
7175 if source != dest:
7185 try:
7176 try:
7186 dother = hg.peer(repo, {}, dest)
7177 dother = hg.peer(repo, {}, dest)
7187 except error.RepoError:
7178 except error.RepoError:
7188 if opts.get(b'remote'):
7179 if opts.get(b'remote'):
7189 raise
7180 raise
7190 return dest, dbranch, None, None
7181 return dest, dbranch, None, None
7191 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7182 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7192 elif sother is None:
7183 elif sother is None:
7193 # there is no explicit destination peer, but source one is invalid
7184 # there is no explicit destination peer, but source one is invalid
7194 return dest, dbranch, None, None
7185 return dest, dbranch, None, None
7195 else:
7186 else:
7196 dother = sother
7187 dother = sother
7197 if source != dest or (sbranch is not None and sbranch != dbranch):
7188 if source != dest or (sbranch is not None and sbranch != dbranch):
7198 common = None
7189 common = None
7199 else:
7190 else:
7200 common = commoninc
7191 common = commoninc
7201 if revs:
7192 if revs:
7202 revs = [repo.lookup(rev) for rev in revs]
7193 revs = [repo.lookup(rev) for rev in revs]
7203 repo.ui.pushbuffer()
7194 repo.ui.pushbuffer()
7204 outgoing = discovery.findcommonoutgoing(
7195 outgoing = discovery.findcommonoutgoing(
7205 repo, dother, onlyheads=revs, commoninc=common
7196 repo, dother, onlyheads=revs, commoninc=common
7206 )
7197 )
7207 repo.ui.popbuffer()
7198 repo.ui.popbuffer()
7208 return dest, dbranch, dother, outgoing
7199 return dest, dbranch, dother, outgoing
7209
7200
7210 if needsoutgoing:
7201 if needsoutgoing:
7211 dest, dbranch, dother, outgoing = getoutgoing()
7202 dest, dbranch, dother, outgoing = getoutgoing()
7212 else:
7203 else:
7213 dest = dbranch = dother = outgoing = None
7204 dest = dbranch = dother = outgoing = None
7214
7205
7215 if opts.get(b'remote'):
7206 if opts.get(b'remote'):
7216 t = []
7207 t = []
7217 if incoming:
7208 if incoming:
7218 t.append(_(b'1 or more incoming'))
7209 t.append(_(b'1 or more incoming'))
7219 o = outgoing.missing
7210 o = outgoing.missing
7220 if o:
7211 if o:
7221 t.append(_(b'%d outgoing') % len(o))
7212 t.append(_(b'%d outgoing') % len(o))
7222 other = dother or sother
7213 other = dother or sother
7223 if b'bookmarks' in other.listkeys(b'namespaces'):
7214 if b'bookmarks' in other.listkeys(b'namespaces'):
7224 counts = bookmarks.summary(repo, other)
7215 counts = bookmarks.summary(repo, other)
7225 if counts[0] > 0:
7216 if counts[0] > 0:
7226 t.append(_(b'%d incoming bookmarks') % counts[0])
7217 t.append(_(b'%d incoming bookmarks') % counts[0])
7227 if counts[1] > 0:
7218 if counts[1] > 0:
7228 t.append(_(b'%d outgoing bookmarks') % counts[1])
7219 t.append(_(b'%d outgoing bookmarks') % counts[1])
7229
7220
7230 if t:
7221 if t:
7231 # i18n: column positioning for "hg summary"
7222 # i18n: column positioning for "hg summary"
7232 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7223 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7233 else:
7224 else:
7234 # i18n: column positioning for "hg summary"
7225 # i18n: column positioning for "hg summary"
7235 ui.status(_(b'remote: (synced)\n'))
7226 ui.status(_(b'remote: (synced)\n'))
7236
7227
7237 cmdutil.summaryremotehooks(
7228 cmdutil.summaryremotehooks(
7238 ui,
7229 ui,
7239 repo,
7230 repo,
7240 opts,
7231 opts,
7241 (
7232 (
7242 (source, sbranch, sother, commoninc),
7233 (source, sbranch, sother, commoninc),
7243 (dest, dbranch, dother, outgoing),
7234 (dest, dbranch, dother, outgoing),
7244 ),
7235 ),
7245 )
7236 )
7246
7237
7247
7238
7248 @command(
7239 @command(
7249 b'tag',
7240 b'tag',
7250 [
7241 [
7251 (b'f', b'force', None, _(b'force tag')),
7242 (b'f', b'force', None, _(b'force tag')),
7252 (b'l', b'local', None, _(b'make the tag local')),
7243 (b'l', b'local', None, _(b'make the tag local')),
7253 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7244 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7254 (b'', b'remove', None, _(b'remove a tag')),
7245 (b'', b'remove', None, _(b'remove a tag')),
7255 # -l/--local is already there, commitopts cannot be used
7246 # -l/--local is already there, commitopts cannot be used
7256 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7247 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7257 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7248 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7258 ]
7249 ]
7259 + commitopts2,
7250 + commitopts2,
7260 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7251 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7261 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7252 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7262 )
7253 )
7263 def tag(ui, repo, name1, *names, **opts):
7254 def tag(ui, repo, name1, *names, **opts):
7264 """add one or more tags for the current or given revision
7255 """add one or more tags for the current or given revision
7265
7256
7266 Name a particular revision using <name>.
7257 Name a particular revision using <name>.
7267
7258
7268 Tags are used to name particular revisions of the repository and are
7259 Tags are used to name particular revisions of the repository and are
7269 very useful to compare different revisions, to go back to significant
7260 very useful to compare different revisions, to go back to significant
7270 earlier versions or to mark branch points as releases, etc. Changing
7261 earlier versions or to mark branch points as releases, etc. Changing
7271 an existing tag is normally disallowed; use -f/--force to override.
7262 an existing tag is normally disallowed; use -f/--force to override.
7272
7263
7273 If no revision is given, the parent of the working directory is
7264 If no revision is given, the parent of the working directory is
7274 used.
7265 used.
7275
7266
7276 To facilitate version control, distribution, and merging of tags,
7267 To facilitate version control, distribution, and merging of tags,
7277 they are stored as a file named ".hgtags" which is managed similarly
7268 they are stored as a file named ".hgtags" which is managed similarly
7278 to other project files and can be hand-edited if necessary. This
7269 to other project files and can be hand-edited if necessary. This
7279 also means that tagging creates a new commit. The file
7270 also means that tagging creates a new commit. The file
7280 ".hg/localtags" is used for local tags (not shared among
7271 ".hg/localtags" is used for local tags (not shared among
7281 repositories).
7272 repositories).
7282
7273
7283 Tag commits are usually made at the head of a branch. If the parent
7274 Tag commits are usually made at the head of a branch. If the parent
7284 of the working directory is not a branch head, :hg:`tag` aborts; use
7275 of the working directory is not a branch head, :hg:`tag` aborts; use
7285 -f/--force to force the tag commit to be based on a non-head
7276 -f/--force to force the tag commit to be based on a non-head
7286 changeset.
7277 changeset.
7287
7278
7288 See :hg:`help dates` for a list of formats valid for -d/--date.
7279 See :hg:`help dates` for a list of formats valid for -d/--date.
7289
7280
7290 Since tag names have priority over branch names during revision
7281 Since tag names have priority over branch names during revision
7291 lookup, using an existing branch name as a tag name is discouraged.
7282 lookup, using an existing branch name as a tag name is discouraged.
7292
7283
7293 Returns 0 on success.
7284 Returns 0 on success.
7294 """
7285 """
7295 opts = pycompat.byteskwargs(opts)
7286 opts = pycompat.byteskwargs(opts)
7296 with repo.wlock(), repo.lock():
7287 with repo.wlock(), repo.lock():
7297 rev_ = b"."
7288 rev_ = b"."
7298 names = [t.strip() for t in (name1,) + names]
7289 names = [t.strip() for t in (name1,) + names]
7299 if len(names) != len(set(names)):
7290 if len(names) != len(set(names)):
7300 raise error.Abort(_(b'tag names must be unique'))
7291 raise error.Abort(_(b'tag names must be unique'))
7301 for n in names:
7292 for n in names:
7302 scmutil.checknewlabel(repo, n, b'tag')
7293 scmutil.checknewlabel(repo, n, b'tag')
7303 if not n:
7294 if not n:
7304 raise error.Abort(
7295 raise error.Abort(
7305 _(b'tag names cannot consist entirely of whitespace')
7296 _(b'tag names cannot consist entirely of whitespace')
7306 )
7297 )
7307 if opts.get(b'rev') and opts.get(b'remove'):
7298 if opts.get(b'rev') and opts.get(b'remove'):
7308 raise error.Abort(_(b"--rev and --remove are incompatible"))
7299 raise error.Abort(_(b"--rev and --remove are incompatible"))
7309 if opts.get(b'rev'):
7300 if opts.get(b'rev'):
7310 rev_ = opts[b'rev']
7301 rev_ = opts[b'rev']
7311 message = opts.get(b'message')
7302 message = opts.get(b'message')
7312 if opts.get(b'remove'):
7303 if opts.get(b'remove'):
7313 if opts.get(b'local'):
7304 if opts.get(b'local'):
7314 expectedtype = b'local'
7305 expectedtype = b'local'
7315 else:
7306 else:
7316 expectedtype = b'global'
7307 expectedtype = b'global'
7317
7308
7318 for n in names:
7309 for n in names:
7319 if repo.tagtype(n) == b'global':
7310 if repo.tagtype(n) == b'global':
7320 alltags = tagsmod.findglobaltags(ui, repo)
7311 alltags = tagsmod.findglobaltags(ui, repo)
7321 if alltags[n][0] == nullid:
7312 if alltags[n][0] == nullid:
7322 raise error.Abort(_(b"tag '%s' is already removed") % n)
7313 raise error.Abort(_(b"tag '%s' is already removed") % n)
7323 if not repo.tagtype(n):
7314 if not repo.tagtype(n):
7324 raise error.Abort(_(b"tag '%s' does not exist") % n)
7315 raise error.Abort(_(b"tag '%s' does not exist") % n)
7325 if repo.tagtype(n) != expectedtype:
7316 if repo.tagtype(n) != expectedtype:
7326 if expectedtype == b'global':
7317 if expectedtype == b'global':
7327 raise error.Abort(
7318 raise error.Abort(
7328 _(b"tag '%s' is not a global tag") % n
7319 _(b"tag '%s' is not a global tag") % n
7329 )
7320 )
7330 else:
7321 else:
7331 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7322 raise error.Abort(_(b"tag '%s' is not a local tag") % n)
7332 rev_ = b'null'
7323 rev_ = b'null'
7333 if not message:
7324 if not message:
7334 # we don't translate commit messages
7325 # we don't translate commit messages
7335 message = b'Removed tag %s' % b', '.join(names)
7326 message = b'Removed tag %s' % b', '.join(names)
7336 elif not opts.get(b'force'):
7327 elif not opts.get(b'force'):
7337 for n in names:
7328 for n in names:
7338 if n in repo.tags():
7329 if n in repo.tags():
7339 raise error.Abort(
7330 raise error.Abort(
7340 _(b"tag '%s' already exists (use -f to force)") % n
7331 _(b"tag '%s' already exists (use -f to force)") % n
7341 )
7332 )
7342 if not opts.get(b'local'):
7333 if not opts.get(b'local'):
7343 p1, p2 = repo.dirstate.parents()
7334 p1, p2 = repo.dirstate.parents()
7344 if p2 != nullid:
7335 if p2 != nullid:
7345 raise error.Abort(_(b'uncommitted merge'))
7336 raise error.Abort(_(b'uncommitted merge'))
7346 bheads = repo.branchheads()
7337 bheads = repo.branchheads()
7347 if not opts.get(b'force') and bheads and p1 not in bheads:
7338 if not opts.get(b'force') and bheads and p1 not in bheads:
7348 raise error.Abort(
7339 raise error.Abort(
7349 _(
7340 _(
7350 b'working directory is not at a branch head '
7341 b'working directory is not at a branch head '
7351 b'(use -f to force)'
7342 b'(use -f to force)'
7352 )
7343 )
7353 )
7344 )
7354 node = scmutil.revsingle(repo, rev_).node()
7345 node = scmutil.revsingle(repo, rev_).node()
7355
7346
7356 if not message:
7347 if not message:
7357 # we don't translate commit messages
7348 # we don't translate commit messages
7358 message = b'Added tag %s for changeset %s' % (
7349 message = b'Added tag %s for changeset %s' % (
7359 b', '.join(names),
7350 b', '.join(names),
7360 short(node),
7351 short(node),
7361 )
7352 )
7362
7353
7363 date = opts.get(b'date')
7354 date = opts.get(b'date')
7364 if date:
7355 if date:
7365 date = dateutil.parsedate(date)
7356 date = dateutil.parsedate(date)
7366
7357
7367 if opts.get(b'remove'):
7358 if opts.get(b'remove'):
7368 editform = b'tag.remove'
7359 editform = b'tag.remove'
7369 else:
7360 else:
7370 editform = b'tag.add'
7361 editform = b'tag.add'
7371 editor = cmdutil.getcommiteditor(
7362 editor = cmdutil.getcommiteditor(
7372 editform=editform, **pycompat.strkwargs(opts)
7363 editform=editform, **pycompat.strkwargs(opts)
7373 )
7364 )
7374
7365
7375 # don't allow tagging the null rev
7366 # don't allow tagging the null rev
7376 if (
7367 if (
7377 not opts.get(b'remove')
7368 not opts.get(b'remove')
7378 and scmutil.revsingle(repo, rev_).rev() == nullrev
7369 and scmutil.revsingle(repo, rev_).rev() == nullrev
7379 ):
7370 ):
7380 raise error.Abort(_(b"cannot tag null revision"))
7371 raise error.Abort(_(b"cannot tag null revision"))
7381
7372
7382 tagsmod.tag(
7373 tagsmod.tag(
7383 repo,
7374 repo,
7384 names,
7375 names,
7385 node,
7376 node,
7386 message,
7377 message,
7387 opts.get(b'local'),
7378 opts.get(b'local'),
7388 opts.get(b'user'),
7379 opts.get(b'user'),
7389 date,
7380 date,
7390 editor=editor,
7381 editor=editor,
7391 )
7382 )
7392
7383
7393
7384
7394 @command(
7385 @command(
7395 b'tags',
7386 b'tags',
7396 formatteropts,
7387 formatteropts,
7397 b'',
7388 b'',
7398 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7389 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7399 intents={INTENT_READONLY},
7390 intents={INTENT_READONLY},
7400 )
7391 )
7401 def tags(ui, repo, **opts):
7392 def tags(ui, repo, **opts):
7402 """list repository tags
7393 """list repository tags
7403
7394
7404 This lists both regular and local tags. When the -v/--verbose
7395 This lists both regular and local tags. When the -v/--verbose
7405 switch is used, a third column "local" is printed for local tags.
7396 switch is used, a third column "local" is printed for local tags.
7406 When the -q/--quiet switch is used, only the tag name is printed.
7397 When the -q/--quiet switch is used, only the tag name is printed.
7407
7398
7408 .. container:: verbose
7399 .. container:: verbose
7409
7400
7410 Template:
7401 Template:
7411
7402
7412 The following keywords are supported in addition to the common template
7403 The following keywords are supported in addition to the common template
7413 keywords and functions such as ``{tag}``. See also
7404 keywords and functions such as ``{tag}``. See also
7414 :hg:`help templates`.
7405 :hg:`help templates`.
7415
7406
7416 :type: String. ``local`` for local tags.
7407 :type: String. ``local`` for local tags.
7417
7408
7418 Returns 0 on success.
7409 Returns 0 on success.
7419 """
7410 """
7420
7411
7421 opts = pycompat.byteskwargs(opts)
7412 opts = pycompat.byteskwargs(opts)
7422 ui.pager(b'tags')
7413 ui.pager(b'tags')
7423 fm = ui.formatter(b'tags', opts)
7414 fm = ui.formatter(b'tags', opts)
7424 hexfunc = fm.hexfunc
7415 hexfunc = fm.hexfunc
7425
7416
7426 for t, n in reversed(repo.tagslist()):
7417 for t, n in reversed(repo.tagslist()):
7427 hn = hexfunc(n)
7418 hn = hexfunc(n)
7428 label = b'tags.normal'
7419 label = b'tags.normal'
7429 tagtype = b''
7420 tagtype = b''
7430 if repo.tagtype(t) == b'local':
7421 if repo.tagtype(t) == b'local':
7431 label = b'tags.local'
7422 label = b'tags.local'
7432 tagtype = b'local'
7423 tagtype = b'local'
7433
7424
7434 fm.startitem()
7425 fm.startitem()
7435 fm.context(repo=repo)
7426 fm.context(repo=repo)
7436 fm.write(b'tag', b'%s', t, label=label)
7427 fm.write(b'tag', b'%s', t, label=label)
7437 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7428 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7438 fm.condwrite(
7429 fm.condwrite(
7439 not ui.quiet,
7430 not ui.quiet,
7440 b'rev node',
7431 b'rev node',
7441 fmt,
7432 fmt,
7442 repo.changelog.rev(n),
7433 repo.changelog.rev(n),
7443 hn,
7434 hn,
7444 label=label,
7435 label=label,
7445 )
7436 )
7446 fm.condwrite(
7437 fm.condwrite(
7447 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7438 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7448 )
7439 )
7449 fm.plain(b'\n')
7440 fm.plain(b'\n')
7450 fm.end()
7441 fm.end()
7451
7442
7452
7443
7453 @command(
7444 @command(
7454 b'tip',
7445 b'tip',
7455 [
7446 [
7456 (b'p', b'patch', None, _(b'show patch')),
7447 (b'p', b'patch', None, _(b'show patch')),
7457 (b'g', b'git', None, _(b'use git extended diff format')),
7448 (b'g', b'git', None, _(b'use git extended diff format')),
7458 ]
7449 ]
7459 + templateopts,
7450 + templateopts,
7460 _(b'[-p] [-g]'),
7451 _(b'[-p] [-g]'),
7461 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7452 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7462 )
7453 )
7463 def tip(ui, repo, **opts):
7454 def tip(ui, repo, **opts):
7464 """show the tip revision (DEPRECATED)
7455 """show the tip revision (DEPRECATED)
7465
7456
7466 The tip revision (usually just called the tip) is the changeset
7457 The tip revision (usually just called the tip) is the changeset
7467 most recently added to the repository (and therefore the most
7458 most recently added to the repository (and therefore the most
7468 recently changed head).
7459 recently changed head).
7469
7460
7470 If you have just made a commit, that commit will be the tip. If
7461 If you have just made a commit, that commit will be the tip. If
7471 you have just pulled changes from another repository, the tip of
7462 you have just pulled changes from another repository, the tip of
7472 that repository becomes the current tip. The "tip" tag is special
7463 that repository becomes the current tip. The "tip" tag is special
7473 and cannot be renamed or assigned to a different changeset.
7464 and cannot be renamed or assigned to a different changeset.
7474
7465
7475 This command is deprecated, please use :hg:`heads` instead.
7466 This command is deprecated, please use :hg:`heads` instead.
7476
7467
7477 Returns 0 on success.
7468 Returns 0 on success.
7478 """
7469 """
7479 opts = pycompat.byteskwargs(opts)
7470 opts = pycompat.byteskwargs(opts)
7480 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7471 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7481 displayer.show(repo[b'tip'])
7472 displayer.show(repo[b'tip'])
7482 displayer.close()
7473 displayer.close()
7483
7474
7484
7475
7485 @command(
7476 @command(
7486 b'unbundle',
7477 b'unbundle',
7487 [
7478 [
7488 (
7479 (
7489 b'u',
7480 b'u',
7490 b'update',
7481 b'update',
7491 None,
7482 None,
7492 _(b'update to new branch head if changesets were unbundled'),
7483 _(b'update to new branch head if changesets were unbundled'),
7493 )
7484 )
7494 ],
7485 ],
7495 _(b'[-u] FILE...'),
7486 _(b'[-u] FILE...'),
7496 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7487 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7497 )
7488 )
7498 def unbundle(ui, repo, fname1, *fnames, **opts):
7489 def unbundle(ui, repo, fname1, *fnames, **opts):
7499 """apply one or more bundle files
7490 """apply one or more bundle files
7500
7491
7501 Apply one or more bundle files generated by :hg:`bundle`.
7492 Apply one or more bundle files generated by :hg:`bundle`.
7502
7493
7503 Returns 0 on success, 1 if an update has unresolved files.
7494 Returns 0 on success, 1 if an update has unresolved files.
7504 """
7495 """
7505 fnames = (fname1,) + fnames
7496 fnames = (fname1,) + fnames
7506
7497
7507 with repo.lock():
7498 with repo.lock():
7508 for fname in fnames:
7499 for fname in fnames:
7509 f = hg.openpath(ui, fname)
7500 f = hg.openpath(ui, fname)
7510 gen = exchange.readbundle(ui, f, fname)
7501 gen = exchange.readbundle(ui, f, fname)
7511 if isinstance(gen, streamclone.streamcloneapplier):
7502 if isinstance(gen, streamclone.streamcloneapplier):
7512 raise error.Abort(
7503 raise error.Abort(
7513 _(
7504 _(
7514 b'packed bundles cannot be applied with '
7505 b'packed bundles cannot be applied with '
7515 b'"hg unbundle"'
7506 b'"hg unbundle"'
7516 ),
7507 ),
7517 hint=_(b'use "hg debugapplystreamclonebundle"'),
7508 hint=_(b'use "hg debugapplystreamclonebundle"'),
7518 )
7509 )
7519 url = b'bundle:' + fname
7510 url = b'bundle:' + fname
7520 try:
7511 try:
7521 txnname = b'unbundle'
7512 txnname = b'unbundle'
7522 if not isinstance(gen, bundle2.unbundle20):
7513 if not isinstance(gen, bundle2.unbundle20):
7523 txnname = b'unbundle\n%s' % util.hidepassword(url)
7514 txnname = b'unbundle\n%s' % util.hidepassword(url)
7524 with repo.transaction(txnname) as tr:
7515 with repo.transaction(txnname) as tr:
7525 op = bundle2.applybundle(
7516 op = bundle2.applybundle(
7526 repo, gen, tr, source=b'unbundle', url=url
7517 repo, gen, tr, source=b'unbundle', url=url
7527 )
7518 )
7528 except error.BundleUnknownFeatureError as exc:
7519 except error.BundleUnknownFeatureError as exc:
7529 raise error.Abort(
7520 raise error.Abort(
7530 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7521 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7531 hint=_(
7522 hint=_(
7532 b"see https://mercurial-scm.org/"
7523 b"see https://mercurial-scm.org/"
7533 b"wiki/BundleFeature for more "
7524 b"wiki/BundleFeature for more "
7534 b"information"
7525 b"information"
7535 ),
7526 ),
7536 )
7527 )
7537 modheads = bundle2.combinechangegroupresults(op)
7528 modheads = bundle2.combinechangegroupresults(op)
7538
7529
7539 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7530 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7540
7531
7541
7532
7542 @command(
7533 @command(
7543 b'unshelve',
7534 b'unshelve',
7544 [
7535 [
7545 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7536 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7546 (
7537 (
7547 b'c',
7538 b'c',
7548 b'continue',
7539 b'continue',
7549 None,
7540 None,
7550 _(b'continue an incomplete unshelve operation'),
7541 _(b'continue an incomplete unshelve operation'),
7551 ),
7542 ),
7552 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7543 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7553 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7544 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7554 (
7545 (
7555 b'n',
7546 b'n',
7556 b'name',
7547 b'name',
7557 b'',
7548 b'',
7558 _(b'restore shelved change with given name'),
7549 _(b'restore shelved change with given name'),
7559 _(b'NAME'),
7550 _(b'NAME'),
7560 ),
7551 ),
7561 (b't', b'tool', b'', _(b'specify merge tool')),
7552 (b't', b'tool', b'', _(b'specify merge tool')),
7562 (
7553 (
7563 b'',
7554 b'',
7564 b'date',
7555 b'date',
7565 b'',
7556 b'',
7566 _(b'set date for temporary commits (DEPRECATED)'),
7557 _(b'set date for temporary commits (DEPRECATED)'),
7567 _(b'DATE'),
7558 _(b'DATE'),
7568 ),
7559 ),
7569 ],
7560 ],
7570 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7561 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7571 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7562 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7572 )
7563 )
7573 def unshelve(ui, repo, *shelved, **opts):
7564 def unshelve(ui, repo, *shelved, **opts):
7574 """restore a shelved change to the working directory
7565 """restore a shelved change to the working directory
7575
7566
7576 This command accepts an optional name of a shelved change to
7567 This command accepts an optional name of a shelved change to
7577 restore. If none is given, the most recent shelved change is used.
7568 restore. If none is given, the most recent shelved change is used.
7578
7569
7579 If a shelved change is applied successfully, the bundle that
7570 If a shelved change is applied successfully, the bundle that
7580 contains the shelved changes is moved to a backup location
7571 contains the shelved changes is moved to a backup location
7581 (.hg/shelve-backup).
7572 (.hg/shelve-backup).
7582
7573
7583 Since you can restore a shelved change on top of an arbitrary
7574 Since you can restore a shelved change on top of an arbitrary
7584 commit, it is possible that unshelving will result in a conflict
7575 commit, it is possible that unshelving will result in a conflict
7585 between your changes and the commits you are unshelving onto. If
7576 between your changes and the commits you are unshelving onto. If
7586 this occurs, you must resolve the conflict, then use
7577 this occurs, you must resolve the conflict, then use
7587 ``--continue`` to complete the unshelve operation. (The bundle
7578 ``--continue`` to complete the unshelve operation. (The bundle
7588 will not be moved until you successfully complete the unshelve.)
7579 will not be moved until you successfully complete the unshelve.)
7589
7580
7590 (Alternatively, you can use ``--abort`` to abandon an unshelve
7581 (Alternatively, you can use ``--abort`` to abandon an unshelve
7591 that causes a conflict. This reverts the unshelved changes, and
7582 that causes a conflict. This reverts the unshelved changes, and
7592 leaves the bundle in place.)
7583 leaves the bundle in place.)
7593
7584
7594 If bare shelved change (without interactive, include and exclude
7585 If bare shelved change (without interactive, include and exclude
7595 option) was done on newly created branch it would restore branch
7586 option) was done on newly created branch it would restore branch
7596 information to the working directory.
7587 information to the working directory.
7597
7588
7598 After a successful unshelve, the shelved changes are stored in a
7589 After a successful unshelve, the shelved changes are stored in a
7599 backup directory. Only the N most recent backups are kept. N
7590 backup directory. Only the N most recent backups are kept. N
7600 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7591 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7601 configuration option.
7592 configuration option.
7602
7593
7603 .. container:: verbose
7594 .. container:: verbose
7604
7595
7605 Timestamp in seconds is used to decide order of backups. More
7596 Timestamp in seconds is used to decide order of backups. More
7606 than ``maxbackups`` backups are kept, if same timestamp
7597 than ``maxbackups`` backups are kept, if same timestamp
7607 prevents from deciding exact order of them, for safety.
7598 prevents from deciding exact order of them, for safety.
7608
7599
7609 Selected changes can be unshelved with ``--interactive`` flag.
7600 Selected changes can be unshelved with ``--interactive`` flag.
7610 The working directory is updated with the selected changes, and
7601 The working directory is updated with the selected changes, and
7611 only the unselected changes remain shelved.
7602 only the unselected changes remain shelved.
7612 Note: The whole shelve is applied to working directory first before
7603 Note: The whole shelve is applied to working directory first before
7613 running interactively. So, this will bring up all the conflicts between
7604 running interactively. So, this will bring up all the conflicts between
7614 working directory and the shelve, irrespective of which changes will be
7605 working directory and the shelve, irrespective of which changes will be
7615 unshelved.
7606 unshelved.
7616 """
7607 """
7617 with repo.wlock():
7608 with repo.wlock():
7618 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7609 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7619
7610
7620
7611
7621 statemod.addunfinished(
7612 statemod.addunfinished(
7622 b'unshelve',
7613 b'unshelve',
7623 fname=b'shelvedstate',
7614 fname=b'shelvedstate',
7624 continueflag=True,
7615 continueflag=True,
7625 abortfunc=shelvemod.hgabortunshelve,
7616 abortfunc=shelvemod.hgabortunshelve,
7626 continuefunc=shelvemod.hgcontinueunshelve,
7617 continuefunc=shelvemod.hgcontinueunshelve,
7627 cmdmsg=_(b'unshelve already in progress'),
7618 cmdmsg=_(b'unshelve already in progress'),
7628 )
7619 )
7629
7620
7630
7621
7631 @command(
7622 @command(
7632 b'update|up|checkout|co',
7623 b'update|up|checkout|co',
7633 [
7624 [
7634 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7625 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7635 (b'c', b'check', None, _(b'require clean working directory')),
7626 (b'c', b'check', None, _(b'require clean working directory')),
7636 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7627 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7637 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7628 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7638 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7629 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7639 ]
7630 ]
7640 + mergetoolopts,
7631 + mergetoolopts,
7641 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7632 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7642 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7633 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7643 helpbasic=True,
7634 helpbasic=True,
7644 )
7635 )
7645 def update(ui, repo, node=None, **opts):
7636 def update(ui, repo, node=None, **opts):
7646 """update working directory (or switch revisions)
7637 """update working directory (or switch revisions)
7647
7638
7648 Update the repository's working directory to the specified
7639 Update the repository's working directory to the specified
7649 changeset. If no changeset is specified, update to the tip of the
7640 changeset. If no changeset is specified, update to the tip of the
7650 current named branch and move the active bookmark (see :hg:`help
7641 current named branch and move the active bookmark (see :hg:`help
7651 bookmarks`).
7642 bookmarks`).
7652
7643
7653 Update sets the working directory's parent revision to the specified
7644 Update sets the working directory's parent revision to the specified
7654 changeset (see :hg:`help parents`).
7645 changeset (see :hg:`help parents`).
7655
7646
7656 If the changeset is not a descendant or ancestor of the working
7647 If the changeset is not a descendant or ancestor of the working
7657 directory's parent and there are uncommitted changes, the update is
7648 directory's parent and there are uncommitted changes, the update is
7658 aborted. With the -c/--check option, the working directory is checked
7649 aborted. With the -c/--check option, the working directory is checked
7659 for uncommitted changes; if none are found, the working directory is
7650 for uncommitted changes; if none are found, the working directory is
7660 updated to the specified changeset.
7651 updated to the specified changeset.
7661
7652
7662 .. container:: verbose
7653 .. container:: verbose
7663
7654
7664 The -C/--clean, -c/--check, and -m/--merge options control what
7655 The -C/--clean, -c/--check, and -m/--merge options control what
7665 happens if the working directory contains uncommitted changes.
7656 happens if the working directory contains uncommitted changes.
7666 At most of one of them can be specified.
7657 At most of one of them can be specified.
7667
7658
7668 1. If no option is specified, and if
7659 1. If no option is specified, and if
7669 the requested changeset is an ancestor or descendant of
7660 the requested changeset is an ancestor or descendant of
7670 the working directory's parent, the uncommitted changes
7661 the working directory's parent, the uncommitted changes
7671 are merged into the requested changeset and the merged
7662 are merged into the requested changeset and the merged
7672 result is left uncommitted. If the requested changeset is
7663 result is left uncommitted. If the requested changeset is
7673 not an ancestor or descendant (that is, it is on another
7664 not an ancestor or descendant (that is, it is on another
7674 branch), the update is aborted and the uncommitted changes
7665 branch), the update is aborted and the uncommitted changes
7675 are preserved.
7666 are preserved.
7676
7667
7677 2. With the -m/--merge option, the update is allowed even if the
7668 2. With the -m/--merge option, the update is allowed even if the
7678 requested changeset is not an ancestor or descendant of
7669 requested changeset is not an ancestor or descendant of
7679 the working directory's parent.
7670 the working directory's parent.
7680
7671
7681 3. With the -c/--check option, the update is aborted and the
7672 3. With the -c/--check option, the update is aborted and the
7682 uncommitted changes are preserved.
7673 uncommitted changes are preserved.
7683
7674
7684 4. With the -C/--clean option, uncommitted changes are discarded and
7675 4. With the -C/--clean option, uncommitted changes are discarded and
7685 the working directory is updated to the requested changeset.
7676 the working directory is updated to the requested changeset.
7686
7677
7687 To cancel an uncommitted merge (and lose your changes), use
7678 To cancel an uncommitted merge (and lose your changes), use
7688 :hg:`merge --abort`.
7679 :hg:`merge --abort`.
7689
7680
7690 Use null as the changeset to remove the working directory (like
7681 Use null as the changeset to remove the working directory (like
7691 :hg:`clone -U`).
7682 :hg:`clone -U`).
7692
7683
7693 If you want to revert just one file to an older revision, use
7684 If you want to revert just one file to an older revision, use
7694 :hg:`revert [-r REV] NAME`.
7685 :hg:`revert [-r REV] NAME`.
7695
7686
7696 See :hg:`help dates` for a list of formats valid for -d/--date.
7687 See :hg:`help dates` for a list of formats valid for -d/--date.
7697
7688
7698 Returns 0 on success, 1 if there are unresolved files.
7689 Returns 0 on success, 1 if there are unresolved files.
7699 """
7690 """
7700 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7691 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7701 rev = opts.get('rev')
7692 rev = opts.get('rev')
7702 date = opts.get('date')
7693 date = opts.get('date')
7703 clean = opts.get('clean')
7694 clean = opts.get('clean')
7704 check = opts.get('check')
7695 check = opts.get('check')
7705 merge = opts.get('merge')
7696 merge = opts.get('merge')
7706 if rev and node:
7697 if rev and node:
7707 raise error.Abort(_(b"please specify just one revision"))
7698 raise error.Abort(_(b"please specify just one revision"))
7708
7699
7709 if ui.configbool(b'commands', b'update.requiredest'):
7700 if ui.configbool(b'commands', b'update.requiredest'):
7710 if not node and not rev and not date:
7701 if not node and not rev and not date:
7711 raise error.Abort(
7702 raise error.Abort(
7712 _(b'you must specify a destination'),
7703 _(b'you must specify a destination'),
7713 hint=_(b'for example: hg update ".::"'),
7704 hint=_(b'for example: hg update ".::"'),
7714 )
7705 )
7715
7706
7716 if rev is None or rev == b'':
7707 if rev is None or rev == b'':
7717 rev = node
7708 rev = node
7718
7709
7719 if date and rev is not None:
7710 if date and rev is not None:
7720 raise error.Abort(_(b"you can't specify a revision and a date"))
7711 raise error.Abort(_(b"you can't specify a revision and a date"))
7721
7712
7722 updatecheck = None
7713 updatecheck = None
7723 if check:
7714 if check:
7724 updatecheck = b'abort'
7715 updatecheck = b'abort'
7725 elif merge:
7716 elif merge:
7726 updatecheck = b'none'
7717 updatecheck = b'none'
7727
7718
7728 with repo.wlock():
7719 with repo.wlock():
7729 cmdutil.clearunfinished(repo)
7720 cmdutil.clearunfinished(repo)
7730 if date:
7721 if date:
7731 rev = cmdutil.finddate(ui, repo, date)
7722 rev = cmdutil.finddate(ui, repo, date)
7732
7723
7733 # if we defined a bookmark, we have to remember the original name
7724 # if we defined a bookmark, we have to remember the original name
7734 brev = rev
7725 brev = rev
7735 if rev:
7726 if rev:
7736 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7727 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7737 ctx = scmutil.revsingle(repo, rev, default=None)
7728 ctx = scmutil.revsingle(repo, rev, default=None)
7738 rev = ctx.rev()
7729 rev = ctx.rev()
7739 hidden = ctx.hidden()
7730 hidden = ctx.hidden()
7740 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7731 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7741 with ui.configoverride(overrides, b'update'):
7732 with ui.configoverride(overrides, b'update'):
7742 ret = hg.updatetotally(
7733 ret = hg.updatetotally(
7743 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7734 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7744 )
7735 )
7745 if hidden:
7736 if hidden:
7746 ctxstr = ctx.hex()[:12]
7737 ctxstr = ctx.hex()[:12]
7747 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7738 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7748
7739
7749 if ctx.obsolete():
7740 if ctx.obsolete():
7750 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7741 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7751 ui.warn(b"(%s)\n" % obsfatemsg)
7742 ui.warn(b"(%s)\n" % obsfatemsg)
7752 return ret
7743 return ret
7753
7744
7754
7745
7755 @command(
7746 @command(
7756 b'verify',
7747 b'verify',
7757 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7748 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7758 helpcategory=command.CATEGORY_MAINTENANCE,
7749 helpcategory=command.CATEGORY_MAINTENANCE,
7759 )
7750 )
7760 def verify(ui, repo, **opts):
7751 def verify(ui, repo, **opts):
7761 """verify the integrity of the repository
7752 """verify the integrity of the repository
7762
7753
7763 Verify the integrity of the current repository.
7754 Verify the integrity of the current repository.
7764
7755
7765 This will perform an extensive check of the repository's
7756 This will perform an extensive check of the repository's
7766 integrity, validating the hashes and checksums of each entry in
7757 integrity, validating the hashes and checksums of each entry in
7767 the changelog, manifest, and tracked files, as well as the
7758 the changelog, manifest, and tracked files, as well as the
7768 integrity of their crosslinks and indices.
7759 integrity of their crosslinks and indices.
7769
7760
7770 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7761 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7771 for more information about recovery from corruption of the
7762 for more information about recovery from corruption of the
7772 repository.
7763 repository.
7773
7764
7774 Returns 0 on success, 1 if errors are encountered.
7765 Returns 0 on success, 1 if errors are encountered.
7775 """
7766 """
7776 opts = pycompat.byteskwargs(opts)
7767 opts = pycompat.byteskwargs(opts)
7777
7768
7778 level = None
7769 level = None
7779 if opts[b'full']:
7770 if opts[b'full']:
7780 level = verifymod.VERIFY_FULL
7771 level = verifymod.VERIFY_FULL
7781 return hg.verify(repo, level)
7772 return hg.verify(repo, level)
7782
7773
7783
7774
7784 @command(
7775 @command(
7785 b'version',
7776 b'version',
7786 [] + formatteropts,
7777 [] + formatteropts,
7787 helpcategory=command.CATEGORY_HELP,
7778 helpcategory=command.CATEGORY_HELP,
7788 norepo=True,
7779 norepo=True,
7789 intents={INTENT_READONLY},
7780 intents={INTENT_READONLY},
7790 )
7781 )
7791 def version_(ui, **opts):
7782 def version_(ui, **opts):
7792 """output version and copyright information
7783 """output version and copyright information
7793
7784
7794 .. container:: verbose
7785 .. container:: verbose
7795
7786
7796 Template:
7787 Template:
7797
7788
7798 The following keywords are supported. See also :hg:`help templates`.
7789 The following keywords are supported. See also :hg:`help templates`.
7799
7790
7800 :extensions: List of extensions.
7791 :extensions: List of extensions.
7801 :ver: String. Version number.
7792 :ver: String. Version number.
7802
7793
7803 And each entry of ``{extensions}`` provides the following sub-keywords
7794 And each entry of ``{extensions}`` provides the following sub-keywords
7804 in addition to ``{ver}``.
7795 in addition to ``{ver}``.
7805
7796
7806 :bundled: Boolean. True if included in the release.
7797 :bundled: Boolean. True if included in the release.
7807 :name: String. Extension name.
7798 :name: String. Extension name.
7808 """
7799 """
7809 opts = pycompat.byteskwargs(opts)
7800 opts = pycompat.byteskwargs(opts)
7810 if ui.verbose:
7801 if ui.verbose:
7811 ui.pager(b'version')
7802 ui.pager(b'version')
7812 fm = ui.formatter(b"version", opts)
7803 fm = ui.formatter(b"version", opts)
7813 fm.startitem()
7804 fm.startitem()
7814 fm.write(
7805 fm.write(
7815 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7806 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7816 )
7807 )
7817 license = _(
7808 license = _(
7818 b"(see https://mercurial-scm.org for more information)\n"
7809 b"(see https://mercurial-scm.org for more information)\n"
7819 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7810 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7820 b"This is free software; see the source for copying conditions. "
7811 b"This is free software; see the source for copying conditions. "
7821 b"There is NO\nwarranty; "
7812 b"There is NO\nwarranty; "
7822 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7813 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7823 )
7814 )
7824 if not ui.quiet:
7815 if not ui.quiet:
7825 fm.plain(license)
7816 fm.plain(license)
7826
7817
7827 if ui.verbose:
7818 if ui.verbose:
7828 fm.plain(_(b"\nEnabled extensions:\n\n"))
7819 fm.plain(_(b"\nEnabled extensions:\n\n"))
7829 # format names and versions into columns
7820 # format names and versions into columns
7830 names = []
7821 names = []
7831 vers = []
7822 vers = []
7832 isinternals = []
7823 isinternals = []
7833 for name, module in sorted(extensions.extensions()):
7824 for name, module in sorted(extensions.extensions()):
7834 names.append(name)
7825 names.append(name)
7835 vers.append(extensions.moduleversion(module) or None)
7826 vers.append(extensions.moduleversion(module) or None)
7836 isinternals.append(extensions.ismoduleinternal(module))
7827 isinternals.append(extensions.ismoduleinternal(module))
7837 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7828 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7838 if names:
7829 if names:
7839 namefmt = b" %%-%ds " % max(len(n) for n in names)
7830 namefmt = b" %%-%ds " % max(len(n) for n in names)
7840 places = [_(b"external"), _(b"internal")]
7831 places = [_(b"external"), _(b"internal")]
7841 for n, v, p in zip(names, vers, isinternals):
7832 for n, v, p in zip(names, vers, isinternals):
7842 fn.startitem()
7833 fn.startitem()
7843 fn.condwrite(ui.verbose, b"name", namefmt, n)
7834 fn.condwrite(ui.verbose, b"name", namefmt, n)
7844 if ui.verbose:
7835 if ui.verbose:
7845 fn.plain(b"%s " % places[p])
7836 fn.plain(b"%s " % places[p])
7846 fn.data(bundled=p)
7837 fn.data(bundled=p)
7847 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7838 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7848 if ui.verbose:
7839 if ui.verbose:
7849 fn.plain(b"\n")
7840 fn.plain(b"\n")
7850 fn.end()
7841 fn.end()
7851 fm.end()
7842 fm.end()
7852
7843
7853
7844
7854 def loadcmdtable(ui, name, cmdtable):
7845 def loadcmdtable(ui, name, cmdtable):
7855 """Load command functions from specified cmdtable
7846 """Load command functions from specified cmdtable
7856 """
7847 """
7857 overrides = [cmd for cmd in cmdtable if cmd in table]
7848 overrides = [cmd for cmd in cmdtable if cmd in table]
7858 if overrides:
7849 if overrides:
7859 ui.warn(
7850 ui.warn(
7860 _(b"extension '%s' overrides commands: %s\n")
7851 _(b"extension '%s' overrides commands: %s\n")
7861 % (name, b" ".join(overrides))
7852 % (name, b" ".join(overrides))
7862 )
7853 )
7863 table.update(cmdtable)
7854 table.update(cmdtable)
@@ -1,771 +1,771 b''
1 #testcases abortcommand abortflag
1 #testcases abortcommand abortflag
2
2
3 #if abortflag
3 #if abortflag
4 $ cat >> $HGRCPATH <<EOF
4 $ cat >> $HGRCPATH <<EOF
5 > [alias]
5 > [alias]
6 > abort = graft --abort
6 > abort = graft --abort
7 > EOF
7 > EOF
8 #endif
8 #endif
9
9
10
10
11 Testing the reading of old format graftstate file with newer mercurial
11 Testing the reading of old format graftstate file with newer mercurial
12
12
13 $ hg init oldgraft
13 $ hg init oldgraft
14 $ cd oldgraft
14 $ cd oldgraft
15 $ for ch in a b c; do echo foo > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
15 $ for ch in a b c; do echo foo > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
16 $ hg log -GT "{rev}:{node|short} {desc}\n"
16 $ hg log -GT "{rev}:{node|short} {desc}\n"
17 @ 2:8be98ac1a569 added c
17 @ 2:8be98ac1a569 added c
18 |
18 |
19 o 1:80e6d2c47cfe added b
19 o 1:80e6d2c47cfe added b
20 |
20 |
21 o 0:f7ad41964313 added a
21 o 0:f7ad41964313 added a
22
22
23 $ hg up 0
23 $ hg up 0
24 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
24 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
25 $ echo bar > b
25 $ echo bar > b
26 $ hg add b
26 $ hg add b
27 $ hg ci -m "bar to b"
27 $ hg ci -m "bar to b"
28 created new head
28 created new head
29 $ hg graft -r 1 -r 2
29 $ hg graft -r 1 -r 2
30 grafting 1:80e6d2c47cfe "added b"
30 grafting 1:80e6d2c47cfe "added b"
31 merging b
31 merging b
32 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
32 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
33 abort: unresolved conflicts, can't continue
33 abort: unresolved conflicts, can't continue
34 (use 'hg resolve' and 'hg graft --continue')
34 (use 'hg resolve' and 'hg graft --continue')
35 [1]
35 [1]
36
36
37 Writing the nodes in old format to graftstate
37 Writing the nodes in old format to graftstate
38
38
39 $ hg log -r 1 -r 2 -T '{node}\n' > .hg/graftstate
39 $ hg log -r 1 -r 2 -T '{node}\n' > .hg/graftstate
40 $ echo foo > b
40 $ echo foo > b
41 $ hg resolve -m
41 $ hg resolve -m
42 (no more unresolved files)
42 (no more unresolved files)
43 continue: hg graft --continue
43 continue: hg graft --continue
44 $ hg graft --continue
44 $ hg graft --continue
45 grafting 1:80e6d2c47cfe "added b"
45 grafting 1:80e6d2c47cfe "added b"
46 grafting 2:8be98ac1a569 "added c"
46 grafting 2:8be98ac1a569 "added c"
47
47
48 Testing that --user is preserved during conflicts and value is reused while
48 Testing that --user is preserved during conflicts and value is reused while
49 running `hg graft --continue`
49 running `hg graft --continue`
50
50
51 $ hg log -G
51 $ hg log -G
52 @ changeset: 5:711e9fa999f1
52 @ changeset: 5:711e9fa999f1
53 | tag: tip
53 | tag: tip
54 | user: test
54 | user: test
55 | date: Thu Jan 01 00:00:00 1970 +0000
55 | date: Thu Jan 01 00:00:00 1970 +0000
56 | summary: added c
56 | summary: added c
57 |
57 |
58 o changeset: 4:e5ad7353b408
58 o changeset: 4:e5ad7353b408
59 | user: test
59 | user: test
60 | date: Thu Jan 01 00:00:00 1970 +0000
60 | date: Thu Jan 01 00:00:00 1970 +0000
61 | summary: added b
61 | summary: added b
62 |
62 |
63 o changeset: 3:9e887f7a939c
63 o changeset: 3:9e887f7a939c
64 | parent: 0:f7ad41964313
64 | parent: 0:f7ad41964313
65 | user: test
65 | user: test
66 | date: Thu Jan 01 00:00:00 1970 +0000
66 | date: Thu Jan 01 00:00:00 1970 +0000
67 | summary: bar to b
67 | summary: bar to b
68 |
68 |
69 | o changeset: 2:8be98ac1a569
69 | o changeset: 2:8be98ac1a569
70 | | user: test
70 | | user: test
71 | | date: Thu Jan 01 00:00:00 1970 +0000
71 | | date: Thu Jan 01 00:00:00 1970 +0000
72 | | summary: added c
72 | | summary: added c
73 | |
73 | |
74 | o changeset: 1:80e6d2c47cfe
74 | o changeset: 1:80e6d2c47cfe
75 |/ user: test
75 |/ user: test
76 | date: Thu Jan 01 00:00:00 1970 +0000
76 | date: Thu Jan 01 00:00:00 1970 +0000
77 | summary: added b
77 | summary: added b
78 |
78 |
79 o changeset: 0:f7ad41964313
79 o changeset: 0:f7ad41964313
80 user: test
80 user: test
81 date: Thu Jan 01 00:00:00 1970 +0000
81 date: Thu Jan 01 00:00:00 1970 +0000
82 summary: added a
82 summary: added a
83
83
84
84
85 $ hg up '.^^'
85 $ hg up '.^^'
86 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
86 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
87
87
88 $ hg graft -r 1 -r 2 --user batman
88 $ hg graft -r 1 -r 2 --user batman
89 grafting 1:80e6d2c47cfe "added b"
89 grafting 1:80e6d2c47cfe "added b"
90 merging b
90 merging b
91 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
91 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
92 abort: unresolved conflicts, can't continue
92 abort: unresolved conflicts, can't continue
93 (use 'hg resolve' and 'hg graft --continue')
93 (use 'hg resolve' and 'hg graft --continue')
94 [1]
94 [1]
95
95
96 $ echo wat > b
96 $ echo wat > b
97 $ hg resolve -m
97 $ hg resolve -m
98 (no more unresolved files)
98 (no more unresolved files)
99 continue: hg graft --continue
99 continue: hg graft --continue
100
100
101 $ hg graft --continue
101 $ hg graft --continue
102 grafting 1:80e6d2c47cfe "added b"
102 grafting 1:80e6d2c47cfe "added b"
103 grafting 2:8be98ac1a569 "added c"
103 grafting 2:8be98ac1a569 "added c"
104
104
105 $ hg log -Gr 3::
105 $ hg log -Gr 3::
106 @ changeset: 7:11a36ffaacf2
106 @ changeset: 7:11a36ffaacf2
107 | tag: tip
107 | tag: tip
108 | user: batman
108 | user: batman
109 | date: Thu Jan 01 00:00:00 1970 +0000
109 | date: Thu Jan 01 00:00:00 1970 +0000
110 | summary: added c
110 | summary: added c
111 |
111 |
112 o changeset: 6:76803afc6511
112 o changeset: 6:76803afc6511
113 | parent: 3:9e887f7a939c
113 | parent: 3:9e887f7a939c
114 | user: batman
114 | user: batman
115 | date: Thu Jan 01 00:00:00 1970 +0000
115 | date: Thu Jan 01 00:00:00 1970 +0000
116 | summary: added b
116 | summary: added b
117 |
117 |
118 | o changeset: 5:711e9fa999f1
118 | o changeset: 5:711e9fa999f1
119 | | user: test
119 | | user: test
120 | | date: Thu Jan 01 00:00:00 1970 +0000
120 | | date: Thu Jan 01 00:00:00 1970 +0000
121 | | summary: added c
121 | | summary: added c
122 | |
122 | |
123 | o changeset: 4:e5ad7353b408
123 | o changeset: 4:e5ad7353b408
124 |/ user: test
124 |/ user: test
125 | date: Thu Jan 01 00:00:00 1970 +0000
125 | date: Thu Jan 01 00:00:00 1970 +0000
126 | summary: added b
126 | summary: added b
127 |
127 |
128 o changeset: 3:9e887f7a939c
128 o changeset: 3:9e887f7a939c
129 | parent: 0:f7ad41964313
129 | parent: 0:f7ad41964313
130 ~ user: test
130 ~ user: test
131 date: Thu Jan 01 00:00:00 1970 +0000
131 date: Thu Jan 01 00:00:00 1970 +0000
132 summary: bar to b
132 summary: bar to b
133
133
134 Test that --date is preserved and reused in `hg graft --continue`
134 Test that --date is preserved and reused in `hg graft --continue`
135
135
136 $ hg up '.^^'
136 $ hg up '.^^'
137 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
137 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
138 $ hg graft -r 1 -r 2 --date '1234560000 120'
138 $ hg graft -r 1 -r 2 --date '1234560000 120'
139 grafting 1:80e6d2c47cfe "added b"
139 grafting 1:80e6d2c47cfe "added b"
140 merging b
140 merging b
141 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
141 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
142 abort: unresolved conflicts, can't continue
142 abort: unresolved conflicts, can't continue
143 (use 'hg resolve' and 'hg graft --continue')
143 (use 'hg resolve' and 'hg graft --continue')
144 [1]
144 [1]
145
145
146 $ echo foobar > b
146 $ echo foobar > b
147 $ hg resolve -m
147 $ hg resolve -m
148 (no more unresolved files)
148 (no more unresolved files)
149 continue: hg graft --continue
149 continue: hg graft --continue
150 $ hg graft --continue
150 $ hg graft --continue
151 grafting 1:80e6d2c47cfe "added b"
151 grafting 1:80e6d2c47cfe "added b"
152 grafting 2:8be98ac1a569 "added c"
152 grafting 2:8be98ac1a569 "added c"
153
153
154 $ hg log -Gr '.^^::.'
154 $ hg log -Gr '.^^::.'
155 @ changeset: 9:1896b76e007a
155 @ changeset: 9:1896b76e007a
156 | tag: tip
156 | tag: tip
157 | user: test
157 | user: test
158 | date: Fri Feb 13 21:18:00 2009 -0002
158 | date: Fri Feb 13 21:18:00 2009 -0002
159 | summary: added c
159 | summary: added c
160 |
160 |
161 o changeset: 8:ce2b4f1632af
161 o changeset: 8:ce2b4f1632af
162 | parent: 3:9e887f7a939c
162 | parent: 3:9e887f7a939c
163 | user: test
163 | user: test
164 | date: Fri Feb 13 21:18:00 2009 -0002
164 | date: Fri Feb 13 21:18:00 2009 -0002
165 | summary: added b
165 | summary: added b
166 |
166 |
167 o changeset: 3:9e887f7a939c
167 o changeset: 3:9e887f7a939c
168 | parent: 0:f7ad41964313
168 | parent: 0:f7ad41964313
169 ~ user: test
169 ~ user: test
170 date: Thu Jan 01 00:00:00 1970 +0000
170 date: Thu Jan 01 00:00:00 1970 +0000
171 summary: bar to b
171 summary: bar to b
172
172
173 Test that --log is preserved and reused in `hg graft --continue`
173 Test that --log is preserved and reused in `hg graft --continue`
174
174
175 $ hg up '.^^'
175 $ hg up '.^^'
176 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
176 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
177 $ hg graft -r 1 -r 2 --log
177 $ hg graft -r 1 -r 2 --log
178 grafting 1:80e6d2c47cfe "added b"
178 grafting 1:80e6d2c47cfe "added b"
179 merging b
179 merging b
180 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
180 warning: conflicts while merging b! (edit, then use 'hg resolve --mark')
181 abort: unresolved conflicts, can't continue
181 abort: unresolved conflicts, can't continue
182 (use 'hg resolve' and 'hg graft --continue')
182 (use 'hg resolve' and 'hg graft --continue')
183 [1]
183 [1]
184
184
185 $ echo foobar > b
185 $ echo foobar > b
186 $ hg resolve -m
186 $ hg resolve -m
187 (no more unresolved files)
187 (no more unresolved files)
188 continue: hg graft --continue
188 continue: hg graft --continue
189
189
190 $ hg graft --continue
190 $ hg graft --continue
191 grafting 1:80e6d2c47cfe "added b"
191 grafting 1:80e6d2c47cfe "added b"
192 grafting 2:8be98ac1a569 "added c"
192 grafting 2:8be98ac1a569 "added c"
193
193
194 $ hg log -GT "{rev}:{node|short} {desc}" -r '.^^::.'
194 $ hg log -GT "{rev}:{node|short} {desc}" -r '.^^::.'
195 @ 11:30c1050a58b2 added c
195 @ 11:30c1050a58b2 added c
196 | (grafted from 8be98ac1a56990c2d9ca6861041b8390af7bd6f3)
196 | (grafted from 8be98ac1a56990c2d9ca6861041b8390af7bd6f3)
197 o 10:ec7eda2313e2 added b
197 o 10:ec7eda2313e2 added b
198 | (grafted from 80e6d2c47cfe5b3185519568327a17a061c7efb6)
198 | (grafted from 80e6d2c47cfe5b3185519568327a17a061c7efb6)
199 o 3:9e887f7a939c bar to b
199 o 3:9e887f7a939c bar to b
200 |
200 |
201 ~
201 ~
202
202
203 $ cd ..
203 $ cd ..
204
204
205 Testing the --stop flag of `hg graft` which stops the interrupted graft
205 Testing the --stop flag of `hg graft` which stops the interrupted graft
206
206
207 $ hg init stopgraft
207 $ hg init stopgraft
208 $ cd stopgraft
208 $ cd stopgraft
209 $ for ch in a b c d; do echo $ch > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
209 $ for ch in a b c d; do echo $ch > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
210
210
211 $ hg log -G
211 $ hg log -G
212 @ changeset: 3:9150fe93bec6
212 @ changeset: 3:9150fe93bec6
213 | tag: tip
213 | tag: tip
214 | user: test
214 | user: test
215 | date: Thu Jan 01 00:00:00 1970 +0000
215 | date: Thu Jan 01 00:00:00 1970 +0000
216 | summary: added d
216 | summary: added d
217 |
217 |
218 o changeset: 2:155349b645be
218 o changeset: 2:155349b645be
219 | user: test
219 | user: test
220 | date: Thu Jan 01 00:00:00 1970 +0000
220 | date: Thu Jan 01 00:00:00 1970 +0000
221 | summary: added c
221 | summary: added c
222 |
222 |
223 o changeset: 1:5f6d8a4bf34a
223 o changeset: 1:5f6d8a4bf34a
224 | user: test
224 | user: test
225 | date: Thu Jan 01 00:00:00 1970 +0000
225 | date: Thu Jan 01 00:00:00 1970 +0000
226 | summary: added b
226 | summary: added b
227 |
227 |
228 o changeset: 0:9092f1db7931
228 o changeset: 0:9092f1db7931
229 user: test
229 user: test
230 date: Thu Jan 01 00:00:00 1970 +0000
230 date: Thu Jan 01 00:00:00 1970 +0000
231 summary: added a
231 summary: added a
232
232
233 $ hg up '.^^'
233 $ hg up '.^^'
234 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
234 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
235
235
236 $ echo foo > d
236 $ echo foo > d
237 $ hg ci -Aqm "added foo to d"
237 $ hg ci -Aqm "added foo to d"
238
238
239 $ hg graft --stop
239 $ hg graft --stop
240 abort: no interrupted graft found
240 abort: no interrupted graft found
241 [255]
241 [255]
242
242
243 $ hg graft -r 3
243 $ hg graft -r 3
244 grafting 3:9150fe93bec6 "added d"
244 grafting 3:9150fe93bec6 "added d"
245 merging d
245 merging d
246 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
246 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
247 abort: unresolved conflicts, can't continue
247 abort: unresolved conflicts, can't continue
248 (use 'hg resolve' and 'hg graft --continue')
248 (use 'hg resolve' and 'hg graft --continue')
249 [1]
249 [1]
250
250
251 $ hg graft --stop --continue
251 $ hg graft --stop --continue
252 abort: cannot use '--continue' and '--stop' together
252 abort: cannot specify both --stop and --continue
253 [255]
253 [255]
254
254
255 $ hg graft --stop -U
255 $ hg graft --stop -U
256 abort: cannot specify any other flag with '--stop'
256 abort: cannot specify any other flag with '--stop'
257 [255]
257 [255]
258 $ hg graft --stop --rev 4
258 $ hg graft --stop --rev 4
259 abort: cannot specify any other flag with '--stop'
259 abort: cannot specify any other flag with '--stop'
260 [255]
260 [255]
261 $ hg graft --stop --log
261 $ hg graft --stop --log
262 abort: cannot specify any other flag with '--stop'
262 abort: cannot specify any other flag with '--stop'
263 [255]
263 [255]
264
264
265 $ hg graft --stop
265 $ hg graft --stop
266 stopped the interrupted graft
266 stopped the interrupted graft
267 working directory is now at a0deacecd59d
267 working directory is now at a0deacecd59d
268
268
269 $ hg diff
269 $ hg diff
270
270
271 $ hg log -Gr '.'
271 $ hg log -Gr '.'
272 @ changeset: 4:a0deacecd59d
272 @ changeset: 4:a0deacecd59d
273 | tag: tip
273 | tag: tip
274 ~ parent: 1:5f6d8a4bf34a
274 ~ parent: 1:5f6d8a4bf34a
275 user: test
275 user: test
276 date: Thu Jan 01 00:00:00 1970 +0000
276 date: Thu Jan 01 00:00:00 1970 +0000
277 summary: added foo to d
277 summary: added foo to d
278
278
279 $ hg graft -r 2 -r 3
279 $ hg graft -r 2 -r 3
280 grafting 2:155349b645be "added c"
280 grafting 2:155349b645be "added c"
281 grafting 3:9150fe93bec6 "added d"
281 grafting 3:9150fe93bec6 "added d"
282 merging d
282 merging d
283 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
283 warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
284 abort: unresolved conflicts, can't continue
284 abort: unresolved conflicts, can't continue
285 (use 'hg resolve' and 'hg graft --continue')
285 (use 'hg resolve' and 'hg graft --continue')
286 [1]
286 [1]
287
287
288 $ hg graft --stop
288 $ hg graft --stop
289 stopped the interrupted graft
289 stopped the interrupted graft
290 working directory is now at 75b447541a9e
290 working directory is now at 75b447541a9e
291
291
292 $ hg diff
292 $ hg diff
293
293
294 $ hg log -G -T "{rev}:{node|short} {desc}"
294 $ hg log -G -T "{rev}:{node|short} {desc}"
295 @ 5:75b447541a9e added c
295 @ 5:75b447541a9e added c
296 |
296 |
297 o 4:a0deacecd59d added foo to d
297 o 4:a0deacecd59d added foo to d
298 |
298 |
299 | o 3:9150fe93bec6 added d
299 | o 3:9150fe93bec6 added d
300 | |
300 | |
301 | o 2:155349b645be added c
301 | o 2:155349b645be added c
302 |/
302 |/
303 o 1:5f6d8a4bf34a added b
303 o 1:5f6d8a4bf34a added b
304 |
304 |
305 o 0:9092f1db7931 added a
305 o 0:9092f1db7931 added a
306
306
307 $ cd ..
307 $ cd ..
308
308
309 Testing the --abort flag for `hg graft` which aborts and rollback to state
309 Testing the --abort flag for `hg graft` which aborts and rollback to state
310 before the graft
310 before the graft
311
311
312 $ hg init abortgraft
312 $ hg init abortgraft
313 $ cd abortgraft
313 $ cd abortgraft
314 $ for ch in a b c d; do echo $ch > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
314 $ for ch in a b c d; do echo $ch > $ch; hg add $ch; hg ci -Aqm "added "$ch; done;
315
315
316 $ hg up '.^^'
316 $ hg up '.^^'
317 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
317 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
318
318
319 $ echo x > x
319 $ echo x > x
320 $ hg ci -Aqm "added x"
320 $ hg ci -Aqm "added x"
321 $ hg up '.^'
321 $ hg up '.^'
322 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
322 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
323 $ echo foo > c
323 $ echo foo > c
324 $ hg ci -Aqm "added foo to c"
324 $ hg ci -Aqm "added foo to c"
325
325
326 $ hg log -GT "{rev}:{node|short} {desc}"
326 $ hg log -GT "{rev}:{node|short} {desc}"
327 @ 5:36b793615f78 added foo to c
327 @ 5:36b793615f78 added foo to c
328 |
328 |
329 | o 4:863a25e1a9ea added x
329 | o 4:863a25e1a9ea added x
330 |/
330 |/
331 | o 3:9150fe93bec6 added d
331 | o 3:9150fe93bec6 added d
332 | |
332 | |
333 | o 2:155349b645be added c
333 | o 2:155349b645be added c
334 |/
334 |/
335 o 1:5f6d8a4bf34a added b
335 o 1:5f6d8a4bf34a added b
336 |
336 |
337 o 0:9092f1db7931 added a
337 o 0:9092f1db7931 added a
338
338
339 $ hg up 9150fe93bec6
339 $ hg up 9150fe93bec6
340 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
340 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
341
341
342 $ hg abort
342 $ hg abort
343 abort: no interrupted graft to abort (abortflag !)
343 abort: no interrupted graft to abort (abortflag !)
344 abort: no operation in progress (abortcommand !)
344 abort: no operation in progress (abortcommand !)
345 [255]
345 [255]
346
346
347 when stripping is required
347 when stripping is required
348 $ hg graft -r 4 -r 5
348 $ hg graft -r 4 -r 5
349 grafting 4:863a25e1a9ea "added x"
349 grafting 4:863a25e1a9ea "added x"
350 grafting 5:36b793615f78 "added foo to c" (tip)
350 grafting 5:36b793615f78 "added foo to c" (tip)
351 merging c
351 merging c
352 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
352 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
353 abort: unresolved conflicts, can't continue
353 abort: unresolved conflicts, can't continue
354 (use 'hg resolve' and 'hg graft --continue')
354 (use 'hg resolve' and 'hg graft --continue')
355 [1]
355 [1]
356
356
357 $ hg graft --continue --abort
357 $ hg graft --continue --abort
358 abort: cannot use '--continue' and '--abort' together
358 abort: cannot specify both --abort and --continue
359 [255]
359 [255]
360
360
361 $ hg graft --abort --stop
361 $ hg graft --abort --stop
362 abort: cannot use '--abort' and '--stop' together
362 abort: cannot specify both --abort and --stop
363 [255]
363 [255]
364
364
365 $ hg graft --abort --currentuser
365 $ hg graft --abort --currentuser
366 abort: cannot specify any other flag with '--abort'
366 abort: cannot specify any other flag with '--abort'
367 [255]
367 [255]
368
368
369 $ hg graft --abort --edit
369 $ hg graft --abort --edit
370 abort: cannot specify any other flag with '--abort'
370 abort: cannot specify any other flag with '--abort'
371 [255]
371 [255]
372
372
373 #if abortcommand
373 #if abortcommand
374 when in dry-run mode
374 when in dry-run mode
375 $ hg abort --dry-run
375 $ hg abort --dry-run
376 graft in progress, will be aborted
376 graft in progress, will be aborted
377 #endif
377 #endif
378
378
379 $ hg abort
379 $ hg abort
380 graft aborted
380 graft aborted
381 working directory is now at 9150fe93bec6
381 working directory is now at 9150fe93bec6
382 $ hg log -GT "{rev}:{node|short} {desc}"
382 $ hg log -GT "{rev}:{node|short} {desc}"
383 o 5:36b793615f78 added foo to c
383 o 5:36b793615f78 added foo to c
384 |
384 |
385 | o 4:863a25e1a9ea added x
385 | o 4:863a25e1a9ea added x
386 |/
386 |/
387 | @ 3:9150fe93bec6 added d
387 | @ 3:9150fe93bec6 added d
388 | |
388 | |
389 | o 2:155349b645be added c
389 | o 2:155349b645be added c
390 |/
390 |/
391 o 1:5f6d8a4bf34a added b
391 o 1:5f6d8a4bf34a added b
392 |
392 |
393 o 0:9092f1db7931 added a
393 o 0:9092f1db7931 added a
394
394
395 when stripping is not required
395 when stripping is not required
396 $ hg graft -r 5
396 $ hg graft -r 5
397 grafting 5:36b793615f78 "added foo to c" (tip)
397 grafting 5:36b793615f78 "added foo to c" (tip)
398 merging c
398 merging c
399 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
399 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
400 abort: unresolved conflicts, can't continue
400 abort: unresolved conflicts, can't continue
401 (use 'hg resolve' and 'hg graft --continue')
401 (use 'hg resolve' and 'hg graft --continue')
402 [1]
402 [1]
403
403
404 $ hg abort
404 $ hg abort
405 graft aborted
405 graft aborted
406 working directory is now at 9150fe93bec6
406 working directory is now at 9150fe93bec6
407 $ hg log -GT "{rev}:{node|short} {desc}"
407 $ hg log -GT "{rev}:{node|short} {desc}"
408 o 5:36b793615f78 added foo to c
408 o 5:36b793615f78 added foo to c
409 |
409 |
410 | o 4:863a25e1a9ea added x
410 | o 4:863a25e1a9ea added x
411 |/
411 |/
412 | @ 3:9150fe93bec6 added d
412 | @ 3:9150fe93bec6 added d
413 | |
413 | |
414 | o 2:155349b645be added c
414 | o 2:155349b645be added c
415 |/
415 |/
416 o 1:5f6d8a4bf34a added b
416 o 1:5f6d8a4bf34a added b
417 |
417 |
418 o 0:9092f1db7931 added a
418 o 0:9092f1db7931 added a
419
419
420 when some of the changesets became public
420 when some of the changesets became public
421
421
422 $ hg graft -r 4 -r 5
422 $ hg graft -r 4 -r 5
423 grafting 4:863a25e1a9ea "added x"
423 grafting 4:863a25e1a9ea "added x"
424 grafting 5:36b793615f78 "added foo to c" (tip)
424 grafting 5:36b793615f78 "added foo to c" (tip)
425 merging c
425 merging c
426 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
426 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
427 abort: unresolved conflicts, can't continue
427 abort: unresolved conflicts, can't continue
428 (use 'hg resolve' and 'hg graft --continue')
428 (use 'hg resolve' and 'hg graft --continue')
429 [1]
429 [1]
430
430
431 $ hg log -GT "{rev}:{node|short} {desc}"
431 $ hg log -GT "{rev}:{node|short} {desc}"
432 @ 6:6ec71c037d94 added x
432 @ 6:6ec71c037d94 added x
433 |
433 |
434 | % 5:36b793615f78 added foo to c
434 | % 5:36b793615f78 added foo to c
435 | |
435 | |
436 | | o 4:863a25e1a9ea added x
436 | | o 4:863a25e1a9ea added x
437 | |/
437 | |/
438 o | 3:9150fe93bec6 added d
438 o | 3:9150fe93bec6 added d
439 | |
439 | |
440 o | 2:155349b645be added c
440 o | 2:155349b645be added c
441 |/
441 |/
442 o 1:5f6d8a4bf34a added b
442 o 1:5f6d8a4bf34a added b
443 |
443 |
444 o 0:9092f1db7931 added a
444 o 0:9092f1db7931 added a
445
445
446 $ hg phase -r 6 --public
446 $ hg phase -r 6 --public
447
447
448 $ hg abort
448 $ hg abort
449 cannot clean up public changesets 6ec71c037d94
449 cannot clean up public changesets 6ec71c037d94
450 graft aborted
450 graft aborted
451 working directory is now at 6ec71c037d94
451 working directory is now at 6ec71c037d94
452
452
453 when we created new changesets on top of existing one
453 when we created new changesets on top of existing one
454
454
455 $ hg up '.^^'
455 $ hg up '.^^'
456 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
456 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
457 $ echo y > y
457 $ echo y > y
458 $ hg ci -Aqm "added y"
458 $ hg ci -Aqm "added y"
459 $ echo z > z
459 $ echo z > z
460 $ hg ci -Aqm "added z"
460 $ hg ci -Aqm "added z"
461
461
462 $ hg up 3
462 $ hg up 3
463 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
463 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
464 $ hg log -GT "{rev}:{node|short} {desc}"
464 $ hg log -GT "{rev}:{node|short} {desc}"
465 o 8:637f9e9bbfd4 added z
465 o 8:637f9e9bbfd4 added z
466 |
466 |
467 o 7:123221671fd4 added y
467 o 7:123221671fd4 added y
468 |
468 |
469 | o 6:6ec71c037d94 added x
469 | o 6:6ec71c037d94 added x
470 | |
470 | |
471 | | o 5:36b793615f78 added foo to c
471 | | o 5:36b793615f78 added foo to c
472 | | |
472 | | |
473 | | | o 4:863a25e1a9ea added x
473 | | | o 4:863a25e1a9ea added x
474 | | |/
474 | | |/
475 | @ | 3:9150fe93bec6 added d
475 | @ | 3:9150fe93bec6 added d
476 |/ /
476 |/ /
477 o / 2:155349b645be added c
477 o / 2:155349b645be added c
478 |/
478 |/
479 o 1:5f6d8a4bf34a added b
479 o 1:5f6d8a4bf34a added b
480 |
480 |
481 o 0:9092f1db7931 added a
481 o 0:9092f1db7931 added a
482
482
483 $ hg graft -r 8 -r 7 -r 5
483 $ hg graft -r 8 -r 7 -r 5
484 grafting 8:637f9e9bbfd4 "added z" (tip)
484 grafting 8:637f9e9bbfd4 "added z" (tip)
485 grafting 7:123221671fd4 "added y"
485 grafting 7:123221671fd4 "added y"
486 grafting 5:36b793615f78 "added foo to c"
486 grafting 5:36b793615f78 "added foo to c"
487 merging c
487 merging c
488 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
488 warning: conflicts while merging c! (edit, then use 'hg resolve --mark')
489 abort: unresolved conflicts, can't continue
489 abort: unresolved conflicts, can't continue
490 (use 'hg resolve' and 'hg graft --continue')
490 (use 'hg resolve' and 'hg graft --continue')
491 [1]
491 [1]
492
492
493 $ cd ..
493 $ cd ..
494 $ hg init pullrepo
494 $ hg init pullrepo
495 $ cd pullrepo
495 $ cd pullrepo
496 $ cat >> .hg/hgrc <<EOF
496 $ cat >> .hg/hgrc <<EOF
497 > [phases]
497 > [phases]
498 > publish=False
498 > publish=False
499 > EOF
499 > EOF
500 $ hg pull ../abortgraft --config phases.publish=False
500 $ hg pull ../abortgraft --config phases.publish=False
501 pulling from ../abortgraft
501 pulling from ../abortgraft
502 requesting all changes
502 requesting all changes
503 adding changesets
503 adding changesets
504 adding manifests
504 adding manifests
505 adding file changes
505 adding file changes
506 added 11 changesets with 9 changes to 8 files (+4 heads)
506 added 11 changesets with 9 changes to 8 files (+4 heads)
507 new changesets 9092f1db7931:6b98ff0062dd (6 drafts)
507 new changesets 9092f1db7931:6b98ff0062dd (6 drafts)
508 (run 'hg heads' to see heads, 'hg merge' to merge)
508 (run 'hg heads' to see heads, 'hg merge' to merge)
509 $ hg up 9
509 $ hg up 9
510 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
510 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
511 $ echo w > w
511 $ echo w > w
512 $ hg ci -Aqm "added w" --config phases.publish=False
512 $ hg ci -Aqm "added w" --config phases.publish=False
513
513
514 $ cd ../abortgraft
514 $ cd ../abortgraft
515 $ hg pull ../pullrepo
515 $ hg pull ../pullrepo
516 pulling from ../pullrepo
516 pulling from ../pullrepo
517 searching for changes
517 searching for changes
518 adding changesets
518 adding changesets
519 adding manifests
519 adding manifests
520 adding file changes
520 adding file changes
521 added 1 changesets with 1 changes to 1 files (+1 heads)
521 added 1 changesets with 1 changes to 1 files (+1 heads)
522 new changesets 311dfc6cf3bf (1 drafts)
522 new changesets 311dfc6cf3bf (1 drafts)
523 (run 'hg heads .' to see heads, 'hg merge' to merge)
523 (run 'hg heads .' to see heads, 'hg merge' to merge)
524
524
525 $ hg abort
525 $ hg abort
526 new changesets detected on destination branch, can't strip
526 new changesets detected on destination branch, can't strip
527 graft aborted
527 graft aborted
528 working directory is now at 6b98ff0062dd
528 working directory is now at 6b98ff0062dd
529
529
530 $ cd ..
530 $ cd ..
531
531
532 ============================
532 ============================
533 Testing --no-commit option:|
533 Testing --no-commit option:|
534 ============================
534 ============================
535
535
536 $ hg init nocommit
536 $ hg init nocommit
537 $ cd nocommit
537 $ cd nocommit
538 $ echo a > a
538 $ echo a > a
539 $ hg ci -qAma
539 $ hg ci -qAma
540 $ echo b > b
540 $ echo b > b
541 $ hg ci -qAmb
541 $ hg ci -qAmb
542 $ hg up -q 0
542 $ hg up -q 0
543 $ echo c > c
543 $ echo c > c
544 $ hg ci -qAmc
544 $ hg ci -qAmc
545 $ hg log -GT "{rev}:{node|short} {desc}\n"
545 $ hg log -GT "{rev}:{node|short} {desc}\n"
546 @ 2:d36c0562f908 c
546 @ 2:d36c0562f908 c
547 |
547 |
548 | o 1:d2ae7f538514 b
548 | o 1:d2ae7f538514 b
549 |/
549 |/
550 o 0:cb9a9f314b8b a
550 o 0:cb9a9f314b8b a
551
551
552
552
553 Check reporting when --no-commit used with non-applicable options:
553 Check reporting when --no-commit used with non-applicable options:
554
554
555 $ hg graft 1 --no-commit -e
555 $ hg graft 1 --no-commit -e
556 abort: cannot specify --no-commit and --edit together
556 abort: cannot specify --no-commit and --edit together
557 [255]
557 [255]
558
558
559 $ hg graft 1 --no-commit --log
559 $ hg graft 1 --no-commit --log
560 abort: cannot specify --no-commit and --log together
560 abort: cannot specify --no-commit and --log together
561 [255]
561 [255]
562
562
563 $ hg graft 1 --no-commit -D
563 $ hg graft 1 --no-commit -D
564 abort: cannot specify --no-commit and --currentdate together
564 abort: cannot specify --no-commit and --currentdate together
565 [255]
565 [255]
566
566
567 Test --no-commit is working:
567 Test --no-commit is working:
568 $ hg graft 1 --no-commit
568 $ hg graft 1 --no-commit
569 grafting 1:d2ae7f538514 "b"
569 grafting 1:d2ae7f538514 "b"
570
570
571 $ hg log -GT "{rev}:{node|short} {desc}\n"
571 $ hg log -GT "{rev}:{node|short} {desc}\n"
572 @ 2:d36c0562f908 c
572 @ 2:d36c0562f908 c
573 |
573 |
574 | o 1:d2ae7f538514 b
574 | o 1:d2ae7f538514 b
575 |/
575 |/
576 o 0:cb9a9f314b8b a
576 o 0:cb9a9f314b8b a
577
577
578
578
579 $ hg diff
579 $ hg diff
580 diff -r d36c0562f908 b
580 diff -r d36c0562f908 b
581 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
581 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
582 +++ b/b Thu Jan 01 00:00:00 1970 +0000
582 +++ b/b Thu Jan 01 00:00:00 1970 +0000
583 @@ -0,0 +1,1 @@
583 @@ -0,0 +1,1 @@
584 +b
584 +b
585
585
586 Prepare wrdir to check --no-commit is resepected after --continue:
586 Prepare wrdir to check --no-commit is resepected after --continue:
587
587
588 $ hg up -qC
588 $ hg up -qC
589 $ echo A>a
589 $ echo A>a
590 $ hg ci -qm "A in file a"
590 $ hg ci -qm "A in file a"
591 $ hg up -q 1
591 $ hg up -q 1
592 $ echo B>a
592 $ echo B>a
593 $ hg ci -qm "B in file a"
593 $ hg ci -qm "B in file a"
594 $ hg log -GT "{rev}:{node|short} {desc}\n"
594 $ hg log -GT "{rev}:{node|short} {desc}\n"
595 @ 4:2aa9ad1006ff B in file a
595 @ 4:2aa9ad1006ff B in file a
596 |
596 |
597 | o 3:09e253b87e17 A in file a
597 | o 3:09e253b87e17 A in file a
598 | |
598 | |
599 | o 2:d36c0562f908 c
599 | o 2:d36c0562f908 c
600 | |
600 | |
601 o | 1:d2ae7f538514 b
601 o | 1:d2ae7f538514 b
602 |/
602 |/
603 o 0:cb9a9f314b8b a
603 o 0:cb9a9f314b8b a
604
604
605
605
606 $ hg graft 3 --no-commit
606 $ hg graft 3 --no-commit
607 grafting 3:09e253b87e17 "A in file a"
607 grafting 3:09e253b87e17 "A in file a"
608 merging a
608 merging a
609 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
609 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
610 abort: unresolved conflicts, can't continue
610 abort: unresolved conflicts, can't continue
611 (use 'hg resolve' and 'hg graft --continue')
611 (use 'hg resolve' and 'hg graft --continue')
612 [1]
612 [1]
613
613
614 Resolve conflict:
614 Resolve conflict:
615 $ echo A>a
615 $ echo A>a
616 $ hg resolve --mark
616 $ hg resolve --mark
617 (no more unresolved files)
617 (no more unresolved files)
618 continue: hg graft --continue
618 continue: hg graft --continue
619
619
620 $ hg graft --continue
620 $ hg graft --continue
621 grafting 3:09e253b87e17 "A in file a"
621 grafting 3:09e253b87e17 "A in file a"
622 $ hg log -GT "{rev}:{node|short} {desc}\n"
622 $ hg log -GT "{rev}:{node|short} {desc}\n"
623 @ 4:2aa9ad1006ff B in file a
623 @ 4:2aa9ad1006ff B in file a
624 |
624 |
625 | % 3:09e253b87e17 A in file a
625 | % 3:09e253b87e17 A in file a
626 | |
626 | |
627 | o 2:d36c0562f908 c
627 | o 2:d36c0562f908 c
628 | |
628 | |
629 o | 1:d2ae7f538514 b
629 o | 1:d2ae7f538514 b
630 |/
630 |/
631 o 0:cb9a9f314b8b a
631 o 0:cb9a9f314b8b a
632
632
633 $ hg diff
633 $ hg diff
634 diff -r 2aa9ad1006ff a
634 diff -r 2aa9ad1006ff a
635 --- a/a Thu Jan 01 00:00:00 1970 +0000
635 --- a/a Thu Jan 01 00:00:00 1970 +0000
636 +++ b/a Thu Jan 01 00:00:00 1970 +0000
636 +++ b/a Thu Jan 01 00:00:00 1970 +0000
637 @@ -1,1 +1,1 @@
637 @@ -1,1 +1,1 @@
638 -B
638 -B
639 +A
639 +A
640
640
641 $ hg up -qC
641 $ hg up -qC
642
642
643 Check --no-commit is resepected when passed with --continue:
643 Check --no-commit is resepected when passed with --continue:
644
644
645 $ hg graft 3
645 $ hg graft 3
646 grafting 3:09e253b87e17 "A in file a"
646 grafting 3:09e253b87e17 "A in file a"
647 merging a
647 merging a
648 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
648 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
649 abort: unresolved conflicts, can't continue
649 abort: unresolved conflicts, can't continue
650 (use 'hg resolve' and 'hg graft --continue')
650 (use 'hg resolve' and 'hg graft --continue')
651 [1]
651 [1]
652
652
653 Resolve conflict:
653 Resolve conflict:
654 $ echo A>a
654 $ echo A>a
655 $ hg resolve --mark
655 $ hg resolve --mark
656 (no more unresolved files)
656 (no more unresolved files)
657 continue: hg graft --continue
657 continue: hg graft --continue
658
658
659 $ hg graft --continue --no-commit
659 $ hg graft --continue --no-commit
660 grafting 3:09e253b87e17 "A in file a"
660 grafting 3:09e253b87e17 "A in file a"
661 $ hg diff
661 $ hg diff
662 diff -r 2aa9ad1006ff a
662 diff -r 2aa9ad1006ff a
663 --- a/a Thu Jan 01 00:00:00 1970 +0000
663 --- a/a Thu Jan 01 00:00:00 1970 +0000
664 +++ b/a Thu Jan 01 00:00:00 1970 +0000
664 +++ b/a Thu Jan 01 00:00:00 1970 +0000
665 @@ -1,1 +1,1 @@
665 @@ -1,1 +1,1 @@
666 -B
666 -B
667 +A
667 +A
668
668
669 $ hg log -GT "{rev}:{node|short} {desc}\n"
669 $ hg log -GT "{rev}:{node|short} {desc}\n"
670 @ 4:2aa9ad1006ff B in file a
670 @ 4:2aa9ad1006ff B in file a
671 |
671 |
672 | % 3:09e253b87e17 A in file a
672 | % 3:09e253b87e17 A in file a
673 | |
673 | |
674 | o 2:d36c0562f908 c
674 | o 2:d36c0562f908 c
675 | |
675 | |
676 o | 1:d2ae7f538514 b
676 o | 1:d2ae7f538514 b
677 |/
677 |/
678 o 0:cb9a9f314b8b a
678 o 0:cb9a9f314b8b a
679
679
680 $ hg up -qC
680 $ hg up -qC
681
681
682 Test --no-commit when graft multiple revisions:
682 Test --no-commit when graft multiple revisions:
683 When there is conflict:
683 When there is conflict:
684 $ hg graft -r "2::3" --no-commit
684 $ hg graft -r "2::3" --no-commit
685 grafting 2:d36c0562f908 "c"
685 grafting 2:d36c0562f908 "c"
686 grafting 3:09e253b87e17 "A in file a"
686 grafting 3:09e253b87e17 "A in file a"
687 merging a
687 merging a
688 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
688 warning: conflicts while merging a! (edit, then use 'hg resolve --mark')
689 abort: unresolved conflicts, can't continue
689 abort: unresolved conflicts, can't continue
690 (use 'hg resolve' and 'hg graft --continue')
690 (use 'hg resolve' and 'hg graft --continue')
691 [1]
691 [1]
692
692
693 $ echo A>a
693 $ echo A>a
694 $ hg resolve --mark
694 $ hg resolve --mark
695 (no more unresolved files)
695 (no more unresolved files)
696 continue: hg graft --continue
696 continue: hg graft --continue
697 $ hg graft --continue
697 $ hg graft --continue
698 grafting 3:09e253b87e17 "A in file a"
698 grafting 3:09e253b87e17 "A in file a"
699 $ hg diff
699 $ hg diff
700 diff -r 2aa9ad1006ff a
700 diff -r 2aa9ad1006ff a
701 --- a/a Thu Jan 01 00:00:00 1970 +0000
701 --- a/a Thu Jan 01 00:00:00 1970 +0000
702 +++ b/a Thu Jan 01 00:00:00 1970 +0000
702 +++ b/a Thu Jan 01 00:00:00 1970 +0000
703 @@ -1,1 +1,1 @@
703 @@ -1,1 +1,1 @@
704 -B
704 -B
705 +A
705 +A
706 diff -r 2aa9ad1006ff c
706 diff -r 2aa9ad1006ff c
707 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
707 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
708 +++ b/c Thu Jan 01 00:00:00 1970 +0000
708 +++ b/c Thu Jan 01 00:00:00 1970 +0000
709 @@ -0,0 +1,1 @@
709 @@ -0,0 +1,1 @@
710 +c
710 +c
711
711
712 $ hg log -GT "{rev}:{node|short} {desc}\n"
712 $ hg log -GT "{rev}:{node|short} {desc}\n"
713 @ 4:2aa9ad1006ff B in file a
713 @ 4:2aa9ad1006ff B in file a
714 |
714 |
715 | % 3:09e253b87e17 A in file a
715 | % 3:09e253b87e17 A in file a
716 | |
716 | |
717 | o 2:d36c0562f908 c
717 | o 2:d36c0562f908 c
718 | |
718 | |
719 o | 1:d2ae7f538514 b
719 o | 1:d2ae7f538514 b
720 |/
720 |/
721 o 0:cb9a9f314b8b a
721 o 0:cb9a9f314b8b a
722
722
723 $ hg up -qC
723 $ hg up -qC
724
724
725 When there is no conflict:
725 When there is no conflict:
726 $ echo d>d
726 $ echo d>d
727 $ hg add d -q
727 $ hg add d -q
728 $ hg ci -qmd
728 $ hg ci -qmd
729 $ hg up 3 -q
729 $ hg up 3 -q
730 $ hg log -GT "{rev}:{node|short} {desc}\n"
730 $ hg log -GT "{rev}:{node|short} {desc}\n"
731 o 5:baefa8927fc0 d
731 o 5:baefa8927fc0 d
732 |
732 |
733 o 4:2aa9ad1006ff B in file a
733 o 4:2aa9ad1006ff B in file a
734 |
734 |
735 | @ 3:09e253b87e17 A in file a
735 | @ 3:09e253b87e17 A in file a
736 | |
736 | |
737 | o 2:d36c0562f908 c
737 | o 2:d36c0562f908 c
738 | |
738 | |
739 o | 1:d2ae7f538514 b
739 o | 1:d2ae7f538514 b
740 |/
740 |/
741 o 0:cb9a9f314b8b a
741 o 0:cb9a9f314b8b a
742
742
743
743
744 $ hg graft -r 1 -r 5 --no-commit
744 $ hg graft -r 1 -r 5 --no-commit
745 grafting 1:d2ae7f538514 "b"
745 grafting 1:d2ae7f538514 "b"
746 grafting 5:baefa8927fc0 "d" (tip)
746 grafting 5:baefa8927fc0 "d" (tip)
747 $ hg diff
747 $ hg diff
748 diff -r 09e253b87e17 b
748 diff -r 09e253b87e17 b
749 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
749 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
750 +++ b/b Thu Jan 01 00:00:00 1970 +0000
750 +++ b/b Thu Jan 01 00:00:00 1970 +0000
751 @@ -0,0 +1,1 @@
751 @@ -0,0 +1,1 @@
752 +b
752 +b
753 diff -r 09e253b87e17 d
753 diff -r 09e253b87e17 d
754 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
754 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
755 +++ b/d Thu Jan 01 00:00:00 1970 +0000
755 +++ b/d Thu Jan 01 00:00:00 1970 +0000
756 @@ -0,0 +1,1 @@
756 @@ -0,0 +1,1 @@
757 +d
757 +d
758 $ hg log -GT "{rev}:{node|short} {desc}\n"
758 $ hg log -GT "{rev}:{node|short} {desc}\n"
759 o 5:baefa8927fc0 d
759 o 5:baefa8927fc0 d
760 |
760 |
761 o 4:2aa9ad1006ff B in file a
761 o 4:2aa9ad1006ff B in file a
762 |
762 |
763 | @ 3:09e253b87e17 A in file a
763 | @ 3:09e253b87e17 A in file a
764 | |
764 | |
765 | o 2:d36c0562f908 c
765 | o 2:d36c0562f908 c
766 | |
766 | |
767 o | 1:d2ae7f538514 b
767 o | 1:d2ae7f538514 b
768 |/
768 |/
769 o 0:cb9a9f314b8b a
769 o 0:cb9a9f314b8b a
770
770
771 $ cd ..
771 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now