##// END OF EJS Templates
commit: add a check if it is trying to close an already closed branch head...
Sushil khanchi -
r42693:9f7cb777 default
parent child Browse files
Show More
@@ -1,6269 +1,6272 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 . import (
25 from . import (
26 archival,
26 archival,
27 bookmarks,
27 bookmarks,
28 bundle2,
28 bundle2,
29 changegroup,
29 changegroup,
30 cmdutil,
30 cmdutil,
31 copies,
31 copies,
32 debugcommands as debugcommandsmod,
32 debugcommands as debugcommandsmod,
33 destutil,
33 destutil,
34 dirstateguard,
34 dirstateguard,
35 discovery,
35 discovery,
36 encoding,
36 encoding,
37 error,
37 error,
38 exchange,
38 exchange,
39 extensions,
39 extensions,
40 filemerge,
40 filemerge,
41 formatter,
41 formatter,
42 graphmod,
42 graphmod,
43 hbisect,
43 hbisect,
44 help,
44 help,
45 hg,
45 hg,
46 logcmdutil,
46 logcmdutil,
47 merge as mergemod,
47 merge as mergemod,
48 narrowspec,
48 narrowspec,
49 obsolete,
49 obsolete,
50 obsutil,
50 obsutil,
51 patch,
51 patch,
52 phases,
52 phases,
53 pycompat,
53 pycompat,
54 rcutil,
54 rcutil,
55 registrar,
55 registrar,
56 repair,
56 repair,
57 revsetlang,
57 revsetlang,
58 rewriteutil,
58 rewriteutil,
59 scmutil,
59 scmutil,
60 server,
60 server,
61 state as statemod,
61 state as statemod,
62 streamclone,
62 streamclone,
63 tags as tagsmod,
63 tags as tagsmod,
64 ui as uimod,
64 ui as uimod,
65 util,
65 util,
66 verify as verifymod,
66 verify as verifymod,
67 wireprotoserver,
67 wireprotoserver,
68 )
68 )
69 from .utils import (
69 from .utils import (
70 dateutil,
70 dateutil,
71 stringutil,
71 stringutil,
72 )
72 )
73
73
74 table = {}
74 table = {}
75 table.update(debugcommandsmod.command._table)
75 table.update(debugcommandsmod.command._table)
76
76
77 command = registrar.command(table)
77 command = registrar.command(table)
78 INTENT_READONLY = registrar.INTENT_READONLY
78 INTENT_READONLY = registrar.INTENT_READONLY
79
79
80 # common command options
80 # common command options
81
81
82 globalopts = [
82 globalopts = [
83 ('R', 'repository', '',
83 ('R', 'repository', '',
84 _('repository root directory or name of overlay bundle file'),
84 _('repository root directory or name of overlay bundle file'),
85 _('REPO')),
85 _('REPO')),
86 ('', 'cwd', '',
86 ('', 'cwd', '',
87 _('change working directory'), _('DIR')),
87 _('change working directory'), _('DIR')),
88 ('y', 'noninteractive', None,
88 ('y', 'noninteractive', None,
89 _('do not prompt, automatically pick the first choice for all prompts')),
89 _('do not prompt, automatically pick the first choice for all prompts')),
90 ('q', 'quiet', None, _('suppress output')),
90 ('q', 'quiet', None, _('suppress output')),
91 ('v', 'verbose', None, _('enable additional output')),
91 ('v', 'verbose', None, _('enable additional output')),
92 ('', 'color', '',
92 ('', 'color', '',
93 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
93 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
94 # and should not be translated
94 # and should not be translated
95 _("when to colorize (boolean, always, auto, never, or debug)"),
95 _("when to colorize (boolean, always, auto, never, or debug)"),
96 _('TYPE')),
96 _('TYPE')),
97 ('', 'config', [],
97 ('', 'config', [],
98 _('set/override config option (use \'section.name=value\')'),
98 _('set/override config option (use \'section.name=value\')'),
99 _('CONFIG')),
99 _('CONFIG')),
100 ('', 'debug', None, _('enable debugging output')),
100 ('', 'debug', None, _('enable debugging output')),
101 ('', 'debugger', None, _('start debugger')),
101 ('', 'debugger', None, _('start debugger')),
102 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
102 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
103 _('ENCODE')),
103 _('ENCODE')),
104 ('', 'encodingmode', encoding.encodingmode,
104 ('', 'encodingmode', encoding.encodingmode,
105 _('set the charset encoding mode'), _('MODE')),
105 _('set the charset encoding mode'), _('MODE')),
106 ('', 'traceback', None, _('always print a traceback on exception')),
106 ('', 'traceback', None, _('always print a traceback on exception')),
107 ('', 'time', None, _('time how long the command takes')),
107 ('', 'time', None, _('time how long the command takes')),
108 ('', 'profile', None, _('print command execution profile')),
108 ('', 'profile', None, _('print command execution profile')),
109 ('', 'version', None, _('output version information and exit')),
109 ('', 'version', None, _('output version information and exit')),
110 ('h', 'help', None, _('display help and exit')),
110 ('h', 'help', None, _('display help and exit')),
111 ('', 'hidden', False, _('consider hidden changesets')),
111 ('', 'hidden', False, _('consider hidden changesets')),
112 ('', 'pager', 'auto',
112 ('', 'pager', 'auto',
113 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
113 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
114 ]
114 ]
115
115
116 dryrunopts = cmdutil.dryrunopts
116 dryrunopts = cmdutil.dryrunopts
117 remoteopts = cmdutil.remoteopts
117 remoteopts = cmdutil.remoteopts
118 walkopts = cmdutil.walkopts
118 walkopts = cmdutil.walkopts
119 commitopts = cmdutil.commitopts
119 commitopts = cmdutil.commitopts
120 commitopts2 = cmdutil.commitopts2
120 commitopts2 = cmdutil.commitopts2
121 formatteropts = cmdutil.formatteropts
121 formatteropts = cmdutil.formatteropts
122 templateopts = cmdutil.templateopts
122 templateopts = cmdutil.templateopts
123 logopts = cmdutil.logopts
123 logopts = cmdutil.logopts
124 diffopts = cmdutil.diffopts
124 diffopts = cmdutil.diffopts
125 diffwsopts = cmdutil.diffwsopts
125 diffwsopts = cmdutil.diffwsopts
126 diffopts2 = cmdutil.diffopts2
126 diffopts2 = cmdutil.diffopts2
127 mergetoolopts = cmdutil.mergetoolopts
127 mergetoolopts = cmdutil.mergetoolopts
128 similarityopts = cmdutil.similarityopts
128 similarityopts = cmdutil.similarityopts
129 subrepoopts = cmdutil.subrepoopts
129 subrepoopts = cmdutil.subrepoopts
130 debugrevlogopts = cmdutil.debugrevlogopts
130 debugrevlogopts = cmdutil.debugrevlogopts
131
131
132 # Commands start here, listed alphabetically
132 # Commands start here, listed alphabetically
133
133
134 @command('add',
134 @command('add',
135 walkopts + subrepoopts + dryrunopts,
135 walkopts + subrepoopts + dryrunopts,
136 _('[OPTION]... [FILE]...'),
136 _('[OPTION]... [FILE]...'),
137 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
137 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
138 helpbasic=True, inferrepo=True)
138 helpbasic=True, inferrepo=True)
139 def add(ui, repo, *pats, **opts):
139 def add(ui, repo, *pats, **opts):
140 """add the specified files on the next commit
140 """add the specified files on the next commit
141
141
142 Schedule files to be version controlled and added to the
142 Schedule files to be version controlled and added to the
143 repository.
143 repository.
144
144
145 The files will be added to the repository at the next commit. To
145 The files will be added to the repository at the next commit. To
146 undo an add before that, see :hg:`forget`.
146 undo an add before that, see :hg:`forget`.
147
147
148 If no names are given, add all files to the repository (except
148 If no names are given, add all files to the repository (except
149 files matching ``.hgignore``).
149 files matching ``.hgignore``).
150
150
151 .. container:: verbose
151 .. container:: verbose
152
152
153 Examples:
153 Examples:
154
154
155 - New (unknown) files are added
155 - New (unknown) files are added
156 automatically by :hg:`add`::
156 automatically by :hg:`add`::
157
157
158 $ ls
158 $ ls
159 foo.c
159 foo.c
160 $ hg status
160 $ hg status
161 ? foo.c
161 ? foo.c
162 $ hg add
162 $ hg add
163 adding foo.c
163 adding foo.c
164 $ hg status
164 $ hg status
165 A foo.c
165 A foo.c
166
166
167 - Specific files to be added can be specified::
167 - Specific files to be added can be specified::
168
168
169 $ ls
169 $ ls
170 bar.c foo.c
170 bar.c foo.c
171 $ hg status
171 $ hg status
172 ? bar.c
172 ? bar.c
173 ? foo.c
173 ? foo.c
174 $ hg add bar.c
174 $ hg add bar.c
175 $ hg status
175 $ hg status
176 A bar.c
176 A bar.c
177 ? foo.c
177 ? foo.c
178
178
179 Returns 0 if all files are successfully added.
179 Returns 0 if all files are successfully added.
180 """
180 """
181
181
182 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
182 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
183 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
183 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
184 rejected = cmdutil.add(ui, repo, m, "", uipathfn, False, **opts)
184 rejected = cmdutil.add(ui, repo, m, "", uipathfn, False, **opts)
185 return rejected and 1 or 0
185 return rejected and 1 or 0
186
186
187 @command('addremove',
187 @command('addremove',
188 similarityopts + subrepoopts + walkopts + dryrunopts,
188 similarityopts + subrepoopts + walkopts + dryrunopts,
189 _('[OPTION]... [FILE]...'),
189 _('[OPTION]... [FILE]...'),
190 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
190 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
191 inferrepo=True)
191 inferrepo=True)
192 def addremove(ui, repo, *pats, **opts):
192 def addremove(ui, repo, *pats, **opts):
193 """add all new files, delete all missing files
193 """add all new files, delete all missing files
194
194
195 Add all new files and remove all missing files from the
195 Add all new files and remove all missing files from the
196 repository.
196 repository.
197
197
198 Unless names are given, new files are ignored if they match any of
198 Unless names are given, new files are ignored if they match any of
199 the patterns in ``.hgignore``. As with add, these changes take
199 the patterns in ``.hgignore``. As with add, these changes take
200 effect at the next commit.
200 effect at the next commit.
201
201
202 Use the -s/--similarity option to detect renamed files. This
202 Use the -s/--similarity option to detect renamed files. This
203 option takes a percentage between 0 (disabled) and 100 (files must
203 option takes a percentage between 0 (disabled) and 100 (files must
204 be identical) as its parameter. With a parameter greater than 0,
204 be identical) as its parameter. With a parameter greater than 0,
205 this compares every removed file with every added file and records
205 this compares every removed file with every added file and records
206 those similar enough as renames. Detecting renamed files this way
206 those similar enough as renames. Detecting renamed files this way
207 can be expensive. After using this option, :hg:`status -C` can be
207 can be expensive. After using this option, :hg:`status -C` can be
208 used to check which files were identified as moved or renamed. If
208 used to check which files were identified as moved or renamed. If
209 not specified, -s/--similarity defaults to 100 and only renames of
209 not specified, -s/--similarity defaults to 100 and only renames of
210 identical files are detected.
210 identical files are detected.
211
211
212 .. container:: verbose
212 .. container:: verbose
213
213
214 Examples:
214 Examples:
215
215
216 - A number of files (bar.c and foo.c) are new,
216 - A number of files (bar.c and foo.c) are new,
217 while foobar.c has been removed (without using :hg:`remove`)
217 while foobar.c has been removed (without using :hg:`remove`)
218 from the repository::
218 from the repository::
219
219
220 $ ls
220 $ ls
221 bar.c foo.c
221 bar.c foo.c
222 $ hg status
222 $ hg status
223 ! foobar.c
223 ! foobar.c
224 ? bar.c
224 ? bar.c
225 ? foo.c
225 ? foo.c
226 $ hg addremove
226 $ hg addremove
227 adding bar.c
227 adding bar.c
228 adding foo.c
228 adding foo.c
229 removing foobar.c
229 removing foobar.c
230 $ hg status
230 $ hg status
231 A bar.c
231 A bar.c
232 A foo.c
232 A foo.c
233 R foobar.c
233 R foobar.c
234
234
235 - A file foobar.c was moved to foo.c without using :hg:`rename`.
235 - A file foobar.c was moved to foo.c without using :hg:`rename`.
236 Afterwards, it was edited slightly::
236 Afterwards, it was edited slightly::
237
237
238 $ ls
238 $ ls
239 foo.c
239 foo.c
240 $ hg status
240 $ hg status
241 ! foobar.c
241 ! foobar.c
242 ? foo.c
242 ? foo.c
243 $ hg addremove --similarity 90
243 $ hg addremove --similarity 90
244 removing foobar.c
244 removing foobar.c
245 adding foo.c
245 adding foo.c
246 recording removal of foobar.c as rename to foo.c (94% similar)
246 recording removal of foobar.c as rename to foo.c (94% similar)
247 $ hg status -C
247 $ hg status -C
248 A foo.c
248 A foo.c
249 foobar.c
249 foobar.c
250 R foobar.c
250 R foobar.c
251
251
252 Returns 0 if all files are successfully added.
252 Returns 0 if all files are successfully added.
253 """
253 """
254 opts = pycompat.byteskwargs(opts)
254 opts = pycompat.byteskwargs(opts)
255 if not opts.get('similarity'):
255 if not opts.get('similarity'):
256 opts['similarity'] = '100'
256 opts['similarity'] = '100'
257 matcher = scmutil.match(repo[None], pats, opts)
257 matcher = scmutil.match(repo[None], pats, opts)
258 relative = scmutil.anypats(pats, opts)
258 relative = scmutil.anypats(pats, opts)
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
260 return scmutil.addremove(repo, matcher, "", uipathfn, opts)
260 return scmutil.addremove(repo, matcher, "", uipathfn, opts)
261
261
262 @command('annotate|blame',
262 @command('annotate|blame',
263 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
263 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
264 ('', 'follow', None,
264 ('', 'follow', None,
265 _('follow copies/renames and list the filename (DEPRECATED)')),
265 _('follow copies/renames and list the filename (DEPRECATED)')),
266 ('', 'no-follow', None, _("don't follow copies and renames")),
266 ('', 'no-follow', None, _("don't follow copies and renames")),
267 ('a', 'text', None, _('treat all files as text')),
267 ('a', 'text', None, _('treat all files as text')),
268 ('u', 'user', None, _('list the author (long with -v)')),
268 ('u', 'user', None, _('list the author (long with -v)')),
269 ('f', 'file', None, _('list the filename')),
269 ('f', 'file', None, _('list the filename')),
270 ('d', 'date', None, _('list the date (short with -q)')),
270 ('d', 'date', None, _('list the date (short with -q)')),
271 ('n', 'number', None, _('list the revision number (default)')),
271 ('n', 'number', None, _('list the revision number (default)')),
272 ('c', 'changeset', None, _('list the changeset')),
272 ('c', 'changeset', None, _('list the changeset')),
273 ('l', 'line-number', None, _('show line number at the first appearance')),
273 ('l', 'line-number', None, _('show line number at the first appearance')),
274 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
274 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
275 ] + diffwsopts + walkopts + formatteropts,
275 ] + diffwsopts + walkopts + formatteropts,
276 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
276 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
277 helpcategory=command.CATEGORY_FILE_CONTENTS,
277 helpcategory=command.CATEGORY_FILE_CONTENTS,
278 helpbasic=True, inferrepo=True)
278 helpbasic=True, inferrepo=True)
279 def annotate(ui, repo, *pats, **opts):
279 def annotate(ui, repo, *pats, **opts):
280 """show changeset information by line for each file
280 """show changeset information by line for each file
281
281
282 List changes in files, showing the revision id responsible for
282 List changes in files, showing the revision id responsible for
283 each line.
283 each line.
284
284
285 This command is useful for discovering when a change was made and
285 This command is useful for discovering when a change was made and
286 by whom.
286 by whom.
287
287
288 If you include --file, --user, or --date, the revision number is
288 If you include --file, --user, or --date, the revision number is
289 suppressed unless you also include --number.
289 suppressed unless you also include --number.
290
290
291 Without the -a/--text option, annotate will avoid processing files
291 Without the -a/--text option, annotate will avoid processing files
292 it detects as binary. With -a, annotate will annotate the file
292 it detects as binary. With -a, annotate will annotate the file
293 anyway, although the results will probably be neither useful
293 anyway, although the results will probably be neither useful
294 nor desirable.
294 nor desirable.
295
295
296 .. container:: verbose
296 .. container:: verbose
297
297
298 Template:
298 Template:
299
299
300 The following keywords are supported in addition to the common template
300 The following keywords are supported in addition to the common template
301 keywords and functions. See also :hg:`help templates`.
301 keywords and functions. See also :hg:`help templates`.
302
302
303 :lines: List of lines with annotation data.
303 :lines: List of lines with annotation data.
304 :path: String. Repository-absolute path of the specified file.
304 :path: String. Repository-absolute path of the specified file.
305
305
306 And each entry of ``{lines}`` provides the following sub-keywords in
306 And each entry of ``{lines}`` provides the following sub-keywords in
307 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
307 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
308
308
309 :line: String. Line content.
309 :line: String. Line content.
310 :lineno: Integer. Line number at that revision.
310 :lineno: Integer. Line number at that revision.
311 :path: String. Repository-absolute path of the file at that revision.
311 :path: String. Repository-absolute path of the file at that revision.
312
312
313 See :hg:`help templates.operators` for the list expansion syntax.
313 See :hg:`help templates.operators` for the list expansion syntax.
314
314
315 Returns 0 on success.
315 Returns 0 on success.
316 """
316 """
317 opts = pycompat.byteskwargs(opts)
317 opts = pycompat.byteskwargs(opts)
318 if not pats:
318 if not pats:
319 raise error.Abort(_('at least one filename or pattern is required'))
319 raise error.Abort(_('at least one filename or pattern is required'))
320
320
321 if opts.get('follow'):
321 if opts.get('follow'):
322 # --follow is deprecated and now just an alias for -f/--file
322 # --follow is deprecated and now just an alias for -f/--file
323 # to mimic the behavior of Mercurial before version 1.5
323 # to mimic the behavior of Mercurial before version 1.5
324 opts['file'] = True
324 opts['file'] = True
325
325
326 if (not opts.get('user') and not opts.get('changeset')
326 if (not opts.get('user') and not opts.get('changeset')
327 and not opts.get('date') and not opts.get('file')):
327 and not opts.get('date') and not opts.get('file')):
328 opts['number'] = True
328 opts['number'] = True
329
329
330 linenumber = opts.get('line_number') is not None
330 linenumber = opts.get('line_number') is not None
331 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
331 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
332 raise error.Abort(_('at least one of -n/-c is required for -l'))
332 raise error.Abort(_('at least one of -n/-c is required for -l'))
333
333
334 rev = opts.get('rev')
334 rev = opts.get('rev')
335 if rev:
335 if rev:
336 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
336 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
337 ctx = scmutil.revsingle(repo, rev)
337 ctx = scmutil.revsingle(repo, rev)
338
338
339 ui.pager('annotate')
339 ui.pager('annotate')
340 rootfm = ui.formatter('annotate', opts)
340 rootfm = ui.formatter('annotate', opts)
341 if ui.debugflag:
341 if ui.debugflag:
342 shorthex = pycompat.identity
342 shorthex = pycompat.identity
343 else:
343 else:
344 def shorthex(h):
344 def shorthex(h):
345 return h[:12]
345 return h[:12]
346 if ui.quiet:
346 if ui.quiet:
347 datefunc = dateutil.shortdate
347 datefunc = dateutil.shortdate
348 else:
348 else:
349 datefunc = dateutil.datestr
349 datefunc = dateutil.datestr
350 if ctx.rev() is None:
350 if ctx.rev() is None:
351 if opts.get('changeset'):
351 if opts.get('changeset'):
352 # omit "+" suffix which is appended to node hex
352 # omit "+" suffix which is appended to node hex
353 def formatrev(rev):
353 def formatrev(rev):
354 if rev == wdirrev:
354 if rev == wdirrev:
355 return '%d' % ctx.p1().rev()
355 return '%d' % ctx.p1().rev()
356 else:
356 else:
357 return '%d' % rev
357 return '%d' % rev
358 else:
358 else:
359 def formatrev(rev):
359 def formatrev(rev):
360 if rev == wdirrev:
360 if rev == wdirrev:
361 return '%d+' % ctx.p1().rev()
361 return '%d+' % ctx.p1().rev()
362 else:
362 else:
363 return '%d ' % rev
363 return '%d ' % rev
364 def formathex(h):
364 def formathex(h):
365 if h == wdirhex:
365 if h == wdirhex:
366 return '%s+' % shorthex(hex(ctx.p1().node()))
366 return '%s+' % shorthex(hex(ctx.p1().node()))
367 else:
367 else:
368 return '%s ' % shorthex(h)
368 return '%s ' % shorthex(h)
369 else:
369 else:
370 formatrev = b'%d'.__mod__
370 formatrev = b'%d'.__mod__
371 formathex = shorthex
371 formathex = shorthex
372
372
373 opmap = [
373 opmap = [
374 ('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
374 ('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
375 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
375 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
376 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
376 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
377 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
377 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
378 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
378 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
379 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
379 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
380 ]
380 ]
381 opnamemap = {
381 opnamemap = {
382 'rev': 'number',
382 'rev': 'number',
383 'node': 'changeset',
383 'node': 'changeset',
384 'path': 'file',
384 'path': 'file',
385 'lineno': 'line_number',
385 'lineno': 'line_number',
386 }
386 }
387
387
388 if rootfm.isplain():
388 if rootfm.isplain():
389 def makefunc(get, fmt):
389 def makefunc(get, fmt):
390 return lambda x: fmt(get(x))
390 return lambda x: fmt(get(x))
391 else:
391 else:
392 def makefunc(get, fmt):
392 def makefunc(get, fmt):
393 return get
393 return get
394 datahint = rootfm.datahint()
394 datahint = rootfm.datahint()
395 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
395 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
396 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
396 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
397 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
397 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
398 fields = ' '.join(fn for fn, sep, get, fmt in opmap
398 fields = ' '.join(fn for fn, sep, get, fmt in opmap
399 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
399 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
400
400
401 def bad(x, y):
401 def bad(x, y):
402 raise error.Abort("%s: %s" % (x, y))
402 raise error.Abort("%s: %s" % (x, y))
403
403
404 m = scmutil.match(ctx, pats, opts, badfn=bad)
404 m = scmutil.match(ctx, pats, opts, badfn=bad)
405
405
406 follow = not opts.get('no_follow')
406 follow = not opts.get('no_follow')
407 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
407 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
408 whitespace=True)
408 whitespace=True)
409 skiprevs = opts.get('skip')
409 skiprevs = opts.get('skip')
410 if skiprevs:
410 if skiprevs:
411 skiprevs = scmutil.revrange(repo, skiprevs)
411 skiprevs = scmutil.revrange(repo, skiprevs)
412
412
413 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
413 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
414 for abs in ctx.walk(m):
414 for abs in ctx.walk(m):
415 fctx = ctx[abs]
415 fctx = ctx[abs]
416 rootfm.startitem()
416 rootfm.startitem()
417 rootfm.data(path=abs)
417 rootfm.data(path=abs)
418 if not opts.get('text') and fctx.isbinary():
418 if not opts.get('text') and fctx.isbinary():
419 rootfm.plain(_("%s: binary file\n") % uipathfn(abs))
419 rootfm.plain(_("%s: binary file\n") % uipathfn(abs))
420 continue
420 continue
421
421
422 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
422 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
423 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
423 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
424 diffopts=diffopts)
424 diffopts=diffopts)
425 if not lines:
425 if not lines:
426 fm.end()
426 fm.end()
427 continue
427 continue
428 formats = []
428 formats = []
429 pieces = []
429 pieces = []
430
430
431 for f, sep in funcmap:
431 for f, sep in funcmap:
432 l = [f(n) for n in lines]
432 l = [f(n) for n in lines]
433 if fm.isplain():
433 if fm.isplain():
434 sizes = [encoding.colwidth(x) for x in l]
434 sizes = [encoding.colwidth(x) for x in l]
435 ml = max(sizes)
435 ml = max(sizes)
436 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
436 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
437 else:
437 else:
438 formats.append(['%s' for x in l])
438 formats.append(['%s' for x in l])
439 pieces.append(l)
439 pieces.append(l)
440
440
441 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
441 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
442 fm.startitem()
442 fm.startitem()
443 fm.context(fctx=n.fctx)
443 fm.context(fctx=n.fctx)
444 fm.write(fields, "".join(f), *p)
444 fm.write(fields, "".join(f), *p)
445 if n.skip:
445 if n.skip:
446 fmt = "* %s"
446 fmt = "* %s"
447 else:
447 else:
448 fmt = ": %s"
448 fmt = ": %s"
449 fm.write('line', fmt, n.text)
449 fm.write('line', fmt, n.text)
450
450
451 if not lines[-1].text.endswith('\n'):
451 if not lines[-1].text.endswith('\n'):
452 fm.plain('\n')
452 fm.plain('\n')
453 fm.end()
453 fm.end()
454
454
455 rootfm.end()
455 rootfm.end()
456
456
457 @command('archive',
457 @command('archive',
458 [('', 'no-decode', None, _('do not pass files through decoders')),
458 [('', 'no-decode', None, _('do not pass files through decoders')),
459 ('p', 'prefix', '', _('directory prefix for files in archive'),
459 ('p', 'prefix', '', _('directory prefix for files in archive'),
460 _('PREFIX')),
460 _('PREFIX')),
461 ('r', 'rev', '', _('revision to distribute'), _('REV')),
461 ('r', 'rev', '', _('revision to distribute'), _('REV')),
462 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
462 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
463 ] + subrepoopts + walkopts,
463 ] + subrepoopts + walkopts,
464 _('[OPTION]... DEST'),
464 _('[OPTION]... DEST'),
465 helpcategory=command.CATEGORY_IMPORT_EXPORT)
465 helpcategory=command.CATEGORY_IMPORT_EXPORT)
466 def archive(ui, repo, dest, **opts):
466 def archive(ui, repo, dest, **opts):
467 '''create an unversioned archive of a repository revision
467 '''create an unversioned archive of a repository revision
468
468
469 By default, the revision used is the parent of the working
469 By default, the revision used is the parent of the working
470 directory; use -r/--rev to specify a different revision.
470 directory; use -r/--rev to specify a different revision.
471
471
472 The archive type is automatically detected based on file
472 The archive type is automatically detected based on file
473 extension (to override, use -t/--type).
473 extension (to override, use -t/--type).
474
474
475 .. container:: verbose
475 .. container:: verbose
476
476
477 Examples:
477 Examples:
478
478
479 - create a zip file containing the 1.0 release::
479 - create a zip file containing the 1.0 release::
480
480
481 hg archive -r 1.0 project-1.0.zip
481 hg archive -r 1.0 project-1.0.zip
482
482
483 - create a tarball excluding .hg files::
483 - create a tarball excluding .hg files::
484
484
485 hg archive project.tar.gz -X ".hg*"
485 hg archive project.tar.gz -X ".hg*"
486
486
487 Valid types are:
487 Valid types are:
488
488
489 :``files``: a directory full of files (default)
489 :``files``: a directory full of files (default)
490 :``tar``: tar archive, uncompressed
490 :``tar``: tar archive, uncompressed
491 :``tbz2``: tar archive, compressed using bzip2
491 :``tbz2``: tar archive, compressed using bzip2
492 :``tgz``: tar archive, compressed using gzip
492 :``tgz``: tar archive, compressed using gzip
493 :``uzip``: zip archive, uncompressed
493 :``uzip``: zip archive, uncompressed
494 :``zip``: zip archive, compressed using deflate
494 :``zip``: zip archive, compressed using deflate
495
495
496 The exact name of the destination archive or directory is given
496 The exact name of the destination archive or directory is given
497 using a format string; see :hg:`help export` for details.
497 using a format string; see :hg:`help export` for details.
498
498
499 Each member added to an archive file has a directory prefix
499 Each member added to an archive file has a directory prefix
500 prepended. Use -p/--prefix to specify a format string for the
500 prepended. Use -p/--prefix to specify a format string for the
501 prefix. The default is the basename of the archive, with suffixes
501 prefix. The default is the basename of the archive, with suffixes
502 removed.
502 removed.
503
503
504 Returns 0 on success.
504 Returns 0 on success.
505 '''
505 '''
506
506
507 opts = pycompat.byteskwargs(opts)
507 opts = pycompat.byteskwargs(opts)
508 rev = opts.get('rev')
508 rev = opts.get('rev')
509 if rev:
509 if rev:
510 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
510 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
511 ctx = scmutil.revsingle(repo, rev)
511 ctx = scmutil.revsingle(repo, rev)
512 if not ctx:
512 if not ctx:
513 raise error.Abort(_('no working directory: please specify a revision'))
513 raise error.Abort(_('no working directory: please specify a revision'))
514 node = ctx.node()
514 node = ctx.node()
515 dest = cmdutil.makefilename(ctx, dest)
515 dest = cmdutil.makefilename(ctx, dest)
516 if os.path.realpath(dest) == repo.root:
516 if os.path.realpath(dest) == repo.root:
517 raise error.Abort(_('repository root cannot be destination'))
517 raise error.Abort(_('repository root cannot be destination'))
518
518
519 kind = opts.get('type') or archival.guesskind(dest) or 'files'
519 kind = opts.get('type') or archival.guesskind(dest) or 'files'
520 prefix = opts.get('prefix')
520 prefix = opts.get('prefix')
521
521
522 if dest == '-':
522 if dest == '-':
523 if kind == 'files':
523 if kind == 'files':
524 raise error.Abort(_('cannot archive plain files to stdout'))
524 raise error.Abort(_('cannot archive plain files to stdout'))
525 dest = cmdutil.makefileobj(ctx, dest)
525 dest = cmdutil.makefileobj(ctx, dest)
526 if not prefix:
526 if not prefix:
527 prefix = os.path.basename(repo.root) + '-%h'
527 prefix = os.path.basename(repo.root) + '-%h'
528
528
529 prefix = cmdutil.makefilename(ctx, prefix)
529 prefix = cmdutil.makefilename(ctx, prefix)
530 match = scmutil.match(ctx, [], opts)
530 match = scmutil.match(ctx, [], opts)
531 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
531 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
532 match, prefix, subrepos=opts.get('subrepos'))
532 match, prefix, subrepos=opts.get('subrepos'))
533
533
534 @command('backout',
534 @command('backout',
535 [('', 'merge', None, _('merge with old dirstate parent after backout')),
535 [('', 'merge', None, _('merge with old dirstate parent after backout')),
536 ('', 'commit', None,
536 ('', 'commit', None,
537 _('commit if no conflicts were encountered (DEPRECATED)')),
537 _('commit if no conflicts were encountered (DEPRECATED)')),
538 ('', 'no-commit', None, _('do not commit')),
538 ('', 'no-commit', None, _('do not commit')),
539 ('', 'parent', '',
539 ('', 'parent', '',
540 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
540 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
541 ('r', 'rev', '', _('revision to backout'), _('REV')),
541 ('r', 'rev', '', _('revision to backout'), _('REV')),
542 ('e', 'edit', False, _('invoke editor on commit messages')),
542 ('e', 'edit', False, _('invoke editor on commit messages')),
543 ] + mergetoolopts + walkopts + commitopts + commitopts2,
543 ] + mergetoolopts + walkopts + commitopts + commitopts2,
544 _('[OPTION]... [-r] REV'),
544 _('[OPTION]... [-r] REV'),
545 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
545 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
546 def backout(ui, repo, node=None, rev=None, **opts):
546 def backout(ui, repo, node=None, rev=None, **opts):
547 '''reverse effect of earlier changeset
547 '''reverse effect of earlier changeset
548
548
549 Prepare a new changeset with the effect of REV undone in the
549 Prepare a new changeset with the effect of REV undone in the
550 current working directory. If no conflicts were encountered,
550 current working directory. If no conflicts were encountered,
551 it will be committed immediately.
551 it will be committed immediately.
552
552
553 If REV is the parent of the working directory, then this new changeset
553 If REV is the parent of the working directory, then this new changeset
554 is committed automatically (unless --no-commit is specified).
554 is committed automatically (unless --no-commit is specified).
555
555
556 .. note::
556 .. note::
557
557
558 :hg:`backout` cannot be used to fix either an unwanted or
558 :hg:`backout` cannot be used to fix either an unwanted or
559 incorrect merge.
559 incorrect merge.
560
560
561 .. container:: verbose
561 .. container:: verbose
562
562
563 Examples:
563 Examples:
564
564
565 - Reverse the effect of the parent of the working directory.
565 - Reverse the effect of the parent of the working directory.
566 This backout will be committed immediately::
566 This backout will be committed immediately::
567
567
568 hg backout -r .
568 hg backout -r .
569
569
570 - Reverse the effect of previous bad revision 23::
570 - Reverse the effect of previous bad revision 23::
571
571
572 hg backout -r 23
572 hg backout -r 23
573
573
574 - Reverse the effect of previous bad revision 23 and
574 - Reverse the effect of previous bad revision 23 and
575 leave changes uncommitted::
575 leave changes uncommitted::
576
576
577 hg backout -r 23 --no-commit
577 hg backout -r 23 --no-commit
578 hg commit -m "Backout revision 23"
578 hg commit -m "Backout revision 23"
579
579
580 By default, the pending changeset will have one parent,
580 By default, the pending changeset will have one parent,
581 maintaining a linear history. With --merge, the pending
581 maintaining a linear history. With --merge, the pending
582 changeset will instead have two parents: the old parent of the
582 changeset will instead have two parents: the old parent of the
583 working directory and a new child of REV that simply undoes REV.
583 working directory and a new child of REV that simply undoes REV.
584
584
585 Before version 1.7, the behavior without --merge was equivalent
585 Before version 1.7, the behavior without --merge was equivalent
586 to specifying --merge followed by :hg:`update --clean .` to
586 to specifying --merge followed by :hg:`update --clean .` to
587 cancel the merge and leave the child of REV as a head to be
587 cancel the merge and leave the child of REV as a head to be
588 merged separately.
588 merged separately.
589
589
590 See :hg:`help dates` for a list of formats valid for -d/--date.
590 See :hg:`help dates` for a list of formats valid for -d/--date.
591
591
592 See :hg:`help revert` for a way to restore files to the state
592 See :hg:`help revert` for a way to restore files to the state
593 of another revision.
593 of another revision.
594
594
595 Returns 0 on success, 1 if nothing to backout or there are unresolved
595 Returns 0 on success, 1 if nothing to backout or there are unresolved
596 files.
596 files.
597 '''
597 '''
598 with repo.wlock(), repo.lock():
598 with repo.wlock(), repo.lock():
599 return _dobackout(ui, repo, node, rev, **opts)
599 return _dobackout(ui, repo, node, rev, **opts)
600
600
601 def _dobackout(ui, repo, node=None, rev=None, **opts):
601 def _dobackout(ui, repo, node=None, rev=None, **opts):
602 opts = pycompat.byteskwargs(opts)
602 opts = pycompat.byteskwargs(opts)
603 if opts.get('commit') and opts.get('no_commit'):
603 if opts.get('commit') and opts.get('no_commit'):
604 raise error.Abort(_("cannot use --commit with --no-commit"))
604 raise error.Abort(_("cannot use --commit with --no-commit"))
605 if opts.get('merge') and opts.get('no_commit'):
605 if opts.get('merge') and opts.get('no_commit'):
606 raise error.Abort(_("cannot use --merge with --no-commit"))
606 raise error.Abort(_("cannot use --merge with --no-commit"))
607
607
608 if rev and node:
608 if rev and node:
609 raise error.Abort(_("please specify just one revision"))
609 raise error.Abort(_("please specify just one revision"))
610
610
611 if not rev:
611 if not rev:
612 rev = node
612 rev = node
613
613
614 if not rev:
614 if not rev:
615 raise error.Abort(_("please specify a revision to backout"))
615 raise error.Abort(_("please specify a revision to backout"))
616
616
617 date = opts.get('date')
617 date = opts.get('date')
618 if date:
618 if date:
619 opts['date'] = dateutil.parsedate(date)
619 opts['date'] = dateutil.parsedate(date)
620
620
621 cmdutil.checkunfinished(repo)
621 cmdutil.checkunfinished(repo)
622 cmdutil.bailifchanged(repo)
622 cmdutil.bailifchanged(repo)
623 node = scmutil.revsingle(repo, rev).node()
623 node = scmutil.revsingle(repo, rev).node()
624
624
625 op1, op2 = repo.dirstate.parents()
625 op1, op2 = repo.dirstate.parents()
626 if not repo.changelog.isancestor(node, op1):
626 if not repo.changelog.isancestor(node, op1):
627 raise error.Abort(_('cannot backout change that is not an ancestor'))
627 raise error.Abort(_('cannot backout change that is not an ancestor'))
628
628
629 p1, p2 = repo.changelog.parents(node)
629 p1, p2 = repo.changelog.parents(node)
630 if p1 == nullid:
630 if p1 == nullid:
631 raise error.Abort(_('cannot backout a change with no parents'))
631 raise error.Abort(_('cannot backout a change with no parents'))
632 if p2 != nullid:
632 if p2 != nullid:
633 if not opts.get('parent'):
633 if not opts.get('parent'):
634 raise error.Abort(_('cannot backout a merge changeset'))
634 raise error.Abort(_('cannot backout a merge changeset'))
635 p = repo.lookup(opts['parent'])
635 p = repo.lookup(opts['parent'])
636 if p not in (p1, p2):
636 if p not in (p1, p2):
637 raise error.Abort(_('%s is not a parent of %s') %
637 raise error.Abort(_('%s is not a parent of %s') %
638 (short(p), short(node)))
638 (short(p), short(node)))
639 parent = p
639 parent = p
640 else:
640 else:
641 if opts.get('parent'):
641 if opts.get('parent'):
642 raise error.Abort(_('cannot use --parent on non-merge changeset'))
642 raise error.Abort(_('cannot use --parent on non-merge changeset'))
643 parent = p1
643 parent = p1
644
644
645 # the backout should appear on the same branch
645 # the backout should appear on the same branch
646 branch = repo.dirstate.branch()
646 branch = repo.dirstate.branch()
647 bheads = repo.branchheads(branch)
647 bheads = repo.branchheads(branch)
648 rctx = scmutil.revsingle(repo, hex(parent))
648 rctx = scmutil.revsingle(repo, hex(parent))
649 if not opts.get('merge') and op1 != node:
649 if not opts.get('merge') and op1 != node:
650 with dirstateguard.dirstateguard(repo, 'backout'):
650 with dirstateguard.dirstateguard(repo, 'backout'):
651 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
651 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
652 with ui.configoverride(overrides, 'backout'):
652 with ui.configoverride(overrides, 'backout'):
653 stats = mergemod.update(repo, parent, branchmerge=True,
653 stats = mergemod.update(repo, parent, branchmerge=True,
654 force=True, ancestor=node,
654 force=True, ancestor=node,
655 mergeancestor=False)
655 mergeancestor=False)
656 repo.setparents(op1, op2)
656 repo.setparents(op1, op2)
657 hg._showstats(repo, stats)
657 hg._showstats(repo, stats)
658 if stats.unresolvedcount:
658 if stats.unresolvedcount:
659 repo.ui.status(_("use 'hg resolve' to retry unresolved "
659 repo.ui.status(_("use 'hg resolve' to retry unresolved "
660 "file merges\n"))
660 "file merges\n"))
661 return 1
661 return 1
662 else:
662 else:
663 hg.clean(repo, node, show_stats=False)
663 hg.clean(repo, node, show_stats=False)
664 repo.dirstate.setbranch(branch)
664 repo.dirstate.setbranch(branch)
665 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
665 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
666
666
667 if opts.get('no_commit'):
667 if opts.get('no_commit'):
668 msg = _("changeset %s backed out, "
668 msg = _("changeset %s backed out, "
669 "don't forget to commit.\n")
669 "don't forget to commit.\n")
670 ui.status(msg % short(node))
670 ui.status(msg % short(node))
671 return 0
671 return 0
672
672
673 def commitfunc(ui, repo, message, match, opts):
673 def commitfunc(ui, repo, message, match, opts):
674 editform = 'backout'
674 editform = 'backout'
675 e = cmdutil.getcommiteditor(editform=editform,
675 e = cmdutil.getcommiteditor(editform=editform,
676 **pycompat.strkwargs(opts))
676 **pycompat.strkwargs(opts))
677 if not message:
677 if not message:
678 # we don't translate commit messages
678 # we don't translate commit messages
679 message = "Backed out changeset %s" % short(node)
679 message = "Backed out changeset %s" % short(node)
680 e = cmdutil.getcommiteditor(edit=True, editform=editform)
680 e = cmdutil.getcommiteditor(edit=True, editform=editform)
681 return repo.commit(message, opts.get('user'), opts.get('date'),
681 return repo.commit(message, opts.get('user'), opts.get('date'),
682 match, editor=e)
682 match, editor=e)
683 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
683 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
684 if not newnode:
684 if not newnode:
685 ui.status(_("nothing changed\n"))
685 ui.status(_("nothing changed\n"))
686 return 1
686 return 1
687 cmdutil.commitstatus(repo, newnode, branch, bheads)
687 cmdutil.commitstatus(repo, newnode, branch, bheads)
688
688
689 def nice(node):
689 def nice(node):
690 return '%d:%s' % (repo.changelog.rev(node), short(node))
690 return '%d:%s' % (repo.changelog.rev(node), short(node))
691 ui.status(_('changeset %s backs out changeset %s\n') %
691 ui.status(_('changeset %s backs out changeset %s\n') %
692 (nice(repo.changelog.tip()), nice(node)))
692 (nice(repo.changelog.tip()), nice(node)))
693 if opts.get('merge') and op1 != node:
693 if opts.get('merge') and op1 != node:
694 hg.clean(repo, op1, show_stats=False)
694 hg.clean(repo, op1, show_stats=False)
695 ui.status(_('merging with changeset %s\n')
695 ui.status(_('merging with changeset %s\n')
696 % nice(repo.changelog.tip()))
696 % nice(repo.changelog.tip()))
697 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
697 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
698 with ui.configoverride(overrides, 'backout'):
698 with ui.configoverride(overrides, 'backout'):
699 return hg.merge(repo, hex(repo.changelog.tip()))
699 return hg.merge(repo, hex(repo.changelog.tip()))
700 return 0
700 return 0
701
701
702 @command('bisect',
702 @command('bisect',
703 [('r', 'reset', False, _('reset bisect state')),
703 [('r', 'reset', False, _('reset bisect state')),
704 ('g', 'good', False, _('mark changeset good')),
704 ('g', 'good', False, _('mark changeset good')),
705 ('b', 'bad', False, _('mark changeset bad')),
705 ('b', 'bad', False, _('mark changeset bad')),
706 ('s', 'skip', False, _('skip testing changeset')),
706 ('s', 'skip', False, _('skip testing changeset')),
707 ('e', 'extend', False, _('extend the bisect range')),
707 ('e', 'extend', False, _('extend the bisect range')),
708 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
708 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
709 ('U', 'noupdate', False, _('do not update to target'))],
709 ('U', 'noupdate', False, _('do not update to target'))],
710 _("[-gbsr] [-U] [-c CMD] [REV]"),
710 _("[-gbsr] [-U] [-c CMD] [REV]"),
711 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
711 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
712 def bisect(ui, repo, rev=None, extra=None, command=None,
712 def bisect(ui, repo, rev=None, extra=None, command=None,
713 reset=None, good=None, bad=None, skip=None, extend=None,
713 reset=None, good=None, bad=None, skip=None, extend=None,
714 noupdate=None):
714 noupdate=None):
715 """subdivision search of changesets
715 """subdivision search of changesets
716
716
717 This command helps to find changesets which introduce problems. To
717 This command helps to find changesets which introduce problems. To
718 use, mark the earliest changeset you know exhibits the problem as
718 use, mark the earliest changeset you know exhibits the problem as
719 bad, then mark the latest changeset which is free from the problem
719 bad, then mark the latest changeset which is free from the problem
720 as good. Bisect will update your working directory to a revision
720 as good. Bisect will update your working directory to a revision
721 for testing (unless the -U/--noupdate option is specified). Once
721 for testing (unless the -U/--noupdate option is specified). Once
722 you have performed tests, mark the working directory as good or
722 you have performed tests, mark the working directory as good or
723 bad, and bisect will either update to another candidate changeset
723 bad, and bisect will either update to another candidate changeset
724 or announce that it has found the bad revision.
724 or announce that it has found the bad revision.
725
725
726 As a shortcut, you can also use the revision argument to mark a
726 As a shortcut, you can also use the revision argument to mark a
727 revision as good or bad without checking it out first.
727 revision as good or bad without checking it out first.
728
728
729 If you supply a command, it will be used for automatic bisection.
729 If you supply a command, it will be used for automatic bisection.
730 The environment variable HG_NODE will contain the ID of the
730 The environment variable HG_NODE will contain the ID of the
731 changeset being tested. The exit status of the command will be
731 changeset being tested. The exit status of the command will be
732 used to mark revisions as good or bad: status 0 means good, 125
732 used to mark revisions as good or bad: status 0 means good, 125
733 means to skip the revision, 127 (command not found) will abort the
733 means to skip the revision, 127 (command not found) will abort the
734 bisection, and any other non-zero exit status means the revision
734 bisection, and any other non-zero exit status means the revision
735 is bad.
735 is bad.
736
736
737 .. container:: verbose
737 .. container:: verbose
738
738
739 Some examples:
739 Some examples:
740
740
741 - start a bisection with known bad revision 34, and good revision 12::
741 - start a bisection with known bad revision 34, and good revision 12::
742
742
743 hg bisect --bad 34
743 hg bisect --bad 34
744 hg bisect --good 12
744 hg bisect --good 12
745
745
746 - advance the current bisection by marking current revision as good or
746 - advance the current bisection by marking current revision as good or
747 bad::
747 bad::
748
748
749 hg bisect --good
749 hg bisect --good
750 hg bisect --bad
750 hg bisect --bad
751
751
752 - mark the current revision, or a known revision, to be skipped (e.g. if
752 - mark the current revision, or a known revision, to be skipped (e.g. if
753 that revision is not usable because of another issue)::
753 that revision is not usable because of another issue)::
754
754
755 hg bisect --skip
755 hg bisect --skip
756 hg bisect --skip 23
756 hg bisect --skip 23
757
757
758 - skip all revisions that do not touch directories ``foo`` or ``bar``::
758 - skip all revisions that do not touch directories ``foo`` or ``bar``::
759
759
760 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
760 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
761
761
762 - forget the current bisection::
762 - forget the current bisection::
763
763
764 hg bisect --reset
764 hg bisect --reset
765
765
766 - use 'make && make tests' to automatically find the first broken
766 - use 'make && make tests' to automatically find the first broken
767 revision::
767 revision::
768
768
769 hg bisect --reset
769 hg bisect --reset
770 hg bisect --bad 34
770 hg bisect --bad 34
771 hg bisect --good 12
771 hg bisect --good 12
772 hg bisect --command "make && make tests"
772 hg bisect --command "make && make tests"
773
773
774 - see all changesets whose states are already known in the current
774 - see all changesets whose states are already known in the current
775 bisection::
775 bisection::
776
776
777 hg log -r "bisect(pruned)"
777 hg log -r "bisect(pruned)"
778
778
779 - see the changeset currently being bisected (especially useful
779 - see the changeset currently being bisected (especially useful
780 if running with -U/--noupdate)::
780 if running with -U/--noupdate)::
781
781
782 hg log -r "bisect(current)"
782 hg log -r "bisect(current)"
783
783
784 - see all changesets that took part in the current bisection::
784 - see all changesets that took part in the current bisection::
785
785
786 hg log -r "bisect(range)"
786 hg log -r "bisect(range)"
787
787
788 - you can even get a nice graph::
788 - you can even get a nice graph::
789
789
790 hg log --graph -r "bisect(range)"
790 hg log --graph -r "bisect(range)"
791
791
792 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
792 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
793
793
794 Returns 0 on success.
794 Returns 0 on success.
795 """
795 """
796 # backward compatibility
796 # backward compatibility
797 if rev in "good bad reset init".split():
797 if rev in "good bad reset init".split():
798 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
798 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
799 cmd, rev, extra = rev, extra, None
799 cmd, rev, extra = rev, extra, None
800 if cmd == "good":
800 if cmd == "good":
801 good = True
801 good = True
802 elif cmd == "bad":
802 elif cmd == "bad":
803 bad = True
803 bad = True
804 else:
804 else:
805 reset = True
805 reset = True
806 elif extra:
806 elif extra:
807 raise error.Abort(_('incompatible arguments'))
807 raise error.Abort(_('incompatible arguments'))
808
808
809 incompatibles = {
809 incompatibles = {
810 '--bad': bad,
810 '--bad': bad,
811 '--command': bool(command),
811 '--command': bool(command),
812 '--extend': extend,
812 '--extend': extend,
813 '--good': good,
813 '--good': good,
814 '--reset': reset,
814 '--reset': reset,
815 '--skip': skip,
815 '--skip': skip,
816 }
816 }
817
817
818 enabled = [x for x in incompatibles if incompatibles[x]]
818 enabled = [x for x in incompatibles if incompatibles[x]]
819
819
820 if len(enabled) > 1:
820 if len(enabled) > 1:
821 raise error.Abort(_('%s and %s are incompatible') %
821 raise error.Abort(_('%s and %s are incompatible') %
822 tuple(sorted(enabled)[0:2]))
822 tuple(sorted(enabled)[0:2]))
823
823
824 if reset:
824 if reset:
825 hbisect.resetstate(repo)
825 hbisect.resetstate(repo)
826 return
826 return
827
827
828 state = hbisect.load_state(repo)
828 state = hbisect.load_state(repo)
829
829
830 # update state
830 # update state
831 if good or bad or skip:
831 if good or bad or skip:
832 if rev:
832 if rev:
833 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
833 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
834 else:
834 else:
835 nodes = [repo.lookup('.')]
835 nodes = [repo.lookup('.')]
836 if good:
836 if good:
837 state['good'] += nodes
837 state['good'] += nodes
838 elif bad:
838 elif bad:
839 state['bad'] += nodes
839 state['bad'] += nodes
840 elif skip:
840 elif skip:
841 state['skip'] += nodes
841 state['skip'] += nodes
842 hbisect.save_state(repo, state)
842 hbisect.save_state(repo, state)
843 if not (state['good'] and state['bad']):
843 if not (state['good'] and state['bad']):
844 return
844 return
845
845
846 def mayupdate(repo, node, show_stats=True):
846 def mayupdate(repo, node, show_stats=True):
847 """common used update sequence"""
847 """common used update sequence"""
848 if noupdate:
848 if noupdate:
849 return
849 return
850 cmdutil.checkunfinished(repo)
850 cmdutil.checkunfinished(repo)
851 cmdutil.bailifchanged(repo)
851 cmdutil.bailifchanged(repo)
852 return hg.clean(repo, node, show_stats=show_stats)
852 return hg.clean(repo, node, show_stats=show_stats)
853
853
854 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
854 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
855
855
856 if command:
856 if command:
857 changesets = 1
857 changesets = 1
858 if noupdate:
858 if noupdate:
859 try:
859 try:
860 node = state['current'][0]
860 node = state['current'][0]
861 except LookupError:
861 except LookupError:
862 raise error.Abort(_('current bisect revision is unknown - '
862 raise error.Abort(_('current bisect revision is unknown - '
863 'start a new bisect to fix'))
863 'start a new bisect to fix'))
864 else:
864 else:
865 node, p2 = repo.dirstate.parents()
865 node, p2 = repo.dirstate.parents()
866 if p2 != nullid:
866 if p2 != nullid:
867 raise error.Abort(_('current bisect revision is a merge'))
867 raise error.Abort(_('current bisect revision is a merge'))
868 if rev:
868 if rev:
869 node = repo[scmutil.revsingle(repo, rev, node)].node()
869 node = repo[scmutil.revsingle(repo, rev, node)].node()
870 try:
870 try:
871 while changesets:
871 while changesets:
872 # update state
872 # update state
873 state['current'] = [node]
873 state['current'] = [node]
874 hbisect.save_state(repo, state)
874 hbisect.save_state(repo, state)
875 status = ui.system(command, environ={'HG_NODE': hex(node)},
875 status = ui.system(command, environ={'HG_NODE': hex(node)},
876 blockedtag='bisect_check')
876 blockedtag='bisect_check')
877 if status == 125:
877 if status == 125:
878 transition = "skip"
878 transition = "skip"
879 elif status == 0:
879 elif status == 0:
880 transition = "good"
880 transition = "good"
881 # status < 0 means process was killed
881 # status < 0 means process was killed
882 elif status == 127:
882 elif status == 127:
883 raise error.Abort(_("failed to execute %s") % command)
883 raise error.Abort(_("failed to execute %s") % command)
884 elif status < 0:
884 elif status < 0:
885 raise error.Abort(_("%s killed") % command)
885 raise error.Abort(_("%s killed") % command)
886 else:
886 else:
887 transition = "bad"
887 transition = "bad"
888 state[transition].append(node)
888 state[transition].append(node)
889 ctx = repo[node]
889 ctx = repo[node]
890 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
890 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
891 transition))
891 transition))
892 hbisect.checkstate(state)
892 hbisect.checkstate(state)
893 # bisect
893 # bisect
894 nodes, changesets, bgood = hbisect.bisect(repo, state)
894 nodes, changesets, bgood = hbisect.bisect(repo, state)
895 # update to next check
895 # update to next check
896 node = nodes[0]
896 node = nodes[0]
897 mayupdate(repo, node, show_stats=False)
897 mayupdate(repo, node, show_stats=False)
898 finally:
898 finally:
899 state['current'] = [node]
899 state['current'] = [node]
900 hbisect.save_state(repo, state)
900 hbisect.save_state(repo, state)
901 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
901 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
902 return
902 return
903
903
904 hbisect.checkstate(state)
904 hbisect.checkstate(state)
905
905
906 # actually bisect
906 # actually bisect
907 nodes, changesets, good = hbisect.bisect(repo, state)
907 nodes, changesets, good = hbisect.bisect(repo, state)
908 if extend:
908 if extend:
909 if not changesets:
909 if not changesets:
910 extendnode = hbisect.extendrange(repo, state, nodes, good)
910 extendnode = hbisect.extendrange(repo, state, nodes, good)
911 if extendnode is not None:
911 if extendnode is not None:
912 ui.write(_("Extending search to changeset %d:%s\n")
912 ui.write(_("Extending search to changeset %d:%s\n")
913 % (extendnode.rev(), extendnode))
913 % (extendnode.rev(), extendnode))
914 state['current'] = [extendnode.node()]
914 state['current'] = [extendnode.node()]
915 hbisect.save_state(repo, state)
915 hbisect.save_state(repo, state)
916 return mayupdate(repo, extendnode.node())
916 return mayupdate(repo, extendnode.node())
917 raise error.Abort(_("nothing to extend"))
917 raise error.Abort(_("nothing to extend"))
918
918
919 if changesets == 0:
919 if changesets == 0:
920 hbisect.printresult(ui, repo, state, displayer, nodes, good)
920 hbisect.printresult(ui, repo, state, displayer, nodes, good)
921 else:
921 else:
922 assert len(nodes) == 1 # only a single node can be tested next
922 assert len(nodes) == 1 # only a single node can be tested next
923 node = nodes[0]
923 node = nodes[0]
924 # compute the approximate number of remaining tests
924 # compute the approximate number of remaining tests
925 tests, size = 0, 2
925 tests, size = 0, 2
926 while size <= changesets:
926 while size <= changesets:
927 tests, size = tests + 1, size * 2
927 tests, size = tests + 1, size * 2
928 rev = repo.changelog.rev(node)
928 rev = repo.changelog.rev(node)
929 ui.write(_("Testing changeset %d:%s "
929 ui.write(_("Testing changeset %d:%s "
930 "(%d changesets remaining, ~%d tests)\n")
930 "(%d changesets remaining, ~%d tests)\n")
931 % (rev, short(node), changesets, tests))
931 % (rev, short(node), changesets, tests))
932 state['current'] = [node]
932 state['current'] = [node]
933 hbisect.save_state(repo, state)
933 hbisect.save_state(repo, state)
934 return mayupdate(repo, node)
934 return mayupdate(repo, node)
935
935
936 @command('bookmarks|bookmark',
936 @command('bookmarks|bookmark',
937 [('f', 'force', False, _('force')),
937 [('f', 'force', False, _('force')),
938 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
938 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
939 ('d', 'delete', False, _('delete a given bookmark')),
939 ('d', 'delete', False, _('delete a given bookmark')),
940 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
940 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
941 ('i', 'inactive', False, _('mark a bookmark inactive')),
941 ('i', 'inactive', False, _('mark a bookmark inactive')),
942 ('l', 'list', False, _('list existing bookmarks')),
942 ('l', 'list', False, _('list existing bookmarks')),
943 ] + formatteropts,
943 ] + formatteropts,
944 _('hg bookmarks [OPTIONS]... [NAME]...'),
944 _('hg bookmarks [OPTIONS]... [NAME]...'),
945 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
945 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
946 def bookmark(ui, repo, *names, **opts):
946 def bookmark(ui, repo, *names, **opts):
947 '''create a new bookmark or list existing bookmarks
947 '''create a new bookmark or list existing bookmarks
948
948
949 Bookmarks are labels on changesets to help track lines of development.
949 Bookmarks are labels on changesets to help track lines of development.
950 Bookmarks are unversioned and can be moved, renamed and deleted.
950 Bookmarks are unversioned and can be moved, renamed and deleted.
951 Deleting or moving a bookmark has no effect on the associated changesets.
951 Deleting or moving a bookmark has no effect on the associated changesets.
952
952
953 Creating or updating to a bookmark causes it to be marked as 'active'.
953 Creating or updating to a bookmark causes it to be marked as 'active'.
954 The active bookmark is indicated with a '*'.
954 The active bookmark is indicated with a '*'.
955 When a commit is made, the active bookmark will advance to the new commit.
955 When a commit is made, the active bookmark will advance to the new commit.
956 A plain :hg:`update` will also advance an active bookmark, if possible.
956 A plain :hg:`update` will also advance an active bookmark, if possible.
957 Updating away from a bookmark will cause it to be deactivated.
957 Updating away from a bookmark will cause it to be deactivated.
958
958
959 Bookmarks can be pushed and pulled between repositories (see
959 Bookmarks can be pushed and pulled between repositories (see
960 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
960 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
961 diverged, a new 'divergent bookmark' of the form 'name@path' will
961 diverged, a new 'divergent bookmark' of the form 'name@path' will
962 be created. Using :hg:`merge` will resolve the divergence.
962 be created. Using :hg:`merge` will resolve the divergence.
963
963
964 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
964 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
965 the active bookmark's name.
965 the active bookmark's name.
966
966
967 A bookmark named '@' has the special property that :hg:`clone` will
967 A bookmark named '@' has the special property that :hg:`clone` will
968 check it out by default if it exists.
968 check it out by default if it exists.
969
969
970 .. container:: verbose
970 .. container:: verbose
971
971
972 Template:
972 Template:
973
973
974 The following keywords are supported in addition to the common template
974 The following keywords are supported in addition to the common template
975 keywords and functions such as ``{bookmark}``. See also
975 keywords and functions such as ``{bookmark}``. See also
976 :hg:`help templates`.
976 :hg:`help templates`.
977
977
978 :active: Boolean. True if the bookmark is active.
978 :active: Boolean. True if the bookmark is active.
979
979
980 Examples:
980 Examples:
981
981
982 - create an active bookmark for a new line of development::
982 - create an active bookmark for a new line of development::
983
983
984 hg book new-feature
984 hg book new-feature
985
985
986 - create an inactive bookmark as a place marker::
986 - create an inactive bookmark as a place marker::
987
987
988 hg book -i reviewed
988 hg book -i reviewed
989
989
990 - create an inactive bookmark on another changeset::
990 - create an inactive bookmark on another changeset::
991
991
992 hg book -r .^ tested
992 hg book -r .^ tested
993
993
994 - rename bookmark turkey to dinner::
994 - rename bookmark turkey to dinner::
995
995
996 hg book -m turkey dinner
996 hg book -m turkey dinner
997
997
998 - move the '@' bookmark from another branch::
998 - move the '@' bookmark from another branch::
999
999
1000 hg book -f @
1000 hg book -f @
1001
1001
1002 - print only the active bookmark name::
1002 - print only the active bookmark name::
1003
1003
1004 hg book -ql .
1004 hg book -ql .
1005 '''
1005 '''
1006 opts = pycompat.byteskwargs(opts)
1006 opts = pycompat.byteskwargs(opts)
1007 force = opts.get('force')
1007 force = opts.get('force')
1008 rev = opts.get('rev')
1008 rev = opts.get('rev')
1009 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1009 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1010
1010
1011 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
1011 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
1012 if len(selactions) > 1:
1012 if len(selactions) > 1:
1013 raise error.Abort(_('--%s and --%s are incompatible')
1013 raise error.Abort(_('--%s and --%s are incompatible')
1014 % tuple(selactions[:2]))
1014 % tuple(selactions[:2]))
1015 if selactions:
1015 if selactions:
1016 action = selactions[0]
1016 action = selactions[0]
1017 elif names or rev:
1017 elif names or rev:
1018 action = 'add'
1018 action = 'add'
1019 elif inactive:
1019 elif inactive:
1020 action = 'inactive' # meaning deactivate
1020 action = 'inactive' # meaning deactivate
1021 else:
1021 else:
1022 action = 'list'
1022 action = 'list'
1023
1023
1024 if rev and action in {'delete', 'rename', 'list'}:
1024 if rev and action in {'delete', 'rename', 'list'}:
1025 raise error.Abort(_("--rev is incompatible with --%s") % action)
1025 raise error.Abort(_("--rev is incompatible with --%s") % action)
1026 if inactive and action in {'delete', 'list'}:
1026 if inactive and action in {'delete', 'list'}:
1027 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1027 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1028 if not names and action in {'add', 'delete'}:
1028 if not names and action in {'add', 'delete'}:
1029 raise error.Abort(_("bookmark name required"))
1029 raise error.Abort(_("bookmark name required"))
1030
1030
1031 if action in {'add', 'delete', 'rename', 'inactive'}:
1031 if action in {'add', 'delete', 'rename', 'inactive'}:
1032 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1032 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1033 if action == 'delete':
1033 if action == 'delete':
1034 names = pycompat.maplist(repo._bookmarks.expandname, names)
1034 names = pycompat.maplist(repo._bookmarks.expandname, names)
1035 bookmarks.delete(repo, tr, names)
1035 bookmarks.delete(repo, tr, names)
1036 elif action == 'rename':
1036 elif action == 'rename':
1037 if not names:
1037 if not names:
1038 raise error.Abort(_("new bookmark name required"))
1038 raise error.Abort(_("new bookmark name required"))
1039 elif len(names) > 1:
1039 elif len(names) > 1:
1040 raise error.Abort(_("only one new bookmark name allowed"))
1040 raise error.Abort(_("only one new bookmark name allowed"))
1041 oldname = repo._bookmarks.expandname(opts['rename'])
1041 oldname = repo._bookmarks.expandname(opts['rename'])
1042 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1042 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1043 elif action == 'add':
1043 elif action == 'add':
1044 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1044 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1045 elif action == 'inactive':
1045 elif action == 'inactive':
1046 if len(repo._bookmarks) == 0:
1046 if len(repo._bookmarks) == 0:
1047 ui.status(_("no bookmarks set\n"))
1047 ui.status(_("no bookmarks set\n"))
1048 elif not repo._activebookmark:
1048 elif not repo._activebookmark:
1049 ui.status(_("no active bookmark\n"))
1049 ui.status(_("no active bookmark\n"))
1050 else:
1050 else:
1051 bookmarks.deactivate(repo)
1051 bookmarks.deactivate(repo)
1052 elif action == 'list':
1052 elif action == 'list':
1053 names = pycompat.maplist(repo._bookmarks.expandname, names)
1053 names = pycompat.maplist(repo._bookmarks.expandname, names)
1054 with ui.formatter('bookmarks', opts) as fm:
1054 with ui.formatter('bookmarks', opts) as fm:
1055 bookmarks.printbookmarks(ui, repo, fm, names)
1055 bookmarks.printbookmarks(ui, repo, fm, names)
1056 else:
1056 else:
1057 raise error.ProgrammingError('invalid action: %s' % action)
1057 raise error.ProgrammingError('invalid action: %s' % action)
1058
1058
1059 @command('branch',
1059 @command('branch',
1060 [('f', 'force', None,
1060 [('f', 'force', None,
1061 _('set branch name even if it shadows an existing branch')),
1061 _('set branch name even if it shadows an existing branch')),
1062 ('C', 'clean', None, _('reset branch name to parent branch name')),
1062 ('C', 'clean', None, _('reset branch name to parent branch name')),
1063 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1063 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1064 ],
1064 ],
1065 _('[-fC] [NAME]'),
1065 _('[-fC] [NAME]'),
1066 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
1066 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
1067 def branch(ui, repo, label=None, **opts):
1067 def branch(ui, repo, label=None, **opts):
1068 """set or show the current branch name
1068 """set or show the current branch name
1069
1069
1070 .. note::
1070 .. note::
1071
1071
1072 Branch names are permanent and global. Use :hg:`bookmark` to create a
1072 Branch names are permanent and global. Use :hg:`bookmark` to create a
1073 light-weight bookmark instead. See :hg:`help glossary` for more
1073 light-weight bookmark instead. See :hg:`help glossary` for more
1074 information about named branches and bookmarks.
1074 information about named branches and bookmarks.
1075
1075
1076 With no argument, show the current branch name. With one argument,
1076 With no argument, show the current branch name. With one argument,
1077 set the working directory branch name (the branch will not exist
1077 set the working directory branch name (the branch will not exist
1078 in the repository until the next commit). Standard practice
1078 in the repository until the next commit). Standard practice
1079 recommends that primary development take place on the 'default'
1079 recommends that primary development take place on the 'default'
1080 branch.
1080 branch.
1081
1081
1082 Unless -f/--force is specified, branch will not let you set a
1082 Unless -f/--force is specified, branch will not let you set a
1083 branch name that already exists.
1083 branch name that already exists.
1084
1084
1085 Use -C/--clean to reset the working directory branch to that of
1085 Use -C/--clean to reset the working directory branch to that of
1086 the parent of the working directory, negating a previous branch
1086 the parent of the working directory, negating a previous branch
1087 change.
1087 change.
1088
1088
1089 Use the command :hg:`update` to switch to an existing branch. Use
1089 Use the command :hg:`update` to switch to an existing branch. Use
1090 :hg:`commit --close-branch` to mark this branch head as closed.
1090 :hg:`commit --close-branch` to mark this branch head as closed.
1091 When all heads of a branch are closed, the branch will be
1091 When all heads of a branch are closed, the branch will be
1092 considered closed.
1092 considered closed.
1093
1093
1094 Returns 0 on success.
1094 Returns 0 on success.
1095 """
1095 """
1096 opts = pycompat.byteskwargs(opts)
1096 opts = pycompat.byteskwargs(opts)
1097 revs = opts.get('rev')
1097 revs = opts.get('rev')
1098 if label:
1098 if label:
1099 label = label.strip()
1099 label = label.strip()
1100
1100
1101 if not opts.get('clean') and not label:
1101 if not opts.get('clean') and not label:
1102 if revs:
1102 if revs:
1103 raise error.Abort(_("no branch name specified for the revisions"))
1103 raise error.Abort(_("no branch name specified for the revisions"))
1104 ui.write("%s\n" % repo.dirstate.branch())
1104 ui.write("%s\n" % repo.dirstate.branch())
1105 return
1105 return
1106
1106
1107 with repo.wlock():
1107 with repo.wlock():
1108 if opts.get('clean'):
1108 if opts.get('clean'):
1109 label = repo['.'].branch()
1109 label = repo['.'].branch()
1110 repo.dirstate.setbranch(label)
1110 repo.dirstate.setbranch(label)
1111 ui.status(_('reset working directory to branch %s\n') % label)
1111 ui.status(_('reset working directory to branch %s\n') % label)
1112 elif label:
1112 elif label:
1113
1113
1114 scmutil.checknewlabel(repo, label, 'branch')
1114 scmutil.checknewlabel(repo, label, 'branch')
1115 if revs:
1115 if revs:
1116 return cmdutil.changebranch(ui, repo, revs, label)
1116 return cmdutil.changebranch(ui, repo, revs, label)
1117
1117
1118 if not opts.get('force') and label in repo.branchmap():
1118 if not opts.get('force') and label in repo.branchmap():
1119 if label not in [p.branch() for p in repo[None].parents()]:
1119 if label not in [p.branch() for p in repo[None].parents()]:
1120 raise error.Abort(_('a branch of the same name already'
1120 raise error.Abort(_('a branch of the same name already'
1121 ' exists'),
1121 ' exists'),
1122 # i18n: "it" refers to an existing branch
1122 # i18n: "it" refers to an existing branch
1123 hint=_("use 'hg update' to switch to it"))
1123 hint=_("use 'hg update' to switch to it"))
1124
1124
1125 repo.dirstate.setbranch(label)
1125 repo.dirstate.setbranch(label)
1126 ui.status(_('marked working directory as branch %s\n') % label)
1126 ui.status(_('marked working directory as branch %s\n') % label)
1127
1127
1128 # find any open named branches aside from default
1128 # find any open named branches aside from default
1129 for n, h, t, c in repo.branchmap().iterbranches():
1129 for n, h, t, c in repo.branchmap().iterbranches():
1130 if n != "default" and not c:
1130 if n != "default" and not c:
1131 return 0
1131 return 0
1132 ui.status(_('(branches are permanent and global, '
1132 ui.status(_('(branches are permanent and global, '
1133 'did you want a bookmark?)\n'))
1133 'did you want a bookmark?)\n'))
1134
1134
1135 @command('branches',
1135 @command('branches',
1136 [('a', 'active', False,
1136 [('a', 'active', False,
1137 _('show only branches that have unmerged heads (DEPRECATED)')),
1137 _('show only branches that have unmerged heads (DEPRECATED)')),
1138 ('c', 'closed', False, _('show normal and closed branches')),
1138 ('c', 'closed', False, _('show normal and closed branches')),
1139 ('r', 'rev', [], _('show branch name(s) of the given rev'))
1139 ('r', 'rev', [], _('show branch name(s) of the given rev'))
1140 ] + formatteropts,
1140 ] + formatteropts,
1141 _('[-c]'),
1141 _('[-c]'),
1142 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1142 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1143 intents={INTENT_READONLY})
1143 intents={INTENT_READONLY})
1144 def branches(ui, repo, active=False, closed=False, **opts):
1144 def branches(ui, repo, active=False, closed=False, **opts):
1145 """list repository named branches
1145 """list repository named branches
1146
1146
1147 List the repository's named branches, indicating which ones are
1147 List the repository's named branches, indicating which ones are
1148 inactive. If -c/--closed is specified, also list branches which have
1148 inactive. If -c/--closed is specified, also list branches which have
1149 been marked closed (see :hg:`commit --close-branch`).
1149 been marked closed (see :hg:`commit --close-branch`).
1150
1150
1151 Use the command :hg:`update` to switch to an existing branch.
1151 Use the command :hg:`update` to switch to an existing branch.
1152
1152
1153 .. container:: verbose
1153 .. container:: verbose
1154
1154
1155 Template:
1155 Template:
1156
1156
1157 The following keywords are supported in addition to the common template
1157 The following keywords are supported in addition to the common template
1158 keywords and functions such as ``{branch}``. See also
1158 keywords and functions such as ``{branch}``. See also
1159 :hg:`help templates`.
1159 :hg:`help templates`.
1160
1160
1161 :active: Boolean. True if the branch is active.
1161 :active: Boolean. True if the branch is active.
1162 :closed: Boolean. True if the branch is closed.
1162 :closed: Boolean. True if the branch is closed.
1163 :current: Boolean. True if it is the current branch.
1163 :current: Boolean. True if it is the current branch.
1164
1164
1165 Returns 0.
1165 Returns 0.
1166 """
1166 """
1167
1167
1168 opts = pycompat.byteskwargs(opts)
1168 opts = pycompat.byteskwargs(opts)
1169 revs = opts.get('rev')
1169 revs = opts.get('rev')
1170 selectedbranches = None
1170 selectedbranches = None
1171 if revs:
1171 if revs:
1172 revs = scmutil.revrange(repo, revs)
1172 revs = scmutil.revrange(repo, revs)
1173 getbi = repo.revbranchcache().branchinfo
1173 getbi = repo.revbranchcache().branchinfo
1174 selectedbranches = {getbi(r)[0] for r in revs}
1174 selectedbranches = {getbi(r)[0] for r in revs}
1175
1175
1176 ui.pager('branches')
1176 ui.pager('branches')
1177 fm = ui.formatter('branches', opts)
1177 fm = ui.formatter('branches', opts)
1178 hexfunc = fm.hexfunc
1178 hexfunc = fm.hexfunc
1179
1179
1180 allheads = set(repo.heads())
1180 allheads = set(repo.heads())
1181 branches = []
1181 branches = []
1182 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1182 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1183 if selectedbranches is not None and tag not in selectedbranches:
1183 if selectedbranches is not None and tag not in selectedbranches:
1184 continue
1184 continue
1185 isactive = False
1185 isactive = False
1186 if not isclosed:
1186 if not isclosed:
1187 openheads = set(repo.branchmap().iteropen(heads))
1187 openheads = set(repo.branchmap().iteropen(heads))
1188 isactive = bool(openheads & allheads)
1188 isactive = bool(openheads & allheads)
1189 branches.append((tag, repo[tip], isactive, not isclosed))
1189 branches.append((tag, repo[tip], isactive, not isclosed))
1190 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1190 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1191 reverse=True)
1191 reverse=True)
1192
1192
1193 for tag, ctx, isactive, isopen in branches:
1193 for tag, ctx, isactive, isopen in branches:
1194 if active and not isactive:
1194 if active and not isactive:
1195 continue
1195 continue
1196 if isactive:
1196 if isactive:
1197 label = 'branches.active'
1197 label = 'branches.active'
1198 notice = ''
1198 notice = ''
1199 elif not isopen:
1199 elif not isopen:
1200 if not closed:
1200 if not closed:
1201 continue
1201 continue
1202 label = 'branches.closed'
1202 label = 'branches.closed'
1203 notice = _(' (closed)')
1203 notice = _(' (closed)')
1204 else:
1204 else:
1205 label = 'branches.inactive'
1205 label = 'branches.inactive'
1206 notice = _(' (inactive)')
1206 notice = _(' (inactive)')
1207 current = (tag == repo.dirstate.branch())
1207 current = (tag == repo.dirstate.branch())
1208 if current:
1208 if current:
1209 label = 'branches.current'
1209 label = 'branches.current'
1210
1210
1211 fm.startitem()
1211 fm.startitem()
1212 fm.write('branch', '%s', tag, label=label)
1212 fm.write('branch', '%s', tag, label=label)
1213 rev = ctx.rev()
1213 rev = ctx.rev()
1214 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1214 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1215 fmt = ' ' * padsize + ' %d:%s'
1215 fmt = ' ' * padsize + ' %d:%s'
1216 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1216 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1217 label='log.changeset changeset.%s' % ctx.phasestr())
1217 label='log.changeset changeset.%s' % ctx.phasestr())
1218 fm.context(ctx=ctx)
1218 fm.context(ctx=ctx)
1219 fm.data(active=isactive, closed=not isopen, current=current)
1219 fm.data(active=isactive, closed=not isopen, current=current)
1220 if not ui.quiet:
1220 if not ui.quiet:
1221 fm.plain(notice)
1221 fm.plain(notice)
1222 fm.plain('\n')
1222 fm.plain('\n')
1223 fm.end()
1223 fm.end()
1224
1224
1225 @command('bundle',
1225 @command('bundle',
1226 [('f', 'force', None, _('run even when the destination is unrelated')),
1226 [('f', 'force', None, _('run even when the destination is unrelated')),
1227 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1227 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1228 _('REV')),
1228 _('REV')),
1229 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1229 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1230 _('BRANCH')),
1230 _('BRANCH')),
1231 ('', 'base', [],
1231 ('', 'base', [],
1232 _('a base changeset assumed to be available at the destination'),
1232 _('a base changeset assumed to be available at the destination'),
1233 _('REV')),
1233 _('REV')),
1234 ('a', 'all', None, _('bundle all changesets in the repository')),
1234 ('a', 'all', None, _('bundle all changesets in the repository')),
1235 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1235 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1236 ] + remoteopts,
1236 ] + remoteopts,
1237 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1237 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1238 helpcategory=command.CATEGORY_IMPORT_EXPORT)
1238 helpcategory=command.CATEGORY_IMPORT_EXPORT)
1239 def bundle(ui, repo, fname, dest=None, **opts):
1239 def bundle(ui, repo, fname, dest=None, **opts):
1240 """create a bundle file
1240 """create a bundle file
1241
1241
1242 Generate a bundle file containing data to be transferred to another
1242 Generate a bundle file containing data to be transferred to another
1243 repository.
1243 repository.
1244
1244
1245 To create a bundle containing all changesets, use -a/--all
1245 To create a bundle containing all changesets, use -a/--all
1246 (or --base null). Otherwise, hg assumes the destination will have
1246 (or --base null). Otherwise, hg assumes the destination will have
1247 all the nodes you specify with --base parameters. Otherwise, hg
1247 all the nodes you specify with --base parameters. Otherwise, hg
1248 will assume the repository has all the nodes in destination, or
1248 will assume the repository has all the nodes in destination, or
1249 default-push/default if no destination is specified, where destination
1249 default-push/default if no destination is specified, where destination
1250 is the repository you provide through DEST option.
1250 is the repository you provide through DEST option.
1251
1251
1252 You can change bundle format with the -t/--type option. See
1252 You can change bundle format with the -t/--type option. See
1253 :hg:`help bundlespec` for documentation on this format. By default,
1253 :hg:`help bundlespec` for documentation on this format. By default,
1254 the most appropriate format is used and compression defaults to
1254 the most appropriate format is used and compression defaults to
1255 bzip2.
1255 bzip2.
1256
1256
1257 The bundle file can then be transferred using conventional means
1257 The bundle file can then be transferred using conventional means
1258 and applied to another repository with the unbundle or pull
1258 and applied to another repository with the unbundle or pull
1259 command. This is useful when direct push and pull are not
1259 command. This is useful when direct push and pull are not
1260 available or when exporting an entire repository is undesirable.
1260 available or when exporting an entire repository is undesirable.
1261
1261
1262 Applying bundles preserves all changeset contents including
1262 Applying bundles preserves all changeset contents including
1263 permissions, copy/rename information, and revision history.
1263 permissions, copy/rename information, and revision history.
1264
1264
1265 Returns 0 on success, 1 if no changes found.
1265 Returns 0 on success, 1 if no changes found.
1266 """
1266 """
1267 opts = pycompat.byteskwargs(opts)
1267 opts = pycompat.byteskwargs(opts)
1268 revs = None
1268 revs = None
1269 if 'rev' in opts:
1269 if 'rev' in opts:
1270 revstrings = opts['rev']
1270 revstrings = opts['rev']
1271 revs = scmutil.revrange(repo, revstrings)
1271 revs = scmutil.revrange(repo, revstrings)
1272 if revstrings and not revs:
1272 if revstrings and not revs:
1273 raise error.Abort(_('no commits to bundle'))
1273 raise error.Abort(_('no commits to bundle'))
1274
1274
1275 bundletype = opts.get('type', 'bzip2').lower()
1275 bundletype = opts.get('type', 'bzip2').lower()
1276 try:
1276 try:
1277 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1277 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1278 except error.UnsupportedBundleSpecification as e:
1278 except error.UnsupportedBundleSpecification as e:
1279 raise error.Abort(pycompat.bytestr(e),
1279 raise error.Abort(pycompat.bytestr(e),
1280 hint=_("see 'hg help bundlespec' for supported "
1280 hint=_("see 'hg help bundlespec' for supported "
1281 "values for --type"))
1281 "values for --type"))
1282 cgversion = bundlespec.contentopts["cg.version"]
1282 cgversion = bundlespec.contentopts["cg.version"]
1283
1283
1284 # Packed bundles are a pseudo bundle format for now.
1284 # Packed bundles are a pseudo bundle format for now.
1285 if cgversion == 's1':
1285 if cgversion == 's1':
1286 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1286 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1287 hint=_("use 'hg debugcreatestreamclonebundle'"))
1287 hint=_("use 'hg debugcreatestreamclonebundle'"))
1288
1288
1289 if opts.get('all'):
1289 if opts.get('all'):
1290 if dest:
1290 if dest:
1291 raise error.Abort(_("--all is incompatible with specifying "
1291 raise error.Abort(_("--all is incompatible with specifying "
1292 "a destination"))
1292 "a destination"))
1293 if opts.get('base'):
1293 if opts.get('base'):
1294 ui.warn(_("ignoring --base because --all was specified\n"))
1294 ui.warn(_("ignoring --base because --all was specified\n"))
1295 base = [nullrev]
1295 base = [nullrev]
1296 else:
1296 else:
1297 base = scmutil.revrange(repo, opts.get('base'))
1297 base = scmutil.revrange(repo, opts.get('base'))
1298 if cgversion not in changegroup.supportedoutgoingversions(repo):
1298 if cgversion not in changegroup.supportedoutgoingversions(repo):
1299 raise error.Abort(_("repository does not support bundle version %s") %
1299 raise error.Abort(_("repository does not support bundle version %s") %
1300 cgversion)
1300 cgversion)
1301
1301
1302 if base:
1302 if base:
1303 if dest:
1303 if dest:
1304 raise error.Abort(_("--base is incompatible with specifying "
1304 raise error.Abort(_("--base is incompatible with specifying "
1305 "a destination"))
1305 "a destination"))
1306 common = [repo[rev].node() for rev in base]
1306 common = [repo[rev].node() for rev in base]
1307 heads = [repo[r].node() for r in revs] if revs else None
1307 heads = [repo[r].node() for r in revs] if revs else None
1308 outgoing = discovery.outgoing(repo, common, heads)
1308 outgoing = discovery.outgoing(repo, common, heads)
1309 else:
1309 else:
1310 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1310 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1311 dest, branches = hg.parseurl(dest, opts.get('branch'))
1311 dest, branches = hg.parseurl(dest, opts.get('branch'))
1312 other = hg.peer(repo, opts, dest)
1312 other = hg.peer(repo, opts, dest)
1313 revs = [repo[r].hex() for r in revs]
1313 revs = [repo[r].hex() for r in revs]
1314 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1314 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1315 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1315 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1316 outgoing = discovery.findcommonoutgoing(repo, other,
1316 outgoing = discovery.findcommonoutgoing(repo, other,
1317 onlyheads=heads,
1317 onlyheads=heads,
1318 force=opts.get('force'),
1318 force=opts.get('force'),
1319 portable=True)
1319 portable=True)
1320
1320
1321 if not outgoing.missing:
1321 if not outgoing.missing:
1322 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1322 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1323 return 1
1323 return 1
1324
1324
1325 if cgversion == '01': #bundle1
1325 if cgversion == '01': #bundle1
1326 bversion = 'HG10' + bundlespec.wirecompression
1326 bversion = 'HG10' + bundlespec.wirecompression
1327 bcompression = None
1327 bcompression = None
1328 elif cgversion in ('02', '03'):
1328 elif cgversion in ('02', '03'):
1329 bversion = 'HG20'
1329 bversion = 'HG20'
1330 bcompression = bundlespec.wirecompression
1330 bcompression = bundlespec.wirecompression
1331 else:
1331 else:
1332 raise error.ProgrammingError(
1332 raise error.ProgrammingError(
1333 'bundle: unexpected changegroup version %s' % cgversion)
1333 'bundle: unexpected changegroup version %s' % cgversion)
1334
1334
1335 # TODO compression options should be derived from bundlespec parsing.
1335 # TODO compression options should be derived from bundlespec parsing.
1336 # This is a temporary hack to allow adjusting bundle compression
1336 # This is a temporary hack to allow adjusting bundle compression
1337 # level without a) formalizing the bundlespec changes to declare it
1337 # level without a) formalizing the bundlespec changes to declare it
1338 # b) introducing a command flag.
1338 # b) introducing a command flag.
1339 compopts = {}
1339 compopts = {}
1340 complevel = ui.configint('experimental',
1340 complevel = ui.configint('experimental',
1341 'bundlecomplevel.' + bundlespec.compression)
1341 'bundlecomplevel.' + bundlespec.compression)
1342 if complevel is None:
1342 if complevel is None:
1343 complevel = ui.configint('experimental', 'bundlecomplevel')
1343 complevel = ui.configint('experimental', 'bundlecomplevel')
1344 if complevel is not None:
1344 if complevel is not None:
1345 compopts['level'] = complevel
1345 compopts['level'] = complevel
1346
1346
1347 # Allow overriding the bundling of obsmarker in phases through
1347 # Allow overriding the bundling of obsmarker in phases through
1348 # configuration while we don't have a bundle version that include them
1348 # configuration while we don't have a bundle version that include them
1349 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1349 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1350 bundlespec.contentopts['obsolescence'] = True
1350 bundlespec.contentopts['obsolescence'] = True
1351 if repo.ui.configbool('experimental', 'bundle-phases'):
1351 if repo.ui.configbool('experimental', 'bundle-phases'):
1352 bundlespec.contentopts['phases'] = True
1352 bundlespec.contentopts['phases'] = True
1353
1353
1354 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1354 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1355 bundlespec.contentopts, compression=bcompression,
1355 bundlespec.contentopts, compression=bcompression,
1356 compopts=compopts)
1356 compopts=compopts)
1357
1357
1358 @command('cat',
1358 @command('cat',
1359 [('o', 'output', '',
1359 [('o', 'output', '',
1360 _('print output to file with formatted name'), _('FORMAT')),
1360 _('print output to file with formatted name'), _('FORMAT')),
1361 ('r', 'rev', '', _('print the given revision'), _('REV')),
1361 ('r', 'rev', '', _('print the given revision'), _('REV')),
1362 ('', 'decode', None, _('apply any matching decode filter')),
1362 ('', 'decode', None, _('apply any matching decode filter')),
1363 ] + walkopts + formatteropts,
1363 ] + walkopts + formatteropts,
1364 _('[OPTION]... FILE...'),
1364 _('[OPTION]... FILE...'),
1365 helpcategory=command.CATEGORY_FILE_CONTENTS,
1365 helpcategory=command.CATEGORY_FILE_CONTENTS,
1366 inferrepo=True,
1366 inferrepo=True,
1367 intents={INTENT_READONLY})
1367 intents={INTENT_READONLY})
1368 def cat(ui, repo, file1, *pats, **opts):
1368 def cat(ui, repo, file1, *pats, **opts):
1369 """output the current or given revision of files
1369 """output the current or given revision of files
1370
1370
1371 Print the specified files as they were at the given revision. If
1371 Print the specified files as they were at the given revision. If
1372 no revision is given, the parent of the working directory is used.
1372 no revision is given, the parent of the working directory is used.
1373
1373
1374 Output may be to a file, in which case the name of the file is
1374 Output may be to a file, in which case the name of the file is
1375 given using a template string. See :hg:`help templates`. In addition
1375 given using a template string. See :hg:`help templates`. In addition
1376 to the common template keywords, the following formatting rules are
1376 to the common template keywords, the following formatting rules are
1377 supported:
1377 supported:
1378
1378
1379 :``%%``: literal "%" character
1379 :``%%``: literal "%" character
1380 :``%s``: basename of file being printed
1380 :``%s``: basename of file being printed
1381 :``%d``: dirname of file being printed, or '.' if in repository root
1381 :``%d``: dirname of file being printed, or '.' if in repository root
1382 :``%p``: root-relative path name of file being printed
1382 :``%p``: root-relative path name of file being printed
1383 :``%H``: changeset hash (40 hexadecimal digits)
1383 :``%H``: changeset hash (40 hexadecimal digits)
1384 :``%R``: changeset revision number
1384 :``%R``: changeset revision number
1385 :``%h``: short-form changeset hash (12 hexadecimal digits)
1385 :``%h``: short-form changeset hash (12 hexadecimal digits)
1386 :``%r``: zero-padded changeset revision number
1386 :``%r``: zero-padded changeset revision number
1387 :``%b``: basename of the exporting repository
1387 :``%b``: basename of the exporting repository
1388 :``\\``: literal "\\" character
1388 :``\\``: literal "\\" character
1389
1389
1390 .. container:: verbose
1390 .. container:: verbose
1391
1391
1392 Template:
1392 Template:
1393
1393
1394 The following keywords are supported in addition to the common template
1394 The following keywords are supported in addition to the common template
1395 keywords and functions. See also :hg:`help templates`.
1395 keywords and functions. See also :hg:`help templates`.
1396
1396
1397 :data: String. File content.
1397 :data: String. File content.
1398 :path: String. Repository-absolute path of the file.
1398 :path: String. Repository-absolute path of the file.
1399
1399
1400 Returns 0 on success.
1400 Returns 0 on success.
1401 """
1401 """
1402 opts = pycompat.byteskwargs(opts)
1402 opts = pycompat.byteskwargs(opts)
1403 rev = opts.get('rev')
1403 rev = opts.get('rev')
1404 if rev:
1404 if rev:
1405 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1405 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1406 ctx = scmutil.revsingle(repo, rev)
1406 ctx = scmutil.revsingle(repo, rev)
1407 m = scmutil.match(ctx, (file1,) + pats, opts)
1407 m = scmutil.match(ctx, (file1,) + pats, opts)
1408 fntemplate = opts.pop('output', '')
1408 fntemplate = opts.pop('output', '')
1409 if cmdutil.isstdiofilename(fntemplate):
1409 if cmdutil.isstdiofilename(fntemplate):
1410 fntemplate = ''
1410 fntemplate = ''
1411
1411
1412 if fntemplate:
1412 if fntemplate:
1413 fm = formatter.nullformatter(ui, 'cat', opts)
1413 fm = formatter.nullformatter(ui, 'cat', opts)
1414 else:
1414 else:
1415 ui.pager('cat')
1415 ui.pager('cat')
1416 fm = ui.formatter('cat', opts)
1416 fm = ui.formatter('cat', opts)
1417 with fm:
1417 with fm:
1418 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1418 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1419 **pycompat.strkwargs(opts))
1419 **pycompat.strkwargs(opts))
1420
1420
1421 @command('clone',
1421 @command('clone',
1422 [('U', 'noupdate', None, _('the clone will include an empty working '
1422 [('U', 'noupdate', None, _('the clone will include an empty working '
1423 'directory (only a repository)')),
1423 'directory (only a repository)')),
1424 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1424 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1425 _('REV')),
1425 _('REV')),
1426 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1426 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1427 ' and its ancestors'), _('REV')),
1427 ' and its ancestors'), _('REV')),
1428 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1428 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1429 ' changesets and their ancestors'), _('BRANCH')),
1429 ' changesets and their ancestors'), _('BRANCH')),
1430 ('', 'pull', None, _('use pull protocol to copy metadata')),
1430 ('', 'pull', None, _('use pull protocol to copy metadata')),
1431 ('', 'uncompressed', None,
1431 ('', 'uncompressed', None,
1432 _('an alias to --stream (DEPRECATED)')),
1432 _('an alias to --stream (DEPRECATED)')),
1433 ('', 'stream', None,
1433 ('', 'stream', None,
1434 _('clone with minimal data processing')),
1434 _('clone with minimal data processing')),
1435 ] + remoteopts,
1435 ] + remoteopts,
1436 _('[OPTION]... SOURCE [DEST]'),
1436 _('[OPTION]... SOURCE [DEST]'),
1437 helpcategory=command.CATEGORY_REPO_CREATION,
1437 helpcategory=command.CATEGORY_REPO_CREATION,
1438 helpbasic=True, norepo=True)
1438 helpbasic=True, norepo=True)
1439 def clone(ui, source, dest=None, **opts):
1439 def clone(ui, source, dest=None, **opts):
1440 """make a copy of an existing repository
1440 """make a copy of an existing repository
1441
1441
1442 Create a copy of an existing repository in a new directory.
1442 Create a copy of an existing repository in a new directory.
1443
1443
1444 If no destination directory name is specified, it defaults to the
1444 If no destination directory name is specified, it defaults to the
1445 basename of the source.
1445 basename of the source.
1446
1446
1447 The location of the source is added to the new repository's
1447 The location of the source is added to the new repository's
1448 ``.hg/hgrc`` file, as the default to be used for future pulls.
1448 ``.hg/hgrc`` file, as the default to be used for future pulls.
1449
1449
1450 Only local paths and ``ssh://`` URLs are supported as
1450 Only local paths and ``ssh://`` URLs are supported as
1451 destinations. For ``ssh://`` destinations, no working directory or
1451 destinations. For ``ssh://`` destinations, no working directory or
1452 ``.hg/hgrc`` will be created on the remote side.
1452 ``.hg/hgrc`` will be created on the remote side.
1453
1453
1454 If the source repository has a bookmark called '@' set, that
1454 If the source repository has a bookmark called '@' set, that
1455 revision will be checked out in the new repository by default.
1455 revision will be checked out in the new repository by default.
1456
1456
1457 To check out a particular version, use -u/--update, or
1457 To check out a particular version, use -u/--update, or
1458 -U/--noupdate to create a clone with no working directory.
1458 -U/--noupdate to create a clone with no working directory.
1459
1459
1460 To pull only a subset of changesets, specify one or more revisions
1460 To pull only a subset of changesets, specify one or more revisions
1461 identifiers with -r/--rev or branches with -b/--branch. The
1461 identifiers with -r/--rev or branches with -b/--branch. The
1462 resulting clone will contain only the specified changesets and
1462 resulting clone will contain only the specified changesets and
1463 their ancestors. These options (or 'clone src#rev dest') imply
1463 their ancestors. These options (or 'clone src#rev dest') imply
1464 --pull, even for local source repositories.
1464 --pull, even for local source repositories.
1465
1465
1466 In normal clone mode, the remote normalizes repository data into a common
1466 In normal clone mode, the remote normalizes repository data into a common
1467 exchange format and the receiving end translates this data into its local
1467 exchange format and the receiving end translates this data into its local
1468 storage format. --stream activates a different clone mode that essentially
1468 storage format. --stream activates a different clone mode that essentially
1469 copies repository files from the remote with minimal data processing. This
1469 copies repository files from the remote with minimal data processing. This
1470 significantly reduces the CPU cost of a clone both remotely and locally.
1470 significantly reduces the CPU cost of a clone both remotely and locally.
1471 However, it often increases the transferred data size by 30-40%. This can
1471 However, it often increases the transferred data size by 30-40%. This can
1472 result in substantially faster clones where I/O throughput is plentiful,
1472 result in substantially faster clones where I/O throughput is plentiful,
1473 especially for larger repositories. A side-effect of --stream clones is
1473 especially for larger repositories. A side-effect of --stream clones is
1474 that storage settings and requirements on the remote are applied locally:
1474 that storage settings and requirements on the remote are applied locally:
1475 a modern client may inherit legacy or inefficient storage used by the
1475 a modern client may inherit legacy or inefficient storage used by the
1476 remote or a legacy Mercurial client may not be able to clone from a
1476 remote or a legacy Mercurial client may not be able to clone from a
1477 modern Mercurial remote.
1477 modern Mercurial remote.
1478
1478
1479 .. note::
1479 .. note::
1480
1480
1481 Specifying a tag will include the tagged changeset but not the
1481 Specifying a tag will include the tagged changeset but not the
1482 changeset containing the tag.
1482 changeset containing the tag.
1483
1483
1484 .. container:: verbose
1484 .. container:: verbose
1485
1485
1486 For efficiency, hardlinks are used for cloning whenever the
1486 For efficiency, hardlinks are used for cloning whenever the
1487 source and destination are on the same filesystem (note this
1487 source and destination are on the same filesystem (note this
1488 applies only to the repository data, not to the working
1488 applies only to the repository data, not to the working
1489 directory). Some filesystems, such as AFS, implement hardlinking
1489 directory). Some filesystems, such as AFS, implement hardlinking
1490 incorrectly, but do not report errors. In these cases, use the
1490 incorrectly, but do not report errors. In these cases, use the
1491 --pull option to avoid hardlinking.
1491 --pull option to avoid hardlinking.
1492
1492
1493 Mercurial will update the working directory to the first applicable
1493 Mercurial will update the working directory to the first applicable
1494 revision from this list:
1494 revision from this list:
1495
1495
1496 a) null if -U or the source repository has no changesets
1496 a) null if -U or the source repository has no changesets
1497 b) if -u . and the source repository is local, the first parent of
1497 b) if -u . and the source repository is local, the first parent of
1498 the source repository's working directory
1498 the source repository's working directory
1499 c) the changeset specified with -u (if a branch name, this means the
1499 c) the changeset specified with -u (if a branch name, this means the
1500 latest head of that branch)
1500 latest head of that branch)
1501 d) the changeset specified with -r
1501 d) the changeset specified with -r
1502 e) the tipmost head specified with -b
1502 e) the tipmost head specified with -b
1503 f) the tipmost head specified with the url#branch source syntax
1503 f) the tipmost head specified with the url#branch source syntax
1504 g) the revision marked with the '@' bookmark, if present
1504 g) the revision marked with the '@' bookmark, if present
1505 h) the tipmost head of the default branch
1505 h) the tipmost head of the default branch
1506 i) tip
1506 i) tip
1507
1507
1508 When cloning from servers that support it, Mercurial may fetch
1508 When cloning from servers that support it, Mercurial may fetch
1509 pre-generated data from a server-advertised URL or inline from the
1509 pre-generated data from a server-advertised URL or inline from the
1510 same stream. When this is done, hooks operating on incoming changesets
1510 same stream. When this is done, hooks operating on incoming changesets
1511 and changegroups may fire more than once, once for each pre-generated
1511 and changegroups may fire more than once, once for each pre-generated
1512 bundle and as well as for any additional remaining data. In addition,
1512 bundle and as well as for any additional remaining data. In addition,
1513 if an error occurs, the repository may be rolled back to a partial
1513 if an error occurs, the repository may be rolled back to a partial
1514 clone. This behavior may change in future releases.
1514 clone. This behavior may change in future releases.
1515 See :hg:`help -e clonebundles` for more.
1515 See :hg:`help -e clonebundles` for more.
1516
1516
1517 Examples:
1517 Examples:
1518
1518
1519 - clone a remote repository to a new directory named hg/::
1519 - clone a remote repository to a new directory named hg/::
1520
1520
1521 hg clone https://www.mercurial-scm.org/repo/hg/
1521 hg clone https://www.mercurial-scm.org/repo/hg/
1522
1522
1523 - create a lightweight local clone::
1523 - create a lightweight local clone::
1524
1524
1525 hg clone project/ project-feature/
1525 hg clone project/ project-feature/
1526
1526
1527 - clone from an absolute path on an ssh server (note double-slash)::
1527 - clone from an absolute path on an ssh server (note double-slash)::
1528
1528
1529 hg clone ssh://user@server//home/projects/alpha/
1529 hg clone ssh://user@server//home/projects/alpha/
1530
1530
1531 - do a streaming clone while checking out a specified version::
1531 - do a streaming clone while checking out a specified version::
1532
1532
1533 hg clone --stream http://server/repo -u 1.5
1533 hg clone --stream http://server/repo -u 1.5
1534
1534
1535 - create a repository without changesets after a particular revision::
1535 - create a repository without changesets after a particular revision::
1536
1536
1537 hg clone -r 04e544 experimental/ good/
1537 hg clone -r 04e544 experimental/ good/
1538
1538
1539 - clone (and track) a particular named branch::
1539 - clone (and track) a particular named branch::
1540
1540
1541 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1541 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1542
1542
1543 See :hg:`help urls` for details on specifying URLs.
1543 See :hg:`help urls` for details on specifying URLs.
1544
1544
1545 Returns 0 on success.
1545 Returns 0 on success.
1546 """
1546 """
1547 opts = pycompat.byteskwargs(opts)
1547 opts = pycompat.byteskwargs(opts)
1548 if opts.get('noupdate') and opts.get('updaterev'):
1548 if opts.get('noupdate') and opts.get('updaterev'):
1549 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1549 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1550
1550
1551 # --include/--exclude can come from narrow or sparse.
1551 # --include/--exclude can come from narrow or sparse.
1552 includepats, excludepats = None, None
1552 includepats, excludepats = None, None
1553
1553
1554 # hg.clone() differentiates between None and an empty set. So make sure
1554 # hg.clone() differentiates between None and an empty set. So make sure
1555 # patterns are sets if narrow is requested without patterns.
1555 # patterns are sets if narrow is requested without patterns.
1556 if opts.get('narrow'):
1556 if opts.get('narrow'):
1557 includepats = set()
1557 includepats = set()
1558 excludepats = set()
1558 excludepats = set()
1559
1559
1560 if opts.get('include'):
1560 if opts.get('include'):
1561 includepats = narrowspec.parsepatterns(opts.get('include'))
1561 includepats = narrowspec.parsepatterns(opts.get('include'))
1562 if opts.get('exclude'):
1562 if opts.get('exclude'):
1563 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1563 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1564
1564
1565 r = hg.clone(ui, opts, source, dest,
1565 r = hg.clone(ui, opts, source, dest,
1566 pull=opts.get('pull'),
1566 pull=opts.get('pull'),
1567 stream=opts.get('stream') or opts.get('uncompressed'),
1567 stream=opts.get('stream') or opts.get('uncompressed'),
1568 revs=opts.get('rev'),
1568 revs=opts.get('rev'),
1569 update=opts.get('updaterev') or not opts.get('noupdate'),
1569 update=opts.get('updaterev') or not opts.get('noupdate'),
1570 branch=opts.get('branch'),
1570 branch=opts.get('branch'),
1571 shareopts=opts.get('shareopts'),
1571 shareopts=opts.get('shareopts'),
1572 storeincludepats=includepats,
1572 storeincludepats=includepats,
1573 storeexcludepats=excludepats,
1573 storeexcludepats=excludepats,
1574 depth=opts.get('depth') or None)
1574 depth=opts.get('depth') or None)
1575
1575
1576 return r is None
1576 return r is None
1577
1577
1578 @command('commit|ci',
1578 @command('commit|ci',
1579 [('A', 'addremove', None,
1579 [('A', 'addremove', None,
1580 _('mark new/missing files as added/removed before committing')),
1580 _('mark new/missing files as added/removed before committing')),
1581 ('', 'close-branch', None,
1581 ('', 'close-branch', None,
1582 _('mark a branch head as closed')),
1582 _('mark a branch head as closed')),
1583 ('', 'amend', None, _('amend the parent of the working directory')),
1583 ('', 'amend', None, _('amend the parent of the working directory')),
1584 ('s', 'secret', None, _('use the secret phase for committing')),
1584 ('s', 'secret', None, _('use the secret phase for committing')),
1585 ('e', 'edit', None, _('invoke editor on commit messages')),
1585 ('e', 'edit', None, _('invoke editor on commit messages')),
1586 ('i', 'interactive', None, _('use interactive mode')),
1586 ('i', 'interactive', None, _('use interactive mode')),
1587 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1587 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1588 _('[OPTION]... [FILE]...'),
1588 _('[OPTION]... [FILE]...'),
1589 helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
1589 helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
1590 inferrepo=True)
1590 inferrepo=True)
1591 def commit(ui, repo, *pats, **opts):
1591 def commit(ui, repo, *pats, **opts):
1592 """commit the specified files or all outstanding changes
1592 """commit the specified files or all outstanding changes
1593
1593
1594 Commit changes to the given files into the repository. Unlike a
1594 Commit changes to the given files into the repository. Unlike a
1595 centralized SCM, this operation is a local operation. See
1595 centralized SCM, this operation is a local operation. See
1596 :hg:`push` for a way to actively distribute your changes.
1596 :hg:`push` for a way to actively distribute your changes.
1597
1597
1598 If a list of files is omitted, all changes reported by :hg:`status`
1598 If a list of files is omitted, all changes reported by :hg:`status`
1599 will be committed.
1599 will be committed.
1600
1600
1601 If you are committing the result of a merge, do not provide any
1601 If you are committing the result of a merge, do not provide any
1602 filenames or -I/-X filters.
1602 filenames or -I/-X filters.
1603
1603
1604 If no commit message is specified, Mercurial starts your
1604 If no commit message is specified, Mercurial starts your
1605 configured editor where you can enter a message. In case your
1605 configured editor where you can enter a message. In case your
1606 commit fails, you will find a backup of your message in
1606 commit fails, you will find a backup of your message in
1607 ``.hg/last-message.txt``.
1607 ``.hg/last-message.txt``.
1608
1608
1609 The --close-branch flag can be used to mark the current branch
1609 The --close-branch flag can be used to mark the current branch
1610 head closed. When all heads of a branch are closed, the branch
1610 head closed. When all heads of a branch are closed, the branch
1611 will be considered closed and no longer listed.
1611 will be considered closed and no longer listed.
1612
1612
1613 The --amend flag can be used to amend the parent of the
1613 The --amend flag can be used to amend the parent of the
1614 working directory with a new commit that contains the changes
1614 working directory with a new commit that contains the changes
1615 in the parent in addition to those currently reported by :hg:`status`,
1615 in the parent in addition to those currently reported by :hg:`status`,
1616 if there are any. The old commit is stored in a backup bundle in
1616 if there are any. The old commit is stored in a backup bundle in
1617 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1617 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1618 on how to restore it).
1618 on how to restore it).
1619
1619
1620 Message, user and date are taken from the amended commit unless
1620 Message, user and date are taken from the amended commit unless
1621 specified. When a message isn't specified on the command line,
1621 specified. When a message isn't specified on the command line,
1622 the editor will open with the message of the amended commit.
1622 the editor will open with the message of the amended commit.
1623
1623
1624 It is not possible to amend public changesets (see :hg:`help phases`)
1624 It is not possible to amend public changesets (see :hg:`help phases`)
1625 or changesets that have children.
1625 or changesets that have children.
1626
1626
1627 See :hg:`help dates` for a list of formats valid for -d/--date.
1627 See :hg:`help dates` for a list of formats valid for -d/--date.
1628
1628
1629 Returns 0 on success, 1 if nothing changed.
1629 Returns 0 on success, 1 if nothing changed.
1630
1630
1631 .. container:: verbose
1631 .. container:: verbose
1632
1632
1633 Examples:
1633 Examples:
1634
1634
1635 - commit all files ending in .py::
1635 - commit all files ending in .py::
1636
1636
1637 hg commit --include "set:**.py"
1637 hg commit --include "set:**.py"
1638
1638
1639 - commit all non-binary files::
1639 - commit all non-binary files::
1640
1640
1641 hg commit --exclude "set:binary()"
1641 hg commit --exclude "set:binary()"
1642
1642
1643 - amend the current commit and set the date to now::
1643 - amend the current commit and set the date to now::
1644
1644
1645 hg commit --amend --date now
1645 hg commit --amend --date now
1646 """
1646 """
1647 with repo.wlock(), repo.lock():
1647 with repo.wlock(), repo.lock():
1648 return _docommit(ui, repo, *pats, **opts)
1648 return _docommit(ui, repo, *pats, **opts)
1649
1649
1650 def _docommit(ui, repo, *pats, **opts):
1650 def _docommit(ui, repo, *pats, **opts):
1651 if opts.get(r'interactive'):
1651 if opts.get(r'interactive'):
1652 opts.pop(r'interactive')
1652 opts.pop(r'interactive')
1653 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1653 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1654 cmdutil.recordfilter, *pats,
1654 cmdutil.recordfilter, *pats,
1655 **opts)
1655 **opts)
1656 # ret can be 0 (no changes to record) or the value returned by
1656 # ret can be 0 (no changes to record) or the value returned by
1657 # commit(), 1 if nothing changed or None on success.
1657 # commit(), 1 if nothing changed or None on success.
1658 return 1 if ret == 0 else ret
1658 return 1 if ret == 0 else ret
1659
1659
1660 opts = pycompat.byteskwargs(opts)
1660 opts = pycompat.byteskwargs(opts)
1661 if opts.get('subrepos'):
1661 if opts.get('subrepos'):
1662 if opts.get('amend'):
1662 if opts.get('amend'):
1663 raise error.Abort(_('cannot amend with --subrepos'))
1663 raise error.Abort(_('cannot amend with --subrepos'))
1664 # Let --subrepos on the command line override config setting.
1664 # Let --subrepos on the command line override config setting.
1665 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1665 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1666
1666
1667 cmdutil.checkunfinished(repo, commit=True)
1667 cmdutil.checkunfinished(repo, commit=True)
1668
1668
1669 branch = repo[None].branch()
1669 branch = repo[None].branch()
1670 bheads = repo.branchheads(branch)
1670 bheads = repo.branchheads(branch)
1671
1671
1672 extra = {}
1672 extra = {}
1673 if opts.get('close_branch'):
1673 if opts.get('close_branch'):
1674 extra['close'] = '1'
1674 extra['close'] = '1'
1675
1675
1676 if not bheads:
1676 if repo['.'].closesbranch():
1677 raise error.Abort(_('current revision is already a branch closing'
1678 ' head'))
1679 elif not bheads:
1677 raise error.Abort(_('can only close branch heads'))
1680 raise error.Abort(_('can only close branch heads'))
1678 elif branch == repo['.'].branch() and repo['.'].node() not in bheads:
1681 elif branch == repo['.'].branch() and repo['.'].node() not in bheads:
1679 raise error.Abort(_('can only close branch heads'))
1682 raise error.Abort(_('can only close branch heads'))
1680 elif opts.get('amend'):
1683 elif opts.get('amend'):
1681 if (repo['.'].p1().branch() != branch and
1684 if (repo['.'].p1().branch() != branch and
1682 repo['.'].p2().branch() != branch):
1685 repo['.'].p2().branch() != branch):
1683 raise error.Abort(_('can only close branch heads'))
1686 raise error.Abort(_('can only close branch heads'))
1684
1687
1685 if opts.get('amend'):
1688 if opts.get('amend'):
1686 if ui.configbool('ui', 'commitsubrepos'):
1689 if ui.configbool('ui', 'commitsubrepos'):
1687 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1690 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1688
1691
1689 old = repo['.']
1692 old = repo['.']
1690 rewriteutil.precheck(repo, [old.rev()], 'amend')
1693 rewriteutil.precheck(repo, [old.rev()], 'amend')
1691
1694
1692 # Currently histedit gets confused if an amend happens while histedit
1695 # Currently histedit gets confused if an amend happens while histedit
1693 # is in progress. Since we have a checkunfinished command, we are
1696 # is in progress. Since we have a checkunfinished command, we are
1694 # temporarily honoring it.
1697 # temporarily honoring it.
1695 #
1698 #
1696 # Note: eventually this guard will be removed. Please do not expect
1699 # Note: eventually this guard will be removed. Please do not expect
1697 # this behavior to remain.
1700 # this behavior to remain.
1698 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1701 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1699 cmdutil.checkunfinished(repo)
1702 cmdutil.checkunfinished(repo)
1700
1703
1701 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1704 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1702 if node == old.node():
1705 if node == old.node():
1703 ui.status(_("nothing changed\n"))
1706 ui.status(_("nothing changed\n"))
1704 return 1
1707 return 1
1705 else:
1708 else:
1706 def commitfunc(ui, repo, message, match, opts):
1709 def commitfunc(ui, repo, message, match, opts):
1707 overrides = {}
1710 overrides = {}
1708 if opts.get('secret'):
1711 if opts.get('secret'):
1709 overrides[('phases', 'new-commit')] = 'secret'
1712 overrides[('phases', 'new-commit')] = 'secret'
1710
1713
1711 baseui = repo.baseui
1714 baseui = repo.baseui
1712 with baseui.configoverride(overrides, 'commit'):
1715 with baseui.configoverride(overrides, 'commit'):
1713 with ui.configoverride(overrides, 'commit'):
1716 with ui.configoverride(overrides, 'commit'):
1714 editform = cmdutil.mergeeditform(repo[None],
1717 editform = cmdutil.mergeeditform(repo[None],
1715 'commit.normal')
1718 'commit.normal')
1716 editor = cmdutil.getcommiteditor(
1719 editor = cmdutil.getcommiteditor(
1717 editform=editform, **pycompat.strkwargs(opts))
1720 editform=editform, **pycompat.strkwargs(opts))
1718 return repo.commit(message,
1721 return repo.commit(message,
1719 opts.get('user'),
1722 opts.get('user'),
1720 opts.get('date'),
1723 opts.get('date'),
1721 match,
1724 match,
1722 editor=editor,
1725 editor=editor,
1723 extra=extra)
1726 extra=extra)
1724
1727
1725 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1728 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1726
1729
1727 if not node:
1730 if not node:
1728 stat = cmdutil.postcommitstatus(repo, pats, opts)
1731 stat = cmdutil.postcommitstatus(repo, pats, opts)
1729 if stat[3]:
1732 if stat[3]:
1730 ui.status(_("nothing changed (%d missing files, see "
1733 ui.status(_("nothing changed (%d missing files, see "
1731 "'hg status')\n") % len(stat[3]))
1734 "'hg status')\n") % len(stat[3]))
1732 else:
1735 else:
1733 ui.status(_("nothing changed\n"))
1736 ui.status(_("nothing changed\n"))
1734 return 1
1737 return 1
1735
1738
1736 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1739 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1737
1740
1738 if not ui.quiet and ui.configbool('commands', 'commit.post-status'):
1741 if not ui.quiet and ui.configbool('commands', 'commit.post-status'):
1739 status(ui, repo, modified=True, added=True, removed=True, deleted=True,
1742 status(ui, repo, modified=True, added=True, removed=True, deleted=True,
1740 unknown=True, subrepos=opts.get('subrepos'))
1743 unknown=True, subrepos=opts.get('subrepos'))
1741
1744
1742 @command('config|showconfig|debugconfig',
1745 @command('config|showconfig|debugconfig',
1743 [('u', 'untrusted', None, _('show untrusted configuration options')),
1746 [('u', 'untrusted', None, _('show untrusted configuration options')),
1744 ('e', 'edit', None, _('edit user config')),
1747 ('e', 'edit', None, _('edit user config')),
1745 ('l', 'local', None, _('edit repository config')),
1748 ('l', 'local', None, _('edit repository config')),
1746 ('g', 'global', None, _('edit global config'))] + formatteropts,
1749 ('g', 'global', None, _('edit global config'))] + formatteropts,
1747 _('[-u] [NAME]...'),
1750 _('[-u] [NAME]...'),
1748 helpcategory=command.CATEGORY_HELP,
1751 helpcategory=command.CATEGORY_HELP,
1749 optionalrepo=True,
1752 optionalrepo=True,
1750 intents={INTENT_READONLY})
1753 intents={INTENT_READONLY})
1751 def config(ui, repo, *values, **opts):
1754 def config(ui, repo, *values, **opts):
1752 """show combined config settings from all hgrc files
1755 """show combined config settings from all hgrc files
1753
1756
1754 With no arguments, print names and values of all config items.
1757 With no arguments, print names and values of all config items.
1755
1758
1756 With one argument of the form section.name, print just the value
1759 With one argument of the form section.name, print just the value
1757 of that config item.
1760 of that config item.
1758
1761
1759 With multiple arguments, print names and values of all config
1762 With multiple arguments, print names and values of all config
1760 items with matching section names or section.names.
1763 items with matching section names or section.names.
1761
1764
1762 With --edit, start an editor on the user-level config file. With
1765 With --edit, start an editor on the user-level config file. With
1763 --global, edit the system-wide config file. With --local, edit the
1766 --global, edit the system-wide config file. With --local, edit the
1764 repository-level config file.
1767 repository-level config file.
1765
1768
1766 With --debug, the source (filename and line number) is printed
1769 With --debug, the source (filename and line number) is printed
1767 for each config item.
1770 for each config item.
1768
1771
1769 See :hg:`help config` for more information about config files.
1772 See :hg:`help config` for more information about config files.
1770
1773
1771 .. container:: verbose
1774 .. container:: verbose
1772
1775
1773 Template:
1776 Template:
1774
1777
1775 The following keywords are supported. See also :hg:`help templates`.
1778 The following keywords are supported. See also :hg:`help templates`.
1776
1779
1777 :name: String. Config name.
1780 :name: String. Config name.
1778 :source: String. Filename and line number where the item is defined.
1781 :source: String. Filename and line number where the item is defined.
1779 :value: String. Config value.
1782 :value: String. Config value.
1780
1783
1781 Returns 0 on success, 1 if NAME does not exist.
1784 Returns 0 on success, 1 if NAME does not exist.
1782
1785
1783 """
1786 """
1784
1787
1785 opts = pycompat.byteskwargs(opts)
1788 opts = pycompat.byteskwargs(opts)
1786 if opts.get('edit') or opts.get('local') or opts.get('global'):
1789 if opts.get('edit') or opts.get('local') or opts.get('global'):
1787 if opts.get('local') and opts.get('global'):
1790 if opts.get('local') and opts.get('global'):
1788 raise error.Abort(_("can't use --local and --global together"))
1791 raise error.Abort(_("can't use --local and --global together"))
1789
1792
1790 if opts.get('local'):
1793 if opts.get('local'):
1791 if not repo:
1794 if not repo:
1792 raise error.Abort(_("can't use --local outside a repository"))
1795 raise error.Abort(_("can't use --local outside a repository"))
1793 paths = [repo.vfs.join('hgrc')]
1796 paths = [repo.vfs.join('hgrc')]
1794 elif opts.get('global'):
1797 elif opts.get('global'):
1795 paths = rcutil.systemrcpath()
1798 paths = rcutil.systemrcpath()
1796 else:
1799 else:
1797 paths = rcutil.userrcpath()
1800 paths = rcutil.userrcpath()
1798
1801
1799 for f in paths:
1802 for f in paths:
1800 if os.path.exists(f):
1803 if os.path.exists(f):
1801 break
1804 break
1802 else:
1805 else:
1803 if opts.get('global'):
1806 if opts.get('global'):
1804 samplehgrc = uimod.samplehgrcs['global']
1807 samplehgrc = uimod.samplehgrcs['global']
1805 elif opts.get('local'):
1808 elif opts.get('local'):
1806 samplehgrc = uimod.samplehgrcs['local']
1809 samplehgrc = uimod.samplehgrcs['local']
1807 else:
1810 else:
1808 samplehgrc = uimod.samplehgrcs['user']
1811 samplehgrc = uimod.samplehgrcs['user']
1809
1812
1810 f = paths[0]
1813 f = paths[0]
1811 fp = open(f, "wb")
1814 fp = open(f, "wb")
1812 fp.write(util.tonativeeol(samplehgrc))
1815 fp.write(util.tonativeeol(samplehgrc))
1813 fp.close()
1816 fp.close()
1814
1817
1815 editor = ui.geteditor()
1818 editor = ui.geteditor()
1816 ui.system("%s \"%s\"" % (editor, f),
1819 ui.system("%s \"%s\"" % (editor, f),
1817 onerr=error.Abort, errprefix=_("edit failed"),
1820 onerr=error.Abort, errprefix=_("edit failed"),
1818 blockedtag='config_edit')
1821 blockedtag='config_edit')
1819 return
1822 return
1820 ui.pager('config')
1823 ui.pager('config')
1821 fm = ui.formatter('config', opts)
1824 fm = ui.formatter('config', opts)
1822 for t, f in rcutil.rccomponents():
1825 for t, f in rcutil.rccomponents():
1823 if t == 'path':
1826 if t == 'path':
1824 ui.debug('read config from: %s\n' % f)
1827 ui.debug('read config from: %s\n' % f)
1825 elif t == 'items':
1828 elif t == 'items':
1826 for section, name, value, source in f:
1829 for section, name, value, source in f:
1827 ui.debug('set config by: %s\n' % source)
1830 ui.debug('set config by: %s\n' % source)
1828 else:
1831 else:
1829 raise error.ProgrammingError('unknown rctype: %s' % t)
1832 raise error.ProgrammingError('unknown rctype: %s' % t)
1830 untrusted = bool(opts.get('untrusted'))
1833 untrusted = bool(opts.get('untrusted'))
1831
1834
1832 selsections = selentries = []
1835 selsections = selentries = []
1833 if values:
1836 if values:
1834 selsections = [v for v in values if '.' not in v]
1837 selsections = [v for v in values if '.' not in v]
1835 selentries = [v for v in values if '.' in v]
1838 selentries = [v for v in values if '.' in v]
1836 uniquesel = (len(selentries) == 1 and not selsections)
1839 uniquesel = (len(selentries) == 1 and not selsections)
1837 selsections = set(selsections)
1840 selsections = set(selsections)
1838 selentries = set(selentries)
1841 selentries = set(selentries)
1839
1842
1840 matched = False
1843 matched = False
1841 for section, name, value in ui.walkconfig(untrusted=untrusted):
1844 for section, name, value in ui.walkconfig(untrusted=untrusted):
1842 source = ui.configsource(section, name, untrusted)
1845 source = ui.configsource(section, name, untrusted)
1843 value = pycompat.bytestr(value)
1846 value = pycompat.bytestr(value)
1844 if fm.isplain():
1847 if fm.isplain():
1845 source = source or 'none'
1848 source = source or 'none'
1846 value = value.replace('\n', '\\n')
1849 value = value.replace('\n', '\\n')
1847 entryname = section + '.' + name
1850 entryname = section + '.' + name
1848 if values and not (section in selsections or entryname in selentries):
1851 if values and not (section in selsections or entryname in selentries):
1849 continue
1852 continue
1850 fm.startitem()
1853 fm.startitem()
1851 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1854 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1852 if uniquesel:
1855 if uniquesel:
1853 fm.data(name=entryname)
1856 fm.data(name=entryname)
1854 fm.write('value', '%s\n', value)
1857 fm.write('value', '%s\n', value)
1855 else:
1858 else:
1856 fm.write('name value', '%s=%s\n', entryname, value)
1859 fm.write('name value', '%s=%s\n', entryname, value)
1857 matched = True
1860 matched = True
1858 fm.end()
1861 fm.end()
1859 if matched:
1862 if matched:
1860 return 0
1863 return 0
1861 return 1
1864 return 1
1862
1865
1863 @command('copy|cp',
1866 @command('copy|cp',
1864 [('A', 'after', None, _('record a copy that has already occurred')),
1867 [('A', 'after', None, _('record a copy that has already occurred')),
1865 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1868 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1866 ] + walkopts + dryrunopts,
1869 ] + walkopts + dryrunopts,
1867 _('[OPTION]... [SOURCE]... DEST'),
1870 _('[OPTION]... [SOURCE]... DEST'),
1868 helpcategory=command.CATEGORY_FILE_CONTENTS)
1871 helpcategory=command.CATEGORY_FILE_CONTENTS)
1869 def copy(ui, repo, *pats, **opts):
1872 def copy(ui, repo, *pats, **opts):
1870 """mark files as copied for the next commit
1873 """mark files as copied for the next commit
1871
1874
1872 Mark dest as having copies of source files. If dest is a
1875 Mark dest as having copies of source files. If dest is a
1873 directory, copies are put in that directory. If dest is a file,
1876 directory, copies are put in that directory. If dest is a file,
1874 the source must be a single file.
1877 the source must be a single file.
1875
1878
1876 By default, this command copies the contents of files as they
1879 By default, this command copies the contents of files as they
1877 exist in the working directory. If invoked with -A/--after, the
1880 exist in the working directory. If invoked with -A/--after, the
1878 operation is recorded, but no copying is performed.
1881 operation is recorded, but no copying is performed.
1879
1882
1880 This command takes effect with the next commit. To undo a copy
1883 This command takes effect with the next commit. To undo a copy
1881 before that, see :hg:`revert`.
1884 before that, see :hg:`revert`.
1882
1885
1883 Returns 0 on success, 1 if errors are encountered.
1886 Returns 0 on success, 1 if errors are encountered.
1884 """
1887 """
1885 opts = pycompat.byteskwargs(opts)
1888 opts = pycompat.byteskwargs(opts)
1886 with repo.wlock(False):
1889 with repo.wlock(False):
1887 return cmdutil.copy(ui, repo, pats, opts)
1890 return cmdutil.copy(ui, repo, pats, opts)
1888
1891
1889 @command(
1892 @command(
1890 'debugcommands', [], _('[COMMAND]'),
1893 'debugcommands', [], _('[COMMAND]'),
1891 helpcategory=command.CATEGORY_HELP,
1894 helpcategory=command.CATEGORY_HELP,
1892 norepo=True)
1895 norepo=True)
1893 def debugcommands(ui, cmd='', *args):
1896 def debugcommands(ui, cmd='', *args):
1894 """list all available commands and options"""
1897 """list all available commands and options"""
1895 for cmd, vals in sorted(table.iteritems()):
1898 for cmd, vals in sorted(table.iteritems()):
1896 cmd = cmd.split('|')[0]
1899 cmd = cmd.split('|')[0]
1897 opts = ', '.join([i[1] for i in vals[1]])
1900 opts = ', '.join([i[1] for i in vals[1]])
1898 ui.write('%s: %s\n' % (cmd, opts))
1901 ui.write('%s: %s\n' % (cmd, opts))
1899
1902
1900 @command('debugcomplete',
1903 @command('debugcomplete',
1901 [('o', 'options', None, _('show the command options'))],
1904 [('o', 'options', None, _('show the command options'))],
1902 _('[-o] CMD'),
1905 _('[-o] CMD'),
1903 helpcategory=command.CATEGORY_HELP,
1906 helpcategory=command.CATEGORY_HELP,
1904 norepo=True)
1907 norepo=True)
1905 def debugcomplete(ui, cmd='', **opts):
1908 def debugcomplete(ui, cmd='', **opts):
1906 """returns the completion list associated with the given command"""
1909 """returns the completion list associated with the given command"""
1907
1910
1908 if opts.get(r'options'):
1911 if opts.get(r'options'):
1909 options = []
1912 options = []
1910 otables = [globalopts]
1913 otables = [globalopts]
1911 if cmd:
1914 if cmd:
1912 aliases, entry = cmdutil.findcmd(cmd, table, False)
1915 aliases, entry = cmdutil.findcmd(cmd, table, False)
1913 otables.append(entry[1])
1916 otables.append(entry[1])
1914 for t in otables:
1917 for t in otables:
1915 for o in t:
1918 for o in t:
1916 if "(DEPRECATED)" in o[3]:
1919 if "(DEPRECATED)" in o[3]:
1917 continue
1920 continue
1918 if o[0]:
1921 if o[0]:
1919 options.append('-%s' % o[0])
1922 options.append('-%s' % o[0])
1920 options.append('--%s' % o[1])
1923 options.append('--%s' % o[1])
1921 ui.write("%s\n" % "\n".join(options))
1924 ui.write("%s\n" % "\n".join(options))
1922 return
1925 return
1923
1926
1924 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1927 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1925 if ui.verbose:
1928 if ui.verbose:
1926 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1929 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1927 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1930 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1928
1931
1929 @command('diff',
1932 @command('diff',
1930 [('r', 'rev', [], _('revision'), _('REV')),
1933 [('r', 'rev', [], _('revision'), _('REV')),
1931 ('c', 'change', '', _('change made by revision'), _('REV'))
1934 ('c', 'change', '', _('change made by revision'), _('REV'))
1932 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1935 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1933 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1936 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1934 helpcategory=command.CATEGORY_FILE_CONTENTS,
1937 helpcategory=command.CATEGORY_FILE_CONTENTS,
1935 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1938 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1936 def diff(ui, repo, *pats, **opts):
1939 def diff(ui, repo, *pats, **opts):
1937 """diff repository (or selected files)
1940 """diff repository (or selected files)
1938
1941
1939 Show differences between revisions for the specified files.
1942 Show differences between revisions for the specified files.
1940
1943
1941 Differences between files are shown using the unified diff format.
1944 Differences between files are shown using the unified diff format.
1942
1945
1943 .. note::
1946 .. note::
1944
1947
1945 :hg:`diff` may generate unexpected results for merges, as it will
1948 :hg:`diff` may generate unexpected results for merges, as it will
1946 default to comparing against the working directory's first
1949 default to comparing against the working directory's first
1947 parent changeset if no revisions are specified.
1950 parent changeset if no revisions are specified.
1948
1951
1949 When two revision arguments are given, then changes are shown
1952 When two revision arguments are given, then changes are shown
1950 between those revisions. If only one revision is specified then
1953 between those revisions. If only one revision is specified then
1951 that revision is compared to the working directory, and, when no
1954 that revision is compared to the working directory, and, when no
1952 revisions are specified, the working directory files are compared
1955 revisions are specified, the working directory files are compared
1953 to its first parent.
1956 to its first parent.
1954
1957
1955 Alternatively you can specify -c/--change with a revision to see
1958 Alternatively you can specify -c/--change with a revision to see
1956 the changes in that changeset relative to its first parent.
1959 the changes in that changeset relative to its first parent.
1957
1960
1958 Without the -a/--text option, diff will avoid generating diffs of
1961 Without the -a/--text option, diff will avoid generating diffs of
1959 files it detects as binary. With -a, diff will generate a diff
1962 files it detects as binary. With -a, diff will generate a diff
1960 anyway, probably with undesirable results.
1963 anyway, probably with undesirable results.
1961
1964
1962 Use the -g/--git option to generate diffs in the git extended diff
1965 Use the -g/--git option to generate diffs in the git extended diff
1963 format. For more information, read :hg:`help diffs`.
1966 format. For more information, read :hg:`help diffs`.
1964
1967
1965 .. container:: verbose
1968 .. container:: verbose
1966
1969
1967 Examples:
1970 Examples:
1968
1971
1969 - compare a file in the current working directory to its parent::
1972 - compare a file in the current working directory to its parent::
1970
1973
1971 hg diff foo.c
1974 hg diff foo.c
1972
1975
1973 - compare two historical versions of a directory, with rename info::
1976 - compare two historical versions of a directory, with rename info::
1974
1977
1975 hg diff --git -r 1.0:1.2 lib/
1978 hg diff --git -r 1.0:1.2 lib/
1976
1979
1977 - get change stats relative to the last change on some date::
1980 - get change stats relative to the last change on some date::
1978
1981
1979 hg diff --stat -r "date('may 2')"
1982 hg diff --stat -r "date('may 2')"
1980
1983
1981 - diff all newly-added files that contain a keyword::
1984 - diff all newly-added files that contain a keyword::
1982
1985
1983 hg diff "set:added() and grep(GNU)"
1986 hg diff "set:added() and grep(GNU)"
1984
1987
1985 - compare a revision and its parents::
1988 - compare a revision and its parents::
1986
1989
1987 hg diff -c 9353 # compare against first parent
1990 hg diff -c 9353 # compare against first parent
1988 hg diff -r 9353^:9353 # same using revset syntax
1991 hg diff -r 9353^:9353 # same using revset syntax
1989 hg diff -r 9353^2:9353 # compare against the second parent
1992 hg diff -r 9353^2:9353 # compare against the second parent
1990
1993
1991 Returns 0 on success.
1994 Returns 0 on success.
1992 """
1995 """
1993
1996
1994 opts = pycompat.byteskwargs(opts)
1997 opts = pycompat.byteskwargs(opts)
1995 revs = opts.get('rev')
1998 revs = opts.get('rev')
1996 change = opts.get('change')
1999 change = opts.get('change')
1997 stat = opts.get('stat')
2000 stat = opts.get('stat')
1998 reverse = opts.get('reverse')
2001 reverse = opts.get('reverse')
1999
2002
2000 if revs and change:
2003 if revs and change:
2001 msg = _('cannot specify --rev and --change at the same time')
2004 msg = _('cannot specify --rev and --change at the same time')
2002 raise error.Abort(msg)
2005 raise error.Abort(msg)
2003 elif change:
2006 elif change:
2004 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
2007 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
2005 ctx2 = scmutil.revsingle(repo, change, None)
2008 ctx2 = scmutil.revsingle(repo, change, None)
2006 ctx1 = ctx2.p1()
2009 ctx1 = ctx2.p1()
2007 else:
2010 else:
2008 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
2011 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
2009 ctx1, ctx2 = scmutil.revpair(repo, revs)
2012 ctx1, ctx2 = scmutil.revpair(repo, revs)
2010 node1, node2 = ctx1.node(), ctx2.node()
2013 node1, node2 = ctx1.node(), ctx2.node()
2011
2014
2012 if reverse:
2015 if reverse:
2013 node1, node2 = node2, node1
2016 node1, node2 = node2, node1
2014
2017
2015 diffopts = patch.diffallopts(ui, opts)
2018 diffopts = patch.diffallopts(ui, opts)
2016 m = scmutil.match(ctx2, pats, opts)
2019 m = scmutil.match(ctx2, pats, opts)
2017 m = repo.narrowmatch(m)
2020 m = repo.narrowmatch(m)
2018 ui.pager('diff')
2021 ui.pager('diff')
2019 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2022 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2020 listsubrepos=opts.get('subrepos'),
2023 listsubrepos=opts.get('subrepos'),
2021 root=opts.get('root'))
2024 root=opts.get('root'))
2022
2025
2023 @command('export',
2026 @command('export',
2024 [('B', 'bookmark', '',
2027 [('B', 'bookmark', '',
2025 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2028 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2026 ('o', 'output', '',
2029 ('o', 'output', '',
2027 _('print output to file with formatted name'), _('FORMAT')),
2030 _('print output to file with formatted name'), _('FORMAT')),
2028 ('', 'switch-parent', None, _('diff against the second parent')),
2031 ('', 'switch-parent', None, _('diff against the second parent')),
2029 ('r', 'rev', [], _('revisions to export'), _('REV')),
2032 ('r', 'rev', [], _('revisions to export'), _('REV')),
2030 ] + diffopts + formatteropts,
2033 ] + diffopts + formatteropts,
2031 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2034 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2032 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2035 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2033 helpbasic=True, intents={INTENT_READONLY})
2036 helpbasic=True, intents={INTENT_READONLY})
2034 def export(ui, repo, *changesets, **opts):
2037 def export(ui, repo, *changesets, **opts):
2035 """dump the header and diffs for one or more changesets
2038 """dump the header and diffs for one or more changesets
2036
2039
2037 Print the changeset header and diffs for one or more revisions.
2040 Print the changeset header and diffs for one or more revisions.
2038 If no revision is given, the parent of the working directory is used.
2041 If no revision is given, the parent of the working directory is used.
2039
2042
2040 The information shown in the changeset header is: author, date,
2043 The information shown in the changeset header is: author, date,
2041 branch name (if non-default), changeset hash, parent(s) and commit
2044 branch name (if non-default), changeset hash, parent(s) and commit
2042 comment.
2045 comment.
2043
2046
2044 .. note::
2047 .. note::
2045
2048
2046 :hg:`export` may generate unexpected diff output for merge
2049 :hg:`export` may generate unexpected diff output for merge
2047 changesets, as it will compare the merge changeset against its
2050 changesets, as it will compare the merge changeset against its
2048 first parent only.
2051 first parent only.
2049
2052
2050 Output may be to a file, in which case the name of the file is
2053 Output may be to a file, in which case the name of the file is
2051 given using a template string. See :hg:`help templates`. In addition
2054 given using a template string. See :hg:`help templates`. In addition
2052 to the common template keywords, the following formatting rules are
2055 to the common template keywords, the following formatting rules are
2053 supported:
2056 supported:
2054
2057
2055 :``%%``: literal "%" character
2058 :``%%``: literal "%" character
2056 :``%H``: changeset hash (40 hexadecimal digits)
2059 :``%H``: changeset hash (40 hexadecimal digits)
2057 :``%N``: number of patches being generated
2060 :``%N``: number of patches being generated
2058 :``%R``: changeset revision number
2061 :``%R``: changeset revision number
2059 :``%b``: basename of the exporting repository
2062 :``%b``: basename of the exporting repository
2060 :``%h``: short-form changeset hash (12 hexadecimal digits)
2063 :``%h``: short-form changeset hash (12 hexadecimal digits)
2061 :``%m``: first line of the commit message (only alphanumeric characters)
2064 :``%m``: first line of the commit message (only alphanumeric characters)
2062 :``%n``: zero-padded sequence number, starting at 1
2065 :``%n``: zero-padded sequence number, starting at 1
2063 :``%r``: zero-padded changeset revision number
2066 :``%r``: zero-padded changeset revision number
2064 :``\\``: literal "\\" character
2067 :``\\``: literal "\\" character
2065
2068
2066 Without the -a/--text option, export will avoid generating diffs
2069 Without the -a/--text option, export will avoid generating diffs
2067 of files it detects as binary. With -a, export will generate a
2070 of files it detects as binary. With -a, export will generate a
2068 diff anyway, probably with undesirable results.
2071 diff anyway, probably with undesirable results.
2069
2072
2070 With -B/--bookmark changesets reachable by the given bookmark are
2073 With -B/--bookmark changesets reachable by the given bookmark are
2071 selected.
2074 selected.
2072
2075
2073 Use the -g/--git option to generate diffs in the git extended diff
2076 Use the -g/--git option to generate diffs in the git extended diff
2074 format. See :hg:`help diffs` for more information.
2077 format. See :hg:`help diffs` for more information.
2075
2078
2076 With the --switch-parent option, the diff will be against the
2079 With the --switch-parent option, the diff will be against the
2077 second parent. It can be useful to review a merge.
2080 second parent. It can be useful to review a merge.
2078
2081
2079 .. container:: verbose
2082 .. container:: verbose
2080
2083
2081 Template:
2084 Template:
2082
2085
2083 The following keywords are supported in addition to the common template
2086 The following keywords are supported in addition to the common template
2084 keywords and functions. See also :hg:`help templates`.
2087 keywords and functions. See also :hg:`help templates`.
2085
2088
2086 :diff: String. Diff content.
2089 :diff: String. Diff content.
2087 :parents: List of strings. Parent nodes of the changeset.
2090 :parents: List of strings. Parent nodes of the changeset.
2088
2091
2089 Examples:
2092 Examples:
2090
2093
2091 - use export and import to transplant a bugfix to the current
2094 - use export and import to transplant a bugfix to the current
2092 branch::
2095 branch::
2093
2096
2094 hg export -r 9353 | hg import -
2097 hg export -r 9353 | hg import -
2095
2098
2096 - export all the changesets between two revisions to a file with
2099 - export all the changesets between two revisions to a file with
2097 rename information::
2100 rename information::
2098
2101
2099 hg export --git -r 123:150 > changes.txt
2102 hg export --git -r 123:150 > changes.txt
2100
2103
2101 - split outgoing changes into a series of patches with
2104 - split outgoing changes into a series of patches with
2102 descriptive names::
2105 descriptive names::
2103
2106
2104 hg export -r "outgoing()" -o "%n-%m.patch"
2107 hg export -r "outgoing()" -o "%n-%m.patch"
2105
2108
2106 Returns 0 on success.
2109 Returns 0 on success.
2107 """
2110 """
2108 opts = pycompat.byteskwargs(opts)
2111 opts = pycompat.byteskwargs(opts)
2109 bookmark = opts.get('bookmark')
2112 bookmark = opts.get('bookmark')
2110 changesets += tuple(opts.get('rev', []))
2113 changesets += tuple(opts.get('rev', []))
2111
2114
2112 if bookmark and changesets:
2115 if bookmark and changesets:
2113 raise error.Abort(_("-r and -B are mutually exclusive"))
2116 raise error.Abort(_("-r and -B are mutually exclusive"))
2114
2117
2115 if bookmark:
2118 if bookmark:
2116 if bookmark not in repo._bookmarks:
2119 if bookmark not in repo._bookmarks:
2117 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2120 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2118
2121
2119 revs = scmutil.bookmarkrevs(repo, bookmark)
2122 revs = scmutil.bookmarkrevs(repo, bookmark)
2120 else:
2123 else:
2121 if not changesets:
2124 if not changesets:
2122 changesets = ['.']
2125 changesets = ['.']
2123
2126
2124 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2127 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2125 revs = scmutil.revrange(repo, changesets)
2128 revs = scmutil.revrange(repo, changesets)
2126
2129
2127 if not revs:
2130 if not revs:
2128 raise error.Abort(_("export requires at least one changeset"))
2131 raise error.Abort(_("export requires at least one changeset"))
2129 if len(revs) > 1:
2132 if len(revs) > 1:
2130 ui.note(_('exporting patches:\n'))
2133 ui.note(_('exporting patches:\n'))
2131 else:
2134 else:
2132 ui.note(_('exporting patch:\n'))
2135 ui.note(_('exporting patch:\n'))
2133
2136
2134 fntemplate = opts.get('output')
2137 fntemplate = opts.get('output')
2135 if cmdutil.isstdiofilename(fntemplate):
2138 if cmdutil.isstdiofilename(fntemplate):
2136 fntemplate = ''
2139 fntemplate = ''
2137
2140
2138 if fntemplate:
2141 if fntemplate:
2139 fm = formatter.nullformatter(ui, 'export', opts)
2142 fm = formatter.nullformatter(ui, 'export', opts)
2140 else:
2143 else:
2141 ui.pager('export')
2144 ui.pager('export')
2142 fm = ui.formatter('export', opts)
2145 fm = ui.formatter('export', opts)
2143 with fm:
2146 with fm:
2144 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2147 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2145 switch_parent=opts.get('switch_parent'),
2148 switch_parent=opts.get('switch_parent'),
2146 opts=patch.diffallopts(ui, opts))
2149 opts=patch.diffallopts(ui, opts))
2147
2150
2148 @command('files',
2151 @command('files',
2149 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2152 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2150 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2153 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2151 ] + walkopts + formatteropts + subrepoopts,
2154 ] + walkopts + formatteropts + subrepoopts,
2152 _('[OPTION]... [FILE]...'),
2155 _('[OPTION]... [FILE]...'),
2153 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2156 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2154 intents={INTENT_READONLY})
2157 intents={INTENT_READONLY})
2155 def files(ui, repo, *pats, **opts):
2158 def files(ui, repo, *pats, **opts):
2156 """list tracked files
2159 """list tracked files
2157
2160
2158 Print files under Mercurial control in the working directory or
2161 Print files under Mercurial control in the working directory or
2159 specified revision for given files (excluding removed files).
2162 specified revision for given files (excluding removed files).
2160 Files can be specified as filenames or filesets.
2163 Files can be specified as filenames or filesets.
2161
2164
2162 If no files are given to match, this command prints the names
2165 If no files are given to match, this command prints the names
2163 of all files under Mercurial control.
2166 of all files under Mercurial control.
2164
2167
2165 .. container:: verbose
2168 .. container:: verbose
2166
2169
2167 Template:
2170 Template:
2168
2171
2169 The following keywords are supported in addition to the common template
2172 The following keywords are supported in addition to the common template
2170 keywords and functions. See also :hg:`help templates`.
2173 keywords and functions. See also :hg:`help templates`.
2171
2174
2172 :flags: String. Character denoting file's symlink and executable bits.
2175 :flags: String. Character denoting file's symlink and executable bits.
2173 :path: String. Repository-absolute path of the file.
2176 :path: String. Repository-absolute path of the file.
2174 :size: Integer. Size of the file in bytes.
2177 :size: Integer. Size of the file in bytes.
2175
2178
2176 Examples:
2179 Examples:
2177
2180
2178 - list all files under the current directory::
2181 - list all files under the current directory::
2179
2182
2180 hg files .
2183 hg files .
2181
2184
2182 - shows sizes and flags for current revision::
2185 - shows sizes and flags for current revision::
2183
2186
2184 hg files -vr .
2187 hg files -vr .
2185
2188
2186 - list all files named README::
2189 - list all files named README::
2187
2190
2188 hg files -I "**/README"
2191 hg files -I "**/README"
2189
2192
2190 - list all binary files::
2193 - list all binary files::
2191
2194
2192 hg files "set:binary()"
2195 hg files "set:binary()"
2193
2196
2194 - find files containing a regular expression::
2197 - find files containing a regular expression::
2195
2198
2196 hg files "set:grep('bob')"
2199 hg files "set:grep('bob')"
2197
2200
2198 - search tracked file contents with xargs and grep::
2201 - search tracked file contents with xargs and grep::
2199
2202
2200 hg files -0 | xargs -0 grep foo
2203 hg files -0 | xargs -0 grep foo
2201
2204
2202 See :hg:`help patterns` and :hg:`help filesets` for more information
2205 See :hg:`help patterns` and :hg:`help filesets` for more information
2203 on specifying file patterns.
2206 on specifying file patterns.
2204
2207
2205 Returns 0 if a match is found, 1 otherwise.
2208 Returns 0 if a match is found, 1 otherwise.
2206
2209
2207 """
2210 """
2208
2211
2209 opts = pycompat.byteskwargs(opts)
2212 opts = pycompat.byteskwargs(opts)
2210 rev = opts.get('rev')
2213 rev = opts.get('rev')
2211 if rev:
2214 if rev:
2212 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2215 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2213 ctx = scmutil.revsingle(repo, rev, None)
2216 ctx = scmutil.revsingle(repo, rev, None)
2214
2217
2215 end = '\n'
2218 end = '\n'
2216 if opts.get('print0'):
2219 if opts.get('print0'):
2217 end = '\0'
2220 end = '\0'
2218 fmt = '%s' + end
2221 fmt = '%s' + end
2219
2222
2220 m = scmutil.match(ctx, pats, opts)
2223 m = scmutil.match(ctx, pats, opts)
2221 ui.pager('files')
2224 ui.pager('files')
2222 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2225 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2223 with ui.formatter('files', opts) as fm:
2226 with ui.formatter('files', opts) as fm:
2224 return cmdutil.files(ui, ctx, m, uipathfn, fm, fmt,
2227 return cmdutil.files(ui, ctx, m, uipathfn, fm, fmt,
2225 opts.get('subrepos'))
2228 opts.get('subrepos'))
2226
2229
2227 @command(
2230 @command(
2228 'forget',
2231 'forget',
2229 [('i', 'interactive', None, _('use interactive mode')),
2232 [('i', 'interactive', None, _('use interactive mode')),
2230 ] + walkopts + dryrunopts,
2233 ] + walkopts + dryrunopts,
2231 _('[OPTION]... FILE...'),
2234 _('[OPTION]... FILE...'),
2232 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2235 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2233 helpbasic=True, inferrepo=True)
2236 helpbasic=True, inferrepo=True)
2234 def forget(ui, repo, *pats, **opts):
2237 def forget(ui, repo, *pats, **opts):
2235 """forget the specified files on the next commit
2238 """forget the specified files on the next commit
2236
2239
2237 Mark the specified files so they will no longer be tracked
2240 Mark the specified files so they will no longer be tracked
2238 after the next commit.
2241 after the next commit.
2239
2242
2240 This only removes files from the current branch, not from the
2243 This only removes files from the current branch, not from the
2241 entire project history, and it does not delete them from the
2244 entire project history, and it does not delete them from the
2242 working directory.
2245 working directory.
2243
2246
2244 To delete the file from the working directory, see :hg:`remove`.
2247 To delete the file from the working directory, see :hg:`remove`.
2245
2248
2246 To undo a forget before the next commit, see :hg:`add`.
2249 To undo a forget before the next commit, see :hg:`add`.
2247
2250
2248 .. container:: verbose
2251 .. container:: verbose
2249
2252
2250 Examples:
2253 Examples:
2251
2254
2252 - forget newly-added binary files::
2255 - forget newly-added binary files::
2253
2256
2254 hg forget "set:added() and binary()"
2257 hg forget "set:added() and binary()"
2255
2258
2256 - forget files that would be excluded by .hgignore::
2259 - forget files that would be excluded by .hgignore::
2257
2260
2258 hg forget "set:hgignore()"
2261 hg forget "set:hgignore()"
2259
2262
2260 Returns 0 on success.
2263 Returns 0 on success.
2261 """
2264 """
2262
2265
2263 opts = pycompat.byteskwargs(opts)
2266 opts = pycompat.byteskwargs(opts)
2264 if not pats:
2267 if not pats:
2265 raise error.Abort(_('no files specified'))
2268 raise error.Abort(_('no files specified'))
2266
2269
2267 m = scmutil.match(repo[None], pats, opts)
2270 m = scmutil.match(repo[None], pats, opts)
2268 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2271 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2269 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2272 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2270 rejected = cmdutil.forget(ui, repo, m, prefix="", uipathfn=uipathfn,
2273 rejected = cmdutil.forget(ui, repo, m, prefix="", uipathfn=uipathfn,
2271 explicitonly=False, dryrun=dryrun,
2274 explicitonly=False, dryrun=dryrun,
2272 interactive=interactive)[0]
2275 interactive=interactive)[0]
2273 return rejected and 1 or 0
2276 return rejected and 1 or 0
2274
2277
2275 @command(
2278 @command(
2276 'graft',
2279 'graft',
2277 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2280 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2278 ('', 'base', '',
2281 ('', 'base', '',
2279 _('base revision when doing the graft merge (ADVANCED)'), _('REV')),
2282 _('base revision when doing the graft merge (ADVANCED)'), _('REV')),
2280 ('c', 'continue', False, _('resume interrupted graft')),
2283 ('c', 'continue', False, _('resume interrupted graft')),
2281 ('', 'stop', False, _('stop interrupted graft')),
2284 ('', 'stop', False, _('stop interrupted graft')),
2282 ('', 'abort', False, _('abort interrupted graft')),
2285 ('', 'abort', False, _('abort interrupted graft')),
2283 ('e', 'edit', False, _('invoke editor on commit messages')),
2286 ('e', 'edit', False, _('invoke editor on commit messages')),
2284 ('', 'log', None, _('append graft info to log message')),
2287 ('', 'log', None, _('append graft info to log message')),
2285 ('', 'no-commit', None,
2288 ('', 'no-commit', None,
2286 _("don't commit, just apply the changes in working directory")),
2289 _("don't commit, just apply the changes in working directory")),
2287 ('f', 'force', False, _('force graft')),
2290 ('f', 'force', False, _('force graft')),
2288 ('D', 'currentdate', False,
2291 ('D', 'currentdate', False,
2289 _('record the current date as commit date')),
2292 _('record the current date as commit date')),
2290 ('U', 'currentuser', False,
2293 ('U', 'currentuser', False,
2291 _('record the current user as committer'))]
2294 _('record the current user as committer'))]
2292 + commitopts2 + mergetoolopts + dryrunopts,
2295 + commitopts2 + mergetoolopts + dryrunopts,
2293 _('[OPTION]... [-r REV]... REV...'),
2296 _('[OPTION]... [-r REV]... REV...'),
2294 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2297 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2295 def graft(ui, repo, *revs, **opts):
2298 def graft(ui, repo, *revs, **opts):
2296 '''copy changes from other branches onto the current branch
2299 '''copy changes from other branches onto the current branch
2297
2300
2298 This command uses Mercurial's merge logic to copy individual
2301 This command uses Mercurial's merge logic to copy individual
2299 changes from other branches without merging branches in the
2302 changes from other branches without merging branches in the
2300 history graph. This is sometimes known as 'backporting' or
2303 history graph. This is sometimes known as 'backporting' or
2301 'cherry-picking'. By default, graft will copy user, date, and
2304 'cherry-picking'. By default, graft will copy user, date, and
2302 description from the source changesets.
2305 description from the source changesets.
2303
2306
2304 Changesets that are ancestors of the current revision, that have
2307 Changesets that are ancestors of the current revision, that have
2305 already been grafted, or that are merges will be skipped.
2308 already been grafted, or that are merges will be skipped.
2306
2309
2307 If --log is specified, log messages will have a comment appended
2310 If --log is specified, log messages will have a comment appended
2308 of the form::
2311 of the form::
2309
2312
2310 (grafted from CHANGESETHASH)
2313 (grafted from CHANGESETHASH)
2311
2314
2312 If --force is specified, revisions will be grafted even if they
2315 If --force is specified, revisions will be grafted even if they
2313 are already ancestors of, or have been grafted to, the destination.
2316 are already ancestors of, or have been grafted to, the destination.
2314 This is useful when the revisions have since been backed out.
2317 This is useful when the revisions have since been backed out.
2315
2318
2316 If a graft merge results in conflicts, the graft process is
2319 If a graft merge results in conflicts, the graft process is
2317 interrupted so that the current merge can be manually resolved.
2320 interrupted so that the current merge can be manually resolved.
2318 Once all conflicts are addressed, the graft process can be
2321 Once all conflicts are addressed, the graft process can be
2319 continued with the -c/--continue option.
2322 continued with the -c/--continue option.
2320
2323
2321 The -c/--continue option reapplies all the earlier options.
2324 The -c/--continue option reapplies all the earlier options.
2322
2325
2323 .. container:: verbose
2326 .. container:: verbose
2324
2327
2325 The --base option exposes more of how graft internally uses merge with a
2328 The --base option exposes more of how graft internally uses merge with a
2326 custom base revision. --base can be used to specify another ancestor than
2329 custom base revision. --base can be used to specify another ancestor than
2327 the first and only parent.
2330 the first and only parent.
2328
2331
2329 The command::
2332 The command::
2330
2333
2331 hg graft -r 345 --base 234
2334 hg graft -r 345 --base 234
2332
2335
2333 is thus pretty much the same as::
2336 is thus pretty much the same as::
2334
2337
2335 hg diff -r 234 -r 345 | hg import
2338 hg diff -r 234 -r 345 | hg import
2336
2339
2337 but using merge to resolve conflicts and track moved files.
2340 but using merge to resolve conflicts and track moved files.
2338
2341
2339 The result of a merge can thus be backported as a single commit by
2342 The result of a merge can thus be backported as a single commit by
2340 specifying one of the merge parents as base, and thus effectively
2343 specifying one of the merge parents as base, and thus effectively
2341 grafting the changes from the other side.
2344 grafting the changes from the other side.
2342
2345
2343 It is also possible to collapse multiple changesets and clean up history
2346 It is also possible to collapse multiple changesets and clean up history
2344 by specifying another ancestor as base, much like rebase --collapse
2347 by specifying another ancestor as base, much like rebase --collapse
2345 --keep.
2348 --keep.
2346
2349
2347 The commit message can be tweaked after the fact using commit --amend .
2350 The commit message can be tweaked after the fact using commit --amend .
2348
2351
2349 For using non-ancestors as the base to backout changes, see the backout
2352 For using non-ancestors as the base to backout changes, see the backout
2350 command and the hidden --parent option.
2353 command and the hidden --parent option.
2351
2354
2352 .. container:: verbose
2355 .. container:: verbose
2353
2356
2354 Examples:
2357 Examples:
2355
2358
2356 - copy a single change to the stable branch and edit its description::
2359 - copy a single change to the stable branch and edit its description::
2357
2360
2358 hg update stable
2361 hg update stable
2359 hg graft --edit 9393
2362 hg graft --edit 9393
2360
2363
2361 - graft a range of changesets with one exception, updating dates::
2364 - graft a range of changesets with one exception, updating dates::
2362
2365
2363 hg graft -D "2085::2093 and not 2091"
2366 hg graft -D "2085::2093 and not 2091"
2364
2367
2365 - continue a graft after resolving conflicts::
2368 - continue a graft after resolving conflicts::
2366
2369
2367 hg graft -c
2370 hg graft -c
2368
2371
2369 - show the source of a grafted changeset::
2372 - show the source of a grafted changeset::
2370
2373
2371 hg log --debug -r .
2374 hg log --debug -r .
2372
2375
2373 - show revisions sorted by date::
2376 - show revisions sorted by date::
2374
2377
2375 hg log -r "sort(all(), date)"
2378 hg log -r "sort(all(), date)"
2376
2379
2377 - backport the result of a merge as a single commit::
2380 - backport the result of a merge as a single commit::
2378
2381
2379 hg graft -r 123 --base 123^
2382 hg graft -r 123 --base 123^
2380
2383
2381 - land a feature branch as one changeset::
2384 - land a feature branch as one changeset::
2382
2385
2383 hg up -cr default
2386 hg up -cr default
2384 hg graft -r featureX --base "ancestor('featureX', 'default')"
2387 hg graft -r featureX --base "ancestor('featureX', 'default')"
2385
2388
2386 See :hg:`help revisions` for more about specifying revisions.
2389 See :hg:`help revisions` for more about specifying revisions.
2387
2390
2388 Returns 0 on successful completion.
2391 Returns 0 on successful completion.
2389 '''
2392 '''
2390 with repo.wlock():
2393 with repo.wlock():
2391 return _dograft(ui, repo, *revs, **opts)
2394 return _dograft(ui, repo, *revs, **opts)
2392
2395
2393 def _dograft(ui, repo, *revs, **opts):
2396 def _dograft(ui, repo, *revs, **opts):
2394 opts = pycompat.byteskwargs(opts)
2397 opts = pycompat.byteskwargs(opts)
2395 if revs and opts.get('rev'):
2398 if revs and opts.get('rev'):
2396 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2399 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2397 'revision ordering!\n'))
2400 'revision ordering!\n'))
2398
2401
2399 revs = list(revs)
2402 revs = list(revs)
2400 revs.extend(opts.get('rev'))
2403 revs.extend(opts.get('rev'))
2401 basectx = None
2404 basectx = None
2402 if opts.get('base'):
2405 if opts.get('base'):
2403 basectx = scmutil.revsingle(repo, opts['base'], None)
2406 basectx = scmutil.revsingle(repo, opts['base'], None)
2404 # a dict of data to be stored in state file
2407 # a dict of data to be stored in state file
2405 statedata = {}
2408 statedata = {}
2406 # list of new nodes created by ongoing graft
2409 # list of new nodes created by ongoing graft
2407 statedata['newnodes'] = []
2410 statedata['newnodes'] = []
2408
2411
2409 if opts.get('user') and opts.get('currentuser'):
2412 if opts.get('user') and opts.get('currentuser'):
2410 raise error.Abort(_('--user and --currentuser are mutually exclusive'))
2413 raise error.Abort(_('--user and --currentuser are mutually exclusive'))
2411 if opts.get('date') and opts.get('currentdate'):
2414 if opts.get('date') and opts.get('currentdate'):
2412 raise error.Abort(_('--date and --currentdate are mutually exclusive'))
2415 raise error.Abort(_('--date and --currentdate are mutually exclusive'))
2413 if not opts.get('user') and opts.get('currentuser'):
2416 if not opts.get('user') and opts.get('currentuser'):
2414 opts['user'] = ui.username()
2417 opts['user'] = ui.username()
2415 if not opts.get('date') and opts.get('currentdate'):
2418 if not opts.get('date') and opts.get('currentdate'):
2416 opts['date'] = "%d %d" % dateutil.makedate()
2419 opts['date'] = "%d %d" % dateutil.makedate()
2417
2420
2418 editor = cmdutil.getcommiteditor(editform='graft',
2421 editor = cmdutil.getcommiteditor(editform='graft',
2419 **pycompat.strkwargs(opts))
2422 **pycompat.strkwargs(opts))
2420
2423
2421 cont = False
2424 cont = False
2422 if opts.get('no_commit'):
2425 if opts.get('no_commit'):
2423 if opts.get('edit'):
2426 if opts.get('edit'):
2424 raise error.Abort(_("cannot specify --no-commit and "
2427 raise error.Abort(_("cannot specify --no-commit and "
2425 "--edit together"))
2428 "--edit together"))
2426 if opts.get('currentuser'):
2429 if opts.get('currentuser'):
2427 raise error.Abort(_("cannot specify --no-commit and "
2430 raise error.Abort(_("cannot specify --no-commit and "
2428 "--currentuser together"))
2431 "--currentuser together"))
2429 if opts.get('currentdate'):
2432 if opts.get('currentdate'):
2430 raise error.Abort(_("cannot specify --no-commit and "
2433 raise error.Abort(_("cannot specify --no-commit and "
2431 "--currentdate together"))
2434 "--currentdate together"))
2432 if opts.get('log'):
2435 if opts.get('log'):
2433 raise error.Abort(_("cannot specify --no-commit and "
2436 raise error.Abort(_("cannot specify --no-commit and "
2434 "--log together"))
2437 "--log together"))
2435
2438
2436 graftstate = statemod.cmdstate(repo, 'graftstate')
2439 graftstate = statemod.cmdstate(repo, 'graftstate')
2437
2440
2438 if opts.get('stop'):
2441 if opts.get('stop'):
2439 if opts.get('continue'):
2442 if opts.get('continue'):
2440 raise error.Abort(_("cannot use '--continue' and "
2443 raise error.Abort(_("cannot use '--continue' and "
2441 "'--stop' together"))
2444 "'--stop' together"))
2442 if opts.get('abort'):
2445 if opts.get('abort'):
2443 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2446 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2444
2447
2445 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2448 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2446 opts.get('date'), opts.get('currentdate'),
2449 opts.get('date'), opts.get('currentdate'),
2447 opts.get('currentuser'), opts.get('rev'))):
2450 opts.get('currentuser'), opts.get('rev'))):
2448 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2451 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2449 return _stopgraft(ui, repo, graftstate)
2452 return _stopgraft(ui, repo, graftstate)
2450 elif opts.get('abort'):
2453 elif opts.get('abort'):
2451 if opts.get('continue'):
2454 if opts.get('continue'):
2452 raise error.Abort(_("cannot use '--continue' and "
2455 raise error.Abort(_("cannot use '--continue' and "
2453 "'--abort' together"))
2456 "'--abort' together"))
2454 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2457 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2455 opts.get('date'), opts.get('currentdate'),
2458 opts.get('date'), opts.get('currentdate'),
2456 opts.get('currentuser'), opts.get('rev'))):
2459 opts.get('currentuser'), opts.get('rev'))):
2457 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2460 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2458
2461
2459 return _abortgraft(ui, repo, graftstate)
2462 return _abortgraft(ui, repo, graftstate)
2460 elif opts.get('continue'):
2463 elif opts.get('continue'):
2461 cont = True
2464 cont = True
2462 if revs:
2465 if revs:
2463 raise error.Abort(_("can't specify --continue and revisions"))
2466 raise error.Abort(_("can't specify --continue and revisions"))
2464 # read in unfinished revisions
2467 # read in unfinished revisions
2465 if graftstate.exists():
2468 if graftstate.exists():
2466 statedata = _readgraftstate(repo, graftstate)
2469 statedata = _readgraftstate(repo, graftstate)
2467 if statedata.get('date'):
2470 if statedata.get('date'):
2468 opts['date'] = statedata['date']
2471 opts['date'] = statedata['date']
2469 if statedata.get('user'):
2472 if statedata.get('user'):
2470 opts['user'] = statedata['user']
2473 opts['user'] = statedata['user']
2471 if statedata.get('log'):
2474 if statedata.get('log'):
2472 opts['log'] = True
2475 opts['log'] = True
2473 if statedata.get('no_commit'):
2476 if statedata.get('no_commit'):
2474 opts['no_commit'] = statedata.get('no_commit')
2477 opts['no_commit'] = statedata.get('no_commit')
2475 nodes = statedata['nodes']
2478 nodes = statedata['nodes']
2476 revs = [repo[node].rev() for node in nodes]
2479 revs = [repo[node].rev() for node in nodes]
2477 else:
2480 else:
2478 cmdutil.wrongtooltocontinue(repo, _('graft'))
2481 cmdutil.wrongtooltocontinue(repo, _('graft'))
2479 else:
2482 else:
2480 if not revs:
2483 if not revs:
2481 raise error.Abort(_('no revisions specified'))
2484 raise error.Abort(_('no revisions specified'))
2482 cmdutil.checkunfinished(repo)
2485 cmdutil.checkunfinished(repo)
2483 cmdutil.bailifchanged(repo)
2486 cmdutil.bailifchanged(repo)
2484 revs = scmutil.revrange(repo, revs)
2487 revs = scmutil.revrange(repo, revs)
2485
2488
2486 skipped = set()
2489 skipped = set()
2487 if basectx is None:
2490 if basectx is None:
2488 # check for merges
2491 # check for merges
2489 for rev in repo.revs('%ld and merge()', revs):
2492 for rev in repo.revs('%ld and merge()', revs):
2490 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2493 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2491 skipped.add(rev)
2494 skipped.add(rev)
2492 revs = [r for r in revs if r not in skipped]
2495 revs = [r for r in revs if r not in skipped]
2493 if not revs:
2496 if not revs:
2494 return -1
2497 return -1
2495 if basectx is not None and len(revs) != 1:
2498 if basectx is not None and len(revs) != 1:
2496 raise error.Abort(_('only one revision allowed with --base '))
2499 raise error.Abort(_('only one revision allowed with --base '))
2497
2500
2498 # Don't check in the --continue case, in effect retaining --force across
2501 # Don't check in the --continue case, in effect retaining --force across
2499 # --continues. That's because without --force, any revisions we decided to
2502 # --continues. That's because without --force, any revisions we decided to
2500 # skip would have been filtered out here, so they wouldn't have made their
2503 # skip would have been filtered out here, so they wouldn't have made their
2501 # way to the graftstate. With --force, any revisions we would have otherwise
2504 # way to the graftstate. With --force, any revisions we would have otherwise
2502 # skipped would not have been filtered out, and if they hadn't been applied
2505 # skipped would not have been filtered out, and if they hadn't been applied
2503 # already, they'd have been in the graftstate.
2506 # already, they'd have been in the graftstate.
2504 if not (cont or opts.get('force')) and basectx is None:
2507 if not (cont or opts.get('force')) and basectx is None:
2505 # check for ancestors of dest branch
2508 # check for ancestors of dest branch
2506 crev = repo['.'].rev()
2509 crev = repo['.'].rev()
2507 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2510 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2508 # XXX make this lazy in the future
2511 # XXX make this lazy in the future
2509 # don't mutate while iterating, create a copy
2512 # don't mutate while iterating, create a copy
2510 for rev in list(revs):
2513 for rev in list(revs):
2511 if rev in ancestors:
2514 if rev in ancestors:
2512 ui.warn(_('skipping ancestor revision %d:%s\n') %
2515 ui.warn(_('skipping ancestor revision %d:%s\n') %
2513 (rev, repo[rev]))
2516 (rev, repo[rev]))
2514 # XXX remove on list is slow
2517 # XXX remove on list is slow
2515 revs.remove(rev)
2518 revs.remove(rev)
2516 if not revs:
2519 if not revs:
2517 return -1
2520 return -1
2518
2521
2519 # analyze revs for earlier grafts
2522 # analyze revs for earlier grafts
2520 ids = {}
2523 ids = {}
2521 for ctx in repo.set("%ld", revs):
2524 for ctx in repo.set("%ld", revs):
2522 ids[ctx.hex()] = ctx.rev()
2525 ids[ctx.hex()] = ctx.rev()
2523 n = ctx.extra().get('source')
2526 n = ctx.extra().get('source')
2524 if n:
2527 if n:
2525 ids[n] = ctx.rev()
2528 ids[n] = ctx.rev()
2526
2529
2527 # check ancestors for earlier grafts
2530 # check ancestors for earlier grafts
2528 ui.debug('scanning for duplicate grafts\n')
2531 ui.debug('scanning for duplicate grafts\n')
2529
2532
2530 # The only changesets we can be sure doesn't contain grafts of any
2533 # The only changesets we can be sure doesn't contain grafts of any
2531 # revs, are the ones that are common ancestors of *all* revs:
2534 # revs, are the ones that are common ancestors of *all* revs:
2532 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2535 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2533 ctx = repo[rev]
2536 ctx = repo[rev]
2534 n = ctx.extra().get('source')
2537 n = ctx.extra().get('source')
2535 if n in ids:
2538 if n in ids:
2536 try:
2539 try:
2537 r = repo[n].rev()
2540 r = repo[n].rev()
2538 except error.RepoLookupError:
2541 except error.RepoLookupError:
2539 r = None
2542 r = None
2540 if r in revs:
2543 if r in revs:
2541 ui.warn(_('skipping revision %d:%s '
2544 ui.warn(_('skipping revision %d:%s '
2542 '(already grafted to %d:%s)\n')
2545 '(already grafted to %d:%s)\n')
2543 % (r, repo[r], rev, ctx))
2546 % (r, repo[r], rev, ctx))
2544 revs.remove(r)
2547 revs.remove(r)
2545 elif ids[n] in revs:
2548 elif ids[n] in revs:
2546 if r is None:
2549 if r is None:
2547 ui.warn(_('skipping already grafted revision %d:%s '
2550 ui.warn(_('skipping already grafted revision %d:%s '
2548 '(%d:%s also has unknown origin %s)\n')
2551 '(%d:%s also has unknown origin %s)\n')
2549 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2552 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2550 else:
2553 else:
2551 ui.warn(_('skipping already grafted revision %d:%s '
2554 ui.warn(_('skipping already grafted revision %d:%s '
2552 '(%d:%s also has origin %d:%s)\n')
2555 '(%d:%s also has origin %d:%s)\n')
2553 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2556 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2554 revs.remove(ids[n])
2557 revs.remove(ids[n])
2555 elif ctx.hex() in ids:
2558 elif ctx.hex() in ids:
2556 r = ids[ctx.hex()]
2559 r = ids[ctx.hex()]
2557 if r in revs:
2560 if r in revs:
2558 ui.warn(_('skipping already grafted revision %d:%s '
2561 ui.warn(_('skipping already grafted revision %d:%s '
2559 '(was grafted from %d:%s)\n') %
2562 '(was grafted from %d:%s)\n') %
2560 (r, repo[r], rev, ctx))
2563 (r, repo[r], rev, ctx))
2561 revs.remove(r)
2564 revs.remove(r)
2562 if not revs:
2565 if not revs:
2563 return -1
2566 return -1
2564
2567
2565 if opts.get('no_commit'):
2568 if opts.get('no_commit'):
2566 statedata['no_commit'] = True
2569 statedata['no_commit'] = True
2567 for pos, ctx in enumerate(repo.set("%ld", revs)):
2570 for pos, ctx in enumerate(repo.set("%ld", revs)):
2568 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2571 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2569 ctx.description().split('\n', 1)[0])
2572 ctx.description().split('\n', 1)[0])
2570 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2573 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2571 if names:
2574 if names:
2572 desc += ' (%s)' % ' '.join(names)
2575 desc += ' (%s)' % ' '.join(names)
2573 ui.status(_('grafting %s\n') % desc)
2576 ui.status(_('grafting %s\n') % desc)
2574 if opts.get('dry_run'):
2577 if opts.get('dry_run'):
2575 continue
2578 continue
2576
2579
2577 source = ctx.extra().get('source')
2580 source = ctx.extra().get('source')
2578 extra = {}
2581 extra = {}
2579 if source:
2582 if source:
2580 extra['source'] = source
2583 extra['source'] = source
2581 extra['intermediate-source'] = ctx.hex()
2584 extra['intermediate-source'] = ctx.hex()
2582 else:
2585 else:
2583 extra['source'] = ctx.hex()
2586 extra['source'] = ctx.hex()
2584 user = ctx.user()
2587 user = ctx.user()
2585 if opts.get('user'):
2588 if opts.get('user'):
2586 user = opts['user']
2589 user = opts['user']
2587 statedata['user'] = user
2590 statedata['user'] = user
2588 date = ctx.date()
2591 date = ctx.date()
2589 if opts.get('date'):
2592 if opts.get('date'):
2590 date = opts['date']
2593 date = opts['date']
2591 statedata['date'] = date
2594 statedata['date'] = date
2592 message = ctx.description()
2595 message = ctx.description()
2593 if opts.get('log'):
2596 if opts.get('log'):
2594 message += '\n(grafted from %s)' % ctx.hex()
2597 message += '\n(grafted from %s)' % ctx.hex()
2595 statedata['log'] = True
2598 statedata['log'] = True
2596
2599
2597 # we don't merge the first commit when continuing
2600 # we don't merge the first commit when continuing
2598 if not cont:
2601 if not cont:
2599 # perform the graft merge with p1(rev) as 'ancestor'
2602 # perform the graft merge with p1(rev) as 'ancestor'
2600 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2603 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2601 base = ctx.p1() if basectx is None else basectx
2604 base = ctx.p1() if basectx is None else basectx
2602 with ui.configoverride(overrides, 'graft'):
2605 with ui.configoverride(overrides, 'graft'):
2603 stats = mergemod.graft(repo, ctx, base, ['local', 'graft'])
2606 stats = mergemod.graft(repo, ctx, base, ['local', 'graft'])
2604 # report any conflicts
2607 # report any conflicts
2605 if stats.unresolvedcount > 0:
2608 if stats.unresolvedcount > 0:
2606 # write out state for --continue
2609 # write out state for --continue
2607 nodes = [repo[rev].hex() for rev in revs[pos:]]
2610 nodes = [repo[rev].hex() for rev in revs[pos:]]
2608 statedata['nodes'] = nodes
2611 statedata['nodes'] = nodes
2609 stateversion = 1
2612 stateversion = 1
2610 graftstate.save(stateversion, statedata)
2613 graftstate.save(stateversion, statedata)
2611 hint = _("use 'hg resolve' and 'hg graft --continue'")
2614 hint = _("use 'hg resolve' and 'hg graft --continue'")
2612 raise error.Abort(
2615 raise error.Abort(
2613 _("unresolved conflicts, can't continue"),
2616 _("unresolved conflicts, can't continue"),
2614 hint=hint)
2617 hint=hint)
2615 else:
2618 else:
2616 cont = False
2619 cont = False
2617
2620
2618 # commit if --no-commit is false
2621 # commit if --no-commit is false
2619 if not opts.get('no_commit'):
2622 if not opts.get('no_commit'):
2620 node = repo.commit(text=message, user=user, date=date, extra=extra,
2623 node = repo.commit(text=message, user=user, date=date, extra=extra,
2621 editor=editor)
2624 editor=editor)
2622 if node is None:
2625 if node is None:
2623 ui.warn(
2626 ui.warn(
2624 _('note: graft of %d:%s created no changes to commit\n') %
2627 _('note: graft of %d:%s created no changes to commit\n') %
2625 (ctx.rev(), ctx))
2628 (ctx.rev(), ctx))
2626 # checking that newnodes exist because old state files won't have it
2629 # checking that newnodes exist because old state files won't have it
2627 elif statedata.get('newnodes') is not None:
2630 elif statedata.get('newnodes') is not None:
2628 statedata['newnodes'].append(node)
2631 statedata['newnodes'].append(node)
2629
2632
2630 # remove state when we complete successfully
2633 # remove state when we complete successfully
2631 if not opts.get('dry_run'):
2634 if not opts.get('dry_run'):
2632 graftstate.delete()
2635 graftstate.delete()
2633
2636
2634 return 0
2637 return 0
2635
2638
2636 def _abortgraft(ui, repo, graftstate):
2639 def _abortgraft(ui, repo, graftstate):
2637 """abort the interrupted graft and rollbacks to the state before interrupted
2640 """abort the interrupted graft and rollbacks to the state before interrupted
2638 graft"""
2641 graft"""
2639 if not graftstate.exists():
2642 if not graftstate.exists():
2640 raise error.Abort(_("no interrupted graft to abort"))
2643 raise error.Abort(_("no interrupted graft to abort"))
2641 statedata = _readgraftstate(repo, graftstate)
2644 statedata = _readgraftstate(repo, graftstate)
2642 newnodes = statedata.get('newnodes')
2645 newnodes = statedata.get('newnodes')
2643 if newnodes is None:
2646 if newnodes is None:
2644 # and old graft state which does not have all the data required to abort
2647 # and old graft state which does not have all the data required to abort
2645 # the graft
2648 # the graft
2646 raise error.Abort(_("cannot abort using an old graftstate"))
2649 raise error.Abort(_("cannot abort using an old graftstate"))
2647
2650
2648 # changeset from which graft operation was started
2651 # changeset from which graft operation was started
2649 if len(newnodes) > 0:
2652 if len(newnodes) > 0:
2650 startctx = repo[newnodes[0]].p1()
2653 startctx = repo[newnodes[0]].p1()
2651 else:
2654 else:
2652 startctx = repo['.']
2655 startctx = repo['.']
2653 # whether to strip or not
2656 # whether to strip or not
2654 cleanup = False
2657 cleanup = False
2655 if newnodes:
2658 if newnodes:
2656 newnodes = [repo[r].rev() for r in newnodes]
2659 newnodes = [repo[r].rev() for r in newnodes]
2657 cleanup = True
2660 cleanup = True
2658 # checking that none of the newnodes turned public or is public
2661 # checking that none of the newnodes turned public or is public
2659 immutable = [c for c in newnodes if not repo[c].mutable()]
2662 immutable = [c for c in newnodes if not repo[c].mutable()]
2660 if immutable:
2663 if immutable:
2661 repo.ui.warn(_("cannot clean up public changesets %s\n")
2664 repo.ui.warn(_("cannot clean up public changesets %s\n")
2662 % ', '.join(bytes(repo[r]) for r in immutable),
2665 % ', '.join(bytes(repo[r]) for r in immutable),
2663 hint=_("see 'hg help phases' for details"))
2666 hint=_("see 'hg help phases' for details"))
2664 cleanup = False
2667 cleanup = False
2665
2668
2666 # checking that no new nodes are created on top of grafted revs
2669 # checking that no new nodes are created on top of grafted revs
2667 desc = set(repo.changelog.descendants(newnodes))
2670 desc = set(repo.changelog.descendants(newnodes))
2668 if desc - set(newnodes):
2671 if desc - set(newnodes):
2669 repo.ui.warn(_("new changesets detected on destination "
2672 repo.ui.warn(_("new changesets detected on destination "
2670 "branch, can't strip\n"))
2673 "branch, can't strip\n"))
2671 cleanup = False
2674 cleanup = False
2672
2675
2673 if cleanup:
2676 if cleanup:
2674 with repo.wlock(), repo.lock():
2677 with repo.wlock(), repo.lock():
2675 hg.updaterepo(repo, startctx.node(), overwrite=True)
2678 hg.updaterepo(repo, startctx.node(), overwrite=True)
2676 # stripping the new nodes created
2679 # stripping the new nodes created
2677 strippoints = [c.node() for c in repo.set("roots(%ld)",
2680 strippoints = [c.node() for c in repo.set("roots(%ld)",
2678 newnodes)]
2681 newnodes)]
2679 repair.strip(repo.ui, repo, strippoints, backup=False)
2682 repair.strip(repo.ui, repo, strippoints, backup=False)
2680
2683
2681 if not cleanup:
2684 if not cleanup:
2682 # we don't update to the startnode if we can't strip
2685 # we don't update to the startnode if we can't strip
2683 startctx = repo['.']
2686 startctx = repo['.']
2684 hg.updaterepo(repo, startctx.node(), overwrite=True)
2687 hg.updaterepo(repo, startctx.node(), overwrite=True)
2685
2688
2686 ui.status(_("graft aborted\n"))
2689 ui.status(_("graft aborted\n"))
2687 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2690 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2688 graftstate.delete()
2691 graftstate.delete()
2689 return 0
2692 return 0
2690
2693
2691 def _readgraftstate(repo, graftstate):
2694 def _readgraftstate(repo, graftstate):
2692 """read the graft state file and return a dict of the data stored in it"""
2695 """read the graft state file and return a dict of the data stored in it"""
2693 try:
2696 try:
2694 return graftstate.read()
2697 return graftstate.read()
2695 except error.CorruptedState:
2698 except error.CorruptedState:
2696 nodes = repo.vfs.read('graftstate').splitlines()
2699 nodes = repo.vfs.read('graftstate').splitlines()
2697 return {'nodes': nodes}
2700 return {'nodes': nodes}
2698
2701
2699 def _stopgraft(ui, repo, graftstate):
2702 def _stopgraft(ui, repo, graftstate):
2700 """stop the interrupted graft"""
2703 """stop the interrupted graft"""
2701 if not graftstate.exists():
2704 if not graftstate.exists():
2702 raise error.Abort(_("no interrupted graft found"))
2705 raise error.Abort(_("no interrupted graft found"))
2703 pctx = repo['.']
2706 pctx = repo['.']
2704 hg.updaterepo(repo, pctx.node(), overwrite=True)
2707 hg.updaterepo(repo, pctx.node(), overwrite=True)
2705 graftstate.delete()
2708 graftstate.delete()
2706 ui.status(_("stopped the interrupted graft\n"))
2709 ui.status(_("stopped the interrupted graft\n"))
2707 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2710 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2708 return 0
2711 return 0
2709
2712
2710 @command('grep',
2713 @command('grep',
2711 [('0', 'print0', None, _('end fields with NUL')),
2714 [('0', 'print0', None, _('end fields with NUL')),
2712 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2715 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2713 ('', 'diff', None, _('print all revisions when the term was introduced '
2716 ('', 'diff', None, _('print all revisions when the term was introduced '
2714 'or removed')),
2717 'or removed')),
2715 ('a', 'text', None, _('treat all files as text')),
2718 ('a', 'text', None, _('treat all files as text')),
2716 ('f', 'follow', None,
2719 ('f', 'follow', None,
2717 _('follow changeset history,'
2720 _('follow changeset history,'
2718 ' or file history across copies and renames')),
2721 ' or file history across copies and renames')),
2719 ('i', 'ignore-case', None, _('ignore case when matching')),
2722 ('i', 'ignore-case', None, _('ignore case when matching')),
2720 ('l', 'files-with-matches', None,
2723 ('l', 'files-with-matches', None,
2721 _('print only filenames and revisions that match')),
2724 _('print only filenames and revisions that match')),
2722 ('n', 'line-number', None, _('print matching line numbers')),
2725 ('n', 'line-number', None, _('print matching line numbers')),
2723 ('r', 'rev', [],
2726 ('r', 'rev', [],
2724 _('only search files changed within revision range'), _('REV')),
2727 _('only search files changed within revision range'), _('REV')),
2725 ('', 'all-files', None,
2728 ('', 'all-files', None,
2726 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2729 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2727 ('u', 'user', None, _('list the author (long with -v)')),
2730 ('u', 'user', None, _('list the author (long with -v)')),
2728 ('d', 'date', None, _('list the date (short with -q)')),
2731 ('d', 'date', None, _('list the date (short with -q)')),
2729 ] + formatteropts + walkopts,
2732 ] + formatteropts + walkopts,
2730 _('[OPTION]... PATTERN [FILE]...'),
2733 _('[OPTION]... PATTERN [FILE]...'),
2731 helpcategory=command.CATEGORY_FILE_CONTENTS,
2734 helpcategory=command.CATEGORY_FILE_CONTENTS,
2732 inferrepo=True,
2735 inferrepo=True,
2733 intents={INTENT_READONLY})
2736 intents={INTENT_READONLY})
2734 def grep(ui, repo, pattern, *pats, **opts):
2737 def grep(ui, repo, pattern, *pats, **opts):
2735 """search revision history for a pattern in specified files
2738 """search revision history for a pattern in specified files
2736
2739
2737 Search revision history for a regular expression in the specified
2740 Search revision history for a regular expression in the specified
2738 files or the entire project.
2741 files or the entire project.
2739
2742
2740 By default, grep prints the most recent revision number for each
2743 By default, grep prints the most recent revision number for each
2741 file in which it finds a match. To get it to print every revision
2744 file in which it finds a match. To get it to print every revision
2742 that contains a change in match status ("-" for a match that becomes
2745 that contains a change in match status ("-" for a match that becomes
2743 a non-match, or "+" for a non-match that becomes a match), use the
2746 a non-match, or "+" for a non-match that becomes a match), use the
2744 --diff flag.
2747 --diff flag.
2745
2748
2746 PATTERN can be any Python (roughly Perl-compatible) regular
2749 PATTERN can be any Python (roughly Perl-compatible) regular
2747 expression.
2750 expression.
2748
2751
2749 If no FILEs are specified (and -f/--follow isn't set), all files in
2752 If no FILEs are specified (and -f/--follow isn't set), all files in
2750 the repository are searched, including those that don't exist in the
2753 the repository are searched, including those that don't exist in the
2751 current branch or have been deleted in a prior changeset.
2754 current branch or have been deleted in a prior changeset.
2752
2755
2753 .. container:: verbose
2756 .. container:: verbose
2754
2757
2755 Template:
2758 Template:
2756
2759
2757 The following keywords are supported in addition to the common template
2760 The following keywords are supported in addition to the common template
2758 keywords and functions. See also :hg:`help templates`.
2761 keywords and functions. See also :hg:`help templates`.
2759
2762
2760 :change: String. Character denoting insertion ``+`` or removal ``-``.
2763 :change: String. Character denoting insertion ``+`` or removal ``-``.
2761 Available if ``--diff`` is specified.
2764 Available if ``--diff`` is specified.
2762 :lineno: Integer. Line number of the match.
2765 :lineno: Integer. Line number of the match.
2763 :path: String. Repository-absolute path of the file.
2766 :path: String. Repository-absolute path of the file.
2764 :texts: List of text chunks.
2767 :texts: List of text chunks.
2765
2768
2766 And each entry of ``{texts}`` provides the following sub-keywords.
2769 And each entry of ``{texts}`` provides the following sub-keywords.
2767
2770
2768 :matched: Boolean. True if the chunk matches the specified pattern.
2771 :matched: Boolean. True if the chunk matches the specified pattern.
2769 :text: String. Chunk content.
2772 :text: String. Chunk content.
2770
2773
2771 See :hg:`help templates.operators` for the list expansion syntax.
2774 See :hg:`help templates.operators` for the list expansion syntax.
2772
2775
2773 Returns 0 if a match is found, 1 otherwise.
2776 Returns 0 if a match is found, 1 otherwise.
2774 """
2777 """
2775 opts = pycompat.byteskwargs(opts)
2778 opts = pycompat.byteskwargs(opts)
2776 diff = opts.get('all') or opts.get('diff')
2779 diff = opts.get('all') or opts.get('diff')
2777 all_files = opts.get('all_files')
2780 all_files = opts.get('all_files')
2778 if diff and opts.get('all_files'):
2781 if diff and opts.get('all_files'):
2779 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2782 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2780 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2783 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2781 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2784 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2782 # experimental config: commands.grep.all-files
2785 # experimental config: commands.grep.all-files
2783 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2786 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2784 plaingrep = opts.get('all_files') and not opts.get('rev')
2787 plaingrep = opts.get('all_files') and not opts.get('rev')
2785 if plaingrep:
2788 if plaingrep:
2786 opts['rev'] = ['wdir()']
2789 opts['rev'] = ['wdir()']
2787
2790
2788 reflags = re.M
2791 reflags = re.M
2789 if opts.get('ignore_case'):
2792 if opts.get('ignore_case'):
2790 reflags |= re.I
2793 reflags |= re.I
2791 try:
2794 try:
2792 regexp = util.re.compile(pattern, reflags)
2795 regexp = util.re.compile(pattern, reflags)
2793 except re.error as inst:
2796 except re.error as inst:
2794 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2797 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2795 return 1
2798 return 1
2796 sep, eol = ':', '\n'
2799 sep, eol = ':', '\n'
2797 if opts.get('print0'):
2800 if opts.get('print0'):
2798 sep = eol = '\0'
2801 sep = eol = '\0'
2799
2802
2800 getfile = util.lrucachefunc(repo.file)
2803 getfile = util.lrucachefunc(repo.file)
2801
2804
2802 def matchlines(body):
2805 def matchlines(body):
2803 begin = 0
2806 begin = 0
2804 linenum = 0
2807 linenum = 0
2805 while begin < len(body):
2808 while begin < len(body):
2806 match = regexp.search(body, begin)
2809 match = regexp.search(body, begin)
2807 if not match:
2810 if not match:
2808 break
2811 break
2809 mstart, mend = match.span()
2812 mstart, mend = match.span()
2810 linenum += body.count('\n', begin, mstart) + 1
2813 linenum += body.count('\n', begin, mstart) + 1
2811 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2814 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2812 begin = body.find('\n', mend) + 1 or len(body) + 1
2815 begin = body.find('\n', mend) + 1 or len(body) + 1
2813 lend = begin - 1
2816 lend = begin - 1
2814 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2817 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2815
2818
2816 class linestate(object):
2819 class linestate(object):
2817 def __init__(self, line, linenum, colstart, colend):
2820 def __init__(self, line, linenum, colstart, colend):
2818 self.line = line
2821 self.line = line
2819 self.linenum = linenum
2822 self.linenum = linenum
2820 self.colstart = colstart
2823 self.colstart = colstart
2821 self.colend = colend
2824 self.colend = colend
2822
2825
2823 def __hash__(self):
2826 def __hash__(self):
2824 return hash((self.linenum, self.line))
2827 return hash((self.linenum, self.line))
2825
2828
2826 def __eq__(self, other):
2829 def __eq__(self, other):
2827 return self.line == other.line
2830 return self.line == other.line
2828
2831
2829 def findpos(self):
2832 def findpos(self):
2830 """Iterate all (start, end) indices of matches"""
2833 """Iterate all (start, end) indices of matches"""
2831 yield self.colstart, self.colend
2834 yield self.colstart, self.colend
2832 p = self.colend
2835 p = self.colend
2833 while p < len(self.line):
2836 while p < len(self.line):
2834 m = regexp.search(self.line, p)
2837 m = regexp.search(self.line, p)
2835 if not m:
2838 if not m:
2836 break
2839 break
2837 yield m.span()
2840 yield m.span()
2838 p = m.end()
2841 p = m.end()
2839
2842
2840 matches = {}
2843 matches = {}
2841 copies = {}
2844 copies = {}
2842 def grepbody(fn, rev, body):
2845 def grepbody(fn, rev, body):
2843 matches[rev].setdefault(fn, [])
2846 matches[rev].setdefault(fn, [])
2844 m = matches[rev][fn]
2847 m = matches[rev][fn]
2845 for lnum, cstart, cend, line in matchlines(body):
2848 for lnum, cstart, cend, line in matchlines(body):
2846 s = linestate(line, lnum, cstart, cend)
2849 s = linestate(line, lnum, cstart, cend)
2847 m.append(s)
2850 m.append(s)
2848
2851
2849 def difflinestates(a, b):
2852 def difflinestates(a, b):
2850 sm = difflib.SequenceMatcher(None, a, b)
2853 sm = difflib.SequenceMatcher(None, a, b)
2851 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2854 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2852 if tag == r'insert':
2855 if tag == r'insert':
2853 for i in pycompat.xrange(blo, bhi):
2856 for i in pycompat.xrange(blo, bhi):
2854 yield ('+', b[i])
2857 yield ('+', b[i])
2855 elif tag == r'delete':
2858 elif tag == r'delete':
2856 for i in pycompat.xrange(alo, ahi):
2859 for i in pycompat.xrange(alo, ahi):
2857 yield ('-', a[i])
2860 yield ('-', a[i])
2858 elif tag == r'replace':
2861 elif tag == r'replace':
2859 for i in pycompat.xrange(alo, ahi):
2862 for i in pycompat.xrange(alo, ahi):
2860 yield ('-', a[i])
2863 yield ('-', a[i])
2861 for i in pycompat.xrange(blo, bhi):
2864 for i in pycompat.xrange(blo, bhi):
2862 yield ('+', b[i])
2865 yield ('+', b[i])
2863
2866
2864 uipathfn = scmutil.getuipathfn(repo)
2867 uipathfn = scmutil.getuipathfn(repo)
2865 def display(fm, fn, ctx, pstates, states):
2868 def display(fm, fn, ctx, pstates, states):
2866 rev = scmutil.intrev(ctx)
2869 rev = scmutil.intrev(ctx)
2867 if fm.isplain():
2870 if fm.isplain():
2868 formatuser = ui.shortuser
2871 formatuser = ui.shortuser
2869 else:
2872 else:
2870 formatuser = pycompat.bytestr
2873 formatuser = pycompat.bytestr
2871 if ui.quiet:
2874 if ui.quiet:
2872 datefmt = '%Y-%m-%d'
2875 datefmt = '%Y-%m-%d'
2873 else:
2876 else:
2874 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2877 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2875 found = False
2878 found = False
2876 @util.cachefunc
2879 @util.cachefunc
2877 def binary():
2880 def binary():
2878 flog = getfile(fn)
2881 flog = getfile(fn)
2879 try:
2882 try:
2880 return stringutil.binary(flog.read(ctx.filenode(fn)))
2883 return stringutil.binary(flog.read(ctx.filenode(fn)))
2881 except error.WdirUnsupported:
2884 except error.WdirUnsupported:
2882 return ctx[fn].isbinary()
2885 return ctx[fn].isbinary()
2883
2886
2884 fieldnamemap = {'linenumber': 'lineno'}
2887 fieldnamemap = {'linenumber': 'lineno'}
2885 if diff:
2888 if diff:
2886 iter = difflinestates(pstates, states)
2889 iter = difflinestates(pstates, states)
2887 else:
2890 else:
2888 iter = [('', l) for l in states]
2891 iter = [('', l) for l in states]
2889 for change, l in iter:
2892 for change, l in iter:
2890 fm.startitem()
2893 fm.startitem()
2891 fm.context(ctx=ctx)
2894 fm.context(ctx=ctx)
2892 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
2895 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
2893 fm.plain(uipathfn(fn), label='grep.filename')
2896 fm.plain(uipathfn(fn), label='grep.filename')
2894
2897
2895 cols = [
2898 cols = [
2896 ('rev', '%d', rev, not plaingrep, ''),
2899 ('rev', '%d', rev, not plaingrep, ''),
2897 ('linenumber', '%d', l.linenum, opts.get('line_number'), ''),
2900 ('linenumber', '%d', l.linenum, opts.get('line_number'), ''),
2898 ]
2901 ]
2899 if diff:
2902 if diff:
2900 cols.append(
2903 cols.append(
2901 ('change', '%s', change, True,
2904 ('change', '%s', change, True,
2902 'grep.inserted ' if change == '+' else 'grep.deleted ')
2905 'grep.inserted ' if change == '+' else 'grep.deleted ')
2903 )
2906 )
2904 cols.extend([
2907 cols.extend([
2905 ('user', '%s', formatuser(ctx.user()), opts.get('user'), ''),
2908 ('user', '%s', formatuser(ctx.user()), opts.get('user'), ''),
2906 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2909 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2907 opts.get('date'), ''),
2910 opts.get('date'), ''),
2908 ])
2911 ])
2909 for name, fmt, data, cond, extra_label in cols:
2912 for name, fmt, data, cond, extra_label in cols:
2910 if cond:
2913 if cond:
2911 fm.plain(sep, label='grep.sep')
2914 fm.plain(sep, label='grep.sep')
2912 field = fieldnamemap.get(name, name)
2915 field = fieldnamemap.get(name, name)
2913 label = extra_label + ('grep.%s' % name)
2916 label = extra_label + ('grep.%s' % name)
2914 fm.condwrite(cond, field, fmt, data, label=label)
2917 fm.condwrite(cond, field, fmt, data, label=label)
2915 if not opts.get('files_with_matches'):
2918 if not opts.get('files_with_matches'):
2916 fm.plain(sep, label='grep.sep')
2919 fm.plain(sep, label='grep.sep')
2917 if not opts.get('text') and binary():
2920 if not opts.get('text') and binary():
2918 fm.plain(_(" Binary file matches"))
2921 fm.plain(_(" Binary file matches"))
2919 else:
2922 else:
2920 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2923 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2921 fm.plain(eol)
2924 fm.plain(eol)
2922 found = True
2925 found = True
2923 if opts.get('files_with_matches'):
2926 if opts.get('files_with_matches'):
2924 break
2927 break
2925 return found
2928 return found
2926
2929
2927 def displaymatches(fm, l):
2930 def displaymatches(fm, l):
2928 p = 0
2931 p = 0
2929 for s, e in l.findpos():
2932 for s, e in l.findpos():
2930 if p < s:
2933 if p < s:
2931 fm.startitem()
2934 fm.startitem()
2932 fm.write('text', '%s', l.line[p:s])
2935 fm.write('text', '%s', l.line[p:s])
2933 fm.data(matched=False)
2936 fm.data(matched=False)
2934 fm.startitem()
2937 fm.startitem()
2935 fm.write('text', '%s', l.line[s:e], label='grep.match')
2938 fm.write('text', '%s', l.line[s:e], label='grep.match')
2936 fm.data(matched=True)
2939 fm.data(matched=True)
2937 p = e
2940 p = e
2938 if p < len(l.line):
2941 if p < len(l.line):
2939 fm.startitem()
2942 fm.startitem()
2940 fm.write('text', '%s', l.line[p:])
2943 fm.write('text', '%s', l.line[p:])
2941 fm.data(matched=False)
2944 fm.data(matched=False)
2942 fm.end()
2945 fm.end()
2943
2946
2944 skip = set()
2947 skip = set()
2945 revfiles = {}
2948 revfiles = {}
2946 match = scmutil.match(repo[None], pats, opts)
2949 match = scmutil.match(repo[None], pats, opts)
2947 found = False
2950 found = False
2948 follow = opts.get('follow')
2951 follow = opts.get('follow')
2949
2952
2950 getrenamed = scmutil.getrenamedfn(repo)
2953 getrenamed = scmutil.getrenamedfn(repo)
2951 def prep(ctx, fns):
2954 def prep(ctx, fns):
2952 rev = ctx.rev()
2955 rev = ctx.rev()
2953 pctx = ctx.p1()
2956 pctx = ctx.p1()
2954 parent = pctx.rev()
2957 parent = pctx.rev()
2955 matches.setdefault(rev, {})
2958 matches.setdefault(rev, {})
2956 matches.setdefault(parent, {})
2959 matches.setdefault(parent, {})
2957 files = revfiles.setdefault(rev, [])
2960 files = revfiles.setdefault(rev, [])
2958 for fn in fns:
2961 for fn in fns:
2959 flog = getfile(fn)
2962 flog = getfile(fn)
2960 try:
2963 try:
2961 fnode = ctx.filenode(fn)
2964 fnode = ctx.filenode(fn)
2962 except error.LookupError:
2965 except error.LookupError:
2963 continue
2966 continue
2964
2967
2965 copy = None
2968 copy = None
2966 if follow:
2969 if follow:
2967 copy = getrenamed(fn, rev)
2970 copy = getrenamed(fn, rev)
2968 if copy:
2971 if copy:
2969 copies.setdefault(rev, {})[fn] = copy
2972 copies.setdefault(rev, {})[fn] = copy
2970 if fn in skip:
2973 if fn in skip:
2971 skip.add(copy)
2974 skip.add(copy)
2972 if fn in skip:
2975 if fn in skip:
2973 continue
2976 continue
2974 files.append(fn)
2977 files.append(fn)
2975
2978
2976 if fn not in matches[rev]:
2979 if fn not in matches[rev]:
2977 try:
2980 try:
2978 content = flog.read(fnode)
2981 content = flog.read(fnode)
2979 except error.WdirUnsupported:
2982 except error.WdirUnsupported:
2980 content = ctx[fn].data()
2983 content = ctx[fn].data()
2981 grepbody(fn, rev, content)
2984 grepbody(fn, rev, content)
2982
2985
2983 pfn = copy or fn
2986 pfn = copy or fn
2984 if pfn not in matches[parent]:
2987 if pfn not in matches[parent]:
2985 try:
2988 try:
2986 fnode = pctx.filenode(pfn)
2989 fnode = pctx.filenode(pfn)
2987 grepbody(pfn, parent, flog.read(fnode))
2990 grepbody(pfn, parent, flog.read(fnode))
2988 except error.LookupError:
2991 except error.LookupError:
2989 pass
2992 pass
2990
2993
2991 ui.pager('grep')
2994 ui.pager('grep')
2992 fm = ui.formatter('grep', opts)
2995 fm = ui.formatter('grep', opts)
2993 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2996 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2994 rev = ctx.rev()
2997 rev = ctx.rev()
2995 parent = ctx.p1().rev()
2998 parent = ctx.p1().rev()
2996 for fn in sorted(revfiles.get(rev, [])):
2999 for fn in sorted(revfiles.get(rev, [])):
2997 states = matches[rev][fn]
3000 states = matches[rev][fn]
2998 copy = copies.get(rev, {}).get(fn)
3001 copy = copies.get(rev, {}).get(fn)
2999 if fn in skip:
3002 if fn in skip:
3000 if copy:
3003 if copy:
3001 skip.add(copy)
3004 skip.add(copy)
3002 continue
3005 continue
3003 pstates = matches.get(parent, {}).get(copy or fn, [])
3006 pstates = matches.get(parent, {}).get(copy or fn, [])
3004 if pstates or states:
3007 if pstates or states:
3005 r = display(fm, fn, ctx, pstates, states)
3008 r = display(fm, fn, ctx, pstates, states)
3006 found = found or r
3009 found = found or r
3007 if r and not diff and not all_files:
3010 if r and not diff and not all_files:
3008 skip.add(fn)
3011 skip.add(fn)
3009 if copy:
3012 if copy:
3010 skip.add(copy)
3013 skip.add(copy)
3011 del revfiles[rev]
3014 del revfiles[rev]
3012 # We will keep the matches dict for the duration of the window
3015 # We will keep the matches dict for the duration of the window
3013 # clear the matches dict once the window is over
3016 # clear the matches dict once the window is over
3014 if not revfiles:
3017 if not revfiles:
3015 matches.clear()
3018 matches.clear()
3016 fm.end()
3019 fm.end()
3017
3020
3018 return not found
3021 return not found
3019
3022
3020 @command('heads',
3023 @command('heads',
3021 [('r', 'rev', '',
3024 [('r', 'rev', '',
3022 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3025 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3023 ('t', 'topo', False, _('show topological heads only')),
3026 ('t', 'topo', False, _('show topological heads only')),
3024 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3027 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3025 ('c', 'closed', False, _('show normal and closed branch heads')),
3028 ('c', 'closed', False, _('show normal and closed branch heads')),
3026 ] + templateopts,
3029 ] + templateopts,
3027 _('[-ct] [-r STARTREV] [REV]...'),
3030 _('[-ct] [-r STARTREV] [REV]...'),
3028 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3031 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3029 intents={INTENT_READONLY})
3032 intents={INTENT_READONLY})
3030 def heads(ui, repo, *branchrevs, **opts):
3033 def heads(ui, repo, *branchrevs, **opts):
3031 """show branch heads
3034 """show branch heads
3032
3035
3033 With no arguments, show all open branch heads in the repository.
3036 With no arguments, show all open branch heads in the repository.
3034 Branch heads are changesets that have no descendants on the
3037 Branch heads are changesets that have no descendants on the
3035 same branch. They are where development generally takes place and
3038 same branch. They are where development generally takes place and
3036 are the usual targets for update and merge operations.
3039 are the usual targets for update and merge operations.
3037
3040
3038 If one or more REVs are given, only open branch heads on the
3041 If one or more REVs are given, only open branch heads on the
3039 branches associated with the specified changesets are shown. This
3042 branches associated with the specified changesets are shown. This
3040 means that you can use :hg:`heads .` to see the heads on the
3043 means that you can use :hg:`heads .` to see the heads on the
3041 currently checked-out branch.
3044 currently checked-out branch.
3042
3045
3043 If -c/--closed is specified, also show branch heads marked closed
3046 If -c/--closed is specified, also show branch heads marked closed
3044 (see :hg:`commit --close-branch`).
3047 (see :hg:`commit --close-branch`).
3045
3048
3046 If STARTREV is specified, only those heads that are descendants of
3049 If STARTREV is specified, only those heads that are descendants of
3047 STARTREV will be displayed.
3050 STARTREV will be displayed.
3048
3051
3049 If -t/--topo is specified, named branch mechanics will be ignored and only
3052 If -t/--topo is specified, named branch mechanics will be ignored and only
3050 topological heads (changesets with no children) will be shown.
3053 topological heads (changesets with no children) will be shown.
3051
3054
3052 Returns 0 if matching heads are found, 1 if not.
3055 Returns 0 if matching heads are found, 1 if not.
3053 """
3056 """
3054
3057
3055 opts = pycompat.byteskwargs(opts)
3058 opts = pycompat.byteskwargs(opts)
3056 start = None
3059 start = None
3057 rev = opts.get('rev')
3060 rev = opts.get('rev')
3058 if rev:
3061 if rev:
3059 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3062 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3060 start = scmutil.revsingle(repo, rev, None).node()
3063 start = scmutil.revsingle(repo, rev, None).node()
3061
3064
3062 if opts.get('topo'):
3065 if opts.get('topo'):
3063 heads = [repo[h] for h in repo.heads(start)]
3066 heads = [repo[h] for h in repo.heads(start)]
3064 else:
3067 else:
3065 heads = []
3068 heads = []
3066 for branch in repo.branchmap():
3069 for branch in repo.branchmap():
3067 heads += repo.branchheads(branch, start, opts.get('closed'))
3070 heads += repo.branchheads(branch, start, opts.get('closed'))
3068 heads = [repo[h] for h in heads]
3071 heads = [repo[h] for h in heads]
3069
3072
3070 if branchrevs:
3073 if branchrevs:
3071 branches = set(repo[r].branch()
3074 branches = set(repo[r].branch()
3072 for r in scmutil.revrange(repo, branchrevs))
3075 for r in scmutil.revrange(repo, branchrevs))
3073 heads = [h for h in heads if h.branch() in branches]
3076 heads = [h for h in heads if h.branch() in branches]
3074
3077
3075 if opts.get('active') and branchrevs:
3078 if opts.get('active') and branchrevs:
3076 dagheads = repo.heads(start)
3079 dagheads = repo.heads(start)
3077 heads = [h for h in heads if h.node() in dagheads]
3080 heads = [h for h in heads if h.node() in dagheads]
3078
3081
3079 if branchrevs:
3082 if branchrevs:
3080 haveheads = set(h.branch() for h in heads)
3083 haveheads = set(h.branch() for h in heads)
3081 if branches - haveheads:
3084 if branches - haveheads:
3082 headless = ', '.join(b for b in branches - haveheads)
3085 headless = ', '.join(b for b in branches - haveheads)
3083 msg = _('no open branch heads found on branches %s')
3086 msg = _('no open branch heads found on branches %s')
3084 if opts.get('rev'):
3087 if opts.get('rev'):
3085 msg += _(' (started at %s)') % opts['rev']
3088 msg += _(' (started at %s)') % opts['rev']
3086 ui.warn((msg + '\n') % headless)
3089 ui.warn((msg + '\n') % headless)
3087
3090
3088 if not heads:
3091 if not heads:
3089 return 1
3092 return 1
3090
3093
3091 ui.pager('heads')
3094 ui.pager('heads')
3092 heads = sorted(heads, key=lambda x: -x.rev())
3095 heads = sorted(heads, key=lambda x: -x.rev())
3093 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3096 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3094 for ctx in heads:
3097 for ctx in heads:
3095 displayer.show(ctx)
3098 displayer.show(ctx)
3096 displayer.close()
3099 displayer.close()
3097
3100
3098 @command('help',
3101 @command('help',
3099 [('e', 'extension', None, _('show only help for extensions')),
3102 [('e', 'extension', None, _('show only help for extensions')),
3100 ('c', 'command', None, _('show only help for commands')),
3103 ('c', 'command', None, _('show only help for commands')),
3101 ('k', 'keyword', None, _('show topics matching keyword')),
3104 ('k', 'keyword', None, _('show topics matching keyword')),
3102 ('s', 'system', [],
3105 ('s', 'system', [],
3103 _('show help for specific platform(s)'), _('PLATFORM')),
3106 _('show help for specific platform(s)'), _('PLATFORM')),
3104 ],
3107 ],
3105 _('[-eck] [-s PLATFORM] [TOPIC]'),
3108 _('[-eck] [-s PLATFORM] [TOPIC]'),
3106 helpcategory=command.CATEGORY_HELP,
3109 helpcategory=command.CATEGORY_HELP,
3107 norepo=True,
3110 norepo=True,
3108 intents={INTENT_READONLY})
3111 intents={INTENT_READONLY})
3109 def help_(ui, name=None, **opts):
3112 def help_(ui, name=None, **opts):
3110 """show help for a given topic or a help overview
3113 """show help for a given topic or a help overview
3111
3114
3112 With no arguments, print a list of commands with short help messages.
3115 With no arguments, print a list of commands with short help messages.
3113
3116
3114 Given a topic, extension, or command name, print help for that
3117 Given a topic, extension, or command name, print help for that
3115 topic.
3118 topic.
3116
3119
3117 Returns 0 if successful.
3120 Returns 0 if successful.
3118 """
3121 """
3119
3122
3120 keep = opts.get(r'system') or []
3123 keep = opts.get(r'system') or []
3121 if len(keep) == 0:
3124 if len(keep) == 0:
3122 if pycompat.sysplatform.startswith('win'):
3125 if pycompat.sysplatform.startswith('win'):
3123 keep.append('windows')
3126 keep.append('windows')
3124 elif pycompat.sysplatform == 'OpenVMS':
3127 elif pycompat.sysplatform == 'OpenVMS':
3125 keep.append('vms')
3128 keep.append('vms')
3126 elif pycompat.sysplatform == 'plan9':
3129 elif pycompat.sysplatform == 'plan9':
3127 keep.append('plan9')
3130 keep.append('plan9')
3128 else:
3131 else:
3129 keep.append('unix')
3132 keep.append('unix')
3130 keep.append(pycompat.sysplatform.lower())
3133 keep.append(pycompat.sysplatform.lower())
3131 if ui.verbose:
3134 if ui.verbose:
3132 keep.append('verbose')
3135 keep.append('verbose')
3133
3136
3134 commands = sys.modules[__name__]
3137 commands = sys.modules[__name__]
3135 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3138 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3136 ui.pager('help')
3139 ui.pager('help')
3137 ui.write(formatted)
3140 ui.write(formatted)
3138
3141
3139
3142
3140 @command('identify|id',
3143 @command('identify|id',
3141 [('r', 'rev', '',
3144 [('r', 'rev', '',
3142 _('identify the specified revision'), _('REV')),
3145 _('identify the specified revision'), _('REV')),
3143 ('n', 'num', None, _('show local revision number')),
3146 ('n', 'num', None, _('show local revision number')),
3144 ('i', 'id', None, _('show global revision id')),
3147 ('i', 'id', None, _('show global revision id')),
3145 ('b', 'branch', None, _('show branch')),
3148 ('b', 'branch', None, _('show branch')),
3146 ('t', 'tags', None, _('show tags')),
3149 ('t', 'tags', None, _('show tags')),
3147 ('B', 'bookmarks', None, _('show bookmarks')),
3150 ('B', 'bookmarks', None, _('show bookmarks')),
3148 ] + remoteopts + formatteropts,
3151 ] + remoteopts + formatteropts,
3149 _('[-nibtB] [-r REV] [SOURCE]'),
3152 _('[-nibtB] [-r REV] [SOURCE]'),
3150 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3153 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3151 optionalrepo=True,
3154 optionalrepo=True,
3152 intents={INTENT_READONLY})
3155 intents={INTENT_READONLY})
3153 def identify(ui, repo, source=None, rev=None,
3156 def identify(ui, repo, source=None, rev=None,
3154 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3157 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3155 """identify the working directory or specified revision
3158 """identify the working directory or specified revision
3156
3159
3157 Print a summary identifying the repository state at REV using one or
3160 Print a summary identifying the repository state at REV using one or
3158 two parent hash identifiers, followed by a "+" if the working
3161 two parent hash identifiers, followed by a "+" if the working
3159 directory has uncommitted changes, the branch name (if not default),
3162 directory has uncommitted changes, the branch name (if not default),
3160 a list of tags, and a list of bookmarks.
3163 a list of tags, and a list of bookmarks.
3161
3164
3162 When REV is not given, print a summary of the current state of the
3165 When REV is not given, print a summary of the current state of the
3163 repository including the working directory. Specify -r. to get information
3166 repository including the working directory. Specify -r. to get information
3164 of the working directory parent without scanning uncommitted changes.
3167 of the working directory parent without scanning uncommitted changes.
3165
3168
3166 Specifying a path to a repository root or Mercurial bundle will
3169 Specifying a path to a repository root or Mercurial bundle will
3167 cause lookup to operate on that repository/bundle.
3170 cause lookup to operate on that repository/bundle.
3168
3171
3169 .. container:: verbose
3172 .. container:: verbose
3170
3173
3171 Template:
3174 Template:
3172
3175
3173 The following keywords are supported in addition to the common template
3176 The following keywords are supported in addition to the common template
3174 keywords and functions. See also :hg:`help templates`.
3177 keywords and functions. See also :hg:`help templates`.
3175
3178
3176 :dirty: String. Character ``+`` denoting if the working directory has
3179 :dirty: String. Character ``+`` denoting if the working directory has
3177 uncommitted changes.
3180 uncommitted changes.
3178 :id: String. One or two nodes, optionally followed by ``+``.
3181 :id: String. One or two nodes, optionally followed by ``+``.
3179 :parents: List of strings. Parent nodes of the changeset.
3182 :parents: List of strings. Parent nodes of the changeset.
3180
3183
3181 Examples:
3184 Examples:
3182
3185
3183 - generate a build identifier for the working directory::
3186 - generate a build identifier for the working directory::
3184
3187
3185 hg id --id > build-id.dat
3188 hg id --id > build-id.dat
3186
3189
3187 - find the revision corresponding to a tag::
3190 - find the revision corresponding to a tag::
3188
3191
3189 hg id -n -r 1.3
3192 hg id -n -r 1.3
3190
3193
3191 - check the most recent revision of a remote repository::
3194 - check the most recent revision of a remote repository::
3192
3195
3193 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3196 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3194
3197
3195 See :hg:`log` for generating more information about specific revisions,
3198 See :hg:`log` for generating more information about specific revisions,
3196 including full hash identifiers.
3199 including full hash identifiers.
3197
3200
3198 Returns 0 if successful.
3201 Returns 0 if successful.
3199 """
3202 """
3200
3203
3201 opts = pycompat.byteskwargs(opts)
3204 opts = pycompat.byteskwargs(opts)
3202 if not repo and not source:
3205 if not repo and not source:
3203 raise error.Abort(_("there is no Mercurial repository here "
3206 raise error.Abort(_("there is no Mercurial repository here "
3204 "(.hg not found)"))
3207 "(.hg not found)"))
3205
3208
3206 default = not (num or id or branch or tags or bookmarks)
3209 default = not (num or id or branch or tags or bookmarks)
3207 output = []
3210 output = []
3208 revs = []
3211 revs = []
3209
3212
3210 if source:
3213 if source:
3211 source, branches = hg.parseurl(ui.expandpath(source))
3214 source, branches = hg.parseurl(ui.expandpath(source))
3212 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3215 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3213 repo = peer.local()
3216 repo = peer.local()
3214 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3217 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3215
3218
3216 fm = ui.formatter('identify', opts)
3219 fm = ui.formatter('identify', opts)
3217 fm.startitem()
3220 fm.startitem()
3218
3221
3219 if not repo:
3222 if not repo:
3220 if num or branch or tags:
3223 if num or branch or tags:
3221 raise error.Abort(
3224 raise error.Abort(
3222 _("can't query remote revision number, branch, or tags"))
3225 _("can't query remote revision number, branch, or tags"))
3223 if not rev and revs:
3226 if not rev and revs:
3224 rev = revs[0]
3227 rev = revs[0]
3225 if not rev:
3228 if not rev:
3226 rev = "tip"
3229 rev = "tip"
3227
3230
3228 remoterev = peer.lookup(rev)
3231 remoterev = peer.lookup(rev)
3229 hexrev = fm.hexfunc(remoterev)
3232 hexrev = fm.hexfunc(remoterev)
3230 if default or id:
3233 if default or id:
3231 output = [hexrev]
3234 output = [hexrev]
3232 fm.data(id=hexrev)
3235 fm.data(id=hexrev)
3233
3236
3234 @util.cachefunc
3237 @util.cachefunc
3235 def getbms():
3238 def getbms():
3236 bms = []
3239 bms = []
3237
3240
3238 if 'bookmarks' in peer.listkeys('namespaces'):
3241 if 'bookmarks' in peer.listkeys('namespaces'):
3239 hexremoterev = hex(remoterev)
3242 hexremoterev = hex(remoterev)
3240 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3243 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3241 if bmr == hexremoterev]
3244 if bmr == hexremoterev]
3242
3245
3243 return sorted(bms)
3246 return sorted(bms)
3244
3247
3245 if fm.isplain():
3248 if fm.isplain():
3246 if bookmarks:
3249 if bookmarks:
3247 output.extend(getbms())
3250 output.extend(getbms())
3248 elif default and not ui.quiet:
3251 elif default and not ui.quiet:
3249 # multiple bookmarks for a single parent separated by '/'
3252 # multiple bookmarks for a single parent separated by '/'
3250 bm = '/'.join(getbms())
3253 bm = '/'.join(getbms())
3251 if bm:
3254 if bm:
3252 output.append(bm)
3255 output.append(bm)
3253 else:
3256 else:
3254 fm.data(node=hex(remoterev))
3257 fm.data(node=hex(remoterev))
3255 if bookmarks or 'bookmarks' in fm.datahint():
3258 if bookmarks or 'bookmarks' in fm.datahint():
3256 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3259 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3257 else:
3260 else:
3258 if rev:
3261 if rev:
3259 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3262 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3260 ctx = scmutil.revsingle(repo, rev, None)
3263 ctx = scmutil.revsingle(repo, rev, None)
3261
3264
3262 if ctx.rev() is None:
3265 if ctx.rev() is None:
3263 ctx = repo[None]
3266 ctx = repo[None]
3264 parents = ctx.parents()
3267 parents = ctx.parents()
3265 taglist = []
3268 taglist = []
3266 for p in parents:
3269 for p in parents:
3267 taglist.extend(p.tags())
3270 taglist.extend(p.tags())
3268
3271
3269 dirty = ""
3272 dirty = ""
3270 if ctx.dirty(missing=True, merge=False, branch=False):
3273 if ctx.dirty(missing=True, merge=False, branch=False):
3271 dirty = '+'
3274 dirty = '+'
3272 fm.data(dirty=dirty)
3275 fm.data(dirty=dirty)
3273
3276
3274 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3277 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3275 if default or id:
3278 if default or id:
3276 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3279 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3277 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3280 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3278
3281
3279 if num:
3282 if num:
3280 numoutput = ["%d" % p.rev() for p in parents]
3283 numoutput = ["%d" % p.rev() for p in parents]
3281 output.append("%s%s" % ('+'.join(numoutput), dirty))
3284 output.append("%s%s" % ('+'.join(numoutput), dirty))
3282
3285
3283 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3286 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3284 for p in parents], name='node'))
3287 for p in parents], name='node'))
3285 else:
3288 else:
3286 hexoutput = fm.hexfunc(ctx.node())
3289 hexoutput = fm.hexfunc(ctx.node())
3287 if default or id:
3290 if default or id:
3288 output = [hexoutput]
3291 output = [hexoutput]
3289 fm.data(id=hexoutput)
3292 fm.data(id=hexoutput)
3290
3293
3291 if num:
3294 if num:
3292 output.append(pycompat.bytestr(ctx.rev()))
3295 output.append(pycompat.bytestr(ctx.rev()))
3293 taglist = ctx.tags()
3296 taglist = ctx.tags()
3294
3297
3295 if default and not ui.quiet:
3298 if default and not ui.quiet:
3296 b = ctx.branch()
3299 b = ctx.branch()
3297 if b != 'default':
3300 if b != 'default':
3298 output.append("(%s)" % b)
3301 output.append("(%s)" % b)
3299
3302
3300 # multiple tags for a single parent separated by '/'
3303 # multiple tags for a single parent separated by '/'
3301 t = '/'.join(taglist)
3304 t = '/'.join(taglist)
3302 if t:
3305 if t:
3303 output.append(t)
3306 output.append(t)
3304
3307
3305 # multiple bookmarks for a single parent separated by '/'
3308 # multiple bookmarks for a single parent separated by '/'
3306 bm = '/'.join(ctx.bookmarks())
3309 bm = '/'.join(ctx.bookmarks())
3307 if bm:
3310 if bm:
3308 output.append(bm)
3311 output.append(bm)
3309 else:
3312 else:
3310 if branch:
3313 if branch:
3311 output.append(ctx.branch())
3314 output.append(ctx.branch())
3312
3315
3313 if tags:
3316 if tags:
3314 output.extend(taglist)
3317 output.extend(taglist)
3315
3318
3316 if bookmarks:
3319 if bookmarks:
3317 output.extend(ctx.bookmarks())
3320 output.extend(ctx.bookmarks())
3318
3321
3319 fm.data(node=ctx.hex())
3322 fm.data(node=ctx.hex())
3320 fm.data(branch=ctx.branch())
3323 fm.data(branch=ctx.branch())
3321 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3324 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3322 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3325 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3323 fm.context(ctx=ctx)
3326 fm.context(ctx=ctx)
3324
3327
3325 fm.plain("%s\n" % ' '.join(output))
3328 fm.plain("%s\n" % ' '.join(output))
3326 fm.end()
3329 fm.end()
3327
3330
3328 @command('import|patch',
3331 @command('import|patch',
3329 [('p', 'strip', 1,
3332 [('p', 'strip', 1,
3330 _('directory strip option for patch. This has the same '
3333 _('directory strip option for patch. This has the same '
3331 'meaning as the corresponding patch option'), _('NUM')),
3334 'meaning as the corresponding patch option'), _('NUM')),
3332 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3335 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3333 ('e', 'edit', False, _('invoke editor on commit messages')),
3336 ('e', 'edit', False, _('invoke editor on commit messages')),
3334 ('f', 'force', None,
3337 ('f', 'force', None,
3335 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3338 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3336 ('', 'no-commit', None,
3339 ('', 'no-commit', None,
3337 _("don't commit, just update the working directory")),
3340 _("don't commit, just update the working directory")),
3338 ('', 'bypass', None,
3341 ('', 'bypass', None,
3339 _("apply patch without touching the working directory")),
3342 _("apply patch without touching the working directory")),
3340 ('', 'partial', None,
3343 ('', 'partial', None,
3341 _('commit even if some hunks fail')),
3344 _('commit even if some hunks fail')),
3342 ('', 'exact', None,
3345 ('', 'exact', None,
3343 _('abort if patch would apply lossily')),
3346 _('abort if patch would apply lossily')),
3344 ('', 'prefix', '',
3347 ('', 'prefix', '',
3345 _('apply patch to subdirectory'), _('DIR')),
3348 _('apply patch to subdirectory'), _('DIR')),
3346 ('', 'import-branch', None,
3349 ('', 'import-branch', None,
3347 _('use any branch information in patch (implied by --exact)'))] +
3350 _('use any branch information in patch (implied by --exact)'))] +
3348 commitopts + commitopts2 + similarityopts,
3351 commitopts + commitopts2 + similarityopts,
3349 _('[OPTION]... PATCH...'),
3352 _('[OPTION]... PATCH...'),
3350 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3353 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3351 def import_(ui, repo, patch1=None, *patches, **opts):
3354 def import_(ui, repo, patch1=None, *patches, **opts):
3352 """import an ordered set of patches
3355 """import an ordered set of patches
3353
3356
3354 Import a list of patches and commit them individually (unless
3357 Import a list of patches and commit them individually (unless
3355 --no-commit is specified).
3358 --no-commit is specified).
3356
3359
3357 To read a patch from standard input (stdin), use "-" as the patch
3360 To read a patch from standard input (stdin), use "-" as the patch
3358 name. If a URL is specified, the patch will be downloaded from
3361 name. If a URL is specified, the patch will be downloaded from
3359 there.
3362 there.
3360
3363
3361 Import first applies changes to the working directory (unless
3364 Import first applies changes to the working directory (unless
3362 --bypass is specified), import will abort if there are outstanding
3365 --bypass is specified), import will abort if there are outstanding
3363 changes.
3366 changes.
3364
3367
3365 Use --bypass to apply and commit patches directly to the
3368 Use --bypass to apply and commit patches directly to the
3366 repository, without affecting the working directory. Without
3369 repository, without affecting the working directory. Without
3367 --exact, patches will be applied on top of the working directory
3370 --exact, patches will be applied on top of the working directory
3368 parent revision.
3371 parent revision.
3369
3372
3370 You can import a patch straight from a mail message. Even patches
3373 You can import a patch straight from a mail message. Even patches
3371 as attachments work (to use the body part, it must have type
3374 as attachments work (to use the body part, it must have type
3372 text/plain or text/x-patch). From and Subject headers of email
3375 text/plain or text/x-patch). From and Subject headers of email
3373 message are used as default committer and commit message. All
3376 message are used as default committer and commit message. All
3374 text/plain body parts before first diff are added to the commit
3377 text/plain body parts before first diff are added to the commit
3375 message.
3378 message.
3376
3379
3377 If the imported patch was generated by :hg:`export`, user and
3380 If the imported patch was generated by :hg:`export`, user and
3378 description from patch override values from message headers and
3381 description from patch override values from message headers and
3379 body. Values given on command line with -m/--message and -u/--user
3382 body. Values given on command line with -m/--message and -u/--user
3380 override these.
3383 override these.
3381
3384
3382 If --exact is specified, import will set the working directory to
3385 If --exact is specified, import will set the working directory to
3383 the parent of each patch before applying it, and will abort if the
3386 the parent of each patch before applying it, and will abort if the
3384 resulting changeset has a different ID than the one recorded in
3387 resulting changeset has a different ID than the one recorded in
3385 the patch. This will guard against various ways that portable
3388 the patch. This will guard against various ways that portable
3386 patch formats and mail systems might fail to transfer Mercurial
3389 patch formats and mail systems might fail to transfer Mercurial
3387 data or metadata. See :hg:`bundle` for lossless transmission.
3390 data or metadata. See :hg:`bundle` for lossless transmission.
3388
3391
3389 Use --partial to ensure a changeset will be created from the patch
3392 Use --partial to ensure a changeset will be created from the patch
3390 even if some hunks fail to apply. Hunks that fail to apply will be
3393 even if some hunks fail to apply. Hunks that fail to apply will be
3391 written to a <target-file>.rej file. Conflicts can then be resolved
3394 written to a <target-file>.rej file. Conflicts can then be resolved
3392 by hand before :hg:`commit --amend` is run to update the created
3395 by hand before :hg:`commit --amend` is run to update the created
3393 changeset. This flag exists to let people import patches that
3396 changeset. This flag exists to let people import patches that
3394 partially apply without losing the associated metadata (author,
3397 partially apply without losing the associated metadata (author,
3395 date, description, ...).
3398 date, description, ...).
3396
3399
3397 .. note::
3400 .. note::
3398
3401
3399 When no hunks apply cleanly, :hg:`import --partial` will create
3402 When no hunks apply cleanly, :hg:`import --partial` will create
3400 an empty changeset, importing only the patch metadata.
3403 an empty changeset, importing only the patch metadata.
3401
3404
3402 With -s/--similarity, hg will attempt to discover renames and
3405 With -s/--similarity, hg will attempt to discover renames and
3403 copies in the patch in the same way as :hg:`addremove`.
3406 copies in the patch in the same way as :hg:`addremove`.
3404
3407
3405 It is possible to use external patch programs to perform the patch
3408 It is possible to use external patch programs to perform the patch
3406 by setting the ``ui.patch`` configuration option. For the default
3409 by setting the ``ui.patch`` configuration option. For the default
3407 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3410 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3408 See :hg:`help config` for more information about configuration
3411 See :hg:`help config` for more information about configuration
3409 files and how to use these options.
3412 files and how to use these options.
3410
3413
3411 See :hg:`help dates` for a list of formats valid for -d/--date.
3414 See :hg:`help dates` for a list of formats valid for -d/--date.
3412
3415
3413 .. container:: verbose
3416 .. container:: verbose
3414
3417
3415 Examples:
3418 Examples:
3416
3419
3417 - import a traditional patch from a website and detect renames::
3420 - import a traditional patch from a website and detect renames::
3418
3421
3419 hg import -s 80 http://example.com/bugfix.patch
3422 hg import -s 80 http://example.com/bugfix.patch
3420
3423
3421 - import a changeset from an hgweb server::
3424 - import a changeset from an hgweb server::
3422
3425
3423 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3426 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3424
3427
3425 - import all the patches in an Unix-style mbox::
3428 - import all the patches in an Unix-style mbox::
3426
3429
3427 hg import incoming-patches.mbox
3430 hg import incoming-patches.mbox
3428
3431
3429 - import patches from stdin::
3432 - import patches from stdin::
3430
3433
3431 hg import -
3434 hg import -
3432
3435
3433 - attempt to exactly restore an exported changeset (not always
3436 - attempt to exactly restore an exported changeset (not always
3434 possible)::
3437 possible)::
3435
3438
3436 hg import --exact proposed-fix.patch
3439 hg import --exact proposed-fix.patch
3437
3440
3438 - use an external tool to apply a patch which is too fuzzy for
3441 - use an external tool to apply a patch which is too fuzzy for
3439 the default internal tool.
3442 the default internal tool.
3440
3443
3441 hg import --config ui.patch="patch --merge" fuzzy.patch
3444 hg import --config ui.patch="patch --merge" fuzzy.patch
3442
3445
3443 - change the default fuzzing from 2 to a less strict 7
3446 - change the default fuzzing from 2 to a less strict 7
3444
3447
3445 hg import --config ui.fuzz=7 fuzz.patch
3448 hg import --config ui.fuzz=7 fuzz.patch
3446
3449
3447 Returns 0 on success, 1 on partial success (see --partial).
3450 Returns 0 on success, 1 on partial success (see --partial).
3448 """
3451 """
3449
3452
3450 opts = pycompat.byteskwargs(opts)
3453 opts = pycompat.byteskwargs(opts)
3451 if not patch1:
3454 if not patch1:
3452 raise error.Abort(_('need at least one patch to import'))
3455 raise error.Abort(_('need at least one patch to import'))
3453
3456
3454 patches = (patch1,) + patches
3457 patches = (patch1,) + patches
3455
3458
3456 date = opts.get('date')
3459 date = opts.get('date')
3457 if date:
3460 if date:
3458 opts['date'] = dateutil.parsedate(date)
3461 opts['date'] = dateutil.parsedate(date)
3459
3462
3460 exact = opts.get('exact')
3463 exact = opts.get('exact')
3461 update = not opts.get('bypass')
3464 update = not opts.get('bypass')
3462 if not update and opts.get('no_commit'):
3465 if not update and opts.get('no_commit'):
3463 raise error.Abort(_('cannot use --no-commit with --bypass'))
3466 raise error.Abort(_('cannot use --no-commit with --bypass'))
3464 try:
3467 try:
3465 sim = float(opts.get('similarity') or 0)
3468 sim = float(opts.get('similarity') or 0)
3466 except ValueError:
3469 except ValueError:
3467 raise error.Abort(_('similarity must be a number'))
3470 raise error.Abort(_('similarity must be a number'))
3468 if sim < 0 or sim > 100:
3471 if sim < 0 or sim > 100:
3469 raise error.Abort(_('similarity must be between 0 and 100'))
3472 raise error.Abort(_('similarity must be between 0 and 100'))
3470 if sim and not update:
3473 if sim and not update:
3471 raise error.Abort(_('cannot use --similarity with --bypass'))
3474 raise error.Abort(_('cannot use --similarity with --bypass'))
3472 if exact:
3475 if exact:
3473 if opts.get('edit'):
3476 if opts.get('edit'):
3474 raise error.Abort(_('cannot use --exact with --edit'))
3477 raise error.Abort(_('cannot use --exact with --edit'))
3475 if opts.get('prefix'):
3478 if opts.get('prefix'):
3476 raise error.Abort(_('cannot use --exact with --prefix'))
3479 raise error.Abort(_('cannot use --exact with --prefix'))
3477
3480
3478 base = opts["base"]
3481 base = opts["base"]
3479 msgs = []
3482 msgs = []
3480 ret = 0
3483 ret = 0
3481
3484
3482 with repo.wlock():
3485 with repo.wlock():
3483 if update:
3486 if update:
3484 cmdutil.checkunfinished(repo)
3487 cmdutil.checkunfinished(repo)
3485 if (exact or not opts.get('force')):
3488 if (exact or not opts.get('force')):
3486 cmdutil.bailifchanged(repo)
3489 cmdutil.bailifchanged(repo)
3487
3490
3488 if not opts.get('no_commit'):
3491 if not opts.get('no_commit'):
3489 lock = repo.lock
3492 lock = repo.lock
3490 tr = lambda: repo.transaction('import')
3493 tr = lambda: repo.transaction('import')
3491 dsguard = util.nullcontextmanager
3494 dsguard = util.nullcontextmanager
3492 else:
3495 else:
3493 lock = util.nullcontextmanager
3496 lock = util.nullcontextmanager
3494 tr = util.nullcontextmanager
3497 tr = util.nullcontextmanager
3495 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3498 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3496 with lock(), tr(), dsguard():
3499 with lock(), tr(), dsguard():
3497 parents = repo[None].parents()
3500 parents = repo[None].parents()
3498 for patchurl in patches:
3501 for patchurl in patches:
3499 if patchurl == '-':
3502 if patchurl == '-':
3500 ui.status(_('applying patch from stdin\n'))
3503 ui.status(_('applying patch from stdin\n'))
3501 patchfile = ui.fin
3504 patchfile = ui.fin
3502 patchurl = 'stdin' # for error message
3505 patchurl = 'stdin' # for error message
3503 else:
3506 else:
3504 patchurl = os.path.join(base, patchurl)
3507 patchurl = os.path.join(base, patchurl)
3505 ui.status(_('applying %s\n') % patchurl)
3508 ui.status(_('applying %s\n') % patchurl)
3506 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
3509 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
3507
3510
3508 haspatch = False
3511 haspatch = False
3509 for hunk in patch.split(patchfile):
3512 for hunk in patch.split(patchfile):
3510 with patch.extract(ui, hunk) as patchdata:
3513 with patch.extract(ui, hunk) as patchdata:
3511 msg, node, rej = cmdutil.tryimportone(ui, repo,
3514 msg, node, rej = cmdutil.tryimportone(ui, repo,
3512 patchdata,
3515 patchdata,
3513 parents, opts,
3516 parents, opts,
3514 msgs, hg.clean)
3517 msgs, hg.clean)
3515 if msg:
3518 if msg:
3516 haspatch = True
3519 haspatch = True
3517 ui.note(msg + '\n')
3520 ui.note(msg + '\n')
3518 if update or exact:
3521 if update or exact:
3519 parents = repo[None].parents()
3522 parents = repo[None].parents()
3520 else:
3523 else:
3521 parents = [repo[node]]
3524 parents = [repo[node]]
3522 if rej:
3525 if rej:
3523 ui.write_err(_("patch applied partially\n"))
3526 ui.write_err(_("patch applied partially\n"))
3524 ui.write_err(_("(fix the .rej files and run "
3527 ui.write_err(_("(fix the .rej files and run "
3525 "`hg commit --amend`)\n"))
3528 "`hg commit --amend`)\n"))
3526 ret = 1
3529 ret = 1
3527 break
3530 break
3528
3531
3529 if not haspatch:
3532 if not haspatch:
3530 raise error.Abort(_('%s: no diffs found') % patchurl)
3533 raise error.Abort(_('%s: no diffs found') % patchurl)
3531
3534
3532 if msgs:
3535 if msgs:
3533 repo.savecommitmessage('\n* * *\n'.join(msgs))
3536 repo.savecommitmessage('\n* * *\n'.join(msgs))
3534 return ret
3537 return ret
3535
3538
3536 @command('incoming|in',
3539 @command('incoming|in',
3537 [('f', 'force', None,
3540 [('f', 'force', None,
3538 _('run even if remote repository is unrelated')),
3541 _('run even if remote repository is unrelated')),
3539 ('n', 'newest-first', None, _('show newest record first')),
3542 ('n', 'newest-first', None, _('show newest record first')),
3540 ('', 'bundle', '',
3543 ('', 'bundle', '',
3541 _('file to store the bundles into'), _('FILE')),
3544 _('file to store the bundles into'), _('FILE')),
3542 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3545 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3543 ('B', 'bookmarks', False, _("compare bookmarks")),
3546 ('B', 'bookmarks', False, _("compare bookmarks")),
3544 ('b', 'branch', [],
3547 ('b', 'branch', [],
3545 _('a specific branch you would like to pull'), _('BRANCH')),
3548 _('a specific branch you would like to pull'), _('BRANCH')),
3546 ] + logopts + remoteopts + subrepoopts,
3549 ] + logopts + remoteopts + subrepoopts,
3547 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3550 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3548 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3551 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3549 def incoming(ui, repo, source="default", **opts):
3552 def incoming(ui, repo, source="default", **opts):
3550 """show new changesets found in source
3553 """show new changesets found in source
3551
3554
3552 Show new changesets found in the specified path/URL or the default
3555 Show new changesets found in the specified path/URL or the default
3553 pull location. These are the changesets that would have been pulled
3556 pull location. These are the changesets that would have been pulled
3554 by :hg:`pull` at the time you issued this command.
3557 by :hg:`pull` at the time you issued this command.
3555
3558
3556 See pull for valid source format details.
3559 See pull for valid source format details.
3557
3560
3558 .. container:: verbose
3561 .. container:: verbose
3559
3562
3560 With -B/--bookmarks, the result of bookmark comparison between
3563 With -B/--bookmarks, the result of bookmark comparison between
3561 local and remote repositories is displayed. With -v/--verbose,
3564 local and remote repositories is displayed. With -v/--verbose,
3562 status is also displayed for each bookmark like below::
3565 status is also displayed for each bookmark like below::
3563
3566
3564 BM1 01234567890a added
3567 BM1 01234567890a added
3565 BM2 1234567890ab advanced
3568 BM2 1234567890ab advanced
3566 BM3 234567890abc diverged
3569 BM3 234567890abc diverged
3567 BM4 34567890abcd changed
3570 BM4 34567890abcd changed
3568
3571
3569 The action taken locally when pulling depends on the
3572 The action taken locally when pulling depends on the
3570 status of each bookmark:
3573 status of each bookmark:
3571
3574
3572 :``added``: pull will create it
3575 :``added``: pull will create it
3573 :``advanced``: pull will update it
3576 :``advanced``: pull will update it
3574 :``diverged``: pull will create a divergent bookmark
3577 :``diverged``: pull will create a divergent bookmark
3575 :``changed``: result depends on remote changesets
3578 :``changed``: result depends on remote changesets
3576
3579
3577 From the point of view of pulling behavior, bookmark
3580 From the point of view of pulling behavior, bookmark
3578 existing only in the remote repository are treated as ``added``,
3581 existing only in the remote repository are treated as ``added``,
3579 even if it is in fact locally deleted.
3582 even if it is in fact locally deleted.
3580
3583
3581 .. container:: verbose
3584 .. container:: verbose
3582
3585
3583 For remote repository, using --bundle avoids downloading the
3586 For remote repository, using --bundle avoids downloading the
3584 changesets twice if the incoming is followed by a pull.
3587 changesets twice if the incoming is followed by a pull.
3585
3588
3586 Examples:
3589 Examples:
3587
3590
3588 - show incoming changes with patches and full description::
3591 - show incoming changes with patches and full description::
3589
3592
3590 hg incoming -vp
3593 hg incoming -vp
3591
3594
3592 - show incoming changes excluding merges, store a bundle::
3595 - show incoming changes excluding merges, store a bundle::
3593
3596
3594 hg in -vpM --bundle incoming.hg
3597 hg in -vpM --bundle incoming.hg
3595 hg pull incoming.hg
3598 hg pull incoming.hg
3596
3599
3597 - briefly list changes inside a bundle::
3600 - briefly list changes inside a bundle::
3598
3601
3599 hg in changes.hg -T "{desc|firstline}\\n"
3602 hg in changes.hg -T "{desc|firstline}\\n"
3600
3603
3601 Returns 0 if there are incoming changes, 1 otherwise.
3604 Returns 0 if there are incoming changes, 1 otherwise.
3602 """
3605 """
3603 opts = pycompat.byteskwargs(opts)
3606 opts = pycompat.byteskwargs(opts)
3604 if opts.get('graph'):
3607 if opts.get('graph'):
3605 logcmdutil.checkunsupportedgraphflags([], opts)
3608 logcmdutil.checkunsupportedgraphflags([], opts)
3606 def display(other, chlist, displayer):
3609 def display(other, chlist, displayer):
3607 revdag = logcmdutil.graphrevs(other, chlist, opts)
3610 revdag = logcmdutil.graphrevs(other, chlist, opts)
3608 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3611 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3609 graphmod.asciiedges)
3612 graphmod.asciiedges)
3610
3613
3611 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3614 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3612 return 0
3615 return 0
3613
3616
3614 if opts.get('bundle') and opts.get('subrepos'):
3617 if opts.get('bundle') and opts.get('subrepos'):
3615 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3618 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3616
3619
3617 if opts.get('bookmarks'):
3620 if opts.get('bookmarks'):
3618 source, branches = hg.parseurl(ui.expandpath(source),
3621 source, branches = hg.parseurl(ui.expandpath(source),
3619 opts.get('branch'))
3622 opts.get('branch'))
3620 other = hg.peer(repo, opts, source)
3623 other = hg.peer(repo, opts, source)
3621 if 'bookmarks' not in other.listkeys('namespaces'):
3624 if 'bookmarks' not in other.listkeys('namespaces'):
3622 ui.warn(_("remote doesn't support bookmarks\n"))
3625 ui.warn(_("remote doesn't support bookmarks\n"))
3623 return 0
3626 return 0
3624 ui.pager('incoming')
3627 ui.pager('incoming')
3625 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3628 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3626 return bookmarks.incoming(ui, repo, other)
3629 return bookmarks.incoming(ui, repo, other)
3627
3630
3628 repo._subtoppath = ui.expandpath(source)
3631 repo._subtoppath = ui.expandpath(source)
3629 try:
3632 try:
3630 return hg.incoming(ui, repo, source, opts)
3633 return hg.incoming(ui, repo, source, opts)
3631 finally:
3634 finally:
3632 del repo._subtoppath
3635 del repo._subtoppath
3633
3636
3634
3637
3635 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3638 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3636 helpcategory=command.CATEGORY_REPO_CREATION,
3639 helpcategory=command.CATEGORY_REPO_CREATION,
3637 helpbasic=True, norepo=True)
3640 helpbasic=True, norepo=True)
3638 def init(ui, dest=".", **opts):
3641 def init(ui, dest=".", **opts):
3639 """create a new repository in the given directory
3642 """create a new repository in the given directory
3640
3643
3641 Initialize a new repository in the given directory. If the given
3644 Initialize a new repository in the given directory. If the given
3642 directory does not exist, it will be created.
3645 directory does not exist, it will be created.
3643
3646
3644 If no directory is given, the current directory is used.
3647 If no directory is given, the current directory is used.
3645
3648
3646 It is possible to specify an ``ssh://`` URL as the destination.
3649 It is possible to specify an ``ssh://`` URL as the destination.
3647 See :hg:`help urls` for more information.
3650 See :hg:`help urls` for more information.
3648
3651
3649 Returns 0 on success.
3652 Returns 0 on success.
3650 """
3653 """
3651 opts = pycompat.byteskwargs(opts)
3654 opts = pycompat.byteskwargs(opts)
3652 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3655 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3653
3656
3654 @command('locate',
3657 @command('locate',
3655 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3658 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3656 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3659 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3657 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3660 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3658 ] + walkopts,
3661 ] + walkopts,
3659 _('[OPTION]... [PATTERN]...'),
3662 _('[OPTION]... [PATTERN]...'),
3660 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3663 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3661 def locate(ui, repo, *pats, **opts):
3664 def locate(ui, repo, *pats, **opts):
3662 """locate files matching specific patterns (DEPRECATED)
3665 """locate files matching specific patterns (DEPRECATED)
3663
3666
3664 Print files under Mercurial control in the working directory whose
3667 Print files under Mercurial control in the working directory whose
3665 names match the given patterns.
3668 names match the given patterns.
3666
3669
3667 By default, this command searches all directories in the working
3670 By default, this command searches all directories in the working
3668 directory. To search just the current directory and its
3671 directory. To search just the current directory and its
3669 subdirectories, use "--include .".
3672 subdirectories, use "--include .".
3670
3673
3671 If no patterns are given to match, this command prints the names
3674 If no patterns are given to match, this command prints the names
3672 of all files under Mercurial control in the working directory.
3675 of all files under Mercurial control in the working directory.
3673
3676
3674 If you want to feed the output of this command into the "xargs"
3677 If you want to feed the output of this command into the "xargs"
3675 command, use the -0 option to both this command and "xargs". This
3678 command, use the -0 option to both this command and "xargs". This
3676 will avoid the problem of "xargs" treating single filenames that
3679 will avoid the problem of "xargs" treating single filenames that
3677 contain whitespace as multiple filenames.
3680 contain whitespace as multiple filenames.
3678
3681
3679 See :hg:`help files` for a more versatile command.
3682 See :hg:`help files` for a more versatile command.
3680
3683
3681 Returns 0 if a match is found, 1 otherwise.
3684 Returns 0 if a match is found, 1 otherwise.
3682 """
3685 """
3683 opts = pycompat.byteskwargs(opts)
3686 opts = pycompat.byteskwargs(opts)
3684 if opts.get('print0'):
3687 if opts.get('print0'):
3685 end = '\0'
3688 end = '\0'
3686 else:
3689 else:
3687 end = '\n'
3690 end = '\n'
3688 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3691 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3689
3692
3690 ret = 1
3693 ret = 1
3691 m = scmutil.match(ctx, pats, opts, default='relglob',
3694 m = scmutil.match(ctx, pats, opts, default='relglob',
3692 badfn=lambda x, y: False)
3695 badfn=lambda x, y: False)
3693
3696
3694 ui.pager('locate')
3697 ui.pager('locate')
3695 if ctx.rev() is None:
3698 if ctx.rev() is None:
3696 # When run on the working copy, "locate" includes removed files, so
3699 # When run on the working copy, "locate" includes removed files, so
3697 # we get the list of files from the dirstate.
3700 # we get the list of files from the dirstate.
3698 filesgen = sorted(repo.dirstate.matches(m))
3701 filesgen = sorted(repo.dirstate.matches(m))
3699 else:
3702 else:
3700 filesgen = ctx.matches(m)
3703 filesgen = ctx.matches(m)
3701 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
3704 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
3702 for abs in filesgen:
3705 for abs in filesgen:
3703 if opts.get('fullpath'):
3706 if opts.get('fullpath'):
3704 ui.write(repo.wjoin(abs), end)
3707 ui.write(repo.wjoin(abs), end)
3705 else:
3708 else:
3706 ui.write(uipathfn(abs), end)
3709 ui.write(uipathfn(abs), end)
3707 ret = 0
3710 ret = 0
3708
3711
3709 return ret
3712 return ret
3710
3713
3711 @command('log|history',
3714 @command('log|history',
3712 [('f', 'follow', None,
3715 [('f', 'follow', None,
3713 _('follow changeset history, or file history across copies and renames')),
3716 _('follow changeset history, or file history across copies and renames')),
3714 ('', 'follow-first', None,
3717 ('', 'follow-first', None,
3715 _('only follow the first parent of merge changesets (DEPRECATED)')),
3718 _('only follow the first parent of merge changesets (DEPRECATED)')),
3716 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3719 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3717 ('C', 'copies', None, _('show copied files')),
3720 ('C', 'copies', None, _('show copied files')),
3718 ('k', 'keyword', [],
3721 ('k', 'keyword', [],
3719 _('do case-insensitive search for a given text'), _('TEXT')),
3722 _('do case-insensitive search for a given text'), _('TEXT')),
3720 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3723 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3721 ('L', 'line-range', [],
3724 ('L', 'line-range', [],
3722 _('follow line range of specified file (EXPERIMENTAL)'),
3725 _('follow line range of specified file (EXPERIMENTAL)'),
3723 _('FILE,RANGE')),
3726 _('FILE,RANGE')),
3724 ('', 'removed', None, _('include revisions where files were removed')),
3727 ('', 'removed', None, _('include revisions where files were removed')),
3725 ('m', 'only-merges', None,
3728 ('m', 'only-merges', None,
3726 _('show only merges (DEPRECATED) (use -r "merge()" instead)')),
3729 _('show only merges (DEPRECATED) (use -r "merge()" instead)')),
3727 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3730 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3728 ('', 'only-branch', [],
3731 ('', 'only-branch', [],
3729 _('show only changesets within the given named branch (DEPRECATED)'),
3732 _('show only changesets within the given named branch (DEPRECATED)'),
3730 _('BRANCH')),
3733 _('BRANCH')),
3731 ('b', 'branch', [],
3734 ('b', 'branch', [],
3732 _('show changesets within the given named branch'), _('BRANCH')),
3735 _('show changesets within the given named branch'), _('BRANCH')),
3733 ('P', 'prune', [],
3736 ('P', 'prune', [],
3734 _('do not display revision or any of its ancestors'), _('REV')),
3737 _('do not display revision or any of its ancestors'), _('REV')),
3735 ] + logopts + walkopts,
3738 ] + logopts + walkopts,
3736 _('[OPTION]... [FILE]'),
3739 _('[OPTION]... [FILE]'),
3737 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3740 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3738 helpbasic=True, inferrepo=True,
3741 helpbasic=True, inferrepo=True,
3739 intents={INTENT_READONLY})
3742 intents={INTENT_READONLY})
3740 def log(ui, repo, *pats, **opts):
3743 def log(ui, repo, *pats, **opts):
3741 """show revision history of entire repository or files
3744 """show revision history of entire repository or files
3742
3745
3743 Print the revision history of the specified files or the entire
3746 Print the revision history of the specified files or the entire
3744 project.
3747 project.
3745
3748
3746 If no revision range is specified, the default is ``tip:0`` unless
3749 If no revision range is specified, the default is ``tip:0`` unless
3747 --follow is set, in which case the working directory parent is
3750 --follow is set, in which case the working directory parent is
3748 used as the starting revision.
3751 used as the starting revision.
3749
3752
3750 File history is shown without following rename or copy history of
3753 File history is shown without following rename or copy history of
3751 files. Use -f/--follow with a filename to follow history across
3754 files. Use -f/--follow with a filename to follow history across
3752 renames and copies. --follow without a filename will only show
3755 renames and copies. --follow without a filename will only show
3753 ancestors of the starting revision.
3756 ancestors of the starting revision.
3754
3757
3755 By default this command prints revision number and changeset id,
3758 By default this command prints revision number and changeset id,
3756 tags, non-trivial parents, user, date and time, and a summary for
3759 tags, non-trivial parents, user, date and time, and a summary for
3757 each commit. When the -v/--verbose switch is used, the list of
3760 each commit. When the -v/--verbose switch is used, the list of
3758 changed files and full commit message are shown.
3761 changed files and full commit message are shown.
3759
3762
3760 With --graph the revisions are shown as an ASCII art DAG with the most
3763 With --graph the revisions are shown as an ASCII art DAG with the most
3761 recent changeset at the top.
3764 recent changeset at the top.
3762 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3765 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3763 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3766 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3764 changeset from the lines below is a parent of the 'o' merge on the same
3767 changeset from the lines below is a parent of the 'o' merge on the same
3765 line.
3768 line.
3766 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3769 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3767 of a '|' indicates one or more revisions in a path are omitted.
3770 of a '|' indicates one or more revisions in a path are omitted.
3768
3771
3769 .. container:: verbose
3772 .. container:: verbose
3770
3773
3771 Use -L/--line-range FILE,M:N options to follow the history of lines
3774 Use -L/--line-range FILE,M:N options to follow the history of lines
3772 from M to N in FILE. With -p/--patch only diff hunks affecting
3775 from M to N in FILE. With -p/--patch only diff hunks affecting
3773 specified line range will be shown. This option requires --follow;
3776 specified line range will be shown. This option requires --follow;
3774 it can be specified multiple times. Currently, this option is not
3777 it can be specified multiple times. Currently, this option is not
3775 compatible with --graph. This option is experimental.
3778 compatible with --graph. This option is experimental.
3776
3779
3777 .. note::
3780 .. note::
3778
3781
3779 :hg:`log --patch` may generate unexpected diff output for merge
3782 :hg:`log --patch` may generate unexpected diff output for merge
3780 changesets, as it will only compare the merge changeset against
3783 changesets, as it will only compare the merge changeset against
3781 its first parent. Also, only files different from BOTH parents
3784 its first parent. Also, only files different from BOTH parents
3782 will appear in files:.
3785 will appear in files:.
3783
3786
3784 .. note::
3787 .. note::
3785
3788
3786 For performance reasons, :hg:`log FILE` may omit duplicate changes
3789 For performance reasons, :hg:`log FILE` may omit duplicate changes
3787 made on branches and will not show removals or mode changes. To
3790 made on branches and will not show removals or mode changes. To
3788 see all such changes, use the --removed switch.
3791 see all such changes, use the --removed switch.
3789
3792
3790 .. container:: verbose
3793 .. container:: verbose
3791
3794
3792 .. note::
3795 .. note::
3793
3796
3794 The history resulting from -L/--line-range options depends on diff
3797 The history resulting from -L/--line-range options depends on diff
3795 options; for instance if white-spaces are ignored, respective changes
3798 options; for instance if white-spaces are ignored, respective changes
3796 with only white-spaces in specified line range will not be listed.
3799 with only white-spaces in specified line range will not be listed.
3797
3800
3798 .. container:: verbose
3801 .. container:: verbose
3799
3802
3800 Some examples:
3803 Some examples:
3801
3804
3802 - changesets with full descriptions and file lists::
3805 - changesets with full descriptions and file lists::
3803
3806
3804 hg log -v
3807 hg log -v
3805
3808
3806 - changesets ancestral to the working directory::
3809 - changesets ancestral to the working directory::
3807
3810
3808 hg log -f
3811 hg log -f
3809
3812
3810 - last 10 commits on the current branch::
3813 - last 10 commits on the current branch::
3811
3814
3812 hg log -l 10 -b .
3815 hg log -l 10 -b .
3813
3816
3814 - changesets showing all modifications of a file, including removals::
3817 - changesets showing all modifications of a file, including removals::
3815
3818
3816 hg log --removed file.c
3819 hg log --removed file.c
3817
3820
3818 - all changesets that touch a directory, with diffs, excluding merges::
3821 - all changesets that touch a directory, with diffs, excluding merges::
3819
3822
3820 hg log -Mp lib/
3823 hg log -Mp lib/
3821
3824
3822 - all revision numbers that match a keyword::
3825 - all revision numbers that match a keyword::
3823
3826
3824 hg log -k bug --template "{rev}\\n"
3827 hg log -k bug --template "{rev}\\n"
3825
3828
3826 - the full hash identifier of the working directory parent::
3829 - the full hash identifier of the working directory parent::
3827
3830
3828 hg log -r . --template "{node}\\n"
3831 hg log -r . --template "{node}\\n"
3829
3832
3830 - list available log templates::
3833 - list available log templates::
3831
3834
3832 hg log -T list
3835 hg log -T list
3833
3836
3834 - check if a given changeset is included in a tagged release::
3837 - check if a given changeset is included in a tagged release::
3835
3838
3836 hg log -r "a21ccf and ancestor(1.9)"
3839 hg log -r "a21ccf and ancestor(1.9)"
3837
3840
3838 - find all changesets by some user in a date range::
3841 - find all changesets by some user in a date range::
3839
3842
3840 hg log -k alice -d "may 2008 to jul 2008"
3843 hg log -k alice -d "may 2008 to jul 2008"
3841
3844
3842 - summary of all changesets after the last tag::
3845 - summary of all changesets after the last tag::
3843
3846
3844 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3847 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3845
3848
3846 - changesets touching lines 13 to 23 for file.c::
3849 - changesets touching lines 13 to 23 for file.c::
3847
3850
3848 hg log -L file.c,13:23
3851 hg log -L file.c,13:23
3849
3852
3850 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3853 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3851 main.c with patch::
3854 main.c with patch::
3852
3855
3853 hg log -L file.c,13:23 -L main.c,2:6 -p
3856 hg log -L file.c,13:23 -L main.c,2:6 -p
3854
3857
3855 See :hg:`help dates` for a list of formats valid for -d/--date.
3858 See :hg:`help dates` for a list of formats valid for -d/--date.
3856
3859
3857 See :hg:`help revisions` for more about specifying and ordering
3860 See :hg:`help revisions` for more about specifying and ordering
3858 revisions.
3861 revisions.
3859
3862
3860 See :hg:`help templates` for more about pre-packaged styles and
3863 See :hg:`help templates` for more about pre-packaged styles and
3861 specifying custom templates. The default template used by the log
3864 specifying custom templates. The default template used by the log
3862 command can be customized via the ``ui.logtemplate`` configuration
3865 command can be customized via the ``ui.logtemplate`` configuration
3863 setting.
3866 setting.
3864
3867
3865 Returns 0 on success.
3868 Returns 0 on success.
3866
3869
3867 """
3870 """
3868 opts = pycompat.byteskwargs(opts)
3871 opts = pycompat.byteskwargs(opts)
3869 linerange = opts.get('line_range')
3872 linerange = opts.get('line_range')
3870
3873
3871 if linerange and not opts.get('follow'):
3874 if linerange and not opts.get('follow'):
3872 raise error.Abort(_('--line-range requires --follow'))
3875 raise error.Abort(_('--line-range requires --follow'))
3873
3876
3874 if linerange and pats:
3877 if linerange and pats:
3875 # TODO: take pats as patterns with no line-range filter
3878 # TODO: take pats as patterns with no line-range filter
3876 raise error.Abort(
3879 raise error.Abort(
3877 _('FILE arguments are not compatible with --line-range option')
3880 _('FILE arguments are not compatible with --line-range option')
3878 )
3881 )
3879
3882
3880 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3883 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3881 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3884 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3882 if linerange:
3885 if linerange:
3883 # TODO: should follow file history from logcmdutil._initialrevs(),
3886 # TODO: should follow file history from logcmdutil._initialrevs(),
3884 # then filter the result by logcmdutil._makerevset() and --limit
3887 # then filter the result by logcmdutil._makerevset() and --limit
3885 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3888 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3886
3889
3887 getrenamed = None
3890 getrenamed = None
3888 if opts.get('copies'):
3891 if opts.get('copies'):
3889 endrev = None
3892 endrev = None
3890 if revs:
3893 if revs:
3891 endrev = revs.max() + 1
3894 endrev = revs.max() + 1
3892 getrenamed = scmutil.getrenamedfn(repo, endrev=endrev)
3895 getrenamed = scmutil.getrenamedfn(repo, endrev=endrev)
3893
3896
3894 ui.pager('log')
3897 ui.pager('log')
3895 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3898 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3896 buffered=True)
3899 buffered=True)
3897 if opts.get('graph'):
3900 if opts.get('graph'):
3898 displayfn = logcmdutil.displaygraphrevs
3901 displayfn = logcmdutil.displaygraphrevs
3899 else:
3902 else:
3900 displayfn = logcmdutil.displayrevs
3903 displayfn = logcmdutil.displayrevs
3901 displayfn(ui, repo, revs, displayer, getrenamed)
3904 displayfn(ui, repo, revs, displayer, getrenamed)
3902
3905
3903 @command('manifest',
3906 @command('manifest',
3904 [('r', 'rev', '', _('revision to display'), _('REV')),
3907 [('r', 'rev', '', _('revision to display'), _('REV')),
3905 ('', 'all', False, _("list files from all revisions"))]
3908 ('', 'all', False, _("list files from all revisions"))]
3906 + formatteropts,
3909 + formatteropts,
3907 _('[-r REV]'),
3910 _('[-r REV]'),
3908 helpcategory=command.CATEGORY_MAINTENANCE,
3911 helpcategory=command.CATEGORY_MAINTENANCE,
3909 intents={INTENT_READONLY})
3912 intents={INTENT_READONLY})
3910 def manifest(ui, repo, node=None, rev=None, **opts):
3913 def manifest(ui, repo, node=None, rev=None, **opts):
3911 """output the current or given revision of the project manifest
3914 """output the current or given revision of the project manifest
3912
3915
3913 Print a list of version controlled files for the given revision.
3916 Print a list of version controlled files for the given revision.
3914 If no revision is given, the first parent of the working directory
3917 If no revision is given, the first parent of the working directory
3915 is used, or the null revision if no revision is checked out.
3918 is used, or the null revision if no revision is checked out.
3916
3919
3917 With -v, print file permissions, symlink and executable bits.
3920 With -v, print file permissions, symlink and executable bits.
3918 With --debug, print file revision hashes.
3921 With --debug, print file revision hashes.
3919
3922
3920 If option --all is specified, the list of all files from all revisions
3923 If option --all is specified, the list of all files from all revisions
3921 is printed. This includes deleted and renamed files.
3924 is printed. This includes deleted and renamed files.
3922
3925
3923 Returns 0 on success.
3926 Returns 0 on success.
3924 """
3927 """
3925 opts = pycompat.byteskwargs(opts)
3928 opts = pycompat.byteskwargs(opts)
3926 fm = ui.formatter('manifest', opts)
3929 fm = ui.formatter('manifest', opts)
3927
3930
3928 if opts.get('all'):
3931 if opts.get('all'):
3929 if rev or node:
3932 if rev or node:
3930 raise error.Abort(_("can't specify a revision with --all"))
3933 raise error.Abort(_("can't specify a revision with --all"))
3931
3934
3932 res = set()
3935 res = set()
3933 for rev in repo:
3936 for rev in repo:
3934 ctx = repo[rev]
3937 ctx = repo[rev]
3935 res |= set(ctx.files())
3938 res |= set(ctx.files())
3936
3939
3937 ui.pager('manifest')
3940 ui.pager('manifest')
3938 for f in sorted(res):
3941 for f in sorted(res):
3939 fm.startitem()
3942 fm.startitem()
3940 fm.write("path", '%s\n', f)
3943 fm.write("path", '%s\n', f)
3941 fm.end()
3944 fm.end()
3942 return
3945 return
3943
3946
3944 if rev and node:
3947 if rev and node:
3945 raise error.Abort(_("please specify just one revision"))
3948 raise error.Abort(_("please specify just one revision"))
3946
3949
3947 if not node:
3950 if not node:
3948 node = rev
3951 node = rev
3949
3952
3950 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3953 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3951 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3954 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3952 if node:
3955 if node:
3953 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3956 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3954 ctx = scmutil.revsingle(repo, node)
3957 ctx = scmutil.revsingle(repo, node)
3955 mf = ctx.manifest()
3958 mf = ctx.manifest()
3956 ui.pager('manifest')
3959 ui.pager('manifest')
3957 for f in ctx:
3960 for f in ctx:
3958 fm.startitem()
3961 fm.startitem()
3959 fm.context(ctx=ctx)
3962 fm.context(ctx=ctx)
3960 fl = ctx[f].flags()
3963 fl = ctx[f].flags()
3961 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3964 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3962 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3965 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3963 fm.write('path', '%s\n', f)
3966 fm.write('path', '%s\n', f)
3964 fm.end()
3967 fm.end()
3965
3968
3966 @command('merge',
3969 @command('merge',
3967 [('f', 'force', None,
3970 [('f', 'force', None,
3968 _('force a merge including outstanding changes (DEPRECATED)')),
3971 _('force a merge including outstanding changes (DEPRECATED)')),
3969 ('r', 'rev', '', _('revision to merge'), _('REV')),
3972 ('r', 'rev', '', _('revision to merge'), _('REV')),
3970 ('P', 'preview', None,
3973 ('P', 'preview', None,
3971 _('review revisions to merge (no merge is performed)')),
3974 _('review revisions to merge (no merge is performed)')),
3972 ('', 'abort', None, _('abort the ongoing merge')),
3975 ('', 'abort', None, _('abort the ongoing merge')),
3973 ] + mergetoolopts,
3976 ] + mergetoolopts,
3974 _('[-P] [[-r] REV]'),
3977 _('[-P] [[-r] REV]'),
3975 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3978 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3976 def merge(ui, repo, node=None, **opts):
3979 def merge(ui, repo, node=None, **opts):
3977 """merge another revision into working directory
3980 """merge another revision into working directory
3978
3981
3979 The current working directory is updated with all changes made in
3982 The current working directory is updated with all changes made in
3980 the requested revision since the last common predecessor revision.
3983 the requested revision since the last common predecessor revision.
3981
3984
3982 Files that changed between either parent are marked as changed for
3985 Files that changed between either parent are marked as changed for
3983 the next commit and a commit must be performed before any further
3986 the next commit and a commit must be performed before any further
3984 updates to the repository are allowed. The next commit will have
3987 updates to the repository are allowed. The next commit will have
3985 two parents.
3988 two parents.
3986
3989
3987 ``--tool`` can be used to specify the merge tool used for file
3990 ``--tool`` can be used to specify the merge tool used for file
3988 merges. It overrides the HGMERGE environment variable and your
3991 merges. It overrides the HGMERGE environment variable and your
3989 configuration files. See :hg:`help merge-tools` for options.
3992 configuration files. See :hg:`help merge-tools` for options.
3990
3993
3991 If no revision is specified, the working directory's parent is a
3994 If no revision is specified, the working directory's parent is a
3992 head revision, and the current branch contains exactly one other
3995 head revision, and the current branch contains exactly one other
3993 head, the other head is merged with by default. Otherwise, an
3996 head, the other head is merged with by default. Otherwise, an
3994 explicit revision with which to merge must be provided.
3997 explicit revision with which to merge must be provided.
3995
3998
3996 See :hg:`help resolve` for information on handling file conflicts.
3999 See :hg:`help resolve` for information on handling file conflicts.
3997
4000
3998 To undo an uncommitted merge, use :hg:`merge --abort` which
4001 To undo an uncommitted merge, use :hg:`merge --abort` which
3999 will check out a clean copy of the original merge parent, losing
4002 will check out a clean copy of the original merge parent, losing
4000 all changes.
4003 all changes.
4001
4004
4002 Returns 0 on success, 1 if there are unresolved files.
4005 Returns 0 on success, 1 if there are unresolved files.
4003 """
4006 """
4004
4007
4005 opts = pycompat.byteskwargs(opts)
4008 opts = pycompat.byteskwargs(opts)
4006 abort = opts.get('abort')
4009 abort = opts.get('abort')
4007 if abort and repo.dirstate.p2() == nullid:
4010 if abort and repo.dirstate.p2() == nullid:
4008 cmdutil.wrongtooltocontinue(repo, _('merge'))
4011 cmdutil.wrongtooltocontinue(repo, _('merge'))
4009 if abort:
4012 if abort:
4010 if node:
4013 if node:
4011 raise error.Abort(_("cannot specify a node with --abort"))
4014 raise error.Abort(_("cannot specify a node with --abort"))
4012 if opts.get('rev'):
4015 if opts.get('rev'):
4013 raise error.Abort(_("cannot specify both --rev and --abort"))
4016 raise error.Abort(_("cannot specify both --rev and --abort"))
4014 if opts.get('preview'):
4017 if opts.get('preview'):
4015 raise error.Abort(_("cannot specify --preview with --abort"))
4018 raise error.Abort(_("cannot specify --preview with --abort"))
4016 if opts.get('rev') and node:
4019 if opts.get('rev') and node:
4017 raise error.Abort(_("please specify just one revision"))
4020 raise error.Abort(_("please specify just one revision"))
4018 if not node:
4021 if not node:
4019 node = opts.get('rev')
4022 node = opts.get('rev')
4020
4023
4021 if node:
4024 if node:
4022 node = scmutil.revsingle(repo, node).node()
4025 node = scmutil.revsingle(repo, node).node()
4023
4026
4024 if not node and not abort:
4027 if not node and not abort:
4025 node = repo[destutil.destmerge(repo)].node()
4028 node = repo[destutil.destmerge(repo)].node()
4026
4029
4027 if opts.get('preview'):
4030 if opts.get('preview'):
4028 # find nodes that are ancestors of p2 but not of p1
4031 # find nodes that are ancestors of p2 but not of p1
4029 p1 = repo.lookup('.')
4032 p1 = repo.lookup('.')
4030 p2 = node
4033 p2 = node
4031 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4034 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4032
4035
4033 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4036 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4034 for node in nodes:
4037 for node in nodes:
4035 displayer.show(repo[node])
4038 displayer.show(repo[node])
4036 displayer.close()
4039 displayer.close()
4037 return 0
4040 return 0
4038
4041
4039 # ui.forcemerge is an internal variable, do not document
4042 # ui.forcemerge is an internal variable, do not document
4040 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4043 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4041 with ui.configoverride(overrides, 'merge'):
4044 with ui.configoverride(overrides, 'merge'):
4042 force = opts.get('force')
4045 force = opts.get('force')
4043 labels = ['working copy', 'merge rev']
4046 labels = ['working copy', 'merge rev']
4044 return hg.merge(repo, node, force=force, mergeforce=force,
4047 return hg.merge(repo, node, force=force, mergeforce=force,
4045 labels=labels, abort=abort)
4048 labels=labels, abort=abort)
4046
4049
4047 @command('outgoing|out',
4050 @command('outgoing|out',
4048 [('f', 'force', None, _('run even when the destination is unrelated')),
4051 [('f', 'force', None, _('run even when the destination is unrelated')),
4049 ('r', 'rev', [],
4052 ('r', 'rev', [],
4050 _('a changeset intended to be included in the destination'), _('REV')),
4053 _('a changeset intended to be included in the destination'), _('REV')),
4051 ('n', 'newest-first', None, _('show newest record first')),
4054 ('n', 'newest-first', None, _('show newest record first')),
4052 ('B', 'bookmarks', False, _('compare bookmarks')),
4055 ('B', 'bookmarks', False, _('compare bookmarks')),
4053 ('b', 'branch', [], _('a specific branch you would like to push'),
4056 ('b', 'branch', [], _('a specific branch you would like to push'),
4054 _('BRANCH')),
4057 _('BRANCH')),
4055 ] + logopts + remoteopts + subrepoopts,
4058 ] + logopts + remoteopts + subrepoopts,
4056 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4059 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4057 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
4060 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
4058 def outgoing(ui, repo, dest=None, **opts):
4061 def outgoing(ui, repo, dest=None, **opts):
4059 """show changesets not found in the destination
4062 """show changesets not found in the destination
4060
4063
4061 Show changesets not found in the specified destination repository
4064 Show changesets not found in the specified destination repository
4062 or the default push location. These are the changesets that would
4065 or the default push location. These are the changesets that would
4063 be pushed if a push was requested.
4066 be pushed if a push was requested.
4064
4067
4065 See pull for details of valid destination formats.
4068 See pull for details of valid destination formats.
4066
4069
4067 .. container:: verbose
4070 .. container:: verbose
4068
4071
4069 With -B/--bookmarks, the result of bookmark comparison between
4072 With -B/--bookmarks, the result of bookmark comparison between
4070 local and remote repositories is displayed. With -v/--verbose,
4073 local and remote repositories is displayed. With -v/--verbose,
4071 status is also displayed for each bookmark like below::
4074 status is also displayed for each bookmark like below::
4072
4075
4073 BM1 01234567890a added
4076 BM1 01234567890a added
4074 BM2 deleted
4077 BM2 deleted
4075 BM3 234567890abc advanced
4078 BM3 234567890abc advanced
4076 BM4 34567890abcd diverged
4079 BM4 34567890abcd diverged
4077 BM5 4567890abcde changed
4080 BM5 4567890abcde changed
4078
4081
4079 The action taken when pushing depends on the
4082 The action taken when pushing depends on the
4080 status of each bookmark:
4083 status of each bookmark:
4081
4084
4082 :``added``: push with ``-B`` will create it
4085 :``added``: push with ``-B`` will create it
4083 :``deleted``: push with ``-B`` will delete it
4086 :``deleted``: push with ``-B`` will delete it
4084 :``advanced``: push will update it
4087 :``advanced``: push will update it
4085 :``diverged``: push with ``-B`` will update it
4088 :``diverged``: push with ``-B`` will update it
4086 :``changed``: push with ``-B`` will update it
4089 :``changed``: push with ``-B`` will update it
4087
4090
4088 From the point of view of pushing behavior, bookmarks
4091 From the point of view of pushing behavior, bookmarks
4089 existing only in the remote repository are treated as
4092 existing only in the remote repository are treated as
4090 ``deleted``, even if it is in fact added remotely.
4093 ``deleted``, even if it is in fact added remotely.
4091
4094
4092 Returns 0 if there are outgoing changes, 1 otherwise.
4095 Returns 0 if there are outgoing changes, 1 otherwise.
4093 """
4096 """
4094 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4097 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4095 # style URLs, so don't overwrite dest.
4098 # style URLs, so don't overwrite dest.
4096 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4099 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4097 if not path:
4100 if not path:
4098 raise error.Abort(_('default repository not configured!'),
4101 raise error.Abort(_('default repository not configured!'),
4099 hint=_("see 'hg help config.paths'"))
4102 hint=_("see 'hg help config.paths'"))
4100
4103
4101 opts = pycompat.byteskwargs(opts)
4104 opts = pycompat.byteskwargs(opts)
4102 if opts.get('graph'):
4105 if opts.get('graph'):
4103 logcmdutil.checkunsupportedgraphflags([], opts)
4106 logcmdutil.checkunsupportedgraphflags([], opts)
4104 o, other = hg._outgoing(ui, repo, dest, opts)
4107 o, other = hg._outgoing(ui, repo, dest, opts)
4105 if not o:
4108 if not o:
4106 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4109 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4107 return
4110 return
4108
4111
4109 revdag = logcmdutil.graphrevs(repo, o, opts)
4112 revdag = logcmdutil.graphrevs(repo, o, opts)
4110 ui.pager('outgoing')
4113 ui.pager('outgoing')
4111 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4114 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4112 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4115 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4113 graphmod.asciiedges)
4116 graphmod.asciiedges)
4114 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4117 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4115 return 0
4118 return 0
4116
4119
4117 if opts.get('bookmarks'):
4120 if opts.get('bookmarks'):
4118 dest = path.pushloc or path.loc
4121 dest = path.pushloc or path.loc
4119 other = hg.peer(repo, opts, dest)
4122 other = hg.peer(repo, opts, dest)
4120 if 'bookmarks' not in other.listkeys('namespaces'):
4123 if 'bookmarks' not in other.listkeys('namespaces'):
4121 ui.warn(_("remote doesn't support bookmarks\n"))
4124 ui.warn(_("remote doesn't support bookmarks\n"))
4122 return 0
4125 return 0
4123 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4126 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4124 ui.pager('outgoing')
4127 ui.pager('outgoing')
4125 return bookmarks.outgoing(ui, repo, other)
4128 return bookmarks.outgoing(ui, repo, other)
4126
4129
4127 repo._subtoppath = path.pushloc or path.loc
4130 repo._subtoppath = path.pushloc or path.loc
4128 try:
4131 try:
4129 return hg.outgoing(ui, repo, dest, opts)
4132 return hg.outgoing(ui, repo, dest, opts)
4130 finally:
4133 finally:
4131 del repo._subtoppath
4134 del repo._subtoppath
4132
4135
4133 @command('parents',
4136 @command('parents',
4134 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4137 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4135 ] + templateopts,
4138 ] + templateopts,
4136 _('[-r REV] [FILE]'),
4139 _('[-r REV] [FILE]'),
4137 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4140 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4138 inferrepo=True)
4141 inferrepo=True)
4139 def parents(ui, repo, file_=None, **opts):
4142 def parents(ui, repo, file_=None, **opts):
4140 """show the parents of the working directory or revision (DEPRECATED)
4143 """show the parents of the working directory or revision (DEPRECATED)
4141
4144
4142 Print the working directory's parent revisions. If a revision is
4145 Print the working directory's parent revisions. If a revision is
4143 given via -r/--rev, the parent of that revision will be printed.
4146 given via -r/--rev, the parent of that revision will be printed.
4144 If a file argument is given, the revision in which the file was
4147 If a file argument is given, the revision in which the file was
4145 last changed (before the working directory revision or the
4148 last changed (before the working directory revision or the
4146 argument to --rev if given) is printed.
4149 argument to --rev if given) is printed.
4147
4150
4148 This command is equivalent to::
4151 This command is equivalent to::
4149
4152
4150 hg log -r "p1()+p2()" or
4153 hg log -r "p1()+p2()" or
4151 hg log -r "p1(REV)+p2(REV)" or
4154 hg log -r "p1(REV)+p2(REV)" or
4152 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4155 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4153 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4156 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4154
4157
4155 See :hg:`summary` and :hg:`help revsets` for related information.
4158 See :hg:`summary` and :hg:`help revsets` for related information.
4156
4159
4157 Returns 0 on success.
4160 Returns 0 on success.
4158 """
4161 """
4159
4162
4160 opts = pycompat.byteskwargs(opts)
4163 opts = pycompat.byteskwargs(opts)
4161 rev = opts.get('rev')
4164 rev = opts.get('rev')
4162 if rev:
4165 if rev:
4163 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4166 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4164 ctx = scmutil.revsingle(repo, rev, None)
4167 ctx = scmutil.revsingle(repo, rev, None)
4165
4168
4166 if file_:
4169 if file_:
4167 m = scmutil.match(ctx, (file_,), opts)
4170 m = scmutil.match(ctx, (file_,), opts)
4168 if m.anypats() or len(m.files()) != 1:
4171 if m.anypats() or len(m.files()) != 1:
4169 raise error.Abort(_('can only specify an explicit filename'))
4172 raise error.Abort(_('can only specify an explicit filename'))
4170 file_ = m.files()[0]
4173 file_ = m.files()[0]
4171 filenodes = []
4174 filenodes = []
4172 for cp in ctx.parents():
4175 for cp in ctx.parents():
4173 if not cp:
4176 if not cp:
4174 continue
4177 continue
4175 try:
4178 try:
4176 filenodes.append(cp.filenode(file_))
4179 filenodes.append(cp.filenode(file_))
4177 except error.LookupError:
4180 except error.LookupError:
4178 pass
4181 pass
4179 if not filenodes:
4182 if not filenodes:
4180 raise error.Abort(_("'%s' not found in manifest!") % file_)
4183 raise error.Abort(_("'%s' not found in manifest!") % file_)
4181 p = []
4184 p = []
4182 for fn in filenodes:
4185 for fn in filenodes:
4183 fctx = repo.filectx(file_, fileid=fn)
4186 fctx = repo.filectx(file_, fileid=fn)
4184 p.append(fctx.node())
4187 p.append(fctx.node())
4185 else:
4188 else:
4186 p = [cp.node() for cp in ctx.parents()]
4189 p = [cp.node() for cp in ctx.parents()]
4187
4190
4188 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4191 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4189 for n in p:
4192 for n in p:
4190 if n != nullid:
4193 if n != nullid:
4191 displayer.show(repo[n])
4194 displayer.show(repo[n])
4192 displayer.close()
4195 displayer.close()
4193
4196
4194 @command('paths', formatteropts, _('[NAME]'),
4197 @command('paths', formatteropts, _('[NAME]'),
4195 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4198 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4196 optionalrepo=True, intents={INTENT_READONLY})
4199 optionalrepo=True, intents={INTENT_READONLY})
4197 def paths(ui, repo, search=None, **opts):
4200 def paths(ui, repo, search=None, **opts):
4198 """show aliases for remote repositories
4201 """show aliases for remote repositories
4199
4202
4200 Show definition of symbolic path name NAME. If no name is given,
4203 Show definition of symbolic path name NAME. If no name is given,
4201 show definition of all available names.
4204 show definition of all available names.
4202
4205
4203 Option -q/--quiet suppresses all output when searching for NAME
4206 Option -q/--quiet suppresses all output when searching for NAME
4204 and shows only the path names when listing all definitions.
4207 and shows only the path names when listing all definitions.
4205
4208
4206 Path names are defined in the [paths] section of your
4209 Path names are defined in the [paths] section of your
4207 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4210 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4208 repository, ``.hg/hgrc`` is used, too.
4211 repository, ``.hg/hgrc`` is used, too.
4209
4212
4210 The path names ``default`` and ``default-push`` have a special
4213 The path names ``default`` and ``default-push`` have a special
4211 meaning. When performing a push or pull operation, they are used
4214 meaning. When performing a push or pull operation, they are used
4212 as fallbacks if no location is specified on the command-line.
4215 as fallbacks if no location is specified on the command-line.
4213 When ``default-push`` is set, it will be used for push and
4216 When ``default-push`` is set, it will be used for push and
4214 ``default`` will be used for pull; otherwise ``default`` is used
4217 ``default`` will be used for pull; otherwise ``default`` is used
4215 as the fallback for both. When cloning a repository, the clone
4218 as the fallback for both. When cloning a repository, the clone
4216 source is written as ``default`` in ``.hg/hgrc``.
4219 source is written as ``default`` in ``.hg/hgrc``.
4217
4220
4218 .. note::
4221 .. note::
4219
4222
4220 ``default`` and ``default-push`` apply to all inbound (e.g.
4223 ``default`` and ``default-push`` apply to all inbound (e.g.
4221 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4224 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4222 and :hg:`bundle`) operations.
4225 and :hg:`bundle`) operations.
4223
4226
4224 See :hg:`help urls` for more information.
4227 See :hg:`help urls` for more information.
4225
4228
4226 .. container:: verbose
4229 .. container:: verbose
4227
4230
4228 Template:
4231 Template:
4229
4232
4230 The following keywords are supported. See also :hg:`help templates`.
4233 The following keywords are supported. See also :hg:`help templates`.
4231
4234
4232 :name: String. Symbolic name of the path alias.
4235 :name: String. Symbolic name of the path alias.
4233 :pushurl: String. URL for push operations.
4236 :pushurl: String. URL for push operations.
4234 :url: String. URL or directory path for the other operations.
4237 :url: String. URL or directory path for the other operations.
4235
4238
4236 Returns 0 on success.
4239 Returns 0 on success.
4237 """
4240 """
4238
4241
4239 opts = pycompat.byteskwargs(opts)
4242 opts = pycompat.byteskwargs(opts)
4240 ui.pager('paths')
4243 ui.pager('paths')
4241 if search:
4244 if search:
4242 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4245 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4243 if name == search]
4246 if name == search]
4244 else:
4247 else:
4245 pathitems = sorted(ui.paths.iteritems())
4248 pathitems = sorted(ui.paths.iteritems())
4246
4249
4247 fm = ui.formatter('paths', opts)
4250 fm = ui.formatter('paths', opts)
4248 if fm.isplain():
4251 if fm.isplain():
4249 hidepassword = util.hidepassword
4252 hidepassword = util.hidepassword
4250 else:
4253 else:
4251 hidepassword = bytes
4254 hidepassword = bytes
4252 if ui.quiet:
4255 if ui.quiet:
4253 namefmt = '%s\n'
4256 namefmt = '%s\n'
4254 else:
4257 else:
4255 namefmt = '%s = '
4258 namefmt = '%s = '
4256 showsubopts = not search and not ui.quiet
4259 showsubopts = not search and not ui.quiet
4257
4260
4258 for name, path in pathitems:
4261 for name, path in pathitems:
4259 fm.startitem()
4262 fm.startitem()
4260 fm.condwrite(not search, 'name', namefmt, name)
4263 fm.condwrite(not search, 'name', namefmt, name)
4261 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4264 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4262 for subopt, value in sorted(path.suboptions.items()):
4265 for subopt, value in sorted(path.suboptions.items()):
4263 assert subopt not in ('name', 'url')
4266 assert subopt not in ('name', 'url')
4264 if showsubopts:
4267 if showsubopts:
4265 fm.plain('%s:%s = ' % (name, subopt))
4268 fm.plain('%s:%s = ' % (name, subopt))
4266 fm.condwrite(showsubopts, subopt, '%s\n', value)
4269 fm.condwrite(showsubopts, subopt, '%s\n', value)
4267
4270
4268 fm.end()
4271 fm.end()
4269
4272
4270 if search and not pathitems:
4273 if search and not pathitems:
4271 if not ui.quiet:
4274 if not ui.quiet:
4272 ui.warn(_("not found!\n"))
4275 ui.warn(_("not found!\n"))
4273 return 1
4276 return 1
4274 else:
4277 else:
4275 return 0
4278 return 0
4276
4279
4277 @command('phase',
4280 @command('phase',
4278 [('p', 'public', False, _('set changeset phase to public')),
4281 [('p', 'public', False, _('set changeset phase to public')),
4279 ('d', 'draft', False, _('set changeset phase to draft')),
4282 ('d', 'draft', False, _('set changeset phase to draft')),
4280 ('s', 'secret', False, _('set changeset phase to secret')),
4283 ('s', 'secret', False, _('set changeset phase to secret')),
4281 ('f', 'force', False, _('allow to move boundary backward')),
4284 ('f', 'force', False, _('allow to move boundary backward')),
4282 ('r', 'rev', [], _('target revision'), _('REV')),
4285 ('r', 'rev', [], _('target revision'), _('REV')),
4283 ],
4286 ],
4284 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4287 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4285 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4288 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4286 def phase(ui, repo, *revs, **opts):
4289 def phase(ui, repo, *revs, **opts):
4287 """set or show the current phase name
4290 """set or show the current phase name
4288
4291
4289 With no argument, show the phase name of the current revision(s).
4292 With no argument, show the phase name of the current revision(s).
4290
4293
4291 With one of -p/--public, -d/--draft or -s/--secret, change the
4294 With one of -p/--public, -d/--draft or -s/--secret, change the
4292 phase value of the specified revisions.
4295 phase value of the specified revisions.
4293
4296
4294 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4297 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4295 lower phase to a higher phase. Phases are ordered as follows::
4298 lower phase to a higher phase. Phases are ordered as follows::
4296
4299
4297 public < draft < secret
4300 public < draft < secret
4298
4301
4299 Returns 0 on success, 1 if some phases could not be changed.
4302 Returns 0 on success, 1 if some phases could not be changed.
4300
4303
4301 (For more information about the phases concept, see :hg:`help phases`.)
4304 (For more information about the phases concept, see :hg:`help phases`.)
4302 """
4305 """
4303 opts = pycompat.byteskwargs(opts)
4306 opts = pycompat.byteskwargs(opts)
4304 # search for a unique phase argument
4307 # search for a unique phase argument
4305 targetphase = None
4308 targetphase = None
4306 for idx, name in enumerate(phases.cmdphasenames):
4309 for idx, name in enumerate(phases.cmdphasenames):
4307 if opts[name]:
4310 if opts[name]:
4308 if targetphase is not None:
4311 if targetphase is not None:
4309 raise error.Abort(_('only one phase can be specified'))
4312 raise error.Abort(_('only one phase can be specified'))
4310 targetphase = idx
4313 targetphase = idx
4311
4314
4312 # look for specified revision
4315 # look for specified revision
4313 revs = list(revs)
4316 revs = list(revs)
4314 revs.extend(opts['rev'])
4317 revs.extend(opts['rev'])
4315 if not revs:
4318 if not revs:
4316 # display both parents as the second parent phase can influence
4319 # display both parents as the second parent phase can influence
4317 # the phase of a merge commit
4320 # the phase of a merge commit
4318 revs = [c.rev() for c in repo[None].parents()]
4321 revs = [c.rev() for c in repo[None].parents()]
4319
4322
4320 revs = scmutil.revrange(repo, revs)
4323 revs = scmutil.revrange(repo, revs)
4321
4324
4322 ret = 0
4325 ret = 0
4323 if targetphase is None:
4326 if targetphase is None:
4324 # display
4327 # display
4325 for r in revs:
4328 for r in revs:
4326 ctx = repo[r]
4329 ctx = repo[r]
4327 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4330 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4328 else:
4331 else:
4329 with repo.lock(), repo.transaction("phase") as tr:
4332 with repo.lock(), repo.transaction("phase") as tr:
4330 # set phase
4333 # set phase
4331 if not revs:
4334 if not revs:
4332 raise error.Abort(_('empty revision set'))
4335 raise error.Abort(_('empty revision set'))
4333 nodes = [repo[r].node() for r in revs]
4336 nodes = [repo[r].node() for r in revs]
4334 # moving revision from public to draft may hide them
4337 # moving revision from public to draft may hide them
4335 # We have to check result on an unfiltered repository
4338 # We have to check result on an unfiltered repository
4336 unfi = repo.unfiltered()
4339 unfi = repo.unfiltered()
4337 getphase = unfi._phasecache.phase
4340 getphase = unfi._phasecache.phase
4338 olddata = [getphase(unfi, r) for r in unfi]
4341 olddata = [getphase(unfi, r) for r in unfi]
4339 phases.advanceboundary(repo, tr, targetphase, nodes)
4342 phases.advanceboundary(repo, tr, targetphase, nodes)
4340 if opts['force']:
4343 if opts['force']:
4341 phases.retractboundary(repo, tr, targetphase, nodes)
4344 phases.retractboundary(repo, tr, targetphase, nodes)
4342 getphase = unfi._phasecache.phase
4345 getphase = unfi._phasecache.phase
4343 newdata = [getphase(unfi, r) for r in unfi]
4346 newdata = [getphase(unfi, r) for r in unfi]
4344 changes = sum(newdata[r] != olddata[r] for r in unfi)
4347 changes = sum(newdata[r] != olddata[r] for r in unfi)
4345 cl = unfi.changelog
4348 cl = unfi.changelog
4346 rejected = [n for n in nodes
4349 rejected = [n for n in nodes
4347 if newdata[cl.rev(n)] < targetphase]
4350 if newdata[cl.rev(n)] < targetphase]
4348 if rejected:
4351 if rejected:
4349 ui.warn(_('cannot move %i changesets to a higher '
4352 ui.warn(_('cannot move %i changesets to a higher '
4350 'phase, use --force\n') % len(rejected))
4353 'phase, use --force\n') % len(rejected))
4351 ret = 1
4354 ret = 1
4352 if changes:
4355 if changes:
4353 msg = _('phase changed for %i changesets\n') % changes
4356 msg = _('phase changed for %i changesets\n') % changes
4354 if ret:
4357 if ret:
4355 ui.status(msg)
4358 ui.status(msg)
4356 else:
4359 else:
4357 ui.note(msg)
4360 ui.note(msg)
4358 else:
4361 else:
4359 ui.warn(_('no phases changed\n'))
4362 ui.warn(_('no phases changed\n'))
4360 return ret
4363 return ret
4361
4364
4362 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4365 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4363 """Run after a changegroup has been added via pull/unbundle
4366 """Run after a changegroup has been added via pull/unbundle
4364
4367
4365 This takes arguments below:
4368 This takes arguments below:
4366
4369
4367 :modheads: change of heads by pull/unbundle
4370 :modheads: change of heads by pull/unbundle
4368 :optupdate: updating working directory is needed or not
4371 :optupdate: updating working directory is needed or not
4369 :checkout: update destination revision (or None to default destination)
4372 :checkout: update destination revision (or None to default destination)
4370 :brev: a name, which might be a bookmark to be activated after updating
4373 :brev: a name, which might be a bookmark to be activated after updating
4371 """
4374 """
4372 if modheads == 0:
4375 if modheads == 0:
4373 return
4376 return
4374 if optupdate:
4377 if optupdate:
4375 try:
4378 try:
4376 return hg.updatetotally(ui, repo, checkout, brev)
4379 return hg.updatetotally(ui, repo, checkout, brev)
4377 except error.UpdateAbort as inst:
4380 except error.UpdateAbort as inst:
4378 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4381 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4379 hint = inst.hint
4382 hint = inst.hint
4380 raise error.UpdateAbort(msg, hint=hint)
4383 raise error.UpdateAbort(msg, hint=hint)
4381 if modheads is not None and modheads > 1:
4384 if modheads is not None and modheads > 1:
4382 currentbranchheads = len(repo.branchheads())
4385 currentbranchheads = len(repo.branchheads())
4383 if currentbranchheads == modheads:
4386 if currentbranchheads == modheads:
4384 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4387 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4385 elif currentbranchheads > 1:
4388 elif currentbranchheads > 1:
4386 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4389 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4387 "merge)\n"))
4390 "merge)\n"))
4388 else:
4391 else:
4389 ui.status(_("(run 'hg heads' to see heads)\n"))
4392 ui.status(_("(run 'hg heads' to see heads)\n"))
4390 elif not ui.configbool('commands', 'update.requiredest'):
4393 elif not ui.configbool('commands', 'update.requiredest'):
4391 ui.status(_("(run 'hg update' to get a working copy)\n"))
4394 ui.status(_("(run 'hg update' to get a working copy)\n"))
4392
4395
4393 @command('pull',
4396 @command('pull',
4394 [('u', 'update', None,
4397 [('u', 'update', None,
4395 _('update to new branch head if new descendants were pulled')),
4398 _('update to new branch head if new descendants were pulled')),
4396 ('f', 'force', None, _('run even when remote repository is unrelated')),
4399 ('f', 'force', None, _('run even when remote repository is unrelated')),
4397 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4400 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4398 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4401 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4399 ('b', 'branch', [], _('a specific branch you would like to pull'),
4402 ('b', 'branch', [], _('a specific branch you would like to pull'),
4400 _('BRANCH')),
4403 _('BRANCH')),
4401 ] + remoteopts,
4404 ] + remoteopts,
4402 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4405 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4403 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4406 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4404 helpbasic=True)
4407 helpbasic=True)
4405 def pull(ui, repo, source="default", **opts):
4408 def pull(ui, repo, source="default", **opts):
4406 """pull changes from the specified source
4409 """pull changes from the specified source
4407
4410
4408 Pull changes from a remote repository to a local one.
4411 Pull changes from a remote repository to a local one.
4409
4412
4410 This finds all changes from the repository at the specified path
4413 This finds all changes from the repository at the specified path
4411 or URL and adds them to a local repository (the current one unless
4414 or URL and adds them to a local repository (the current one unless
4412 -R is specified). By default, this does not update the copy of the
4415 -R is specified). By default, this does not update the copy of the
4413 project in the working directory.
4416 project in the working directory.
4414
4417
4415 When cloning from servers that support it, Mercurial may fetch
4418 When cloning from servers that support it, Mercurial may fetch
4416 pre-generated data. When this is done, hooks operating on incoming
4419 pre-generated data. When this is done, hooks operating on incoming
4417 changesets and changegroups may fire more than once, once for each
4420 changesets and changegroups may fire more than once, once for each
4418 pre-generated bundle and as well as for any additional remaining
4421 pre-generated bundle and as well as for any additional remaining
4419 data. See :hg:`help -e clonebundles` for more.
4422 data. See :hg:`help -e clonebundles` for more.
4420
4423
4421 Use :hg:`incoming` if you want to see what would have been added
4424 Use :hg:`incoming` if you want to see what would have been added
4422 by a pull at the time you issued this command. If you then decide
4425 by a pull at the time you issued this command. If you then decide
4423 to add those changes to the repository, you should use :hg:`pull
4426 to add those changes to the repository, you should use :hg:`pull
4424 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4427 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4425
4428
4426 If SOURCE is omitted, the 'default' path will be used.
4429 If SOURCE is omitted, the 'default' path will be used.
4427 See :hg:`help urls` for more information.
4430 See :hg:`help urls` for more information.
4428
4431
4429 Specifying bookmark as ``.`` is equivalent to specifying the active
4432 Specifying bookmark as ``.`` is equivalent to specifying the active
4430 bookmark's name.
4433 bookmark's name.
4431
4434
4432 Returns 0 on success, 1 if an update had unresolved files.
4435 Returns 0 on success, 1 if an update had unresolved files.
4433 """
4436 """
4434
4437
4435 opts = pycompat.byteskwargs(opts)
4438 opts = pycompat.byteskwargs(opts)
4436 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4439 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4437 msg = _('update destination required by configuration')
4440 msg = _('update destination required by configuration')
4438 hint = _('use hg pull followed by hg update DEST')
4441 hint = _('use hg pull followed by hg update DEST')
4439 raise error.Abort(msg, hint=hint)
4442 raise error.Abort(msg, hint=hint)
4440
4443
4441 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4444 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4442 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4445 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4443 other = hg.peer(repo, opts, source)
4446 other = hg.peer(repo, opts, source)
4444 try:
4447 try:
4445 revs, checkout = hg.addbranchrevs(repo, other, branches,
4448 revs, checkout = hg.addbranchrevs(repo, other, branches,
4446 opts.get('rev'))
4449 opts.get('rev'))
4447
4450
4448 pullopargs = {}
4451 pullopargs = {}
4449
4452
4450 nodes = None
4453 nodes = None
4451 if opts.get('bookmark') or revs:
4454 if opts.get('bookmark') or revs:
4452 # The list of bookmark used here is the same used to actually update
4455 # The list of bookmark used here is the same used to actually update
4453 # the bookmark names, to avoid the race from issue 4689 and we do
4456 # the bookmark names, to avoid the race from issue 4689 and we do
4454 # all lookup and bookmark queries in one go so they see the same
4457 # all lookup and bookmark queries in one go so they see the same
4455 # version of the server state (issue 4700).
4458 # version of the server state (issue 4700).
4456 nodes = []
4459 nodes = []
4457 fnodes = []
4460 fnodes = []
4458 revs = revs or []
4461 revs = revs or []
4459 if revs and not other.capable('lookup'):
4462 if revs and not other.capable('lookup'):
4460 err = _("other repository doesn't support revision lookup, "
4463 err = _("other repository doesn't support revision lookup, "
4461 "so a rev cannot be specified.")
4464 "so a rev cannot be specified.")
4462 raise error.Abort(err)
4465 raise error.Abort(err)
4463 with other.commandexecutor() as e:
4466 with other.commandexecutor() as e:
4464 fremotebookmarks = e.callcommand('listkeys', {
4467 fremotebookmarks = e.callcommand('listkeys', {
4465 'namespace': 'bookmarks'
4468 'namespace': 'bookmarks'
4466 })
4469 })
4467 for r in revs:
4470 for r in revs:
4468 fnodes.append(e.callcommand('lookup', {'key': r}))
4471 fnodes.append(e.callcommand('lookup', {'key': r}))
4469 remotebookmarks = fremotebookmarks.result()
4472 remotebookmarks = fremotebookmarks.result()
4470 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4473 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4471 pullopargs['remotebookmarks'] = remotebookmarks
4474 pullopargs['remotebookmarks'] = remotebookmarks
4472 for b in opts.get('bookmark', []):
4475 for b in opts.get('bookmark', []):
4473 b = repo._bookmarks.expandname(b)
4476 b = repo._bookmarks.expandname(b)
4474 if b not in remotebookmarks:
4477 if b not in remotebookmarks:
4475 raise error.Abort(_('remote bookmark %s not found!') % b)
4478 raise error.Abort(_('remote bookmark %s not found!') % b)
4476 nodes.append(remotebookmarks[b])
4479 nodes.append(remotebookmarks[b])
4477 for i, rev in enumerate(revs):
4480 for i, rev in enumerate(revs):
4478 node = fnodes[i].result()
4481 node = fnodes[i].result()
4479 nodes.append(node)
4482 nodes.append(node)
4480 if rev == checkout:
4483 if rev == checkout:
4481 checkout = node
4484 checkout = node
4482
4485
4483 wlock = util.nullcontextmanager()
4486 wlock = util.nullcontextmanager()
4484 if opts.get('update'):
4487 if opts.get('update'):
4485 wlock = repo.wlock()
4488 wlock = repo.wlock()
4486 with wlock:
4489 with wlock:
4487 pullopargs.update(opts.get('opargs', {}))
4490 pullopargs.update(opts.get('opargs', {}))
4488 modheads = exchange.pull(repo, other, heads=nodes,
4491 modheads = exchange.pull(repo, other, heads=nodes,
4489 force=opts.get('force'),
4492 force=opts.get('force'),
4490 bookmarks=opts.get('bookmark', ()),
4493 bookmarks=opts.get('bookmark', ()),
4491 opargs=pullopargs).cgresult
4494 opargs=pullopargs).cgresult
4492
4495
4493 # brev is a name, which might be a bookmark to be activated at
4496 # brev is a name, which might be a bookmark to be activated at
4494 # the end of the update. In other words, it is an explicit
4497 # the end of the update. In other words, it is an explicit
4495 # destination of the update
4498 # destination of the update
4496 brev = None
4499 brev = None
4497
4500
4498 if checkout:
4501 if checkout:
4499 checkout = repo.unfiltered().changelog.rev(checkout)
4502 checkout = repo.unfiltered().changelog.rev(checkout)
4500
4503
4501 # order below depends on implementation of
4504 # order below depends on implementation of
4502 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4505 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4503 # because 'checkout' is determined without it.
4506 # because 'checkout' is determined without it.
4504 if opts.get('rev'):
4507 if opts.get('rev'):
4505 brev = opts['rev'][0]
4508 brev = opts['rev'][0]
4506 elif opts.get('branch'):
4509 elif opts.get('branch'):
4507 brev = opts['branch'][0]
4510 brev = opts['branch'][0]
4508 else:
4511 else:
4509 brev = branches[0]
4512 brev = branches[0]
4510 repo._subtoppath = source
4513 repo._subtoppath = source
4511 try:
4514 try:
4512 ret = postincoming(ui, repo, modheads, opts.get('update'),
4515 ret = postincoming(ui, repo, modheads, opts.get('update'),
4513 checkout, brev)
4516 checkout, brev)
4514 except error.FilteredRepoLookupError as exc:
4517 except error.FilteredRepoLookupError as exc:
4515 msg = _('cannot update to target: %s') % exc.args[0]
4518 msg = _('cannot update to target: %s') % exc.args[0]
4516 exc.args = (msg,) + exc.args[1:]
4519 exc.args = (msg,) + exc.args[1:]
4517 raise
4520 raise
4518 finally:
4521 finally:
4519 del repo._subtoppath
4522 del repo._subtoppath
4520
4523
4521 finally:
4524 finally:
4522 other.close()
4525 other.close()
4523 return ret
4526 return ret
4524
4527
4525 @command('push',
4528 @command('push',
4526 [('f', 'force', None, _('force push')),
4529 [('f', 'force', None, _('force push')),
4527 ('r', 'rev', [],
4530 ('r', 'rev', [],
4528 _('a changeset intended to be included in the destination'),
4531 _('a changeset intended to be included in the destination'),
4529 _('REV')),
4532 _('REV')),
4530 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4533 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4531 ('b', 'branch', [],
4534 ('b', 'branch', [],
4532 _('a specific branch you would like to push'), _('BRANCH')),
4535 _('a specific branch you would like to push'), _('BRANCH')),
4533 ('', 'new-branch', False, _('allow pushing a new branch')),
4536 ('', 'new-branch', False, _('allow pushing a new branch')),
4534 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4537 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4535 ('', 'publish', False, _('push the changeset as public (EXPERIMENTAL)')),
4538 ('', 'publish', False, _('push the changeset as public (EXPERIMENTAL)')),
4536 ] + remoteopts,
4539 ] + remoteopts,
4537 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4540 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4538 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4541 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4539 helpbasic=True)
4542 helpbasic=True)
4540 def push(ui, repo, dest=None, **opts):
4543 def push(ui, repo, dest=None, **opts):
4541 """push changes to the specified destination
4544 """push changes to the specified destination
4542
4545
4543 Push changesets from the local repository to the specified
4546 Push changesets from the local repository to the specified
4544 destination.
4547 destination.
4545
4548
4546 This operation is symmetrical to pull: it is identical to a pull
4549 This operation is symmetrical to pull: it is identical to a pull
4547 in the destination repository from the current one.
4550 in the destination repository from the current one.
4548
4551
4549 By default, push will not allow creation of new heads at the
4552 By default, push will not allow creation of new heads at the
4550 destination, since multiple heads would make it unclear which head
4553 destination, since multiple heads would make it unclear which head
4551 to use. In this situation, it is recommended to pull and merge
4554 to use. In this situation, it is recommended to pull and merge
4552 before pushing.
4555 before pushing.
4553
4556
4554 Use --new-branch if you want to allow push to create a new named
4557 Use --new-branch if you want to allow push to create a new named
4555 branch that is not present at the destination. This allows you to
4558 branch that is not present at the destination. This allows you to
4556 only create a new branch without forcing other changes.
4559 only create a new branch without forcing other changes.
4557
4560
4558 .. note::
4561 .. note::
4559
4562
4560 Extra care should be taken with the -f/--force option,
4563 Extra care should be taken with the -f/--force option,
4561 which will push all new heads on all branches, an action which will
4564 which will push all new heads on all branches, an action which will
4562 almost always cause confusion for collaborators.
4565 almost always cause confusion for collaborators.
4563
4566
4564 If -r/--rev is used, the specified revision and all its ancestors
4567 If -r/--rev is used, the specified revision and all its ancestors
4565 will be pushed to the remote repository.
4568 will be pushed to the remote repository.
4566
4569
4567 If -B/--bookmark is used, the specified bookmarked revision, its
4570 If -B/--bookmark is used, the specified bookmarked revision, its
4568 ancestors, and the bookmark will be pushed to the remote
4571 ancestors, and the bookmark will be pushed to the remote
4569 repository. Specifying ``.`` is equivalent to specifying the active
4572 repository. Specifying ``.`` is equivalent to specifying the active
4570 bookmark's name.
4573 bookmark's name.
4571
4574
4572 Please see :hg:`help urls` for important details about ``ssh://``
4575 Please see :hg:`help urls` for important details about ``ssh://``
4573 URLs. If DESTINATION is omitted, a default path will be used.
4576 URLs. If DESTINATION is omitted, a default path will be used.
4574
4577
4575 .. container:: verbose
4578 .. container:: verbose
4576
4579
4577 The --pushvars option sends strings to the server that become
4580 The --pushvars option sends strings to the server that become
4578 environment variables prepended with ``HG_USERVAR_``. For example,
4581 environment variables prepended with ``HG_USERVAR_``. For example,
4579 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4582 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4580 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4583 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4581
4584
4582 pushvars can provide for user-overridable hooks as well as set debug
4585 pushvars can provide for user-overridable hooks as well as set debug
4583 levels. One example is having a hook that blocks commits containing
4586 levels. One example is having a hook that blocks commits containing
4584 conflict markers, but enables the user to override the hook if the file
4587 conflict markers, but enables the user to override the hook if the file
4585 is using conflict markers for testing purposes or the file format has
4588 is using conflict markers for testing purposes or the file format has
4586 strings that look like conflict markers.
4589 strings that look like conflict markers.
4587
4590
4588 By default, servers will ignore `--pushvars`. To enable it add the
4591 By default, servers will ignore `--pushvars`. To enable it add the
4589 following to your configuration file::
4592 following to your configuration file::
4590
4593
4591 [push]
4594 [push]
4592 pushvars.server = true
4595 pushvars.server = true
4593
4596
4594 Returns 0 if push was successful, 1 if nothing to push.
4597 Returns 0 if push was successful, 1 if nothing to push.
4595 """
4598 """
4596
4599
4597 opts = pycompat.byteskwargs(opts)
4600 opts = pycompat.byteskwargs(opts)
4598 if opts.get('bookmark'):
4601 if opts.get('bookmark'):
4599 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4602 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4600 for b in opts['bookmark']:
4603 for b in opts['bookmark']:
4601 # translate -B options to -r so changesets get pushed
4604 # translate -B options to -r so changesets get pushed
4602 b = repo._bookmarks.expandname(b)
4605 b = repo._bookmarks.expandname(b)
4603 if b in repo._bookmarks:
4606 if b in repo._bookmarks:
4604 opts.setdefault('rev', []).append(b)
4607 opts.setdefault('rev', []).append(b)
4605 else:
4608 else:
4606 # if we try to push a deleted bookmark, translate it to null
4609 # if we try to push a deleted bookmark, translate it to null
4607 # this lets simultaneous -r, -b options continue working
4610 # this lets simultaneous -r, -b options continue working
4608 opts.setdefault('rev', []).append("null")
4611 opts.setdefault('rev', []).append("null")
4609
4612
4610 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4613 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4611 if not path:
4614 if not path:
4612 raise error.Abort(_('default repository not configured!'),
4615 raise error.Abort(_('default repository not configured!'),
4613 hint=_("see 'hg help config.paths'"))
4616 hint=_("see 'hg help config.paths'"))
4614 dest = path.pushloc or path.loc
4617 dest = path.pushloc or path.loc
4615 branches = (path.branch, opts.get('branch') or [])
4618 branches = (path.branch, opts.get('branch') or [])
4616 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4619 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4617 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4620 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4618 other = hg.peer(repo, opts, dest)
4621 other = hg.peer(repo, opts, dest)
4619
4622
4620 if revs:
4623 if revs:
4621 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4624 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4622 if not revs:
4625 if not revs:
4623 raise error.Abort(_("specified revisions evaluate to an empty set"),
4626 raise error.Abort(_("specified revisions evaluate to an empty set"),
4624 hint=_("use different revision arguments"))
4627 hint=_("use different revision arguments"))
4625 elif path.pushrev:
4628 elif path.pushrev:
4626 # It doesn't make any sense to specify ancestor revisions. So limit
4629 # It doesn't make any sense to specify ancestor revisions. So limit
4627 # to DAG heads to make discovery simpler.
4630 # to DAG heads to make discovery simpler.
4628 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4631 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4629 revs = scmutil.revrange(repo, [expr])
4632 revs = scmutil.revrange(repo, [expr])
4630 revs = [repo[rev].node() for rev in revs]
4633 revs = [repo[rev].node() for rev in revs]
4631 if not revs:
4634 if not revs:
4632 raise error.Abort(_('default push revset for path evaluates to an '
4635 raise error.Abort(_('default push revset for path evaluates to an '
4633 'empty set'))
4636 'empty set'))
4634
4637
4635 repo._subtoppath = dest
4638 repo._subtoppath = dest
4636 try:
4639 try:
4637 # push subrepos depth-first for coherent ordering
4640 # push subrepos depth-first for coherent ordering
4638 c = repo['.']
4641 c = repo['.']
4639 subs = c.substate # only repos that are committed
4642 subs = c.substate # only repos that are committed
4640 for s in sorted(subs):
4643 for s in sorted(subs):
4641 result = c.sub(s).push(opts)
4644 result = c.sub(s).push(opts)
4642 if result == 0:
4645 if result == 0:
4643 return not result
4646 return not result
4644 finally:
4647 finally:
4645 del repo._subtoppath
4648 del repo._subtoppath
4646
4649
4647 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4650 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4648 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4651 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4649
4652
4650 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4653 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4651 newbranch=opts.get('new_branch'),
4654 newbranch=opts.get('new_branch'),
4652 bookmarks=opts.get('bookmark', ()),
4655 bookmarks=opts.get('bookmark', ()),
4653 publish=opts.get('publish'),
4656 publish=opts.get('publish'),
4654 opargs=opargs)
4657 opargs=opargs)
4655
4658
4656 result = not pushop.cgresult
4659 result = not pushop.cgresult
4657
4660
4658 if pushop.bkresult is not None:
4661 if pushop.bkresult is not None:
4659 if pushop.bkresult == 2:
4662 if pushop.bkresult == 2:
4660 result = 2
4663 result = 2
4661 elif not result and pushop.bkresult:
4664 elif not result and pushop.bkresult:
4662 result = 2
4665 result = 2
4663
4666
4664 return result
4667 return result
4665
4668
4666 @command('recover',
4669 @command('recover',
4667 [('','verify', True, "run `hg verify` after succesful recover"),
4670 [('','verify', True, "run `hg verify` after succesful recover"),
4668 ],
4671 ],
4669 helpcategory=command.CATEGORY_MAINTENANCE)
4672 helpcategory=command.CATEGORY_MAINTENANCE)
4670 def recover(ui, repo, **opts):
4673 def recover(ui, repo, **opts):
4671 """roll back an interrupted transaction
4674 """roll back an interrupted transaction
4672
4675
4673 Recover from an interrupted commit or pull.
4676 Recover from an interrupted commit or pull.
4674
4677
4675 This command tries to fix the repository status after an
4678 This command tries to fix the repository status after an
4676 interrupted operation. It should only be necessary when Mercurial
4679 interrupted operation. It should only be necessary when Mercurial
4677 suggests it.
4680 suggests it.
4678
4681
4679 Returns 0 if successful, 1 if nothing to recover or verify fails.
4682 Returns 0 if successful, 1 if nothing to recover or verify fails.
4680 """
4683 """
4681 ret = repo.recover()
4684 ret = repo.recover()
4682 if ret:
4685 if ret:
4683 if opts[r'verify']:
4686 if opts[r'verify']:
4684 return hg.verify(repo)
4687 return hg.verify(repo)
4685 else:
4688 else:
4686 msg = _("(verify step skipped, run `hg verify` to check your "
4689 msg = _("(verify step skipped, run `hg verify` to check your "
4687 "repository content)\n")
4690 "repository content)\n")
4688 ui.warn(msg)
4691 ui.warn(msg)
4689 return 0
4692 return 0
4690 return 1
4693 return 1
4691
4694
4692 @command('remove|rm',
4695 @command('remove|rm',
4693 [('A', 'after', None, _('record delete for missing files')),
4696 [('A', 'after', None, _('record delete for missing files')),
4694 ('f', 'force', None,
4697 ('f', 'force', None,
4695 _('forget added files, delete modified files')),
4698 _('forget added files, delete modified files')),
4696 ] + subrepoopts + walkopts + dryrunopts,
4699 ] + subrepoopts + walkopts + dryrunopts,
4697 _('[OPTION]... FILE...'),
4700 _('[OPTION]... FILE...'),
4698 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4701 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4699 helpbasic=True, inferrepo=True)
4702 helpbasic=True, inferrepo=True)
4700 def remove(ui, repo, *pats, **opts):
4703 def remove(ui, repo, *pats, **opts):
4701 """remove the specified files on the next commit
4704 """remove the specified files on the next commit
4702
4705
4703 Schedule the indicated files for removal from the current branch.
4706 Schedule the indicated files for removal from the current branch.
4704
4707
4705 This command schedules the files to be removed at the next commit.
4708 This command schedules the files to be removed at the next commit.
4706 To undo a remove before that, see :hg:`revert`. To undo added
4709 To undo a remove before that, see :hg:`revert`. To undo added
4707 files, see :hg:`forget`.
4710 files, see :hg:`forget`.
4708
4711
4709 .. container:: verbose
4712 .. container:: verbose
4710
4713
4711 -A/--after can be used to remove only files that have already
4714 -A/--after can be used to remove only files that have already
4712 been deleted, -f/--force can be used to force deletion, and -Af
4715 been deleted, -f/--force can be used to force deletion, and -Af
4713 can be used to remove files from the next revision without
4716 can be used to remove files from the next revision without
4714 deleting them from the working directory.
4717 deleting them from the working directory.
4715
4718
4716 The following table details the behavior of remove for different
4719 The following table details the behavior of remove for different
4717 file states (columns) and option combinations (rows). The file
4720 file states (columns) and option combinations (rows). The file
4718 states are Added [A], Clean [C], Modified [M] and Missing [!]
4721 states are Added [A], Clean [C], Modified [M] and Missing [!]
4719 (as reported by :hg:`status`). The actions are Warn, Remove
4722 (as reported by :hg:`status`). The actions are Warn, Remove
4720 (from branch) and Delete (from disk):
4723 (from branch) and Delete (from disk):
4721
4724
4722 ========= == == == ==
4725 ========= == == == ==
4723 opt/state A C M !
4726 opt/state A C M !
4724 ========= == == == ==
4727 ========= == == == ==
4725 none W RD W R
4728 none W RD W R
4726 -f R RD RD R
4729 -f R RD RD R
4727 -A W W W R
4730 -A W W W R
4728 -Af R R R R
4731 -Af R R R R
4729 ========= == == == ==
4732 ========= == == == ==
4730
4733
4731 .. note::
4734 .. note::
4732
4735
4733 :hg:`remove` never deletes files in Added [A] state from the
4736 :hg:`remove` never deletes files in Added [A] state from the
4734 working directory, not even if ``--force`` is specified.
4737 working directory, not even if ``--force`` is specified.
4735
4738
4736 Returns 0 on success, 1 if any warnings encountered.
4739 Returns 0 on success, 1 if any warnings encountered.
4737 """
4740 """
4738
4741
4739 opts = pycompat.byteskwargs(opts)
4742 opts = pycompat.byteskwargs(opts)
4740 after, force = opts.get('after'), opts.get('force')
4743 after, force = opts.get('after'), opts.get('force')
4741 dryrun = opts.get('dry_run')
4744 dryrun = opts.get('dry_run')
4742 if not pats and not after:
4745 if not pats and not after:
4743 raise error.Abort(_('no files specified'))
4746 raise error.Abort(_('no files specified'))
4744
4747
4745 m = scmutil.match(repo[None], pats, opts)
4748 m = scmutil.match(repo[None], pats, opts)
4746 subrepos = opts.get('subrepos')
4749 subrepos = opts.get('subrepos')
4747 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
4750 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
4748 return cmdutil.remove(ui, repo, m, "", uipathfn, after, force, subrepos,
4751 return cmdutil.remove(ui, repo, m, "", uipathfn, after, force, subrepos,
4749 dryrun=dryrun)
4752 dryrun=dryrun)
4750
4753
4751 @command('rename|move|mv',
4754 @command('rename|move|mv',
4752 [('A', 'after', None, _('record a rename that has already occurred')),
4755 [('A', 'after', None, _('record a rename that has already occurred')),
4753 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4756 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4754 ] + walkopts + dryrunopts,
4757 ] + walkopts + dryrunopts,
4755 _('[OPTION]... SOURCE... DEST'),
4758 _('[OPTION]... SOURCE... DEST'),
4756 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4759 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4757 def rename(ui, repo, *pats, **opts):
4760 def rename(ui, repo, *pats, **opts):
4758 """rename files; equivalent of copy + remove
4761 """rename files; equivalent of copy + remove
4759
4762
4760 Mark dest as copies of sources; mark sources for deletion. If dest
4763 Mark dest as copies of sources; mark sources for deletion. If dest
4761 is a directory, copies are put in that directory. If dest is a
4764 is a directory, copies are put in that directory. If dest is a
4762 file, there can only be one source.
4765 file, there can only be one source.
4763
4766
4764 By default, this command copies the contents of files as they
4767 By default, this command copies the contents of files as they
4765 exist in the working directory. If invoked with -A/--after, the
4768 exist in the working directory. If invoked with -A/--after, the
4766 operation is recorded, but no copying is performed.
4769 operation is recorded, but no copying is performed.
4767
4770
4768 This command takes effect at the next commit. To undo a rename
4771 This command takes effect at the next commit. To undo a rename
4769 before that, see :hg:`revert`.
4772 before that, see :hg:`revert`.
4770
4773
4771 Returns 0 on success, 1 if errors are encountered.
4774 Returns 0 on success, 1 if errors are encountered.
4772 """
4775 """
4773 opts = pycompat.byteskwargs(opts)
4776 opts = pycompat.byteskwargs(opts)
4774 with repo.wlock(False):
4777 with repo.wlock(False):
4775 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4778 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4776
4779
4777 @command('resolve',
4780 @command('resolve',
4778 [('a', 'all', None, _('select all unresolved files')),
4781 [('a', 'all', None, _('select all unresolved files')),
4779 ('l', 'list', None, _('list state of files needing merge')),
4782 ('l', 'list', None, _('list state of files needing merge')),
4780 ('m', 'mark', None, _('mark files as resolved')),
4783 ('m', 'mark', None, _('mark files as resolved')),
4781 ('u', 'unmark', None, _('mark files as unresolved')),
4784 ('u', 'unmark', None, _('mark files as unresolved')),
4782 ('n', 'no-status', None, _('hide status prefix')),
4785 ('n', 'no-status', None, _('hide status prefix')),
4783 ('', 're-merge', None, _('re-merge files'))]
4786 ('', 're-merge', None, _('re-merge files'))]
4784 + mergetoolopts + walkopts + formatteropts,
4787 + mergetoolopts + walkopts + formatteropts,
4785 _('[OPTION]... [FILE]...'),
4788 _('[OPTION]... [FILE]...'),
4786 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4789 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4787 inferrepo=True)
4790 inferrepo=True)
4788 def resolve(ui, repo, *pats, **opts):
4791 def resolve(ui, repo, *pats, **opts):
4789 """redo merges or set/view the merge status of files
4792 """redo merges or set/view the merge status of files
4790
4793
4791 Merges with unresolved conflicts are often the result of
4794 Merges with unresolved conflicts are often the result of
4792 non-interactive merging using the ``internal:merge`` configuration
4795 non-interactive merging using the ``internal:merge`` configuration
4793 setting, or a command-line merge tool like ``diff3``. The resolve
4796 setting, or a command-line merge tool like ``diff3``. The resolve
4794 command is used to manage the files involved in a merge, after
4797 command is used to manage the files involved in a merge, after
4795 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4798 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4796 working directory must have two parents). See :hg:`help
4799 working directory must have two parents). See :hg:`help
4797 merge-tools` for information on configuring merge tools.
4800 merge-tools` for information on configuring merge tools.
4798
4801
4799 The resolve command can be used in the following ways:
4802 The resolve command can be used in the following ways:
4800
4803
4801 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4804 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4802 the specified files, discarding any previous merge attempts. Re-merging
4805 the specified files, discarding any previous merge attempts. Re-merging
4803 is not performed for files already marked as resolved. Use ``--all/-a``
4806 is not performed for files already marked as resolved. Use ``--all/-a``
4804 to select all unresolved files. ``--tool`` can be used to specify
4807 to select all unresolved files. ``--tool`` can be used to specify
4805 the merge tool used for the given files. It overrides the HGMERGE
4808 the merge tool used for the given files. It overrides the HGMERGE
4806 environment variable and your configuration files. Previous file
4809 environment variable and your configuration files. Previous file
4807 contents are saved with a ``.orig`` suffix.
4810 contents are saved with a ``.orig`` suffix.
4808
4811
4809 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4812 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4810 (e.g. after having manually fixed-up the files). The default is
4813 (e.g. after having manually fixed-up the files). The default is
4811 to mark all unresolved files.
4814 to mark all unresolved files.
4812
4815
4813 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4816 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4814 default is to mark all resolved files.
4817 default is to mark all resolved files.
4815
4818
4816 - :hg:`resolve -l`: list files which had or still have conflicts.
4819 - :hg:`resolve -l`: list files which had or still have conflicts.
4817 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4820 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4818 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4821 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4819 the list. See :hg:`help filesets` for details.
4822 the list. See :hg:`help filesets` for details.
4820
4823
4821 .. note::
4824 .. note::
4822
4825
4823 Mercurial will not let you commit files with unresolved merge
4826 Mercurial will not let you commit files with unresolved merge
4824 conflicts. You must use :hg:`resolve -m ...` before you can
4827 conflicts. You must use :hg:`resolve -m ...` before you can
4825 commit after a conflicting merge.
4828 commit after a conflicting merge.
4826
4829
4827 .. container:: verbose
4830 .. container:: verbose
4828
4831
4829 Template:
4832 Template:
4830
4833
4831 The following keywords are supported in addition to the common template
4834 The following keywords are supported in addition to the common template
4832 keywords and functions. See also :hg:`help templates`.
4835 keywords and functions. See also :hg:`help templates`.
4833
4836
4834 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4837 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4835 :path: String. Repository-absolute path of the file.
4838 :path: String. Repository-absolute path of the file.
4836
4839
4837 Returns 0 on success, 1 if any files fail a resolve attempt.
4840 Returns 0 on success, 1 if any files fail a resolve attempt.
4838 """
4841 """
4839
4842
4840 opts = pycompat.byteskwargs(opts)
4843 opts = pycompat.byteskwargs(opts)
4841 confirm = ui.configbool('commands', 'resolve.confirm')
4844 confirm = ui.configbool('commands', 'resolve.confirm')
4842 flaglist = 'all mark unmark list no_status re_merge'.split()
4845 flaglist = 'all mark unmark list no_status re_merge'.split()
4843 all, mark, unmark, show, nostatus, remerge = [
4846 all, mark, unmark, show, nostatus, remerge = [
4844 opts.get(o) for o in flaglist]
4847 opts.get(o) for o in flaglist]
4845
4848
4846 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4849 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4847 if actioncount > 1:
4850 if actioncount > 1:
4848 raise error.Abort(_("too many actions specified"))
4851 raise error.Abort(_("too many actions specified"))
4849 elif (actioncount == 0
4852 elif (actioncount == 0
4850 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4853 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4851 hint = _('use --mark, --unmark, --list or --re-merge')
4854 hint = _('use --mark, --unmark, --list or --re-merge')
4852 raise error.Abort(_('no action specified'), hint=hint)
4855 raise error.Abort(_('no action specified'), hint=hint)
4853 if pats and all:
4856 if pats and all:
4854 raise error.Abort(_("can't specify --all and patterns"))
4857 raise error.Abort(_("can't specify --all and patterns"))
4855 if not (all or pats or show or mark or unmark):
4858 if not (all or pats or show or mark or unmark):
4856 raise error.Abort(_('no files or directories specified'),
4859 raise error.Abort(_('no files or directories specified'),
4857 hint=('use --all to re-merge all unresolved files'))
4860 hint=('use --all to re-merge all unresolved files'))
4858
4861
4859 if confirm:
4862 if confirm:
4860 if all:
4863 if all:
4861 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4864 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4862 b'$$ &Yes $$ &No')):
4865 b'$$ &Yes $$ &No')):
4863 raise error.Abort(_('user quit'))
4866 raise error.Abort(_('user quit'))
4864 if mark and not pats:
4867 if mark and not pats:
4865 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4868 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4866 b'$$ &Yes $$ &No')):
4869 b'$$ &Yes $$ &No')):
4867 raise error.Abort(_('user quit'))
4870 raise error.Abort(_('user quit'))
4868 if unmark and not pats:
4871 if unmark and not pats:
4869 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4872 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4870 b'$$ &Yes $$ &No')):
4873 b'$$ &Yes $$ &No')):
4871 raise error.Abort(_('user quit'))
4874 raise error.Abort(_('user quit'))
4872
4875
4873 uipathfn = scmutil.getuipathfn(repo)
4876 uipathfn = scmutil.getuipathfn(repo)
4874
4877
4875 if show:
4878 if show:
4876 ui.pager('resolve')
4879 ui.pager('resolve')
4877 fm = ui.formatter('resolve', opts)
4880 fm = ui.formatter('resolve', opts)
4878 ms = mergemod.mergestate.read(repo)
4881 ms = mergemod.mergestate.read(repo)
4879 wctx = repo[None]
4882 wctx = repo[None]
4880 m = scmutil.match(wctx, pats, opts)
4883 m = scmutil.match(wctx, pats, opts)
4881
4884
4882 # Labels and keys based on merge state. Unresolved path conflicts show
4885 # Labels and keys based on merge state. Unresolved path conflicts show
4883 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4886 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4884 # resolved conflicts.
4887 # resolved conflicts.
4885 mergestateinfo = {
4888 mergestateinfo = {
4886 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4889 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4887 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4890 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4888 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4891 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4889 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4892 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4890 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4893 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4891 'D'),
4894 'D'),
4892 }
4895 }
4893
4896
4894 for f in ms:
4897 for f in ms:
4895 if not m(f):
4898 if not m(f):
4896 continue
4899 continue
4897
4900
4898 label, key = mergestateinfo[ms[f]]
4901 label, key = mergestateinfo[ms[f]]
4899 fm.startitem()
4902 fm.startitem()
4900 fm.context(ctx=wctx)
4903 fm.context(ctx=wctx)
4901 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4904 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4902 fm.data(path=f)
4905 fm.data(path=f)
4903 fm.plain('%s\n' % uipathfn(f), label=label)
4906 fm.plain('%s\n' % uipathfn(f), label=label)
4904 fm.end()
4907 fm.end()
4905 return 0
4908 return 0
4906
4909
4907 with repo.wlock():
4910 with repo.wlock():
4908 ms = mergemod.mergestate.read(repo)
4911 ms = mergemod.mergestate.read(repo)
4909
4912
4910 if not (ms.active() or repo.dirstate.p2() != nullid):
4913 if not (ms.active() or repo.dirstate.p2() != nullid):
4911 raise error.Abort(
4914 raise error.Abort(
4912 _('resolve command not applicable when not merging'))
4915 _('resolve command not applicable when not merging'))
4913
4916
4914 wctx = repo[None]
4917 wctx = repo[None]
4915
4918
4916 if (ms.mergedriver
4919 if (ms.mergedriver
4917 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4920 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4918 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4921 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4919 ms.commit()
4922 ms.commit()
4920 # allow mark and unmark to go through
4923 # allow mark and unmark to go through
4921 if not mark and not unmark and not proceed:
4924 if not mark and not unmark and not proceed:
4922 return 1
4925 return 1
4923
4926
4924 m = scmutil.match(wctx, pats, opts)
4927 m = scmutil.match(wctx, pats, opts)
4925 ret = 0
4928 ret = 0
4926 didwork = False
4929 didwork = False
4927 runconclude = False
4930 runconclude = False
4928
4931
4929 tocomplete = []
4932 tocomplete = []
4930 hasconflictmarkers = []
4933 hasconflictmarkers = []
4931 if mark:
4934 if mark:
4932 markcheck = ui.config('commands', 'resolve.mark-check')
4935 markcheck = ui.config('commands', 'resolve.mark-check')
4933 if markcheck not in ['warn', 'abort']:
4936 if markcheck not in ['warn', 'abort']:
4934 # Treat all invalid / unrecognized values as 'none'.
4937 # Treat all invalid / unrecognized values as 'none'.
4935 markcheck = False
4938 markcheck = False
4936 for f in ms:
4939 for f in ms:
4937 if not m(f):
4940 if not m(f):
4938 continue
4941 continue
4939
4942
4940 didwork = True
4943 didwork = True
4941
4944
4942 # don't let driver-resolved files be marked, and run the conclude
4945 # don't let driver-resolved files be marked, and run the conclude
4943 # step if asked to resolve
4946 # step if asked to resolve
4944 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4947 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4945 exact = m.exact(f)
4948 exact = m.exact(f)
4946 if mark:
4949 if mark:
4947 if exact:
4950 if exact:
4948 ui.warn(_('not marking %s as it is driver-resolved\n')
4951 ui.warn(_('not marking %s as it is driver-resolved\n')
4949 % uipathfn(f))
4952 % uipathfn(f))
4950 elif unmark:
4953 elif unmark:
4951 if exact:
4954 if exact:
4952 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4955 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4953 % uipathfn(f))
4956 % uipathfn(f))
4954 else:
4957 else:
4955 runconclude = True
4958 runconclude = True
4956 continue
4959 continue
4957
4960
4958 # path conflicts must be resolved manually
4961 # path conflicts must be resolved manually
4959 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4962 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4960 mergemod.MERGE_RECORD_RESOLVED_PATH):
4963 mergemod.MERGE_RECORD_RESOLVED_PATH):
4961 if mark:
4964 if mark:
4962 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4965 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4963 elif unmark:
4966 elif unmark:
4964 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4967 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4965 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4968 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4966 ui.warn(_('%s: path conflict must be resolved manually\n')
4969 ui.warn(_('%s: path conflict must be resolved manually\n')
4967 % uipathfn(f))
4970 % uipathfn(f))
4968 continue
4971 continue
4969
4972
4970 if mark:
4973 if mark:
4971 if markcheck:
4974 if markcheck:
4972 fdata = repo.wvfs.tryread(f)
4975 fdata = repo.wvfs.tryread(f)
4973 if (filemerge.hasconflictmarkers(fdata) and
4976 if (filemerge.hasconflictmarkers(fdata) and
4974 ms[f] != mergemod.MERGE_RECORD_RESOLVED):
4977 ms[f] != mergemod.MERGE_RECORD_RESOLVED):
4975 hasconflictmarkers.append(f)
4978 hasconflictmarkers.append(f)
4976 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4979 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4977 elif unmark:
4980 elif unmark:
4978 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4981 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4979 else:
4982 else:
4980 # backup pre-resolve (merge uses .orig for its own purposes)
4983 # backup pre-resolve (merge uses .orig for its own purposes)
4981 a = repo.wjoin(f)
4984 a = repo.wjoin(f)
4982 try:
4985 try:
4983 util.copyfile(a, a + ".resolve")
4986 util.copyfile(a, a + ".resolve")
4984 except (IOError, OSError) as inst:
4987 except (IOError, OSError) as inst:
4985 if inst.errno != errno.ENOENT:
4988 if inst.errno != errno.ENOENT:
4986 raise
4989 raise
4987
4990
4988 try:
4991 try:
4989 # preresolve file
4992 # preresolve file
4990 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4993 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4991 with ui.configoverride(overrides, 'resolve'):
4994 with ui.configoverride(overrides, 'resolve'):
4992 complete, r = ms.preresolve(f, wctx)
4995 complete, r = ms.preresolve(f, wctx)
4993 if not complete:
4996 if not complete:
4994 tocomplete.append(f)
4997 tocomplete.append(f)
4995 elif r:
4998 elif r:
4996 ret = 1
4999 ret = 1
4997 finally:
5000 finally:
4998 ms.commit()
5001 ms.commit()
4999
5002
5000 # replace filemerge's .orig file with our resolve file, but only
5003 # replace filemerge's .orig file with our resolve file, but only
5001 # for merges that are complete
5004 # for merges that are complete
5002 if complete:
5005 if complete:
5003 try:
5006 try:
5004 util.rename(a + ".resolve",
5007 util.rename(a + ".resolve",
5005 scmutil.backuppath(ui, repo, f))
5008 scmutil.backuppath(ui, repo, f))
5006 except OSError as inst:
5009 except OSError as inst:
5007 if inst.errno != errno.ENOENT:
5010 if inst.errno != errno.ENOENT:
5008 raise
5011 raise
5009
5012
5010 if hasconflictmarkers:
5013 if hasconflictmarkers:
5011 ui.warn(_('warning: the following files still have conflict '
5014 ui.warn(_('warning: the following files still have conflict '
5012 'markers:\n') + ''.join(' ' + uipathfn(f) + '\n'
5015 'markers:\n') + ''.join(' ' + uipathfn(f) + '\n'
5013 for f in hasconflictmarkers))
5016 for f in hasconflictmarkers))
5014 if markcheck == 'abort' and not all and not pats:
5017 if markcheck == 'abort' and not all and not pats:
5015 raise error.Abort(_('conflict markers detected'),
5018 raise error.Abort(_('conflict markers detected'),
5016 hint=_('use --all to mark anyway'))
5019 hint=_('use --all to mark anyway'))
5017
5020
5018 for f in tocomplete:
5021 for f in tocomplete:
5019 try:
5022 try:
5020 # resolve file
5023 # resolve file
5021 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
5024 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
5022 with ui.configoverride(overrides, 'resolve'):
5025 with ui.configoverride(overrides, 'resolve'):
5023 r = ms.resolve(f, wctx)
5026 r = ms.resolve(f, wctx)
5024 if r:
5027 if r:
5025 ret = 1
5028 ret = 1
5026 finally:
5029 finally:
5027 ms.commit()
5030 ms.commit()
5028
5031
5029 # replace filemerge's .orig file with our resolve file
5032 # replace filemerge's .orig file with our resolve file
5030 a = repo.wjoin(f)
5033 a = repo.wjoin(f)
5031 try:
5034 try:
5032 util.rename(a + ".resolve", scmutil.backuppath(ui, repo, f))
5035 util.rename(a + ".resolve", scmutil.backuppath(ui, repo, f))
5033 except OSError as inst:
5036 except OSError as inst:
5034 if inst.errno != errno.ENOENT:
5037 if inst.errno != errno.ENOENT:
5035 raise
5038 raise
5036
5039
5037 ms.commit()
5040 ms.commit()
5038 ms.recordactions()
5041 ms.recordactions()
5039
5042
5040 if not didwork and pats:
5043 if not didwork and pats:
5041 hint = None
5044 hint = None
5042 if not any([p for p in pats if p.find(':') >= 0]):
5045 if not any([p for p in pats if p.find(':') >= 0]):
5043 pats = ['path:%s' % p for p in pats]
5046 pats = ['path:%s' % p for p in pats]
5044 m = scmutil.match(wctx, pats, opts)
5047 m = scmutil.match(wctx, pats, opts)
5045 for f in ms:
5048 for f in ms:
5046 if not m(f):
5049 if not m(f):
5047 continue
5050 continue
5048 def flag(o):
5051 def flag(o):
5049 if o == 're_merge':
5052 if o == 're_merge':
5050 return '--re-merge '
5053 return '--re-merge '
5051 return '-%s ' % o[0:1]
5054 return '-%s ' % o[0:1]
5052 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
5055 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
5053 hint = _("(try: hg resolve %s%s)\n") % (
5056 hint = _("(try: hg resolve %s%s)\n") % (
5054 flags,
5057 flags,
5055 ' '.join(pats))
5058 ' '.join(pats))
5056 break
5059 break
5057 ui.warn(_("arguments do not match paths that need resolving\n"))
5060 ui.warn(_("arguments do not match paths that need resolving\n"))
5058 if hint:
5061 if hint:
5059 ui.warn(hint)
5062 ui.warn(hint)
5060 elif ms.mergedriver and ms.mdstate() != 's':
5063 elif ms.mergedriver and ms.mdstate() != 's':
5061 # run conclude step when either a driver-resolved file is requested
5064 # run conclude step when either a driver-resolved file is requested
5062 # or there are no driver-resolved files
5065 # or there are no driver-resolved files
5063 # we can't use 'ret' to determine whether any files are unresolved
5066 # we can't use 'ret' to determine whether any files are unresolved
5064 # because we might not have tried to resolve some
5067 # because we might not have tried to resolve some
5065 if ((runconclude or not list(ms.driverresolved()))
5068 if ((runconclude or not list(ms.driverresolved()))
5066 and not list(ms.unresolved())):
5069 and not list(ms.unresolved())):
5067 proceed = mergemod.driverconclude(repo, ms, wctx)
5070 proceed = mergemod.driverconclude(repo, ms, wctx)
5068 ms.commit()
5071 ms.commit()
5069 if not proceed:
5072 if not proceed:
5070 return 1
5073 return 1
5071
5074
5072 # Nudge users into finishing an unfinished operation
5075 # Nudge users into finishing an unfinished operation
5073 unresolvedf = list(ms.unresolved())
5076 unresolvedf = list(ms.unresolved())
5074 driverresolvedf = list(ms.driverresolved())
5077 driverresolvedf = list(ms.driverresolved())
5075 if not unresolvedf and not driverresolvedf:
5078 if not unresolvedf and not driverresolvedf:
5076 ui.status(_('(no more unresolved files)\n'))
5079 ui.status(_('(no more unresolved files)\n'))
5077 cmdutil.checkafterresolved(repo)
5080 cmdutil.checkafterresolved(repo)
5078 elif not unresolvedf:
5081 elif not unresolvedf:
5079 ui.status(_('(no more unresolved files -- '
5082 ui.status(_('(no more unresolved files -- '
5080 'run "hg resolve --all" to conclude)\n'))
5083 'run "hg resolve --all" to conclude)\n'))
5081
5084
5082 return ret
5085 return ret
5083
5086
5084 @command('revert',
5087 @command('revert',
5085 [('a', 'all', None, _('revert all changes when no arguments given')),
5088 [('a', 'all', None, _('revert all changes when no arguments given')),
5086 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5089 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5087 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5090 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5088 ('C', 'no-backup', None, _('do not save backup copies of files')),
5091 ('C', 'no-backup', None, _('do not save backup copies of files')),
5089 ('i', 'interactive', None, _('interactively select the changes')),
5092 ('i', 'interactive', None, _('interactively select the changes')),
5090 ] + walkopts + dryrunopts,
5093 ] + walkopts + dryrunopts,
5091 _('[OPTION]... [-r REV] [NAME]...'),
5094 _('[OPTION]... [-r REV] [NAME]...'),
5092 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5095 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5093 def revert(ui, repo, *pats, **opts):
5096 def revert(ui, repo, *pats, **opts):
5094 """restore files to their checkout state
5097 """restore files to their checkout state
5095
5098
5096 .. note::
5099 .. note::
5097
5100
5098 To check out earlier revisions, you should use :hg:`update REV`.
5101 To check out earlier revisions, you should use :hg:`update REV`.
5099 To cancel an uncommitted merge (and lose your changes),
5102 To cancel an uncommitted merge (and lose your changes),
5100 use :hg:`merge --abort`.
5103 use :hg:`merge --abort`.
5101
5104
5102 With no revision specified, revert the specified files or directories
5105 With no revision specified, revert the specified files or directories
5103 to the contents they had in the parent of the working directory.
5106 to the contents they had in the parent of the working directory.
5104 This restores the contents of files to an unmodified
5107 This restores the contents of files to an unmodified
5105 state and unschedules adds, removes, copies, and renames. If the
5108 state and unschedules adds, removes, copies, and renames. If the
5106 working directory has two parents, you must explicitly specify a
5109 working directory has two parents, you must explicitly specify a
5107 revision.
5110 revision.
5108
5111
5109 Using the -r/--rev or -d/--date options, revert the given files or
5112 Using the -r/--rev or -d/--date options, revert the given files or
5110 directories to their states as of a specific revision. Because
5113 directories to their states as of a specific revision. Because
5111 revert does not change the working directory parents, this will
5114 revert does not change the working directory parents, this will
5112 cause these files to appear modified. This can be helpful to "back
5115 cause these files to appear modified. This can be helpful to "back
5113 out" some or all of an earlier change. See :hg:`backout` for a
5116 out" some or all of an earlier change. See :hg:`backout` for a
5114 related method.
5117 related method.
5115
5118
5116 Modified files are saved with a .orig suffix before reverting.
5119 Modified files are saved with a .orig suffix before reverting.
5117 To disable these backups, use --no-backup. It is possible to store
5120 To disable these backups, use --no-backup. It is possible to store
5118 the backup files in a custom directory relative to the root of the
5121 the backup files in a custom directory relative to the root of the
5119 repository by setting the ``ui.origbackuppath`` configuration
5122 repository by setting the ``ui.origbackuppath`` configuration
5120 option.
5123 option.
5121
5124
5122 See :hg:`help dates` for a list of formats valid for -d/--date.
5125 See :hg:`help dates` for a list of formats valid for -d/--date.
5123
5126
5124 See :hg:`help backout` for a way to reverse the effect of an
5127 See :hg:`help backout` for a way to reverse the effect of an
5125 earlier changeset.
5128 earlier changeset.
5126
5129
5127 Returns 0 on success.
5130 Returns 0 on success.
5128 """
5131 """
5129
5132
5130 opts = pycompat.byteskwargs(opts)
5133 opts = pycompat.byteskwargs(opts)
5131 if opts.get("date"):
5134 if opts.get("date"):
5132 if opts.get("rev"):
5135 if opts.get("rev"):
5133 raise error.Abort(_("you can't specify a revision and a date"))
5136 raise error.Abort(_("you can't specify a revision and a date"))
5134 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5137 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5135
5138
5136 parent, p2 = repo.dirstate.parents()
5139 parent, p2 = repo.dirstate.parents()
5137 if not opts.get('rev') and p2 != nullid:
5140 if not opts.get('rev') and p2 != nullid:
5138 # revert after merge is a trap for new users (issue2915)
5141 # revert after merge is a trap for new users (issue2915)
5139 raise error.Abort(_('uncommitted merge with no revision specified'),
5142 raise error.Abort(_('uncommitted merge with no revision specified'),
5140 hint=_("use 'hg update' or see 'hg help revert'"))
5143 hint=_("use 'hg update' or see 'hg help revert'"))
5141
5144
5142 rev = opts.get('rev')
5145 rev = opts.get('rev')
5143 if rev:
5146 if rev:
5144 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5147 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5145 ctx = scmutil.revsingle(repo, rev)
5148 ctx = scmutil.revsingle(repo, rev)
5146
5149
5147 if (not (pats or opts.get('include') or opts.get('exclude') or
5150 if (not (pats or opts.get('include') or opts.get('exclude') or
5148 opts.get('all') or opts.get('interactive'))):
5151 opts.get('all') or opts.get('interactive'))):
5149 msg = _("no files or directories specified")
5152 msg = _("no files or directories specified")
5150 if p2 != nullid:
5153 if p2 != nullid:
5151 hint = _("uncommitted merge, use --all to discard all changes,"
5154 hint = _("uncommitted merge, use --all to discard all changes,"
5152 " or 'hg update -C .' to abort the merge")
5155 " or 'hg update -C .' to abort the merge")
5153 raise error.Abort(msg, hint=hint)
5156 raise error.Abort(msg, hint=hint)
5154 dirty = any(repo.status())
5157 dirty = any(repo.status())
5155 node = ctx.node()
5158 node = ctx.node()
5156 if node != parent:
5159 if node != parent:
5157 if dirty:
5160 if dirty:
5158 hint = _("uncommitted changes, use --all to discard all"
5161 hint = _("uncommitted changes, use --all to discard all"
5159 " changes, or 'hg update %d' to update") % ctx.rev()
5162 " changes, or 'hg update %d' to update") % ctx.rev()
5160 else:
5163 else:
5161 hint = _("use --all to revert all files,"
5164 hint = _("use --all to revert all files,"
5162 " or 'hg update %d' to update") % ctx.rev()
5165 " or 'hg update %d' to update") % ctx.rev()
5163 elif dirty:
5166 elif dirty:
5164 hint = _("uncommitted changes, use --all to discard all changes")
5167 hint = _("uncommitted changes, use --all to discard all changes")
5165 else:
5168 else:
5166 hint = _("use --all to revert all files")
5169 hint = _("use --all to revert all files")
5167 raise error.Abort(msg, hint=hint)
5170 raise error.Abort(msg, hint=hint)
5168
5171
5169 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5172 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5170 **pycompat.strkwargs(opts))
5173 **pycompat.strkwargs(opts))
5171
5174
5172 @command(
5175 @command(
5173 'rollback',
5176 'rollback',
5174 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5177 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5175 helpcategory=command.CATEGORY_MAINTENANCE)
5178 helpcategory=command.CATEGORY_MAINTENANCE)
5176 def rollback(ui, repo, **opts):
5179 def rollback(ui, repo, **opts):
5177 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5180 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5178
5181
5179 Please use :hg:`commit --amend` instead of rollback to correct
5182 Please use :hg:`commit --amend` instead of rollback to correct
5180 mistakes in the last commit.
5183 mistakes in the last commit.
5181
5184
5182 This command should be used with care. There is only one level of
5185 This command should be used with care. There is only one level of
5183 rollback, and there is no way to undo a rollback. It will also
5186 rollback, and there is no way to undo a rollback. It will also
5184 restore the dirstate at the time of the last transaction, losing
5187 restore the dirstate at the time of the last transaction, losing
5185 any dirstate changes since that time. This command does not alter
5188 any dirstate changes since that time. This command does not alter
5186 the working directory.
5189 the working directory.
5187
5190
5188 Transactions are used to encapsulate the effects of all commands
5191 Transactions are used to encapsulate the effects of all commands
5189 that create new changesets or propagate existing changesets into a
5192 that create new changesets or propagate existing changesets into a
5190 repository.
5193 repository.
5191
5194
5192 .. container:: verbose
5195 .. container:: verbose
5193
5196
5194 For example, the following commands are transactional, and their
5197 For example, the following commands are transactional, and their
5195 effects can be rolled back:
5198 effects can be rolled back:
5196
5199
5197 - commit
5200 - commit
5198 - import
5201 - import
5199 - pull
5202 - pull
5200 - push (with this repository as the destination)
5203 - push (with this repository as the destination)
5201 - unbundle
5204 - unbundle
5202
5205
5203 To avoid permanent data loss, rollback will refuse to rollback a
5206 To avoid permanent data loss, rollback will refuse to rollback a
5204 commit transaction if it isn't checked out. Use --force to
5207 commit transaction if it isn't checked out. Use --force to
5205 override this protection.
5208 override this protection.
5206
5209
5207 The rollback command can be entirely disabled by setting the
5210 The rollback command can be entirely disabled by setting the
5208 ``ui.rollback`` configuration setting to false. If you're here
5211 ``ui.rollback`` configuration setting to false. If you're here
5209 because you want to use rollback and it's disabled, you can
5212 because you want to use rollback and it's disabled, you can
5210 re-enable the command by setting ``ui.rollback`` to true.
5213 re-enable the command by setting ``ui.rollback`` to true.
5211
5214
5212 This command is not intended for use on public repositories. Once
5215 This command is not intended for use on public repositories. Once
5213 changes are visible for pull by other users, rolling a transaction
5216 changes are visible for pull by other users, rolling a transaction
5214 back locally is ineffective (someone else may already have pulled
5217 back locally is ineffective (someone else may already have pulled
5215 the changes). Furthermore, a race is possible with readers of the
5218 the changes). Furthermore, a race is possible with readers of the
5216 repository; for example an in-progress pull from the repository
5219 repository; for example an in-progress pull from the repository
5217 may fail if a rollback is performed.
5220 may fail if a rollback is performed.
5218
5221
5219 Returns 0 on success, 1 if no rollback data is available.
5222 Returns 0 on success, 1 if no rollback data is available.
5220 """
5223 """
5221 if not ui.configbool('ui', 'rollback'):
5224 if not ui.configbool('ui', 'rollback'):
5222 raise error.Abort(_('rollback is disabled because it is unsafe'),
5225 raise error.Abort(_('rollback is disabled because it is unsafe'),
5223 hint=('see `hg help -v rollback` for information'))
5226 hint=('see `hg help -v rollback` for information'))
5224 return repo.rollback(dryrun=opts.get(r'dry_run'),
5227 return repo.rollback(dryrun=opts.get(r'dry_run'),
5225 force=opts.get(r'force'))
5228 force=opts.get(r'force'))
5226
5229
5227 @command(
5230 @command(
5228 'root', [] + formatteropts, intents={INTENT_READONLY},
5231 'root', [] + formatteropts, intents={INTENT_READONLY},
5229 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5232 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5230 def root(ui, repo, **opts):
5233 def root(ui, repo, **opts):
5231 """print the root (top) of the current working directory
5234 """print the root (top) of the current working directory
5232
5235
5233 Print the root directory of the current repository.
5236 Print the root directory of the current repository.
5234
5237
5235 .. container:: verbose
5238 .. container:: verbose
5236
5239
5237 Template:
5240 Template:
5238
5241
5239 The following keywords are supported in addition to the common template
5242 The following keywords are supported in addition to the common template
5240 keywords and functions. See also :hg:`help templates`.
5243 keywords and functions. See also :hg:`help templates`.
5241
5244
5242 :hgpath: String. Path to the .hg directory.
5245 :hgpath: String. Path to the .hg directory.
5243 :storepath: String. Path to the directory holding versioned data.
5246 :storepath: String. Path to the directory holding versioned data.
5244
5247
5245 Returns 0 on success.
5248 Returns 0 on success.
5246 """
5249 """
5247 opts = pycompat.byteskwargs(opts)
5250 opts = pycompat.byteskwargs(opts)
5248 with ui.formatter('root', opts) as fm:
5251 with ui.formatter('root', opts) as fm:
5249 fm.startitem()
5252 fm.startitem()
5250 fm.write('reporoot', '%s\n', repo.root)
5253 fm.write('reporoot', '%s\n', repo.root)
5251 fm.data(hgpath=repo.path, storepath=repo.spath)
5254 fm.data(hgpath=repo.path, storepath=repo.spath)
5252
5255
5253 @command('serve',
5256 @command('serve',
5254 [('A', 'accesslog', '', _('name of access log file to write to'),
5257 [('A', 'accesslog', '', _('name of access log file to write to'),
5255 _('FILE')),
5258 _('FILE')),
5256 ('d', 'daemon', None, _('run server in background')),
5259 ('d', 'daemon', None, _('run server in background')),
5257 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5260 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5258 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5261 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5259 # use string type, then we can check if something was passed
5262 # use string type, then we can check if something was passed
5260 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5263 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5261 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5264 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5262 _('ADDR')),
5265 _('ADDR')),
5263 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5266 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5264 _('PREFIX')),
5267 _('PREFIX')),
5265 ('n', 'name', '',
5268 ('n', 'name', '',
5266 _('name to show in web pages (default: working directory)'), _('NAME')),
5269 _('name to show in web pages (default: working directory)'), _('NAME')),
5267 ('', 'web-conf', '',
5270 ('', 'web-conf', '',
5268 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5271 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5269 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5272 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5270 _('FILE')),
5273 _('FILE')),
5271 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5274 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5272 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5275 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5273 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5276 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5274 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5277 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5275 ('', 'style', '', _('template style to use'), _('STYLE')),
5278 ('', 'style', '', _('template style to use'), _('STYLE')),
5276 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5279 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5277 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5280 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5278 ('', 'print-url', None, _('start and print only the URL'))]
5281 ('', 'print-url', None, _('start and print only the URL'))]
5279 + subrepoopts,
5282 + subrepoopts,
5280 _('[OPTION]...'),
5283 _('[OPTION]...'),
5281 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5284 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5282 helpbasic=True, optionalrepo=True)
5285 helpbasic=True, optionalrepo=True)
5283 def serve(ui, repo, **opts):
5286 def serve(ui, repo, **opts):
5284 """start stand-alone webserver
5287 """start stand-alone webserver
5285
5288
5286 Start a local HTTP repository browser and pull server. You can use
5289 Start a local HTTP repository browser and pull server. You can use
5287 this for ad-hoc sharing and browsing of repositories. It is
5290 this for ad-hoc sharing and browsing of repositories. It is
5288 recommended to use a real web server to serve a repository for
5291 recommended to use a real web server to serve a repository for
5289 longer periods of time.
5292 longer periods of time.
5290
5293
5291 Please note that the server does not implement access control.
5294 Please note that the server does not implement access control.
5292 This means that, by default, anybody can read from the server and
5295 This means that, by default, anybody can read from the server and
5293 nobody can write to it by default. Set the ``web.allow-push``
5296 nobody can write to it by default. Set the ``web.allow-push``
5294 option to ``*`` to allow everybody to push to the server. You
5297 option to ``*`` to allow everybody to push to the server. You
5295 should use a real web server if you need to authenticate users.
5298 should use a real web server if you need to authenticate users.
5296
5299
5297 By default, the server logs accesses to stdout and errors to
5300 By default, the server logs accesses to stdout and errors to
5298 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5301 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5299 files.
5302 files.
5300
5303
5301 To have the server choose a free port number to listen on, specify
5304 To have the server choose a free port number to listen on, specify
5302 a port number of 0; in this case, the server will print the port
5305 a port number of 0; in this case, the server will print the port
5303 number it uses.
5306 number it uses.
5304
5307
5305 Returns 0 on success.
5308 Returns 0 on success.
5306 """
5309 """
5307
5310
5308 opts = pycompat.byteskwargs(opts)
5311 opts = pycompat.byteskwargs(opts)
5309 if opts["stdio"] and opts["cmdserver"]:
5312 if opts["stdio"] and opts["cmdserver"]:
5310 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5313 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5311 if opts["print_url"] and ui.verbose:
5314 if opts["print_url"] and ui.verbose:
5312 raise error.Abort(_("cannot use --print-url with --verbose"))
5315 raise error.Abort(_("cannot use --print-url with --verbose"))
5313
5316
5314 if opts["stdio"]:
5317 if opts["stdio"]:
5315 if repo is None:
5318 if repo is None:
5316 raise error.RepoError(_("there is no Mercurial repository here"
5319 raise error.RepoError(_("there is no Mercurial repository here"
5317 " (.hg not found)"))
5320 " (.hg not found)"))
5318 s = wireprotoserver.sshserver(ui, repo)
5321 s = wireprotoserver.sshserver(ui, repo)
5319 s.serve_forever()
5322 s.serve_forever()
5320
5323
5321 service = server.createservice(ui, repo, opts)
5324 service = server.createservice(ui, repo, opts)
5322 return server.runservice(opts, initfn=service.init, runfn=service.run)
5325 return server.runservice(opts, initfn=service.init, runfn=service.run)
5323
5326
5324 _NOTTERSE = 'nothing'
5327 _NOTTERSE = 'nothing'
5325
5328
5326 @command('status|st',
5329 @command('status|st',
5327 [('A', 'all', None, _('show status of all files')),
5330 [('A', 'all', None, _('show status of all files')),
5328 ('m', 'modified', None, _('show only modified files')),
5331 ('m', 'modified', None, _('show only modified files')),
5329 ('a', 'added', None, _('show only added files')),
5332 ('a', 'added', None, _('show only added files')),
5330 ('r', 'removed', None, _('show only removed files')),
5333 ('r', 'removed', None, _('show only removed files')),
5331 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5334 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5332 ('c', 'clean', None, _('show only files without changes')),
5335 ('c', 'clean', None, _('show only files without changes')),
5333 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5336 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5334 ('i', 'ignored', None, _('show only ignored files')),
5337 ('i', 'ignored', None, _('show only ignored files')),
5335 ('n', 'no-status', None, _('hide status prefix')),
5338 ('n', 'no-status', None, _('hide status prefix')),
5336 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5339 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5337 ('C', 'copies', None, _('show source of copied files')),
5340 ('C', 'copies', None, _('show source of copied files')),
5338 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5341 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5339 ('', 'rev', [], _('show difference from revision'), _('REV')),
5342 ('', 'rev', [], _('show difference from revision'), _('REV')),
5340 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5343 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5341 ] + walkopts + subrepoopts + formatteropts,
5344 ] + walkopts + subrepoopts + formatteropts,
5342 _('[OPTION]... [FILE]...'),
5345 _('[OPTION]... [FILE]...'),
5343 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5346 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5344 helpbasic=True, inferrepo=True,
5347 helpbasic=True, inferrepo=True,
5345 intents={INTENT_READONLY})
5348 intents={INTENT_READONLY})
5346 def status(ui, repo, *pats, **opts):
5349 def status(ui, repo, *pats, **opts):
5347 """show changed files in the working directory
5350 """show changed files in the working directory
5348
5351
5349 Show status of files in the repository. If names are given, only
5352 Show status of files in the repository. If names are given, only
5350 files that match are shown. Files that are clean or ignored or
5353 files that match are shown. Files that are clean or ignored or
5351 the source of a copy/move operation, are not listed unless
5354 the source of a copy/move operation, are not listed unless
5352 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5355 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5353 Unless options described with "show only ..." are given, the
5356 Unless options described with "show only ..." are given, the
5354 options -mardu are used.
5357 options -mardu are used.
5355
5358
5356 Option -q/--quiet hides untracked (unknown and ignored) files
5359 Option -q/--quiet hides untracked (unknown and ignored) files
5357 unless explicitly requested with -u/--unknown or -i/--ignored.
5360 unless explicitly requested with -u/--unknown or -i/--ignored.
5358
5361
5359 .. note::
5362 .. note::
5360
5363
5361 :hg:`status` may appear to disagree with diff if permissions have
5364 :hg:`status` may appear to disagree with diff if permissions have
5362 changed or a merge has occurred. The standard diff format does
5365 changed or a merge has occurred. The standard diff format does
5363 not report permission changes and diff only reports changes
5366 not report permission changes and diff only reports changes
5364 relative to one merge parent.
5367 relative to one merge parent.
5365
5368
5366 If one revision is given, it is used as the base revision.
5369 If one revision is given, it is used as the base revision.
5367 If two revisions are given, the differences between them are
5370 If two revisions are given, the differences between them are
5368 shown. The --change option can also be used as a shortcut to list
5371 shown. The --change option can also be used as a shortcut to list
5369 the changed files of a revision from its first parent.
5372 the changed files of a revision from its first parent.
5370
5373
5371 The codes used to show the status of files are::
5374 The codes used to show the status of files are::
5372
5375
5373 M = modified
5376 M = modified
5374 A = added
5377 A = added
5375 R = removed
5378 R = removed
5376 C = clean
5379 C = clean
5377 ! = missing (deleted by non-hg command, but still tracked)
5380 ! = missing (deleted by non-hg command, but still tracked)
5378 ? = not tracked
5381 ? = not tracked
5379 I = ignored
5382 I = ignored
5380 = origin of the previous file (with --copies)
5383 = origin of the previous file (with --copies)
5381
5384
5382 .. container:: verbose
5385 .. container:: verbose
5383
5386
5384 The -t/--terse option abbreviates the output by showing only the directory
5387 The -t/--terse option abbreviates the output by showing only the directory
5385 name if all the files in it share the same status. The option takes an
5388 name if all the files in it share the same status. The option takes an
5386 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5389 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5387 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5390 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5388 for 'ignored' and 'c' for clean.
5391 for 'ignored' and 'c' for clean.
5389
5392
5390 It abbreviates only those statuses which are passed. Note that clean and
5393 It abbreviates only those statuses which are passed. Note that clean and
5391 ignored files are not displayed with '--terse ic' unless the -c/--clean
5394 ignored files are not displayed with '--terse ic' unless the -c/--clean
5392 and -i/--ignored options are also used.
5395 and -i/--ignored options are also used.
5393
5396
5394 The -v/--verbose option shows information when the repository is in an
5397 The -v/--verbose option shows information when the repository is in an
5395 unfinished merge, shelve, rebase state etc. You can have this behavior
5398 unfinished merge, shelve, rebase state etc. You can have this behavior
5396 turned on by default by enabling the ``commands.status.verbose`` option.
5399 turned on by default by enabling the ``commands.status.verbose`` option.
5397
5400
5398 You can skip displaying some of these states by setting
5401 You can skip displaying some of these states by setting
5399 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5402 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5400 'histedit', 'merge', 'rebase', or 'unshelve'.
5403 'histedit', 'merge', 'rebase', or 'unshelve'.
5401
5404
5402 Template:
5405 Template:
5403
5406
5404 The following keywords are supported in addition to the common template
5407 The following keywords are supported in addition to the common template
5405 keywords and functions. See also :hg:`help templates`.
5408 keywords and functions. See also :hg:`help templates`.
5406
5409
5407 :path: String. Repository-absolute path of the file.
5410 :path: String. Repository-absolute path of the file.
5408 :source: String. Repository-absolute path of the file originated from.
5411 :source: String. Repository-absolute path of the file originated from.
5409 Available if ``--copies`` is specified.
5412 Available if ``--copies`` is specified.
5410 :status: String. Character denoting file's status.
5413 :status: String. Character denoting file's status.
5411
5414
5412 Examples:
5415 Examples:
5413
5416
5414 - show changes in the working directory relative to a
5417 - show changes in the working directory relative to a
5415 changeset::
5418 changeset::
5416
5419
5417 hg status --rev 9353
5420 hg status --rev 9353
5418
5421
5419 - show changes in the working directory relative to the
5422 - show changes in the working directory relative to the
5420 current directory (see :hg:`help patterns` for more information)::
5423 current directory (see :hg:`help patterns` for more information)::
5421
5424
5422 hg status re:
5425 hg status re:
5423
5426
5424 - show all changes including copies in an existing changeset::
5427 - show all changes including copies in an existing changeset::
5425
5428
5426 hg status --copies --change 9353
5429 hg status --copies --change 9353
5427
5430
5428 - get a NUL separated list of added files, suitable for xargs::
5431 - get a NUL separated list of added files, suitable for xargs::
5429
5432
5430 hg status -an0
5433 hg status -an0
5431
5434
5432 - show more information about the repository status, abbreviating
5435 - show more information about the repository status, abbreviating
5433 added, removed, modified, deleted, and untracked paths::
5436 added, removed, modified, deleted, and untracked paths::
5434
5437
5435 hg status -v -t mardu
5438 hg status -v -t mardu
5436
5439
5437 Returns 0 on success.
5440 Returns 0 on success.
5438
5441
5439 """
5442 """
5440
5443
5441 opts = pycompat.byteskwargs(opts)
5444 opts = pycompat.byteskwargs(opts)
5442 revs = opts.get('rev')
5445 revs = opts.get('rev')
5443 change = opts.get('change')
5446 change = opts.get('change')
5444 terse = opts.get('terse')
5447 terse = opts.get('terse')
5445 if terse is _NOTTERSE:
5448 if terse is _NOTTERSE:
5446 if revs:
5449 if revs:
5447 terse = ''
5450 terse = ''
5448 else:
5451 else:
5449 terse = ui.config('commands', 'status.terse')
5452 terse = ui.config('commands', 'status.terse')
5450
5453
5451 if revs and change:
5454 if revs and change:
5452 msg = _('cannot specify --rev and --change at the same time')
5455 msg = _('cannot specify --rev and --change at the same time')
5453 raise error.Abort(msg)
5456 raise error.Abort(msg)
5454 elif revs and terse:
5457 elif revs and terse:
5455 msg = _('cannot use --terse with --rev')
5458 msg = _('cannot use --terse with --rev')
5456 raise error.Abort(msg)
5459 raise error.Abort(msg)
5457 elif change:
5460 elif change:
5458 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5461 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5459 ctx2 = scmutil.revsingle(repo, change, None)
5462 ctx2 = scmutil.revsingle(repo, change, None)
5460 ctx1 = ctx2.p1()
5463 ctx1 = ctx2.p1()
5461 else:
5464 else:
5462 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5465 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5463 ctx1, ctx2 = scmutil.revpair(repo, revs)
5466 ctx1, ctx2 = scmutil.revpair(repo, revs)
5464
5467
5465 forcerelativevalue = None
5468 forcerelativevalue = None
5466 if ui.hasconfig('commands', 'status.relative'):
5469 if ui.hasconfig('commands', 'status.relative'):
5467 forcerelativevalue = ui.configbool('commands', 'status.relative')
5470 forcerelativevalue = ui.configbool('commands', 'status.relative')
5468 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats),
5471 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats),
5469 forcerelativevalue=forcerelativevalue)
5472 forcerelativevalue=forcerelativevalue)
5470
5473
5471 if opts.get('print0'):
5474 if opts.get('print0'):
5472 end = '\0'
5475 end = '\0'
5473 else:
5476 else:
5474 end = '\n'
5477 end = '\n'
5475 copy = {}
5478 copy = {}
5476 states = 'modified added removed deleted unknown ignored clean'.split()
5479 states = 'modified added removed deleted unknown ignored clean'.split()
5477 show = [k for k in states if opts.get(k)]
5480 show = [k for k in states if opts.get(k)]
5478 if opts.get('all'):
5481 if opts.get('all'):
5479 show += ui.quiet and (states[:4] + ['clean']) or states
5482 show += ui.quiet and (states[:4] + ['clean']) or states
5480
5483
5481 if not show:
5484 if not show:
5482 if ui.quiet:
5485 if ui.quiet:
5483 show = states[:4]
5486 show = states[:4]
5484 else:
5487 else:
5485 show = states[:5]
5488 show = states[:5]
5486
5489
5487 m = scmutil.match(ctx2, pats, opts)
5490 m = scmutil.match(ctx2, pats, opts)
5488 if terse:
5491 if terse:
5489 # we need to compute clean and unknown to terse
5492 # we need to compute clean and unknown to terse
5490 stat = repo.status(ctx1.node(), ctx2.node(), m,
5493 stat = repo.status(ctx1.node(), ctx2.node(), m,
5491 'ignored' in show or 'i' in terse,
5494 'ignored' in show or 'i' in terse,
5492 clean=True, unknown=True,
5495 clean=True, unknown=True,
5493 listsubrepos=opts.get('subrepos'))
5496 listsubrepos=opts.get('subrepos'))
5494
5497
5495 stat = cmdutil.tersedir(stat, terse)
5498 stat = cmdutil.tersedir(stat, terse)
5496 else:
5499 else:
5497 stat = repo.status(ctx1.node(), ctx2.node(), m,
5500 stat = repo.status(ctx1.node(), ctx2.node(), m,
5498 'ignored' in show, 'clean' in show,
5501 'ignored' in show, 'clean' in show,
5499 'unknown' in show, opts.get('subrepos'))
5502 'unknown' in show, opts.get('subrepos'))
5500
5503
5501 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5504 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5502
5505
5503 if (opts.get('all') or opts.get('copies')
5506 if (opts.get('all') or opts.get('copies')
5504 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5507 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5505 copy = copies.pathcopies(ctx1, ctx2, m)
5508 copy = copies.pathcopies(ctx1, ctx2, m)
5506
5509
5507 ui.pager('status')
5510 ui.pager('status')
5508 fm = ui.formatter('status', opts)
5511 fm = ui.formatter('status', opts)
5509 fmt = '%s' + end
5512 fmt = '%s' + end
5510 showchar = not opts.get('no_status')
5513 showchar = not opts.get('no_status')
5511
5514
5512 for state, char, files in changestates:
5515 for state, char, files in changestates:
5513 if state in show:
5516 if state in show:
5514 label = 'status.' + state
5517 label = 'status.' + state
5515 for f in files:
5518 for f in files:
5516 fm.startitem()
5519 fm.startitem()
5517 fm.context(ctx=ctx2)
5520 fm.context(ctx=ctx2)
5518 fm.data(path=f)
5521 fm.data(path=f)
5519 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5522 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5520 fm.plain(fmt % uipathfn(f), label=label)
5523 fm.plain(fmt % uipathfn(f), label=label)
5521 if f in copy:
5524 if f in copy:
5522 fm.data(source=copy[f])
5525 fm.data(source=copy[f])
5523 fm.plain((' %s' + end) % uipathfn(copy[f]),
5526 fm.plain((' %s' + end) % uipathfn(copy[f]),
5524 label='status.copied')
5527 label='status.copied')
5525
5528
5526 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5529 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5527 and not ui.plain()):
5530 and not ui.plain()):
5528 cmdutil.morestatus(repo, fm)
5531 cmdutil.morestatus(repo, fm)
5529 fm.end()
5532 fm.end()
5530
5533
5531 @command('summary|sum',
5534 @command('summary|sum',
5532 [('', 'remote', None, _('check for push and pull'))],
5535 [('', 'remote', None, _('check for push and pull'))],
5533 '[--remote]',
5536 '[--remote]',
5534 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5537 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5535 helpbasic=True,
5538 helpbasic=True,
5536 intents={INTENT_READONLY})
5539 intents={INTENT_READONLY})
5537 def summary(ui, repo, **opts):
5540 def summary(ui, repo, **opts):
5538 """summarize working directory state
5541 """summarize working directory state
5539
5542
5540 This generates a brief summary of the working directory state,
5543 This generates a brief summary of the working directory state,
5541 including parents, branch, commit status, phase and available updates.
5544 including parents, branch, commit status, phase and available updates.
5542
5545
5543 With the --remote option, this will check the default paths for
5546 With the --remote option, this will check the default paths for
5544 incoming and outgoing changes. This can be time-consuming.
5547 incoming and outgoing changes. This can be time-consuming.
5545
5548
5546 Returns 0 on success.
5549 Returns 0 on success.
5547 """
5550 """
5548
5551
5549 opts = pycompat.byteskwargs(opts)
5552 opts = pycompat.byteskwargs(opts)
5550 ui.pager('summary')
5553 ui.pager('summary')
5551 ctx = repo[None]
5554 ctx = repo[None]
5552 parents = ctx.parents()
5555 parents = ctx.parents()
5553 pnode = parents[0].node()
5556 pnode = parents[0].node()
5554 marks = []
5557 marks = []
5555
5558
5556 try:
5559 try:
5557 ms = mergemod.mergestate.read(repo)
5560 ms = mergemod.mergestate.read(repo)
5558 except error.UnsupportedMergeRecords as e:
5561 except error.UnsupportedMergeRecords as e:
5559 s = ' '.join(e.recordtypes)
5562 s = ' '.join(e.recordtypes)
5560 ui.warn(
5563 ui.warn(
5561 _('warning: merge state has unsupported record types: %s\n') % s)
5564 _('warning: merge state has unsupported record types: %s\n') % s)
5562 unresolved = []
5565 unresolved = []
5563 else:
5566 else:
5564 unresolved = list(ms.unresolved())
5567 unresolved = list(ms.unresolved())
5565
5568
5566 for p in parents:
5569 for p in parents:
5567 # label with log.changeset (instead of log.parent) since this
5570 # label with log.changeset (instead of log.parent) since this
5568 # shows a working directory parent *changeset*:
5571 # shows a working directory parent *changeset*:
5569 # i18n: column positioning for "hg summary"
5572 # i18n: column positioning for "hg summary"
5570 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5573 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5571 label=logcmdutil.changesetlabels(p))
5574 label=logcmdutil.changesetlabels(p))
5572 ui.write(' '.join(p.tags()), label='log.tag')
5575 ui.write(' '.join(p.tags()), label='log.tag')
5573 if p.bookmarks():
5576 if p.bookmarks():
5574 marks.extend(p.bookmarks())
5577 marks.extend(p.bookmarks())
5575 if p.rev() == -1:
5578 if p.rev() == -1:
5576 if not len(repo):
5579 if not len(repo):
5577 ui.write(_(' (empty repository)'))
5580 ui.write(_(' (empty repository)'))
5578 else:
5581 else:
5579 ui.write(_(' (no revision checked out)'))
5582 ui.write(_(' (no revision checked out)'))
5580 if p.obsolete():
5583 if p.obsolete():
5581 ui.write(_(' (obsolete)'))
5584 ui.write(_(' (obsolete)'))
5582 if p.isunstable():
5585 if p.isunstable():
5583 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5586 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5584 for instability in p.instabilities())
5587 for instability in p.instabilities())
5585 ui.write(' ('
5588 ui.write(' ('
5586 + ', '.join(instabilities)
5589 + ', '.join(instabilities)
5587 + ')')
5590 + ')')
5588 ui.write('\n')
5591 ui.write('\n')
5589 if p.description():
5592 if p.description():
5590 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5593 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5591 label='log.summary')
5594 label='log.summary')
5592
5595
5593 branch = ctx.branch()
5596 branch = ctx.branch()
5594 bheads = repo.branchheads(branch)
5597 bheads = repo.branchheads(branch)
5595 # i18n: column positioning for "hg summary"
5598 # i18n: column positioning for "hg summary"
5596 m = _('branch: %s\n') % branch
5599 m = _('branch: %s\n') % branch
5597 if branch != 'default':
5600 if branch != 'default':
5598 ui.write(m, label='log.branch')
5601 ui.write(m, label='log.branch')
5599 else:
5602 else:
5600 ui.status(m, label='log.branch')
5603 ui.status(m, label='log.branch')
5601
5604
5602 if marks:
5605 if marks:
5603 active = repo._activebookmark
5606 active = repo._activebookmark
5604 # i18n: column positioning for "hg summary"
5607 # i18n: column positioning for "hg summary"
5605 ui.write(_('bookmarks:'), label='log.bookmark')
5608 ui.write(_('bookmarks:'), label='log.bookmark')
5606 if active is not None:
5609 if active is not None:
5607 if active in marks:
5610 if active in marks:
5608 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5611 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5609 marks.remove(active)
5612 marks.remove(active)
5610 else:
5613 else:
5611 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5614 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5612 for m in marks:
5615 for m in marks:
5613 ui.write(' ' + m, label='log.bookmark')
5616 ui.write(' ' + m, label='log.bookmark')
5614 ui.write('\n', label='log.bookmark')
5617 ui.write('\n', label='log.bookmark')
5615
5618
5616 status = repo.status(unknown=True)
5619 status = repo.status(unknown=True)
5617
5620
5618 c = repo.dirstate.copies()
5621 c = repo.dirstate.copies()
5619 copied, renamed = [], []
5622 copied, renamed = [], []
5620 for d, s in c.iteritems():
5623 for d, s in c.iteritems():
5621 if s in status.removed:
5624 if s in status.removed:
5622 status.removed.remove(s)
5625 status.removed.remove(s)
5623 renamed.append(d)
5626 renamed.append(d)
5624 else:
5627 else:
5625 copied.append(d)
5628 copied.append(d)
5626 if d in status.added:
5629 if d in status.added:
5627 status.added.remove(d)
5630 status.added.remove(d)
5628
5631
5629 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5632 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5630
5633
5631 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5634 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5632 (ui.label(_('%d added'), 'status.added'), status.added),
5635 (ui.label(_('%d added'), 'status.added'), status.added),
5633 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5636 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5634 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5637 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5635 (ui.label(_('%d copied'), 'status.copied'), copied),
5638 (ui.label(_('%d copied'), 'status.copied'), copied),
5636 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5639 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5637 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5640 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5638 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5641 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5639 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5642 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5640 t = []
5643 t = []
5641 for l, s in labels:
5644 for l, s in labels:
5642 if s:
5645 if s:
5643 t.append(l % len(s))
5646 t.append(l % len(s))
5644
5647
5645 t = ', '.join(t)
5648 t = ', '.join(t)
5646 cleanworkdir = False
5649 cleanworkdir = False
5647
5650
5648 if repo.vfs.exists('graftstate'):
5651 if repo.vfs.exists('graftstate'):
5649 t += _(' (graft in progress)')
5652 t += _(' (graft in progress)')
5650 if repo.vfs.exists('updatestate'):
5653 if repo.vfs.exists('updatestate'):
5651 t += _(' (interrupted update)')
5654 t += _(' (interrupted update)')
5652 elif len(parents) > 1:
5655 elif len(parents) > 1:
5653 t += _(' (merge)')
5656 t += _(' (merge)')
5654 elif branch != parents[0].branch():
5657 elif branch != parents[0].branch():
5655 t += _(' (new branch)')
5658 t += _(' (new branch)')
5656 elif (parents[0].closesbranch() and
5659 elif (parents[0].closesbranch() and
5657 pnode in repo.branchheads(branch, closed=True)):
5660 pnode in repo.branchheads(branch, closed=True)):
5658 t += _(' (head closed)')
5661 t += _(' (head closed)')
5659 elif not (status.modified or status.added or status.removed or renamed or
5662 elif not (status.modified or status.added or status.removed or renamed or
5660 copied or subs):
5663 copied or subs):
5661 t += _(' (clean)')
5664 t += _(' (clean)')
5662 cleanworkdir = True
5665 cleanworkdir = True
5663 elif pnode not in bheads:
5666 elif pnode not in bheads:
5664 t += _(' (new branch head)')
5667 t += _(' (new branch head)')
5665
5668
5666 if parents:
5669 if parents:
5667 pendingphase = max(p.phase() for p in parents)
5670 pendingphase = max(p.phase() for p in parents)
5668 else:
5671 else:
5669 pendingphase = phases.public
5672 pendingphase = phases.public
5670
5673
5671 if pendingphase > phases.newcommitphase(ui):
5674 if pendingphase > phases.newcommitphase(ui):
5672 t += ' (%s)' % phases.phasenames[pendingphase]
5675 t += ' (%s)' % phases.phasenames[pendingphase]
5673
5676
5674 if cleanworkdir:
5677 if cleanworkdir:
5675 # i18n: column positioning for "hg summary"
5678 # i18n: column positioning for "hg summary"
5676 ui.status(_('commit: %s\n') % t.strip())
5679 ui.status(_('commit: %s\n') % t.strip())
5677 else:
5680 else:
5678 # i18n: column positioning for "hg summary"
5681 # i18n: column positioning for "hg summary"
5679 ui.write(_('commit: %s\n') % t.strip())
5682 ui.write(_('commit: %s\n') % t.strip())
5680
5683
5681 # all ancestors of branch heads - all ancestors of parent = new csets
5684 # all ancestors of branch heads - all ancestors of parent = new csets
5682 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5685 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5683 bheads))
5686 bheads))
5684
5687
5685 if new == 0:
5688 if new == 0:
5686 # i18n: column positioning for "hg summary"
5689 # i18n: column positioning for "hg summary"
5687 ui.status(_('update: (current)\n'))
5690 ui.status(_('update: (current)\n'))
5688 elif pnode not in bheads:
5691 elif pnode not in bheads:
5689 # i18n: column positioning for "hg summary"
5692 # i18n: column positioning for "hg summary"
5690 ui.write(_('update: %d new changesets (update)\n') % new)
5693 ui.write(_('update: %d new changesets (update)\n') % new)
5691 else:
5694 else:
5692 # i18n: column positioning for "hg summary"
5695 # i18n: column positioning for "hg summary"
5693 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5696 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5694 (new, len(bheads)))
5697 (new, len(bheads)))
5695
5698
5696 t = []
5699 t = []
5697 draft = len(repo.revs('draft()'))
5700 draft = len(repo.revs('draft()'))
5698 if draft:
5701 if draft:
5699 t.append(_('%d draft') % draft)
5702 t.append(_('%d draft') % draft)
5700 secret = len(repo.revs('secret()'))
5703 secret = len(repo.revs('secret()'))
5701 if secret:
5704 if secret:
5702 t.append(_('%d secret') % secret)
5705 t.append(_('%d secret') % secret)
5703
5706
5704 if draft or secret:
5707 if draft or secret:
5705 ui.status(_('phases: %s\n') % ', '.join(t))
5708 ui.status(_('phases: %s\n') % ', '.join(t))
5706
5709
5707 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5710 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5708 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5711 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5709 numtrouble = len(repo.revs(trouble + "()"))
5712 numtrouble = len(repo.revs(trouble + "()"))
5710 # We write all the possibilities to ease translation
5713 # We write all the possibilities to ease translation
5711 troublemsg = {
5714 troublemsg = {
5712 "orphan": _("orphan: %d changesets"),
5715 "orphan": _("orphan: %d changesets"),
5713 "contentdivergent": _("content-divergent: %d changesets"),
5716 "contentdivergent": _("content-divergent: %d changesets"),
5714 "phasedivergent": _("phase-divergent: %d changesets"),
5717 "phasedivergent": _("phase-divergent: %d changesets"),
5715 }
5718 }
5716 if numtrouble > 0:
5719 if numtrouble > 0:
5717 ui.status(troublemsg[trouble] % numtrouble + "\n")
5720 ui.status(troublemsg[trouble] % numtrouble + "\n")
5718
5721
5719 cmdutil.summaryhooks(ui, repo)
5722 cmdutil.summaryhooks(ui, repo)
5720
5723
5721 if opts.get('remote'):
5724 if opts.get('remote'):
5722 needsincoming, needsoutgoing = True, True
5725 needsincoming, needsoutgoing = True, True
5723 else:
5726 else:
5724 needsincoming, needsoutgoing = False, False
5727 needsincoming, needsoutgoing = False, False
5725 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5728 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5726 if i:
5729 if i:
5727 needsincoming = True
5730 needsincoming = True
5728 if o:
5731 if o:
5729 needsoutgoing = True
5732 needsoutgoing = True
5730 if not needsincoming and not needsoutgoing:
5733 if not needsincoming and not needsoutgoing:
5731 return
5734 return
5732
5735
5733 def getincoming():
5736 def getincoming():
5734 source, branches = hg.parseurl(ui.expandpath('default'))
5737 source, branches = hg.parseurl(ui.expandpath('default'))
5735 sbranch = branches[0]
5738 sbranch = branches[0]
5736 try:
5739 try:
5737 other = hg.peer(repo, {}, source)
5740 other = hg.peer(repo, {}, source)
5738 except error.RepoError:
5741 except error.RepoError:
5739 if opts.get('remote'):
5742 if opts.get('remote'):
5740 raise
5743 raise
5741 return source, sbranch, None, None, None
5744 return source, sbranch, None, None, None
5742 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5745 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5743 if revs:
5746 if revs:
5744 revs = [other.lookup(rev) for rev in revs]
5747 revs = [other.lookup(rev) for rev in revs]
5745 ui.debug('comparing with %s\n' % util.hidepassword(source))
5748 ui.debug('comparing with %s\n' % util.hidepassword(source))
5746 repo.ui.pushbuffer()
5749 repo.ui.pushbuffer()
5747 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5750 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5748 repo.ui.popbuffer()
5751 repo.ui.popbuffer()
5749 return source, sbranch, other, commoninc, commoninc[1]
5752 return source, sbranch, other, commoninc, commoninc[1]
5750
5753
5751 if needsincoming:
5754 if needsincoming:
5752 source, sbranch, sother, commoninc, incoming = getincoming()
5755 source, sbranch, sother, commoninc, incoming = getincoming()
5753 else:
5756 else:
5754 source = sbranch = sother = commoninc = incoming = None
5757 source = sbranch = sother = commoninc = incoming = None
5755
5758
5756 def getoutgoing():
5759 def getoutgoing():
5757 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5760 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5758 dbranch = branches[0]
5761 dbranch = branches[0]
5759 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5762 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5760 if source != dest:
5763 if source != dest:
5761 try:
5764 try:
5762 dother = hg.peer(repo, {}, dest)
5765 dother = hg.peer(repo, {}, dest)
5763 except error.RepoError:
5766 except error.RepoError:
5764 if opts.get('remote'):
5767 if opts.get('remote'):
5765 raise
5768 raise
5766 return dest, dbranch, None, None
5769 return dest, dbranch, None, None
5767 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5770 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5768 elif sother is None:
5771 elif sother is None:
5769 # there is no explicit destination peer, but source one is invalid
5772 # there is no explicit destination peer, but source one is invalid
5770 return dest, dbranch, None, None
5773 return dest, dbranch, None, None
5771 else:
5774 else:
5772 dother = sother
5775 dother = sother
5773 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5776 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5774 common = None
5777 common = None
5775 else:
5778 else:
5776 common = commoninc
5779 common = commoninc
5777 if revs:
5780 if revs:
5778 revs = [repo.lookup(rev) for rev in revs]
5781 revs = [repo.lookup(rev) for rev in revs]
5779 repo.ui.pushbuffer()
5782 repo.ui.pushbuffer()
5780 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5783 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5781 commoninc=common)
5784 commoninc=common)
5782 repo.ui.popbuffer()
5785 repo.ui.popbuffer()
5783 return dest, dbranch, dother, outgoing
5786 return dest, dbranch, dother, outgoing
5784
5787
5785 if needsoutgoing:
5788 if needsoutgoing:
5786 dest, dbranch, dother, outgoing = getoutgoing()
5789 dest, dbranch, dother, outgoing = getoutgoing()
5787 else:
5790 else:
5788 dest = dbranch = dother = outgoing = None
5791 dest = dbranch = dother = outgoing = None
5789
5792
5790 if opts.get('remote'):
5793 if opts.get('remote'):
5791 t = []
5794 t = []
5792 if incoming:
5795 if incoming:
5793 t.append(_('1 or more incoming'))
5796 t.append(_('1 or more incoming'))
5794 o = outgoing.missing
5797 o = outgoing.missing
5795 if o:
5798 if o:
5796 t.append(_('%d outgoing') % len(o))
5799 t.append(_('%d outgoing') % len(o))
5797 other = dother or sother
5800 other = dother or sother
5798 if 'bookmarks' in other.listkeys('namespaces'):
5801 if 'bookmarks' in other.listkeys('namespaces'):
5799 counts = bookmarks.summary(repo, other)
5802 counts = bookmarks.summary(repo, other)
5800 if counts[0] > 0:
5803 if counts[0] > 0:
5801 t.append(_('%d incoming bookmarks') % counts[0])
5804 t.append(_('%d incoming bookmarks') % counts[0])
5802 if counts[1] > 0:
5805 if counts[1] > 0:
5803 t.append(_('%d outgoing bookmarks') % counts[1])
5806 t.append(_('%d outgoing bookmarks') % counts[1])
5804
5807
5805 if t:
5808 if t:
5806 # i18n: column positioning for "hg summary"
5809 # i18n: column positioning for "hg summary"
5807 ui.write(_('remote: %s\n') % (', '.join(t)))
5810 ui.write(_('remote: %s\n') % (', '.join(t)))
5808 else:
5811 else:
5809 # i18n: column positioning for "hg summary"
5812 # i18n: column positioning for "hg summary"
5810 ui.status(_('remote: (synced)\n'))
5813 ui.status(_('remote: (synced)\n'))
5811
5814
5812 cmdutil.summaryremotehooks(ui, repo, opts,
5815 cmdutil.summaryremotehooks(ui, repo, opts,
5813 ((source, sbranch, sother, commoninc),
5816 ((source, sbranch, sother, commoninc),
5814 (dest, dbranch, dother, outgoing)))
5817 (dest, dbranch, dother, outgoing)))
5815
5818
5816 @command('tag',
5819 @command('tag',
5817 [('f', 'force', None, _('force tag')),
5820 [('f', 'force', None, _('force tag')),
5818 ('l', 'local', None, _('make the tag local')),
5821 ('l', 'local', None, _('make the tag local')),
5819 ('r', 'rev', '', _('revision to tag'), _('REV')),
5822 ('r', 'rev', '', _('revision to tag'), _('REV')),
5820 ('', 'remove', None, _('remove a tag')),
5823 ('', 'remove', None, _('remove a tag')),
5821 # -l/--local is already there, commitopts cannot be used
5824 # -l/--local is already there, commitopts cannot be used
5822 ('e', 'edit', None, _('invoke editor on commit messages')),
5825 ('e', 'edit', None, _('invoke editor on commit messages')),
5823 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5826 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5824 ] + commitopts2,
5827 ] + commitopts2,
5825 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5828 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5826 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5829 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5827 def tag(ui, repo, name1, *names, **opts):
5830 def tag(ui, repo, name1, *names, **opts):
5828 """add one or more tags for the current or given revision
5831 """add one or more tags for the current or given revision
5829
5832
5830 Name a particular revision using <name>.
5833 Name a particular revision using <name>.
5831
5834
5832 Tags are used to name particular revisions of the repository and are
5835 Tags are used to name particular revisions of the repository and are
5833 very useful to compare different revisions, to go back to significant
5836 very useful to compare different revisions, to go back to significant
5834 earlier versions or to mark branch points as releases, etc. Changing
5837 earlier versions or to mark branch points as releases, etc. Changing
5835 an existing tag is normally disallowed; use -f/--force to override.
5838 an existing tag is normally disallowed; use -f/--force to override.
5836
5839
5837 If no revision is given, the parent of the working directory is
5840 If no revision is given, the parent of the working directory is
5838 used.
5841 used.
5839
5842
5840 To facilitate version control, distribution, and merging of tags,
5843 To facilitate version control, distribution, and merging of tags,
5841 they are stored as a file named ".hgtags" which is managed similarly
5844 they are stored as a file named ".hgtags" which is managed similarly
5842 to other project files and can be hand-edited if necessary. This
5845 to other project files and can be hand-edited if necessary. This
5843 also means that tagging creates a new commit. The file
5846 also means that tagging creates a new commit. The file
5844 ".hg/localtags" is used for local tags (not shared among
5847 ".hg/localtags" is used for local tags (not shared among
5845 repositories).
5848 repositories).
5846
5849
5847 Tag commits are usually made at the head of a branch. If the parent
5850 Tag commits are usually made at the head of a branch. If the parent
5848 of the working directory is not a branch head, :hg:`tag` aborts; use
5851 of the working directory is not a branch head, :hg:`tag` aborts; use
5849 -f/--force to force the tag commit to be based on a non-head
5852 -f/--force to force the tag commit to be based on a non-head
5850 changeset.
5853 changeset.
5851
5854
5852 See :hg:`help dates` for a list of formats valid for -d/--date.
5855 See :hg:`help dates` for a list of formats valid for -d/--date.
5853
5856
5854 Since tag names have priority over branch names during revision
5857 Since tag names have priority over branch names during revision
5855 lookup, using an existing branch name as a tag name is discouraged.
5858 lookup, using an existing branch name as a tag name is discouraged.
5856
5859
5857 Returns 0 on success.
5860 Returns 0 on success.
5858 """
5861 """
5859 opts = pycompat.byteskwargs(opts)
5862 opts = pycompat.byteskwargs(opts)
5860 with repo.wlock(), repo.lock():
5863 with repo.wlock(), repo.lock():
5861 rev_ = "."
5864 rev_ = "."
5862 names = [t.strip() for t in (name1,) + names]
5865 names = [t.strip() for t in (name1,) + names]
5863 if len(names) != len(set(names)):
5866 if len(names) != len(set(names)):
5864 raise error.Abort(_('tag names must be unique'))
5867 raise error.Abort(_('tag names must be unique'))
5865 for n in names:
5868 for n in names:
5866 scmutil.checknewlabel(repo, n, 'tag')
5869 scmutil.checknewlabel(repo, n, 'tag')
5867 if not n:
5870 if not n:
5868 raise error.Abort(_('tag names cannot consist entirely of '
5871 raise error.Abort(_('tag names cannot consist entirely of '
5869 'whitespace'))
5872 'whitespace'))
5870 if opts.get('rev') and opts.get('remove'):
5873 if opts.get('rev') and opts.get('remove'):
5871 raise error.Abort(_("--rev and --remove are incompatible"))
5874 raise error.Abort(_("--rev and --remove are incompatible"))
5872 if opts.get('rev'):
5875 if opts.get('rev'):
5873 rev_ = opts['rev']
5876 rev_ = opts['rev']
5874 message = opts.get('message')
5877 message = opts.get('message')
5875 if opts.get('remove'):
5878 if opts.get('remove'):
5876 if opts.get('local'):
5879 if opts.get('local'):
5877 expectedtype = 'local'
5880 expectedtype = 'local'
5878 else:
5881 else:
5879 expectedtype = 'global'
5882 expectedtype = 'global'
5880
5883
5881 for n in names:
5884 for n in names:
5882 if repo.tagtype(n) == 'global':
5885 if repo.tagtype(n) == 'global':
5883 alltags = tagsmod.findglobaltags(ui, repo)
5886 alltags = tagsmod.findglobaltags(ui, repo)
5884 if alltags[n][0] == nullid:
5887 if alltags[n][0] == nullid:
5885 raise error.Abort(_("tag '%s' is already removed") % n)
5888 raise error.Abort(_("tag '%s' is already removed") % n)
5886 if not repo.tagtype(n):
5889 if not repo.tagtype(n):
5887 raise error.Abort(_("tag '%s' does not exist") % n)
5890 raise error.Abort(_("tag '%s' does not exist") % n)
5888 if repo.tagtype(n) != expectedtype:
5891 if repo.tagtype(n) != expectedtype:
5889 if expectedtype == 'global':
5892 if expectedtype == 'global':
5890 raise error.Abort(_("tag '%s' is not a global tag") % n)
5893 raise error.Abort(_("tag '%s' is not a global tag") % n)
5891 else:
5894 else:
5892 raise error.Abort(_("tag '%s' is not a local tag") % n)
5895 raise error.Abort(_("tag '%s' is not a local tag") % n)
5893 rev_ = 'null'
5896 rev_ = 'null'
5894 if not message:
5897 if not message:
5895 # we don't translate commit messages
5898 # we don't translate commit messages
5896 message = 'Removed tag %s' % ', '.join(names)
5899 message = 'Removed tag %s' % ', '.join(names)
5897 elif not opts.get('force'):
5900 elif not opts.get('force'):
5898 for n in names:
5901 for n in names:
5899 if n in repo.tags():
5902 if n in repo.tags():
5900 raise error.Abort(_("tag '%s' already exists "
5903 raise error.Abort(_("tag '%s' already exists "
5901 "(use -f to force)") % n)
5904 "(use -f to force)") % n)
5902 if not opts.get('local'):
5905 if not opts.get('local'):
5903 p1, p2 = repo.dirstate.parents()
5906 p1, p2 = repo.dirstate.parents()
5904 if p2 != nullid:
5907 if p2 != nullid:
5905 raise error.Abort(_('uncommitted merge'))
5908 raise error.Abort(_('uncommitted merge'))
5906 bheads = repo.branchheads()
5909 bheads = repo.branchheads()
5907 if not opts.get('force') and bheads and p1 not in bheads:
5910 if not opts.get('force') and bheads and p1 not in bheads:
5908 raise error.Abort(_('working directory is not at a branch head '
5911 raise error.Abort(_('working directory is not at a branch head '
5909 '(use -f to force)'))
5912 '(use -f to force)'))
5910 node = scmutil.revsingle(repo, rev_).node()
5913 node = scmutil.revsingle(repo, rev_).node()
5911
5914
5912 if not message:
5915 if not message:
5913 # we don't translate commit messages
5916 # we don't translate commit messages
5914 message = ('Added tag %s for changeset %s' %
5917 message = ('Added tag %s for changeset %s' %
5915 (', '.join(names), short(node)))
5918 (', '.join(names), short(node)))
5916
5919
5917 date = opts.get('date')
5920 date = opts.get('date')
5918 if date:
5921 if date:
5919 date = dateutil.parsedate(date)
5922 date = dateutil.parsedate(date)
5920
5923
5921 if opts.get('remove'):
5924 if opts.get('remove'):
5922 editform = 'tag.remove'
5925 editform = 'tag.remove'
5923 else:
5926 else:
5924 editform = 'tag.add'
5927 editform = 'tag.add'
5925 editor = cmdutil.getcommiteditor(editform=editform,
5928 editor = cmdutil.getcommiteditor(editform=editform,
5926 **pycompat.strkwargs(opts))
5929 **pycompat.strkwargs(opts))
5927
5930
5928 # don't allow tagging the null rev
5931 # don't allow tagging the null rev
5929 if (not opts.get('remove') and
5932 if (not opts.get('remove') and
5930 scmutil.revsingle(repo, rev_).rev() == nullrev):
5933 scmutil.revsingle(repo, rev_).rev() == nullrev):
5931 raise error.Abort(_("cannot tag null revision"))
5934 raise error.Abort(_("cannot tag null revision"))
5932
5935
5933 tagsmod.tag(repo, names, node, message, opts.get('local'),
5936 tagsmod.tag(repo, names, node, message, opts.get('local'),
5934 opts.get('user'), date, editor=editor)
5937 opts.get('user'), date, editor=editor)
5935
5938
5936 @command(
5939 @command(
5937 'tags', formatteropts, '',
5940 'tags', formatteropts, '',
5938 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5941 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5939 intents={INTENT_READONLY})
5942 intents={INTENT_READONLY})
5940 def tags(ui, repo, **opts):
5943 def tags(ui, repo, **opts):
5941 """list repository tags
5944 """list repository tags
5942
5945
5943 This lists both regular and local tags. When the -v/--verbose
5946 This lists both regular and local tags. When the -v/--verbose
5944 switch is used, a third column "local" is printed for local tags.
5947 switch is used, a third column "local" is printed for local tags.
5945 When the -q/--quiet switch is used, only the tag name is printed.
5948 When the -q/--quiet switch is used, only the tag name is printed.
5946
5949
5947 .. container:: verbose
5950 .. container:: verbose
5948
5951
5949 Template:
5952 Template:
5950
5953
5951 The following keywords are supported in addition to the common template
5954 The following keywords are supported in addition to the common template
5952 keywords and functions such as ``{tag}``. See also
5955 keywords and functions such as ``{tag}``. See also
5953 :hg:`help templates`.
5956 :hg:`help templates`.
5954
5957
5955 :type: String. ``local`` for local tags.
5958 :type: String. ``local`` for local tags.
5956
5959
5957 Returns 0 on success.
5960 Returns 0 on success.
5958 """
5961 """
5959
5962
5960 opts = pycompat.byteskwargs(opts)
5963 opts = pycompat.byteskwargs(opts)
5961 ui.pager('tags')
5964 ui.pager('tags')
5962 fm = ui.formatter('tags', opts)
5965 fm = ui.formatter('tags', opts)
5963 hexfunc = fm.hexfunc
5966 hexfunc = fm.hexfunc
5964
5967
5965 for t, n in reversed(repo.tagslist()):
5968 for t, n in reversed(repo.tagslist()):
5966 hn = hexfunc(n)
5969 hn = hexfunc(n)
5967 label = 'tags.normal'
5970 label = 'tags.normal'
5968 tagtype = ''
5971 tagtype = ''
5969 if repo.tagtype(t) == 'local':
5972 if repo.tagtype(t) == 'local':
5970 label = 'tags.local'
5973 label = 'tags.local'
5971 tagtype = 'local'
5974 tagtype = 'local'
5972
5975
5973 fm.startitem()
5976 fm.startitem()
5974 fm.context(repo=repo)
5977 fm.context(repo=repo)
5975 fm.write('tag', '%s', t, label=label)
5978 fm.write('tag', '%s', t, label=label)
5976 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5979 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5977 fm.condwrite(not ui.quiet, 'rev node', fmt,
5980 fm.condwrite(not ui.quiet, 'rev node', fmt,
5978 repo.changelog.rev(n), hn, label=label)
5981 repo.changelog.rev(n), hn, label=label)
5979 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5982 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5980 tagtype, label=label)
5983 tagtype, label=label)
5981 fm.plain('\n')
5984 fm.plain('\n')
5982 fm.end()
5985 fm.end()
5983
5986
5984 @command('tip',
5987 @command('tip',
5985 [('p', 'patch', None, _('show patch')),
5988 [('p', 'patch', None, _('show patch')),
5986 ('g', 'git', None, _('use git extended diff format')),
5989 ('g', 'git', None, _('use git extended diff format')),
5987 ] + templateopts,
5990 ] + templateopts,
5988 _('[-p] [-g]'),
5991 _('[-p] [-g]'),
5989 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
5992 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
5990 def tip(ui, repo, **opts):
5993 def tip(ui, repo, **opts):
5991 """show the tip revision (DEPRECATED)
5994 """show the tip revision (DEPRECATED)
5992
5995
5993 The tip revision (usually just called the tip) is the changeset
5996 The tip revision (usually just called the tip) is the changeset
5994 most recently added to the repository (and therefore the most
5997 most recently added to the repository (and therefore the most
5995 recently changed head).
5998 recently changed head).
5996
5999
5997 If you have just made a commit, that commit will be the tip. If
6000 If you have just made a commit, that commit will be the tip. If
5998 you have just pulled changes from another repository, the tip of
6001 you have just pulled changes from another repository, the tip of
5999 that repository becomes the current tip. The "tip" tag is special
6002 that repository becomes the current tip. The "tip" tag is special
6000 and cannot be renamed or assigned to a different changeset.
6003 and cannot be renamed or assigned to a different changeset.
6001
6004
6002 This command is deprecated, please use :hg:`heads` instead.
6005 This command is deprecated, please use :hg:`heads` instead.
6003
6006
6004 Returns 0 on success.
6007 Returns 0 on success.
6005 """
6008 """
6006 opts = pycompat.byteskwargs(opts)
6009 opts = pycompat.byteskwargs(opts)
6007 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
6010 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
6008 displayer.show(repo['tip'])
6011 displayer.show(repo['tip'])
6009 displayer.close()
6012 displayer.close()
6010
6013
6011 @command('unbundle',
6014 @command('unbundle',
6012 [('u', 'update', None,
6015 [('u', 'update', None,
6013 _('update to new branch head if changesets were unbundled'))],
6016 _('update to new branch head if changesets were unbundled'))],
6014 _('[-u] FILE...'),
6017 _('[-u] FILE...'),
6015 helpcategory=command.CATEGORY_IMPORT_EXPORT)
6018 helpcategory=command.CATEGORY_IMPORT_EXPORT)
6016 def unbundle(ui, repo, fname1, *fnames, **opts):
6019 def unbundle(ui, repo, fname1, *fnames, **opts):
6017 """apply one or more bundle files
6020 """apply one or more bundle files
6018
6021
6019 Apply one or more bundle files generated by :hg:`bundle`.
6022 Apply one or more bundle files generated by :hg:`bundle`.
6020
6023
6021 Returns 0 on success, 1 if an update has unresolved files.
6024 Returns 0 on success, 1 if an update has unresolved files.
6022 """
6025 """
6023 fnames = (fname1,) + fnames
6026 fnames = (fname1,) + fnames
6024
6027
6025 with repo.lock():
6028 with repo.lock():
6026 for fname in fnames:
6029 for fname in fnames:
6027 f = hg.openpath(ui, fname)
6030 f = hg.openpath(ui, fname)
6028 gen = exchange.readbundle(ui, f, fname)
6031 gen = exchange.readbundle(ui, f, fname)
6029 if isinstance(gen, streamclone.streamcloneapplier):
6032 if isinstance(gen, streamclone.streamcloneapplier):
6030 raise error.Abort(
6033 raise error.Abort(
6031 _('packed bundles cannot be applied with '
6034 _('packed bundles cannot be applied with '
6032 '"hg unbundle"'),
6035 '"hg unbundle"'),
6033 hint=_('use "hg debugapplystreamclonebundle"'))
6036 hint=_('use "hg debugapplystreamclonebundle"'))
6034 url = 'bundle:' + fname
6037 url = 'bundle:' + fname
6035 try:
6038 try:
6036 txnname = 'unbundle'
6039 txnname = 'unbundle'
6037 if not isinstance(gen, bundle2.unbundle20):
6040 if not isinstance(gen, bundle2.unbundle20):
6038 txnname = 'unbundle\n%s' % util.hidepassword(url)
6041 txnname = 'unbundle\n%s' % util.hidepassword(url)
6039 with repo.transaction(txnname) as tr:
6042 with repo.transaction(txnname) as tr:
6040 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6043 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6041 url=url)
6044 url=url)
6042 except error.BundleUnknownFeatureError as exc:
6045 except error.BundleUnknownFeatureError as exc:
6043 raise error.Abort(
6046 raise error.Abort(
6044 _('%s: unknown bundle feature, %s') % (fname, exc),
6047 _('%s: unknown bundle feature, %s') % (fname, exc),
6045 hint=_("see https://mercurial-scm.org/"
6048 hint=_("see https://mercurial-scm.org/"
6046 "wiki/BundleFeature for more "
6049 "wiki/BundleFeature for more "
6047 "information"))
6050 "information"))
6048 modheads = bundle2.combinechangegroupresults(op)
6051 modheads = bundle2.combinechangegroupresults(op)
6049
6052
6050 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
6053 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
6051
6054
6052 @command('update|up|checkout|co',
6055 @command('update|up|checkout|co',
6053 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6056 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6054 ('c', 'check', None, _('require clean working directory')),
6057 ('c', 'check', None, _('require clean working directory')),
6055 ('m', 'merge', None, _('merge uncommitted changes')),
6058 ('m', 'merge', None, _('merge uncommitted changes')),
6056 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6059 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6057 ('r', 'rev', '', _('revision'), _('REV'))
6060 ('r', 'rev', '', _('revision'), _('REV'))
6058 ] + mergetoolopts,
6061 ] + mergetoolopts,
6059 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
6062 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
6060 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6063 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6061 helpbasic=True)
6064 helpbasic=True)
6062 def update(ui, repo, node=None, **opts):
6065 def update(ui, repo, node=None, **opts):
6063 """update working directory (or switch revisions)
6066 """update working directory (or switch revisions)
6064
6067
6065 Update the repository's working directory to the specified
6068 Update the repository's working directory to the specified
6066 changeset. If no changeset is specified, update to the tip of the
6069 changeset. If no changeset is specified, update to the tip of the
6067 current named branch and move the active bookmark (see :hg:`help
6070 current named branch and move the active bookmark (see :hg:`help
6068 bookmarks`).
6071 bookmarks`).
6069
6072
6070 Update sets the working directory's parent revision to the specified
6073 Update sets the working directory's parent revision to the specified
6071 changeset (see :hg:`help parents`).
6074 changeset (see :hg:`help parents`).
6072
6075
6073 If the changeset is not a descendant or ancestor of the working
6076 If the changeset is not a descendant or ancestor of the working
6074 directory's parent and there are uncommitted changes, the update is
6077 directory's parent and there are uncommitted changes, the update is
6075 aborted. With the -c/--check option, the working directory is checked
6078 aborted. With the -c/--check option, the working directory is checked
6076 for uncommitted changes; if none are found, the working directory is
6079 for uncommitted changes; if none are found, the working directory is
6077 updated to the specified changeset.
6080 updated to the specified changeset.
6078
6081
6079 .. container:: verbose
6082 .. container:: verbose
6080
6083
6081 The -C/--clean, -c/--check, and -m/--merge options control what
6084 The -C/--clean, -c/--check, and -m/--merge options control what
6082 happens if the working directory contains uncommitted changes.
6085 happens if the working directory contains uncommitted changes.
6083 At most of one of them can be specified.
6086 At most of one of them can be specified.
6084
6087
6085 1. If no option is specified, and if
6088 1. If no option is specified, and if
6086 the requested changeset is an ancestor or descendant of
6089 the requested changeset is an ancestor or descendant of
6087 the working directory's parent, the uncommitted changes
6090 the working directory's parent, the uncommitted changes
6088 are merged into the requested changeset and the merged
6091 are merged into the requested changeset and the merged
6089 result is left uncommitted. If the requested changeset is
6092 result is left uncommitted. If the requested changeset is
6090 not an ancestor or descendant (that is, it is on another
6093 not an ancestor or descendant (that is, it is on another
6091 branch), the update is aborted and the uncommitted changes
6094 branch), the update is aborted and the uncommitted changes
6092 are preserved.
6095 are preserved.
6093
6096
6094 2. With the -m/--merge option, the update is allowed even if the
6097 2. With the -m/--merge option, the update is allowed even if the
6095 requested changeset is not an ancestor or descendant of
6098 requested changeset is not an ancestor or descendant of
6096 the working directory's parent.
6099 the working directory's parent.
6097
6100
6098 3. With the -c/--check option, the update is aborted and the
6101 3. With the -c/--check option, the update is aborted and the
6099 uncommitted changes are preserved.
6102 uncommitted changes are preserved.
6100
6103
6101 4. With the -C/--clean option, uncommitted changes are discarded and
6104 4. With the -C/--clean option, uncommitted changes are discarded and
6102 the working directory is updated to the requested changeset.
6105 the working directory is updated to the requested changeset.
6103
6106
6104 To cancel an uncommitted merge (and lose your changes), use
6107 To cancel an uncommitted merge (and lose your changes), use
6105 :hg:`merge --abort`.
6108 :hg:`merge --abort`.
6106
6109
6107 Use null as the changeset to remove the working directory (like
6110 Use null as the changeset to remove the working directory (like
6108 :hg:`clone -U`).
6111 :hg:`clone -U`).
6109
6112
6110 If you want to revert just one file to an older revision, use
6113 If you want to revert just one file to an older revision, use
6111 :hg:`revert [-r REV] NAME`.
6114 :hg:`revert [-r REV] NAME`.
6112
6115
6113 See :hg:`help dates` for a list of formats valid for -d/--date.
6116 See :hg:`help dates` for a list of formats valid for -d/--date.
6114
6117
6115 Returns 0 on success, 1 if there are unresolved files.
6118 Returns 0 on success, 1 if there are unresolved files.
6116 """
6119 """
6117 rev = opts.get(r'rev')
6120 rev = opts.get(r'rev')
6118 date = opts.get(r'date')
6121 date = opts.get(r'date')
6119 clean = opts.get(r'clean')
6122 clean = opts.get(r'clean')
6120 check = opts.get(r'check')
6123 check = opts.get(r'check')
6121 merge = opts.get(r'merge')
6124 merge = opts.get(r'merge')
6122 if rev and node:
6125 if rev and node:
6123 raise error.Abort(_("please specify just one revision"))
6126 raise error.Abort(_("please specify just one revision"))
6124
6127
6125 if ui.configbool('commands', 'update.requiredest'):
6128 if ui.configbool('commands', 'update.requiredest'):
6126 if not node and not rev and not date:
6129 if not node and not rev and not date:
6127 raise error.Abort(_('you must specify a destination'),
6130 raise error.Abort(_('you must specify a destination'),
6128 hint=_('for example: hg update ".::"'))
6131 hint=_('for example: hg update ".::"'))
6129
6132
6130 if rev is None or rev == '':
6133 if rev is None or rev == '':
6131 rev = node
6134 rev = node
6132
6135
6133 if date and rev is not None:
6136 if date and rev is not None:
6134 raise error.Abort(_("you can't specify a revision and a date"))
6137 raise error.Abort(_("you can't specify a revision and a date"))
6135
6138
6136 if len([x for x in (clean, check, merge) if x]) > 1:
6139 if len([x for x in (clean, check, merge) if x]) > 1:
6137 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6140 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6138 "or -m/--merge"))
6141 "or -m/--merge"))
6139
6142
6140 updatecheck = None
6143 updatecheck = None
6141 if check:
6144 if check:
6142 updatecheck = 'abort'
6145 updatecheck = 'abort'
6143 elif merge:
6146 elif merge:
6144 updatecheck = 'none'
6147 updatecheck = 'none'
6145
6148
6146 with repo.wlock():
6149 with repo.wlock():
6147 cmdutil.clearunfinished(repo)
6150 cmdutil.clearunfinished(repo)
6148
6151
6149 if date:
6152 if date:
6150 rev = cmdutil.finddate(ui, repo, date)
6153 rev = cmdutil.finddate(ui, repo, date)
6151
6154
6152 # if we defined a bookmark, we have to remember the original name
6155 # if we defined a bookmark, we have to remember the original name
6153 brev = rev
6156 brev = rev
6154 if rev:
6157 if rev:
6155 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6158 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6156 ctx = scmutil.revsingle(repo, rev, default=None)
6159 ctx = scmutil.revsingle(repo, rev, default=None)
6157 rev = ctx.rev()
6160 rev = ctx.rev()
6158 hidden = ctx.hidden()
6161 hidden = ctx.hidden()
6159 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6162 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6160 with ui.configoverride(overrides, 'update'):
6163 with ui.configoverride(overrides, 'update'):
6161 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6164 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6162 updatecheck=updatecheck)
6165 updatecheck=updatecheck)
6163 if hidden:
6166 if hidden:
6164 ctxstr = ctx.hex()[:12]
6167 ctxstr = ctx.hex()[:12]
6165 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6168 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6166
6169
6167 if ctx.obsolete():
6170 if ctx.obsolete():
6168 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6171 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6169 ui.warn("(%s)\n" % obsfatemsg)
6172 ui.warn("(%s)\n" % obsfatemsg)
6170 return ret
6173 return ret
6171
6174
6172 @command('verify',
6175 @command('verify',
6173 [('', 'full', False, 'perform more checks (EXPERIMENTAL)')],
6176 [('', 'full', False, 'perform more checks (EXPERIMENTAL)')],
6174 helpcategory=command.CATEGORY_MAINTENANCE)
6177 helpcategory=command.CATEGORY_MAINTENANCE)
6175 def verify(ui, repo, **opts):
6178 def verify(ui, repo, **opts):
6176 """verify the integrity of the repository
6179 """verify the integrity of the repository
6177
6180
6178 Verify the integrity of the current repository.
6181 Verify the integrity of the current repository.
6179
6182
6180 This will perform an extensive check of the repository's
6183 This will perform an extensive check of the repository's
6181 integrity, validating the hashes and checksums of each entry in
6184 integrity, validating the hashes and checksums of each entry in
6182 the changelog, manifest, and tracked files, as well as the
6185 the changelog, manifest, and tracked files, as well as the
6183 integrity of their crosslinks and indices.
6186 integrity of their crosslinks and indices.
6184
6187
6185 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6188 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6186 for more information about recovery from corruption of the
6189 for more information about recovery from corruption of the
6187 repository.
6190 repository.
6188
6191
6189 Returns 0 on success, 1 if errors are encountered.
6192 Returns 0 on success, 1 if errors are encountered.
6190 """
6193 """
6191 opts = pycompat.byteskwargs(opts)
6194 opts = pycompat.byteskwargs(opts)
6192
6195
6193 level = None
6196 level = None
6194 if opts['full']:
6197 if opts['full']:
6195 level = verifymod.VERIFY_FULL
6198 level = verifymod.VERIFY_FULL
6196 return hg.verify(repo, level)
6199 return hg.verify(repo, level)
6197
6200
6198 @command(
6201 @command(
6199 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6202 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6200 norepo=True, intents={INTENT_READONLY})
6203 norepo=True, intents={INTENT_READONLY})
6201 def version_(ui, **opts):
6204 def version_(ui, **opts):
6202 """output version and copyright information
6205 """output version and copyright information
6203
6206
6204 .. container:: verbose
6207 .. container:: verbose
6205
6208
6206 Template:
6209 Template:
6207
6210
6208 The following keywords are supported. See also :hg:`help templates`.
6211 The following keywords are supported. See also :hg:`help templates`.
6209
6212
6210 :extensions: List of extensions.
6213 :extensions: List of extensions.
6211 :ver: String. Version number.
6214 :ver: String. Version number.
6212
6215
6213 And each entry of ``{extensions}`` provides the following sub-keywords
6216 And each entry of ``{extensions}`` provides the following sub-keywords
6214 in addition to ``{ver}``.
6217 in addition to ``{ver}``.
6215
6218
6216 :bundled: Boolean. True if included in the release.
6219 :bundled: Boolean. True if included in the release.
6217 :name: String. Extension name.
6220 :name: String. Extension name.
6218 """
6221 """
6219 opts = pycompat.byteskwargs(opts)
6222 opts = pycompat.byteskwargs(opts)
6220 if ui.verbose:
6223 if ui.verbose:
6221 ui.pager('version')
6224 ui.pager('version')
6222 fm = ui.formatter("version", opts)
6225 fm = ui.formatter("version", opts)
6223 fm.startitem()
6226 fm.startitem()
6224 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6227 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6225 util.version())
6228 util.version())
6226 license = _(
6229 license = _(
6227 "(see https://mercurial-scm.org for more information)\n"
6230 "(see https://mercurial-scm.org for more information)\n"
6228 "\nCopyright (C) 2005-2019 Matt Mackall and others\n"
6231 "\nCopyright (C) 2005-2019 Matt Mackall and others\n"
6229 "This is free software; see the source for copying conditions. "
6232 "This is free software; see the source for copying conditions. "
6230 "There is NO\nwarranty; "
6233 "There is NO\nwarranty; "
6231 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6234 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6232 )
6235 )
6233 if not ui.quiet:
6236 if not ui.quiet:
6234 fm.plain(license)
6237 fm.plain(license)
6235
6238
6236 if ui.verbose:
6239 if ui.verbose:
6237 fm.plain(_("\nEnabled extensions:\n\n"))
6240 fm.plain(_("\nEnabled extensions:\n\n"))
6238 # format names and versions into columns
6241 # format names and versions into columns
6239 names = []
6242 names = []
6240 vers = []
6243 vers = []
6241 isinternals = []
6244 isinternals = []
6242 for name, module in extensions.extensions():
6245 for name, module in extensions.extensions():
6243 names.append(name)
6246 names.append(name)
6244 vers.append(extensions.moduleversion(module) or None)
6247 vers.append(extensions.moduleversion(module) or None)
6245 isinternals.append(extensions.ismoduleinternal(module))
6248 isinternals.append(extensions.ismoduleinternal(module))
6246 fn = fm.nested("extensions", tmpl='{name}\n')
6249 fn = fm.nested("extensions", tmpl='{name}\n')
6247 if names:
6250 if names:
6248 namefmt = " %%-%ds " % max(len(n) for n in names)
6251 namefmt = " %%-%ds " % max(len(n) for n in names)
6249 places = [_("external"), _("internal")]
6252 places = [_("external"), _("internal")]
6250 for n, v, p in zip(names, vers, isinternals):
6253 for n, v, p in zip(names, vers, isinternals):
6251 fn.startitem()
6254 fn.startitem()
6252 fn.condwrite(ui.verbose, "name", namefmt, n)
6255 fn.condwrite(ui.verbose, "name", namefmt, n)
6253 if ui.verbose:
6256 if ui.verbose:
6254 fn.plain("%s " % places[p])
6257 fn.plain("%s " % places[p])
6255 fn.data(bundled=p)
6258 fn.data(bundled=p)
6256 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6259 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6257 if ui.verbose:
6260 if ui.verbose:
6258 fn.plain("\n")
6261 fn.plain("\n")
6259 fn.end()
6262 fn.end()
6260 fm.end()
6263 fm.end()
6261
6264
6262 def loadcmdtable(ui, name, cmdtable):
6265 def loadcmdtable(ui, name, cmdtable):
6263 """Load command functions from specified cmdtable
6266 """Load command functions from specified cmdtable
6264 """
6267 """
6265 overrides = [cmd for cmd in cmdtable if cmd in table]
6268 overrides = [cmd for cmd in cmdtable if cmd in table]
6266 if overrides:
6269 if overrides:
6267 ui.warn(_("extension '%s' overrides commands: %s\n")
6270 ui.warn(_("extension '%s' overrides commands: %s\n")
6268 % (name, " ".join(overrides)))
6271 % (name, " ".join(overrides)))
6269 table.update(cmdtable)
6272 table.update(cmdtable)
@@ -1,974 +1,974 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3
3
4 Verify checking branch of nullrev before the cache is created doesnt crash
4 Verify checking branch of nullrev before the cache is created doesnt crash
5 $ hg log -r 'branch(.)' -T '{branch}\n'
5 $ hg log -r 'branch(.)' -T '{branch}\n'
6
6
7 Basic test
7 Basic test
8 $ echo 'root' >root
8 $ echo 'root' >root
9 $ hg add root
9 $ hg add root
10 $ hg commit -d '0 0' -m "Adding root node"
10 $ hg commit -d '0 0' -m "Adding root node"
11
11
12 $ echo 'a' >a
12 $ echo 'a' >a
13 $ hg add a
13 $ hg add a
14 $ hg branch a
14 $ hg branch a
15 marked working directory as branch a
15 marked working directory as branch a
16 (branches are permanent and global, did you want a bookmark?)
16 (branches are permanent and global, did you want a bookmark?)
17 $ hg commit -d '1 0' -m "Adding a branch"
17 $ hg commit -d '1 0' -m "Adding a branch"
18
18
19 $ hg branch q
19 $ hg branch q
20 marked working directory as branch q
20 marked working directory as branch q
21 $ echo 'aa' >a
21 $ echo 'aa' >a
22 $ hg branch -C
22 $ hg branch -C
23 reset working directory to branch a
23 reset working directory to branch a
24 $ hg commit -d '2 0' -m "Adding to a branch"
24 $ hg commit -d '2 0' -m "Adding to a branch"
25
25
26 $ hg update -C 0
26 $ hg update -C 0
27 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
27 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
28 $ echo 'b' >b
28 $ echo 'b' >b
29 $ hg add b
29 $ hg add b
30 $ hg branch b
30 $ hg branch b
31 marked working directory as branch b
31 marked working directory as branch b
32 $ hg commit -d '2 0' -m "Adding b branch"
32 $ hg commit -d '2 0' -m "Adding b branch"
33
33
34 $ echo 'bh1' >bh1
34 $ echo 'bh1' >bh1
35 $ hg add bh1
35 $ hg add bh1
36 $ hg commit -d '3 0' -m "Adding b branch head 1"
36 $ hg commit -d '3 0' -m "Adding b branch head 1"
37
37
38 $ hg update -C 2
38 $ hg update -C 2
39 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
39 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
40 $ echo 'bh2' >bh2
40 $ echo 'bh2' >bh2
41 $ hg add bh2
41 $ hg add bh2
42 $ hg commit -d '4 0' -m "Adding b branch head 2"
42 $ hg commit -d '4 0' -m "Adding b branch head 2"
43
43
44 $ echo 'c' >c
44 $ echo 'c' >c
45 $ hg add c
45 $ hg add c
46 $ hg branch c
46 $ hg branch c
47 marked working directory as branch c
47 marked working directory as branch c
48 $ hg commit -d '5 0' -m "Adding c branch"
48 $ hg commit -d '5 0' -m "Adding c branch"
49
49
50 reserved names
50 reserved names
51
51
52 $ hg branch tip
52 $ hg branch tip
53 abort: the name 'tip' is reserved
53 abort: the name 'tip' is reserved
54 [255]
54 [255]
55 $ hg branch null
55 $ hg branch null
56 abort: the name 'null' is reserved
56 abort: the name 'null' is reserved
57 [255]
57 [255]
58 $ hg branch .
58 $ hg branch .
59 abort: the name '.' is reserved
59 abort: the name '.' is reserved
60 [255]
60 [255]
61
61
62 invalid characters
62 invalid characters
63
63
64 $ hg branch 'foo:bar'
64 $ hg branch 'foo:bar'
65 abort: ':' cannot be used in a name
65 abort: ':' cannot be used in a name
66 [255]
66 [255]
67
67
68 $ hg branch 'foo
68 $ hg branch 'foo
69 > bar'
69 > bar'
70 abort: '\n' cannot be used in a name
70 abort: '\n' cannot be used in a name
71 [255]
71 [255]
72
72
73 trailing or leading spaces should be stripped before testing duplicates
73 trailing or leading spaces should be stripped before testing duplicates
74
74
75 $ hg branch 'b '
75 $ hg branch 'b '
76 abort: a branch of the same name already exists
76 abort: a branch of the same name already exists
77 (use 'hg update' to switch to it)
77 (use 'hg update' to switch to it)
78 [255]
78 [255]
79
79
80 $ hg branch ' b'
80 $ hg branch ' b'
81 abort: a branch of the same name already exists
81 abort: a branch of the same name already exists
82 (use 'hg update' to switch to it)
82 (use 'hg update' to switch to it)
83 [255]
83 [255]
84
84
85 verify update will accept invalid legacy branch names
85 verify update will accept invalid legacy branch names
86
86
87 $ hg init test-invalid-branch-name
87 $ hg init test-invalid-branch-name
88 $ cd test-invalid-branch-name
88 $ cd test-invalid-branch-name
89 $ hg unbundle -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
89 $ hg unbundle -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
90 adding changesets
90 adding changesets
91 adding manifests
91 adding manifests
92 adding file changes
92 adding file changes
93 added 3 changesets with 3 changes to 2 files
93 added 3 changesets with 3 changes to 2 files
94 new changesets f0e4c7f04036:33c2ceb9310b (3 drafts)
94 new changesets f0e4c7f04036:33c2ceb9310b (3 drafts)
95 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
96
96
97 $ hg update '"colon:test"'
97 $ hg update '"colon:test"'
98 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 $ cd ..
99 $ cd ..
100
100
101 $ echo 'd' >d
101 $ echo 'd' >d
102 $ hg add d
102 $ hg add d
103 $ hg branch 'a branch name much longer than the default justification used by branches'
103 $ hg branch 'a branch name much longer than the default justification used by branches'
104 marked working directory as branch a branch name much longer than the default justification used by branches
104 marked working directory as branch a branch name much longer than the default justification used by branches
105 $ hg commit -d '6 0' -m "Adding d branch"
105 $ hg commit -d '6 0' -m "Adding d branch"
106
106
107 $ hg branches
107 $ hg branches
108 a branch name much longer than the default justification used by branches 7:10ff5895aa57
108 a branch name much longer than the default justification used by branches 7:10ff5895aa57
109 b 4:aee39cd168d0
109 b 4:aee39cd168d0
110 c 6:589736a22561 (inactive)
110 c 6:589736a22561 (inactive)
111 a 5:d8cbc61dbaa6 (inactive)
111 a 5:d8cbc61dbaa6 (inactive)
112 default 0:19709c5a4e75 (inactive)
112 default 0:19709c5a4e75 (inactive)
113
113
114 -------
114 -------
115
115
116 $ hg branches -a
116 $ hg branches -a
117 a branch name much longer than the default justification used by branches 7:10ff5895aa57
117 a branch name much longer than the default justification used by branches 7:10ff5895aa57
118 b 4:aee39cd168d0
118 b 4:aee39cd168d0
119
119
120 --- Branch a
120 --- Branch a
121
121
122 $ hg log -b a
122 $ hg log -b a
123 changeset: 5:d8cbc61dbaa6
123 changeset: 5:d8cbc61dbaa6
124 branch: a
124 branch: a
125 parent: 2:881fe2b92ad0
125 parent: 2:881fe2b92ad0
126 user: test
126 user: test
127 date: Thu Jan 01 00:00:04 1970 +0000
127 date: Thu Jan 01 00:00:04 1970 +0000
128 summary: Adding b branch head 2
128 summary: Adding b branch head 2
129
129
130 changeset: 2:881fe2b92ad0
130 changeset: 2:881fe2b92ad0
131 branch: a
131 branch: a
132 user: test
132 user: test
133 date: Thu Jan 01 00:00:02 1970 +0000
133 date: Thu Jan 01 00:00:02 1970 +0000
134 summary: Adding to a branch
134 summary: Adding to a branch
135
135
136 changeset: 1:dd6b440dd85a
136 changeset: 1:dd6b440dd85a
137 branch: a
137 branch: a
138 user: test
138 user: test
139 date: Thu Jan 01 00:00:01 1970 +0000
139 date: Thu Jan 01 00:00:01 1970 +0000
140 summary: Adding a branch
140 summary: Adding a branch
141
141
142
142
143 ---- Branch b
143 ---- Branch b
144
144
145 $ hg log -b b
145 $ hg log -b b
146 changeset: 4:aee39cd168d0
146 changeset: 4:aee39cd168d0
147 branch: b
147 branch: b
148 user: test
148 user: test
149 date: Thu Jan 01 00:00:03 1970 +0000
149 date: Thu Jan 01 00:00:03 1970 +0000
150 summary: Adding b branch head 1
150 summary: Adding b branch head 1
151
151
152 changeset: 3:ac22033332d1
152 changeset: 3:ac22033332d1
153 branch: b
153 branch: b
154 parent: 0:19709c5a4e75
154 parent: 0:19709c5a4e75
155 user: test
155 user: test
156 date: Thu Jan 01 00:00:02 1970 +0000
156 date: Thu Jan 01 00:00:02 1970 +0000
157 summary: Adding b branch
157 summary: Adding b branch
158
158
159
159
160 ---- going to test branch listing by rev
160 ---- going to test branch listing by rev
161 $ hg branches -r0
161 $ hg branches -r0
162 default 0:19709c5a4e75 (inactive)
162 default 0:19709c5a4e75 (inactive)
163 $ hg branches -qr0
163 $ hg branches -qr0
164 default
164 default
165 --- now more than one rev
165 --- now more than one rev
166 $ hg branches -r2:5
166 $ hg branches -r2:5
167 b 4:aee39cd168d0
167 b 4:aee39cd168d0
168 a 5:d8cbc61dbaa6 (inactive)
168 a 5:d8cbc61dbaa6 (inactive)
169 $ hg branches -qr2:5
169 $ hg branches -qr2:5
170 b
170 b
171 a
171 a
172 ---- going to test branch closing
172 ---- going to test branch closing
173
173
174 $ hg branches
174 $ hg branches
175 a branch name much longer than the default justification used by branches 7:10ff5895aa57
175 a branch name much longer than the default justification used by branches 7:10ff5895aa57
176 b 4:aee39cd168d0
176 b 4:aee39cd168d0
177 c 6:589736a22561 (inactive)
177 c 6:589736a22561 (inactive)
178 a 5:d8cbc61dbaa6 (inactive)
178 a 5:d8cbc61dbaa6 (inactive)
179 default 0:19709c5a4e75 (inactive)
179 default 0:19709c5a4e75 (inactive)
180 $ hg up -C b
180 $ hg up -C b
181 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
181 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
182 $ echo 'xxx1' >> b
182 $ echo 'xxx1' >> b
183 $ hg commit -d '7 0' -m 'adding cset to branch b'
183 $ hg commit -d '7 0' -m 'adding cset to branch b'
184 $ hg up -C aee39cd168d0
184 $ hg up -C aee39cd168d0
185 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
185 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 $ echo 'xxx2' >> b
186 $ echo 'xxx2' >> b
187 $ hg commit -d '8 0' -m 'adding head to branch b'
187 $ hg commit -d '8 0' -m 'adding head to branch b'
188 created new head
188 created new head
189 $ echo 'xxx3' >> b
189 $ echo 'xxx3' >> b
190 $ hg commit -d '9 0' -m 'adding another cset to branch b'
190 $ hg commit -d '9 0' -m 'adding another cset to branch b'
191 $ hg branches
191 $ hg branches
192 b 10:bfbe841b666e
192 b 10:bfbe841b666e
193 a branch name much longer than the default justification used by branches 7:10ff5895aa57
193 a branch name much longer than the default justification used by branches 7:10ff5895aa57
194 c 6:589736a22561 (inactive)
194 c 6:589736a22561 (inactive)
195 a 5:d8cbc61dbaa6 (inactive)
195 a 5:d8cbc61dbaa6 (inactive)
196 default 0:19709c5a4e75 (inactive)
196 default 0:19709c5a4e75 (inactive)
197 $ hg heads --closed
197 $ hg heads --closed
198 changeset: 10:bfbe841b666e
198 changeset: 10:bfbe841b666e
199 branch: b
199 branch: b
200 tag: tip
200 tag: tip
201 user: test
201 user: test
202 date: Thu Jan 01 00:00:09 1970 +0000
202 date: Thu Jan 01 00:00:09 1970 +0000
203 summary: adding another cset to branch b
203 summary: adding another cset to branch b
204
204
205 changeset: 8:eebb944467c9
205 changeset: 8:eebb944467c9
206 branch: b
206 branch: b
207 parent: 4:aee39cd168d0
207 parent: 4:aee39cd168d0
208 user: test
208 user: test
209 date: Thu Jan 01 00:00:07 1970 +0000
209 date: Thu Jan 01 00:00:07 1970 +0000
210 summary: adding cset to branch b
210 summary: adding cset to branch b
211
211
212 changeset: 7:10ff5895aa57
212 changeset: 7:10ff5895aa57
213 branch: a branch name much longer than the default justification used by branches
213 branch: a branch name much longer than the default justification used by branches
214 user: test
214 user: test
215 date: Thu Jan 01 00:00:06 1970 +0000
215 date: Thu Jan 01 00:00:06 1970 +0000
216 summary: Adding d branch
216 summary: Adding d branch
217
217
218 changeset: 6:589736a22561
218 changeset: 6:589736a22561
219 branch: c
219 branch: c
220 user: test
220 user: test
221 date: Thu Jan 01 00:00:05 1970 +0000
221 date: Thu Jan 01 00:00:05 1970 +0000
222 summary: Adding c branch
222 summary: Adding c branch
223
223
224 changeset: 5:d8cbc61dbaa6
224 changeset: 5:d8cbc61dbaa6
225 branch: a
225 branch: a
226 parent: 2:881fe2b92ad0
226 parent: 2:881fe2b92ad0
227 user: test
227 user: test
228 date: Thu Jan 01 00:00:04 1970 +0000
228 date: Thu Jan 01 00:00:04 1970 +0000
229 summary: Adding b branch head 2
229 summary: Adding b branch head 2
230
230
231 changeset: 0:19709c5a4e75
231 changeset: 0:19709c5a4e75
232 user: test
232 user: test
233 date: Thu Jan 01 00:00:00 1970 +0000
233 date: Thu Jan 01 00:00:00 1970 +0000
234 summary: Adding root node
234 summary: Adding root node
235
235
236 $ hg heads
236 $ hg heads
237 changeset: 10:bfbe841b666e
237 changeset: 10:bfbe841b666e
238 branch: b
238 branch: b
239 tag: tip
239 tag: tip
240 user: test
240 user: test
241 date: Thu Jan 01 00:00:09 1970 +0000
241 date: Thu Jan 01 00:00:09 1970 +0000
242 summary: adding another cset to branch b
242 summary: adding another cset to branch b
243
243
244 changeset: 8:eebb944467c9
244 changeset: 8:eebb944467c9
245 branch: b
245 branch: b
246 parent: 4:aee39cd168d0
246 parent: 4:aee39cd168d0
247 user: test
247 user: test
248 date: Thu Jan 01 00:00:07 1970 +0000
248 date: Thu Jan 01 00:00:07 1970 +0000
249 summary: adding cset to branch b
249 summary: adding cset to branch b
250
250
251 changeset: 7:10ff5895aa57
251 changeset: 7:10ff5895aa57
252 branch: a branch name much longer than the default justification used by branches
252 branch: a branch name much longer than the default justification used by branches
253 user: test
253 user: test
254 date: Thu Jan 01 00:00:06 1970 +0000
254 date: Thu Jan 01 00:00:06 1970 +0000
255 summary: Adding d branch
255 summary: Adding d branch
256
256
257 changeset: 6:589736a22561
257 changeset: 6:589736a22561
258 branch: c
258 branch: c
259 user: test
259 user: test
260 date: Thu Jan 01 00:00:05 1970 +0000
260 date: Thu Jan 01 00:00:05 1970 +0000
261 summary: Adding c branch
261 summary: Adding c branch
262
262
263 changeset: 5:d8cbc61dbaa6
263 changeset: 5:d8cbc61dbaa6
264 branch: a
264 branch: a
265 parent: 2:881fe2b92ad0
265 parent: 2:881fe2b92ad0
266 user: test
266 user: test
267 date: Thu Jan 01 00:00:04 1970 +0000
267 date: Thu Jan 01 00:00:04 1970 +0000
268 summary: Adding b branch head 2
268 summary: Adding b branch head 2
269
269
270 changeset: 0:19709c5a4e75
270 changeset: 0:19709c5a4e75
271 user: test
271 user: test
272 date: Thu Jan 01 00:00:00 1970 +0000
272 date: Thu Jan 01 00:00:00 1970 +0000
273 summary: Adding root node
273 summary: Adding root node
274
274
275 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
275 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
276 $ hg branches -a
276 $ hg branches -a
277 b 8:eebb944467c9
277 b 8:eebb944467c9
278 a branch name much longer than the default justification used by branches 7:10ff5895aa57
278 a branch name much longer than the default justification used by branches 7:10ff5895aa57
279 $ hg up -C b
279 $ hg up -C b
280 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
280 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
281 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
281 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
282 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
282 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
283 abort: can only close branch heads
283 abort: current revision is already a branch closing head
284 [255]
284 [255]
285
285
286 $ hg log -r tip --debug
286 $ hg log -r tip --debug
287 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
287 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
288 branch: b
288 branch: b
289 tag: tip
289 tag: tip
290 phase: draft
290 phase: draft
291 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
291 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
292 parent: -1:0000000000000000000000000000000000000000
292 parent: -1:0000000000000000000000000000000000000000
293 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
293 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
294 user: test
294 user: test
295 date: Thu Jan 01 00:00:09 1970 +0000
295 date: Thu Jan 01 00:00:09 1970 +0000
296 extra: branch=b
296 extra: branch=b
297 extra: close=1
297 extra: close=1
298 description:
298 description:
299 close this part branch too
299 close this part branch too
300
300
301
301
302 --- b branch should be inactive
302 --- b branch should be inactive
303
303
304 $ hg branches
304 $ hg branches
305 a branch name much longer than the default justification used by branches 7:10ff5895aa57
305 a branch name much longer than the default justification used by branches 7:10ff5895aa57
306 c 6:589736a22561 (inactive)
306 c 6:589736a22561 (inactive)
307 a 5:d8cbc61dbaa6 (inactive)
307 a 5:d8cbc61dbaa6 (inactive)
308 default 0:19709c5a4e75 (inactive)
308 default 0:19709c5a4e75 (inactive)
309 $ hg branches -c
309 $ hg branches -c
310 a branch name much longer than the default justification used by branches 7:10ff5895aa57
310 a branch name much longer than the default justification used by branches 7:10ff5895aa57
311 b 12:e3d49c0575d8 (closed)
311 b 12:e3d49c0575d8 (closed)
312 c 6:589736a22561 (inactive)
312 c 6:589736a22561 (inactive)
313 a 5:d8cbc61dbaa6 (inactive)
313 a 5:d8cbc61dbaa6 (inactive)
314 default 0:19709c5a4e75 (inactive)
314 default 0:19709c5a4e75 (inactive)
315 $ hg branches -a
315 $ hg branches -a
316 a branch name much longer than the default justification used by branches 7:10ff5895aa57
316 a branch name much longer than the default justification used by branches 7:10ff5895aa57
317 $ hg branches -q
317 $ hg branches -q
318 a branch name much longer than the default justification used by branches
318 a branch name much longer than the default justification used by branches
319 c
319 c
320 a
320 a
321 default
321 default
322 $ hg heads b
322 $ hg heads b
323 no open branch heads found on branches b
323 no open branch heads found on branches b
324 [1]
324 [1]
325 $ hg heads --closed b
325 $ hg heads --closed b
326 changeset: 12:e3d49c0575d8
326 changeset: 12:e3d49c0575d8
327 branch: b
327 branch: b
328 tag: tip
328 tag: tip
329 parent: 8:eebb944467c9
329 parent: 8:eebb944467c9
330 user: test
330 user: test
331 date: Thu Jan 01 00:00:09 1970 +0000
331 date: Thu Jan 01 00:00:09 1970 +0000
332 summary: close this part branch too
332 summary: close this part branch too
333
333
334 changeset: 11:d3f163457ebf
334 changeset: 11:d3f163457ebf
335 branch: b
335 branch: b
336 user: test
336 user: test
337 date: Thu Jan 01 00:00:09 1970 +0000
337 date: Thu Jan 01 00:00:09 1970 +0000
338 summary: prune bad branch
338 summary: prune bad branch
339
339
340 $ echo 'xxx4' >> b
340 $ echo 'xxx4' >> b
341 $ hg commit -d '9 0' -m 'reopen branch with a change'
341 $ hg commit -d '9 0' -m 'reopen branch with a change'
342 reopening closed branch head 12
342 reopening closed branch head 12
343
343
344 --- branch b is back in action
344 --- branch b is back in action
345
345
346 $ hg branches -a
346 $ hg branches -a
347 b 13:e23b5505d1ad
347 b 13:e23b5505d1ad
348 a branch name much longer than the default justification used by branches 7:10ff5895aa57
348 a branch name much longer than the default justification used by branches 7:10ff5895aa57
349
349
350 ---- test heads listings
350 ---- test heads listings
351
351
352 $ hg heads
352 $ hg heads
353 changeset: 13:e23b5505d1ad
353 changeset: 13:e23b5505d1ad
354 branch: b
354 branch: b
355 tag: tip
355 tag: tip
356 user: test
356 user: test
357 date: Thu Jan 01 00:00:09 1970 +0000
357 date: Thu Jan 01 00:00:09 1970 +0000
358 summary: reopen branch with a change
358 summary: reopen branch with a change
359
359
360 changeset: 7:10ff5895aa57
360 changeset: 7:10ff5895aa57
361 branch: a branch name much longer than the default justification used by branches
361 branch: a branch name much longer than the default justification used by branches
362 user: test
362 user: test
363 date: Thu Jan 01 00:00:06 1970 +0000
363 date: Thu Jan 01 00:00:06 1970 +0000
364 summary: Adding d branch
364 summary: Adding d branch
365
365
366 changeset: 6:589736a22561
366 changeset: 6:589736a22561
367 branch: c
367 branch: c
368 user: test
368 user: test
369 date: Thu Jan 01 00:00:05 1970 +0000
369 date: Thu Jan 01 00:00:05 1970 +0000
370 summary: Adding c branch
370 summary: Adding c branch
371
371
372 changeset: 5:d8cbc61dbaa6
372 changeset: 5:d8cbc61dbaa6
373 branch: a
373 branch: a
374 parent: 2:881fe2b92ad0
374 parent: 2:881fe2b92ad0
375 user: test
375 user: test
376 date: Thu Jan 01 00:00:04 1970 +0000
376 date: Thu Jan 01 00:00:04 1970 +0000
377 summary: Adding b branch head 2
377 summary: Adding b branch head 2
378
378
379 changeset: 0:19709c5a4e75
379 changeset: 0:19709c5a4e75
380 user: test
380 user: test
381 date: Thu Jan 01 00:00:00 1970 +0000
381 date: Thu Jan 01 00:00:00 1970 +0000
382 summary: Adding root node
382 summary: Adding root node
383
383
384
384
385 branch default
385 branch default
386
386
387 $ hg heads default
387 $ hg heads default
388 changeset: 0:19709c5a4e75
388 changeset: 0:19709c5a4e75
389 user: test
389 user: test
390 date: Thu Jan 01 00:00:00 1970 +0000
390 date: Thu Jan 01 00:00:00 1970 +0000
391 summary: Adding root node
391 summary: Adding root node
392
392
393
393
394 branch a
394 branch a
395
395
396 $ hg heads a
396 $ hg heads a
397 changeset: 5:d8cbc61dbaa6
397 changeset: 5:d8cbc61dbaa6
398 branch: a
398 branch: a
399 parent: 2:881fe2b92ad0
399 parent: 2:881fe2b92ad0
400 user: test
400 user: test
401 date: Thu Jan 01 00:00:04 1970 +0000
401 date: Thu Jan 01 00:00:04 1970 +0000
402 summary: Adding b branch head 2
402 summary: Adding b branch head 2
403
403
404 $ hg heads --active a
404 $ hg heads --active a
405 no open branch heads found on branches a
405 no open branch heads found on branches a
406 [1]
406 [1]
407
407
408 branch b
408 branch b
409
409
410 $ hg heads b
410 $ hg heads b
411 changeset: 13:e23b5505d1ad
411 changeset: 13:e23b5505d1ad
412 branch: b
412 branch: b
413 tag: tip
413 tag: tip
414 user: test
414 user: test
415 date: Thu Jan 01 00:00:09 1970 +0000
415 date: Thu Jan 01 00:00:09 1970 +0000
416 summary: reopen branch with a change
416 summary: reopen branch with a change
417
417
418 $ hg heads --closed b
418 $ hg heads --closed b
419 changeset: 13:e23b5505d1ad
419 changeset: 13:e23b5505d1ad
420 branch: b
420 branch: b
421 tag: tip
421 tag: tip
422 user: test
422 user: test
423 date: Thu Jan 01 00:00:09 1970 +0000
423 date: Thu Jan 01 00:00:09 1970 +0000
424 summary: reopen branch with a change
424 summary: reopen branch with a change
425
425
426 changeset: 11:d3f163457ebf
426 changeset: 11:d3f163457ebf
427 branch: b
427 branch: b
428 user: test
428 user: test
429 date: Thu Jan 01 00:00:09 1970 +0000
429 date: Thu Jan 01 00:00:09 1970 +0000
430 summary: prune bad branch
430 summary: prune bad branch
431
431
432
432
433 reclose branch
433 reclose branch
434
434
435 $ hg up -C c
435 $ hg up -C c
436 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
436 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
437 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
437 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
438 $ hg branches
438 $ hg branches
439 b 13:e23b5505d1ad
439 b 13:e23b5505d1ad
440 a branch name much longer than the default justification used by branches 7:10ff5895aa57
440 a branch name much longer than the default justification used by branches 7:10ff5895aa57
441 a 5:d8cbc61dbaa6 (inactive)
441 a 5:d8cbc61dbaa6 (inactive)
442 default 0:19709c5a4e75 (inactive)
442 default 0:19709c5a4e75 (inactive)
443 $ hg branches --closed
443 $ hg branches --closed
444 b 13:e23b5505d1ad
444 b 13:e23b5505d1ad
445 a branch name much longer than the default justification used by branches 7:10ff5895aa57
445 a branch name much longer than the default justification used by branches 7:10ff5895aa57
446 c 14:f894c25619d3 (closed)
446 c 14:f894c25619d3 (closed)
447 a 5:d8cbc61dbaa6 (inactive)
447 a 5:d8cbc61dbaa6 (inactive)
448 default 0:19709c5a4e75 (inactive)
448 default 0:19709c5a4e75 (inactive)
449
449
450 multihead branch
450 multihead branch
451
451
452 $ hg up -C default
452 $ hg up -C default
453 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
453 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
454 $ hg branch m
454 $ hg branch m
455 marked working directory as branch m
455 marked working directory as branch m
456 $ touch m
456 $ touch m
457 $ hg add m
457 $ hg add m
458 $ hg commit -d '10 0' -m 'multihead base'
458 $ hg commit -d '10 0' -m 'multihead base'
459 $ echo "m1" >m
459 $ echo "m1" >m
460 $ hg commit -d '10 0' -m 'head 1'
460 $ hg commit -d '10 0' -m 'head 1'
461 $ hg up -C '.^'
461 $ hg up -C '.^'
462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
463 $ echo "m2" >m
463 $ echo "m2" >m
464 $ hg commit -d '10 0' -m 'head 2'
464 $ hg commit -d '10 0' -m 'head 2'
465 created new head
465 created new head
466 $ hg log -b m
466 $ hg log -b m
467 changeset: 17:df343b0df04f
467 changeset: 17:df343b0df04f
468 branch: m
468 branch: m
469 tag: tip
469 tag: tip
470 parent: 15:f3447637f53e
470 parent: 15:f3447637f53e
471 user: test
471 user: test
472 date: Thu Jan 01 00:00:10 1970 +0000
472 date: Thu Jan 01 00:00:10 1970 +0000
473 summary: head 2
473 summary: head 2
474
474
475 changeset: 16:a58ca5d3bdf3
475 changeset: 16:a58ca5d3bdf3
476 branch: m
476 branch: m
477 user: test
477 user: test
478 date: Thu Jan 01 00:00:10 1970 +0000
478 date: Thu Jan 01 00:00:10 1970 +0000
479 summary: head 1
479 summary: head 1
480
480
481 changeset: 15:f3447637f53e
481 changeset: 15:f3447637f53e
482 branch: m
482 branch: m
483 parent: 0:19709c5a4e75
483 parent: 0:19709c5a4e75
484 user: test
484 user: test
485 date: Thu Jan 01 00:00:10 1970 +0000
485 date: Thu Jan 01 00:00:10 1970 +0000
486 summary: multihead base
486 summary: multihead base
487
487
488 $ hg heads --topo m
488 $ hg heads --topo m
489 changeset: 17:df343b0df04f
489 changeset: 17:df343b0df04f
490 branch: m
490 branch: m
491 tag: tip
491 tag: tip
492 parent: 15:f3447637f53e
492 parent: 15:f3447637f53e
493 user: test
493 user: test
494 date: Thu Jan 01 00:00:10 1970 +0000
494 date: Thu Jan 01 00:00:10 1970 +0000
495 summary: head 2
495 summary: head 2
496
496
497 changeset: 16:a58ca5d3bdf3
497 changeset: 16:a58ca5d3bdf3
498 branch: m
498 branch: m
499 user: test
499 user: test
500 date: Thu Jan 01 00:00:10 1970 +0000
500 date: Thu Jan 01 00:00:10 1970 +0000
501 summary: head 1
501 summary: head 1
502
502
503 $ hg branches
503 $ hg branches
504 m 17:df343b0df04f
504 m 17:df343b0df04f
505 b 13:e23b5505d1ad
505 b 13:e23b5505d1ad
506 a branch name much longer than the default justification used by branches 7:10ff5895aa57
506 a branch name much longer than the default justification used by branches 7:10ff5895aa57
507 a 5:d8cbc61dbaa6 (inactive)
507 a 5:d8cbc61dbaa6 (inactive)
508 default 0:19709c5a4e75 (inactive)
508 default 0:19709c5a4e75 (inactive)
509
509
510 partially merge multihead branch
510 partially merge multihead branch
511
511
512 $ hg up -C default
512 $ hg up -C default
513 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
513 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
514 $ hg branch md
514 $ hg branch md
515 marked working directory as branch md
515 marked working directory as branch md
516 $ hg merge m
516 $ hg merge m
517 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
517 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
518 (branch merge, don't forget to commit)
518 (branch merge, don't forget to commit)
519 $ hg commit -d '11 0' -m 'merge head 2'
519 $ hg commit -d '11 0' -m 'merge head 2'
520 $ hg heads --topo m
520 $ hg heads --topo m
521 changeset: 16:a58ca5d3bdf3
521 changeset: 16:a58ca5d3bdf3
522 branch: m
522 branch: m
523 user: test
523 user: test
524 date: Thu Jan 01 00:00:10 1970 +0000
524 date: Thu Jan 01 00:00:10 1970 +0000
525 summary: head 1
525 summary: head 1
526
526
527 $ hg branches
527 $ hg branches
528 md 18:c914c99f1fbb
528 md 18:c914c99f1fbb
529 m 17:df343b0df04f
529 m 17:df343b0df04f
530 b 13:e23b5505d1ad
530 b 13:e23b5505d1ad
531 a branch name much longer than the default justification used by branches 7:10ff5895aa57
531 a branch name much longer than the default justification used by branches 7:10ff5895aa57
532 a 5:d8cbc61dbaa6 (inactive)
532 a 5:d8cbc61dbaa6 (inactive)
533 default 0:19709c5a4e75 (inactive)
533 default 0:19709c5a4e75 (inactive)
534
534
535 partially close multihead branch
535 partially close multihead branch
536
536
537 $ hg up -C a58ca5d3bdf3
537 $ hg up -C a58ca5d3bdf3
538 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
538 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
539 $ hg commit -d '12 0' -m 'close head 1' --close-branch
539 $ hg commit -d '12 0' -m 'close head 1' --close-branch
540 $ hg heads --topo m
540 $ hg heads --topo m
541 changeset: 19:cd21a80baa3d
541 changeset: 19:cd21a80baa3d
542 branch: m
542 branch: m
543 tag: tip
543 tag: tip
544 parent: 16:a58ca5d3bdf3
544 parent: 16:a58ca5d3bdf3
545 user: test
545 user: test
546 date: Thu Jan 01 00:00:12 1970 +0000
546 date: Thu Jan 01 00:00:12 1970 +0000
547 summary: close head 1
547 summary: close head 1
548
548
549 $ hg branches
549 $ hg branches
550 md 18:c914c99f1fbb
550 md 18:c914c99f1fbb
551 b 13:e23b5505d1ad
551 b 13:e23b5505d1ad
552 a branch name much longer than the default justification used by branches 7:10ff5895aa57
552 a branch name much longer than the default justification used by branches 7:10ff5895aa57
553 m 17:df343b0df04f (inactive)
553 m 17:df343b0df04f (inactive)
554 a 5:d8cbc61dbaa6 (inactive)
554 a 5:d8cbc61dbaa6 (inactive)
555 default 0:19709c5a4e75 (inactive)
555 default 0:19709c5a4e75 (inactive)
556
556
557 default branch colors:
557 default branch colors:
558
558
559 $ cat <<EOF >> $HGRCPATH
559 $ cat <<EOF >> $HGRCPATH
560 > [extensions]
560 > [extensions]
561 > color =
561 > color =
562 > [color]
562 > [color]
563 > mode = ansi
563 > mode = ansi
564 > EOF
564 > EOF
565
565
566 $ hg up -C b
566 $ hg up -C b
567 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
567 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
568 $ hg branches --color=always
568 $ hg branches --color=always
569 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
569 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
570 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
570 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
571 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
571 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
572 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
572 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
573 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
573 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
574 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
574 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
575
575
576 default closed branch color:
576 default closed branch color:
577
577
578 $ hg branches --color=always --closed
578 $ hg branches --color=always --closed
579 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
579 \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc)
580 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
580 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
581 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
581 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
582 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
582 \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc)
583 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
583 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
584 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
584 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
585 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
585 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
586
586
587 $ cat <<EOF >> $HGRCPATH
587 $ cat <<EOF >> $HGRCPATH
588 > [extensions]
588 > [extensions]
589 > color =
589 > color =
590 > [color]
590 > [color]
591 > branches.active = green
591 > branches.active = green
592 > branches.closed = blue
592 > branches.closed = blue
593 > branches.current = red
593 > branches.current = red
594 > branches.inactive = magenta
594 > branches.inactive = magenta
595 > log.changeset = cyan
595 > log.changeset = cyan
596 > EOF
596 > EOF
597
597
598 custom branch colors:
598 custom branch colors:
599
599
600 $ hg branches --color=always
600 $ hg branches --color=always
601 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
601 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
602 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
602 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
603 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
603 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
604 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
604 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
605 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
605 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
606 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
606 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
607
607
608 custom closed branch color:
608 custom closed branch color:
609
609
610 $ hg branches --color=always --closed
610 $ hg branches --color=always --closed
611 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
611 \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc)
612 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
612 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
613 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
613 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
614 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
614 \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc)
615 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
615 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
616 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
616 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
617 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
617 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
618
618
619 template output:
619 template output:
620
620
621 $ hg branches -Tjson --closed
621 $ hg branches -Tjson --closed
622 [
622 [
623 {
623 {
624 "active": true,
624 "active": true,
625 "branch": "md",
625 "branch": "md",
626 "closed": false,
626 "closed": false,
627 "current": false,
627 "current": false,
628 "node": "c914c99f1fbb2b1d785a0a939ed3f67275df18e9",
628 "node": "c914c99f1fbb2b1d785a0a939ed3f67275df18e9",
629 "rev": 18
629 "rev": 18
630 },
630 },
631 {
631 {
632 "active": true,
632 "active": true,
633 "branch": "b",
633 "branch": "b",
634 "closed": false,
634 "closed": false,
635 "current": true,
635 "current": true,
636 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
636 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
637 "rev": 13
637 "rev": 13
638 },
638 },
639 {
639 {
640 "active": true,
640 "active": true,
641 "branch": "a branch name much longer than the default justification used by branches",
641 "branch": "a branch name much longer than the default justification used by branches",
642 "closed": false,
642 "closed": false,
643 "current": false,
643 "current": false,
644 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
644 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
645 "rev": 7
645 "rev": 7
646 },
646 },
647 {
647 {
648 "active": false,
648 "active": false,
649 "branch": "m",
649 "branch": "m",
650 "closed": false,
650 "closed": false,
651 "current": false,
651 "current": false,
652 "node": "df343b0df04feb2a946cd4b6e9520e552fef14ee",
652 "node": "df343b0df04feb2a946cd4b6e9520e552fef14ee",
653 "rev": 17
653 "rev": 17
654 },
654 },
655 {
655 {
656 "active": false,
656 "active": false,
657 "branch": "c",
657 "branch": "c",
658 "closed": true,
658 "closed": true,
659 "current": false,
659 "current": false,
660 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
660 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
661 "rev": 14
661 "rev": 14
662 },
662 },
663 {
663 {
664 "active": false,
664 "active": false,
665 "branch": "a",
665 "branch": "a",
666 "closed": false,
666 "closed": false,
667 "current": false,
667 "current": false,
668 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
668 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
669 "rev": 5
669 "rev": 5
670 },
670 },
671 {
671 {
672 "active": false,
672 "active": false,
673 "branch": "default",
673 "branch": "default",
674 "closed": false,
674 "closed": false,
675 "current": false,
675 "current": false,
676 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
676 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
677 "rev": 0
677 "rev": 0
678 }
678 }
679 ]
679 ]
680
680
681 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
681 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
682 c
682 c
683
683
684 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
684 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
685 md: merge head 2
685 md: merge head 2
686 b: reopen branch with a change
686 b: reopen branch with a change
687 a: Adding d branch
687 a: Adding d branch
688 m: head 2
688 m: head 2
689 a: Adding b branch head 2
689 a: Adding b branch head 2
690 default: Adding root node
690 default: Adding root node
691
691
692 $ cat <<'EOF' > "$TESTTMP/map-myjson"
692 $ cat <<'EOF' > "$TESTTMP/map-myjson"
693 > docheader = '\{\n'
693 > docheader = '\{\n'
694 > docfooter = '\n}\n'
694 > docfooter = '\n}\n'
695 > separator = ',\n'
695 > separator = ',\n'
696 > branches = ' {dict(branch, node|short)|json}'
696 > branches = ' {dict(branch, node|short)|json}'
697 > EOF
697 > EOF
698 $ hg branches -T "$TESTTMP/map-myjson"
698 $ hg branches -T "$TESTTMP/map-myjson"
699 {
699 {
700 {"branch": "md", "node": "c914c99f1fbb"},
700 {"branch": "md", "node": "c914c99f1fbb"},
701 {"branch": "b", "node": "e23b5505d1ad"},
701 {"branch": "b", "node": "e23b5505d1ad"},
702 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
702 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
703 {"branch": "m", "node": "df343b0df04f"},
703 {"branch": "m", "node": "df343b0df04f"},
704 {"branch": "a", "node": "d8cbc61dbaa6"},
704 {"branch": "a", "node": "d8cbc61dbaa6"},
705 {"branch": "default", "node": "19709c5a4e75"}
705 {"branch": "default", "node": "19709c5a4e75"}
706 }
706 }
707
707
708 $ cat <<'EOF' >> .hg/hgrc
708 $ cat <<'EOF' >> .hg/hgrc
709 > [templates]
709 > [templates]
710 > myjson = ' {dict(branch, node|short)|json}'
710 > myjson = ' {dict(branch, node|short)|json}'
711 > myjson:docheader = '\{\n'
711 > myjson:docheader = '\{\n'
712 > myjson:docfooter = '\n}\n'
712 > myjson:docfooter = '\n}\n'
713 > myjson:separator = ',\n'
713 > myjson:separator = ',\n'
714 > EOF
714 > EOF
715 $ hg branches -T myjson
715 $ hg branches -T myjson
716 {
716 {
717 {"branch": "md", "node": "c914c99f1fbb"},
717 {"branch": "md", "node": "c914c99f1fbb"},
718 {"branch": "b", "node": "e23b5505d1ad"},
718 {"branch": "b", "node": "e23b5505d1ad"},
719 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
719 {"branch": "a branch *", "node": "10ff5895aa57"}, (glob)
720 {"branch": "m", "node": "df343b0df04f"},
720 {"branch": "m", "node": "df343b0df04f"},
721 {"branch": "a", "node": "d8cbc61dbaa6"},
721 {"branch": "a", "node": "d8cbc61dbaa6"},
722 {"branch": "default", "node": "19709c5a4e75"}
722 {"branch": "default", "node": "19709c5a4e75"}
723 }
723 }
724
724
725 $ cat <<'EOF' >> .hg/hgrc
725 $ cat <<'EOF' >> .hg/hgrc
726 > [templates]
726 > [templates]
727 > :docheader = 'should not be selected as a docheader for literal templates\n'
727 > :docheader = 'should not be selected as a docheader for literal templates\n'
728 > EOF
728 > EOF
729 $ hg branches -T '{branch}\n'
729 $ hg branches -T '{branch}\n'
730 md
730 md
731 b
731 b
732 a branch name much longer than the default justification used by branches
732 a branch name much longer than the default justification used by branches
733 m
733 m
734 a
734 a
735 default
735 default
736
736
737 Tests of revision branch name caching
737 Tests of revision branch name caching
738
738
739 We rev branch cache is updated automatically. In these tests we use a trick to
739 We rev branch cache is updated automatically. In these tests we use a trick to
740 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
740 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
741 rebuild that also will populate the rev branch cache.
741 rebuild that also will populate the rev branch cache.
742
742
743 revision branch cache is created when building the branch head cache
743 revision branch cache is created when building the branch head cache
744 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
744 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
745 5
745 5
746 $ f --hexdump --size .hg/cache/rbc-*
746 $ f --hexdump --size .hg/cache/rbc-*
747 .hg/cache/rbc-names-v1: size=92
747 .hg/cache/rbc-names-v1: size=92
748 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
748 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
749 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
749 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
750 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
750 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
751 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
751 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
752 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
752 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
753 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 |ranches.m.md|
753 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 |ranches.m.md|
754 .hg/cache/rbc-revs-v1: size=160
754 .hg/cache/rbc-revs-v1: size=160
755 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
755 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
756 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
756 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
757 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
757 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
758 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
758 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
759 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
759 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
760 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
760 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
761 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
761 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
762 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
762 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
763 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
763 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
764 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
764 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
765
765
766 no errors when revbranchcache is not writable
766 no errors when revbranchcache is not writable
767
767
768 $ echo >> .hg/cache/rbc-revs-v1
768 $ echo >> .hg/cache/rbc-revs-v1
769 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
769 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
770 $ mkdir .hg/cache/rbc-revs-v1
770 $ mkdir .hg/cache/rbc-revs-v1
771 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
771 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
772 5
772 5
773 $ rmdir .hg/cache/rbc-revs-v1
773 $ rmdir .hg/cache/rbc-revs-v1
774 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
774 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
775
775
776 no errors when wlock cannot be acquired
776 no errors when wlock cannot be acquired
777
777
778 #if unix-permissions
778 #if unix-permissions
779 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
779 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
780 $ rm -f .hg/cache/branch*
780 $ rm -f .hg/cache/branch*
781 $ chmod 555 .hg
781 $ chmod 555 .hg
782 $ hg head a -T '{rev}\n'
782 $ hg head a -T '{rev}\n'
783 5
783 5
784 $ chmod 755 .hg
784 $ chmod 755 .hg
785 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
785 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
786 #endif
786 #endif
787
787
788 recovery from invalid cache revs file with trailing data
788 recovery from invalid cache revs file with trailing data
789 $ echo >> .hg/cache/rbc-revs-v1
789 $ echo >> .hg/cache/rbc-revs-v1
790 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
790 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
791 5
791 5
792 truncating cache/rbc-revs-v1 to 160
792 truncating cache/rbc-revs-v1 to 160
793 $ f --size .hg/cache/rbc-revs*
793 $ f --size .hg/cache/rbc-revs*
794 .hg/cache/rbc-revs-v1: size=160
794 .hg/cache/rbc-revs-v1: size=160
795 recovery from invalid cache file with partial last record
795 recovery from invalid cache file with partial last record
796 $ mv .hg/cache/rbc-revs-v1 .
796 $ mv .hg/cache/rbc-revs-v1 .
797 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
797 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
798 $ f --size .hg/cache/rbc-revs*
798 $ f --size .hg/cache/rbc-revs*
799 .hg/cache/rbc-revs-v1: size=119
799 .hg/cache/rbc-revs-v1: size=119
800 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
800 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
801 5
801 5
802 truncating cache/rbc-revs-v1 to 112
802 truncating cache/rbc-revs-v1 to 112
803 $ f --size .hg/cache/rbc-revs*
803 $ f --size .hg/cache/rbc-revs*
804 .hg/cache/rbc-revs-v1: size=160
804 .hg/cache/rbc-revs-v1: size=160
805 recovery from invalid cache file with missing record - no truncation
805 recovery from invalid cache file with missing record - no truncation
806 $ mv .hg/cache/rbc-revs-v1 .
806 $ mv .hg/cache/rbc-revs-v1 .
807 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
807 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
808 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
808 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
809 5
809 5
810 $ f --size .hg/cache/rbc-revs*
810 $ f --size .hg/cache/rbc-revs*
811 .hg/cache/rbc-revs-v1: size=160
811 .hg/cache/rbc-revs-v1: size=160
812 recovery from invalid cache file with some bad records
812 recovery from invalid cache file with some bad records
813 $ mv .hg/cache/rbc-revs-v1 .
813 $ mv .hg/cache/rbc-revs-v1 .
814 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
814 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
815 $ f --size .hg/cache/rbc-revs*
815 $ f --size .hg/cache/rbc-revs*
816 .hg/cache/rbc-revs-v1: size=8
816 .hg/cache/rbc-revs-v1: size=8
817 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
817 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
818 $ f --size .hg/cache/rbc-revs*
818 $ f --size .hg/cache/rbc-revs*
819 .hg/cache/rbc-revs-v1: size=120
819 .hg/cache/rbc-revs-v1: size=120
820 $ hg log -r 'branch(.)' -T '{rev} ' --debug
820 $ hg log -r 'branch(.)' -T '{rev} ' --debug
821 history modification detected - truncating revision branch cache to revision 13
821 history modification detected - truncating revision branch cache to revision 13
822 history modification detected - truncating revision branch cache to revision 1
822 history modification detected - truncating revision branch cache to revision 1
823 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
823 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
824 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
824 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
825 5
825 5
826 truncating cache/rbc-revs-v1 to 104
826 truncating cache/rbc-revs-v1 to 104
827 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
827 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
828 .hg/cache/rbc-revs-v1: size=160
828 .hg/cache/rbc-revs-v1: size=160
829 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
829 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
830 cache is updated when committing
830 cache is updated when committing
831 $ hg branch i-will-regret-this
831 $ hg branch i-will-regret-this
832 marked working directory as branch i-will-regret-this
832 marked working directory as branch i-will-regret-this
833 $ hg ci -m regrets
833 $ hg ci -m regrets
834 $ f --size .hg/cache/rbc-*
834 $ f --size .hg/cache/rbc-*
835 .hg/cache/rbc-names-v1: size=111
835 .hg/cache/rbc-names-v1: size=111
836 .hg/cache/rbc-revs-v1: size=168
836 .hg/cache/rbc-revs-v1: size=168
837 update after rollback - the cache will be correct but rbc-names will will still
837 update after rollback - the cache will be correct but rbc-names will will still
838 contain the branch name even though it no longer is used
838 contain the branch name even though it no longer is used
839 $ hg up -qr '.^'
839 $ hg up -qr '.^'
840 $ hg rollback -qf
840 $ hg rollback -qf
841 $ f --size --hexdump .hg/cache/rbc-*
841 $ f --size --hexdump .hg/cache/rbc-*
842 .hg/cache/rbc-names-v1: size=111
842 .hg/cache/rbc-names-v1: size=111
843 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
843 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
844 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
844 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
845 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
845 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
846 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
846 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
847 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
847 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
848 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 00 69 2d 77 |ranches.m.md.i-w|
848 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 00 69 2d 77 |ranches.m.md.i-w|
849 0060: 69 6c 6c 2d 72 65 67 72 65 74 2d 74 68 69 73 |ill-regret-this|
849 0060: 69 6c 6c 2d 72 65 67 72 65 74 2d 74 68 69 73 |ill-regret-this|
850 .hg/cache/rbc-revs-v1: size=160
850 .hg/cache/rbc-revs-v1: size=160
851 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
851 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
852 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
852 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
853 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
853 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
854 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
854 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
855 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
855 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
856 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
856 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
857 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
857 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
858 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
858 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....|
859 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
859 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....|
860 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
860 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......|
861 cache is updated/truncated when stripping - it is thus very hard to get in a
861 cache is updated/truncated when stripping - it is thus very hard to get in a
862 situation where the cache is out of sync and the hash check detects it
862 situation where the cache is out of sync and the hash check detects it
863 $ hg --config extensions.strip= strip -r tip --nob
863 $ hg --config extensions.strip= strip -r tip --nob
864 $ f --size .hg/cache/rbc-revs*
864 $ f --size .hg/cache/rbc-revs*
865 .hg/cache/rbc-revs-v1: size=152
865 .hg/cache/rbc-revs-v1: size=152
866
866
867 cache is rebuilt when corruption is detected
867 cache is rebuilt when corruption is detected
868 $ echo > .hg/cache/rbc-names-v1
868 $ echo > .hg/cache/rbc-names-v1
869 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
869 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
870 referenced branch names not found - rebuilding revision branch cache from scratch
870 referenced branch names not found - rebuilding revision branch cache from scratch
871 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
871 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
872 $ f --size --hexdump .hg/cache/rbc-*
872 $ f --size --hexdump .hg/cache/rbc-*
873 .hg/cache/rbc-names-v1: size=84
873 .hg/cache/rbc-names-v1: size=84
874 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
874 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
875 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
875 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
876 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
876 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
877 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
877 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
878 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 00 |sed by branches.|
878 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 00 |sed by branches.|
879 0050: 6d 00 6d 64 |m.md|
879 0050: 6d 00 6d 64 |m.md|
880 .hg/cache/rbc-revs-v1: size=152
880 .hg/cache/rbc-revs-v1: size=152
881 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
881 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
882 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
882 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
883 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
883 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
884 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
884 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
885 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
885 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
886 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
886 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
887 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
887 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
888 0070: f8 94 c2 56 80 00 00 02 f3 44 76 37 00 00 00 04 |...V.....Dv7....|
888 0070: f8 94 c2 56 80 00 00 02 f3 44 76 37 00 00 00 04 |...V.....Dv7....|
889 0080: a5 8c a5 d3 00 00 00 04 df 34 3b 0d 00 00 00 04 |.........4;.....|
889 0080: a5 8c a5 d3 00 00 00 04 df 34 3b 0d 00 00 00 04 |.........4;.....|
890 0090: c9 14 c9 9f 00 00 00 05 |........|
890 0090: c9 14 c9 9f 00 00 00 05 |........|
891
891
892 Test that cache files are created and grows correctly:
892 Test that cache files are created and grows correctly:
893
893
894 $ rm .hg/cache/rbc*
894 $ rm .hg/cache/rbc*
895 $ hg log -r "5 & branch(5)" -T "{rev}\n"
895 $ hg log -r "5 & branch(5)" -T "{rev}\n"
896 5
896 5
897 $ f --size --hexdump .hg/cache/rbc-*
897 $ f --size --hexdump .hg/cache/rbc-*
898 .hg/cache/rbc-names-v1: size=1
898 .hg/cache/rbc-names-v1: size=1
899 0000: 61 |a|
899 0000: 61 |a|
900 .hg/cache/rbc-revs-v1: size=152
900 .hg/cache/rbc-revs-v1: size=152
901 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
901 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
902 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
902 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
903 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
903 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
904 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
904 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
905 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
905 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
906 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
906 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
907 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
907 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
908 0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
908 0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
909 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
909 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
910 0090: 00 00 00 00 00 00 00 00 |........|
910 0090: 00 00 00 00 00 00 00 00 |........|
911
911
912 $ cd ..
912 $ cd ..
913
913
914 Test for multiple incorrect branch cache entries:
914 Test for multiple incorrect branch cache entries:
915
915
916 $ hg init b
916 $ hg init b
917 $ cd b
917 $ cd b
918 $ touch f
918 $ touch f
919 $ hg ci -Aqmf
919 $ hg ci -Aqmf
920 $ echo >> f
920 $ echo >> f
921 $ hg ci -Amf
921 $ hg ci -Amf
922 $ hg branch -q branch
922 $ hg branch -q branch
923 $ hg ci -Amf
923 $ hg ci -Amf
924
924
925 $ f --size --hexdump .hg/cache/rbc-*
925 $ f --size --hexdump .hg/cache/rbc-*
926 .hg/cache/rbc-names-v1: size=14
926 .hg/cache/rbc-names-v1: size=14
927 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
927 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
928 .hg/cache/rbc-revs-v1: size=24
928 .hg/cache/rbc-revs-v1: size=24
929 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
929 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
930 0010: 56 46 78 69 00 00 00 01 |VFxi....|
930 0010: 56 46 78 69 00 00 00 01 |VFxi....|
931 $ : > .hg/cache/rbc-revs-v1
931 $ : > .hg/cache/rbc-revs-v1
932
932
933 No superfluous rebuilding of cache:
933 No superfluous rebuilding of cache:
934 $ hg log -r "branch(null)&branch(branch)" --debug
934 $ hg log -r "branch(null)&branch(branch)" --debug
935 $ f --size --hexdump .hg/cache/rbc-*
935 $ f --size --hexdump .hg/cache/rbc-*
936 .hg/cache/rbc-names-v1: size=14
936 .hg/cache/rbc-names-v1: size=14
937 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
937 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
938 .hg/cache/rbc-revs-v1: size=24
938 .hg/cache/rbc-revs-v1: size=24
939 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
939 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
940 0010: 56 46 78 69 00 00 00 01 |VFxi....|
940 0010: 56 46 78 69 00 00 00 01 |VFxi....|
941
941
942 $ cd ..
942 $ cd ..
943
943
944 Test to make sure that `--close-branch` only works on a branch head:
944 Test to make sure that `--close-branch` only works on a branch head:
945 --------------------------------------------------------------------
945 --------------------------------------------------------------------
946 $ hg init closebranch
946 $ hg init closebranch
947 $ cd closebranch
947 $ cd closebranch
948 $ for ch in a b c; do
948 $ for ch in a b c; do
949 > echo $ch > $ch
949 > echo $ch > $ch
950 > hg add $ch
950 > hg add $ch
951 > hg ci -m "added "$ch
951 > hg ci -m "added "$ch
952 > done;
952 > done;
953
953
954 $ hg up -r "desc('added b')"
954 $ hg up -r "desc('added b')"
955 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
955 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
956
956
957 trying to close branch from a cset which is not a branch head
957 trying to close branch from a cset which is not a branch head
958 it should abort:
958 it should abort:
959 $ hg ci -m "closing branch" --close-branch
959 $ hg ci -m "closing branch" --close-branch
960 abort: can only close branch heads
960 abort: can only close branch heads
961 [255]
961 [255]
962
962
963 $ hg up 0
963 $ hg up 0
964 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
964 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
965 $ hg log -GT "{rev}: {node|short} {desc|firstline}\n\t{branch}\n\n"
965 $ hg log -GT "{rev}: {node|short} {desc|firstline}\n\t{branch}\n\n"
966 o 2: 155349b645be added c
966 o 2: 155349b645be added c
967 | default
967 | default
968 |
968 |
969 o 1: 5f6d8a4bf34a added b
969 o 1: 5f6d8a4bf34a added b
970 | default
970 | default
971 |
971 |
972 @ 0: 9092f1db7931 added a
972 @ 0: 9092f1db7931 added a
973 default
973 default
974
974
General Comments 0
You need to be logged in to leave comments. Login now