##// END OF EJS Templates
branch: abort if closing branch from a non-branchhead cset...
Sushil khanchi -
r42388:8d14d915 default
parent child Browse files
Show More
@@ -1,6258 +1,6260 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 not bheads:
1677 raise error.Abort(_('can only close branch heads'))
1677 raise error.Abort(_('can only close branch heads'))
1678 elif branch == repo['.'].branch() and repo['.'].node() not in bheads:
1679 raise error.Abort(_('can only close branch heads'))
1678 elif opts.get('amend'):
1680 elif opts.get('amend'):
1679 if (repo['.'].p1().branch() != branch and
1681 if (repo['.'].p1().branch() != branch and
1680 repo['.'].p2().branch() != branch):
1682 repo['.'].p2().branch() != branch):
1681 raise error.Abort(_('can only close branch heads'))
1683 raise error.Abort(_('can only close branch heads'))
1682
1684
1683 if opts.get('amend'):
1685 if opts.get('amend'):
1684 if ui.configbool('ui', 'commitsubrepos'):
1686 if ui.configbool('ui', 'commitsubrepos'):
1685 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1687 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1686
1688
1687 old = repo['.']
1689 old = repo['.']
1688 rewriteutil.precheck(repo, [old.rev()], 'amend')
1690 rewriteutil.precheck(repo, [old.rev()], 'amend')
1689
1691
1690 # Currently histedit gets confused if an amend happens while histedit
1692 # Currently histedit gets confused if an amend happens while histedit
1691 # is in progress. Since we have a checkunfinished command, we are
1693 # is in progress. Since we have a checkunfinished command, we are
1692 # temporarily honoring it.
1694 # temporarily honoring it.
1693 #
1695 #
1694 # Note: eventually this guard will be removed. Please do not expect
1696 # Note: eventually this guard will be removed. Please do not expect
1695 # this behavior to remain.
1697 # this behavior to remain.
1696 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1698 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1697 cmdutil.checkunfinished(repo)
1699 cmdutil.checkunfinished(repo)
1698
1700
1699 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1701 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1700 if node == old.node():
1702 if node == old.node():
1701 ui.status(_("nothing changed\n"))
1703 ui.status(_("nothing changed\n"))
1702 return 1
1704 return 1
1703 else:
1705 else:
1704 def commitfunc(ui, repo, message, match, opts):
1706 def commitfunc(ui, repo, message, match, opts):
1705 overrides = {}
1707 overrides = {}
1706 if opts.get('secret'):
1708 if opts.get('secret'):
1707 overrides[('phases', 'new-commit')] = 'secret'
1709 overrides[('phases', 'new-commit')] = 'secret'
1708
1710
1709 baseui = repo.baseui
1711 baseui = repo.baseui
1710 with baseui.configoverride(overrides, 'commit'):
1712 with baseui.configoverride(overrides, 'commit'):
1711 with ui.configoverride(overrides, 'commit'):
1713 with ui.configoverride(overrides, 'commit'):
1712 editform = cmdutil.mergeeditform(repo[None],
1714 editform = cmdutil.mergeeditform(repo[None],
1713 'commit.normal')
1715 'commit.normal')
1714 editor = cmdutil.getcommiteditor(
1716 editor = cmdutil.getcommiteditor(
1715 editform=editform, **pycompat.strkwargs(opts))
1717 editform=editform, **pycompat.strkwargs(opts))
1716 return repo.commit(message,
1718 return repo.commit(message,
1717 opts.get('user'),
1719 opts.get('user'),
1718 opts.get('date'),
1720 opts.get('date'),
1719 match,
1721 match,
1720 editor=editor,
1722 editor=editor,
1721 extra=extra)
1723 extra=extra)
1722
1724
1723 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1725 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1724
1726
1725 if not node:
1727 if not node:
1726 stat = cmdutil.postcommitstatus(repo, pats, opts)
1728 stat = cmdutil.postcommitstatus(repo, pats, opts)
1727 if stat[3]:
1729 if stat[3]:
1728 ui.status(_("nothing changed (%d missing files, see "
1730 ui.status(_("nothing changed (%d missing files, see "
1729 "'hg status')\n") % len(stat[3]))
1731 "'hg status')\n") % len(stat[3]))
1730 else:
1732 else:
1731 ui.status(_("nothing changed\n"))
1733 ui.status(_("nothing changed\n"))
1732 return 1
1734 return 1
1733
1735
1734 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1736 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1735
1737
1736 @command('config|showconfig|debugconfig',
1738 @command('config|showconfig|debugconfig',
1737 [('u', 'untrusted', None, _('show untrusted configuration options')),
1739 [('u', 'untrusted', None, _('show untrusted configuration options')),
1738 ('e', 'edit', None, _('edit user config')),
1740 ('e', 'edit', None, _('edit user config')),
1739 ('l', 'local', None, _('edit repository config')),
1741 ('l', 'local', None, _('edit repository config')),
1740 ('g', 'global', None, _('edit global config'))] + formatteropts,
1742 ('g', 'global', None, _('edit global config'))] + formatteropts,
1741 _('[-u] [NAME]...'),
1743 _('[-u] [NAME]...'),
1742 helpcategory=command.CATEGORY_HELP,
1744 helpcategory=command.CATEGORY_HELP,
1743 optionalrepo=True,
1745 optionalrepo=True,
1744 intents={INTENT_READONLY})
1746 intents={INTENT_READONLY})
1745 def config(ui, repo, *values, **opts):
1747 def config(ui, repo, *values, **opts):
1746 """show combined config settings from all hgrc files
1748 """show combined config settings from all hgrc files
1747
1749
1748 With no arguments, print names and values of all config items.
1750 With no arguments, print names and values of all config items.
1749
1751
1750 With one argument of the form section.name, print just the value
1752 With one argument of the form section.name, print just the value
1751 of that config item.
1753 of that config item.
1752
1754
1753 With multiple arguments, print names and values of all config
1755 With multiple arguments, print names and values of all config
1754 items with matching section names or section.names.
1756 items with matching section names or section.names.
1755
1757
1756 With --edit, start an editor on the user-level config file. With
1758 With --edit, start an editor on the user-level config file. With
1757 --global, edit the system-wide config file. With --local, edit the
1759 --global, edit the system-wide config file. With --local, edit the
1758 repository-level config file.
1760 repository-level config file.
1759
1761
1760 With --debug, the source (filename and line number) is printed
1762 With --debug, the source (filename and line number) is printed
1761 for each config item.
1763 for each config item.
1762
1764
1763 See :hg:`help config` for more information about config files.
1765 See :hg:`help config` for more information about config files.
1764
1766
1765 .. container:: verbose
1767 .. container:: verbose
1766
1768
1767 Template:
1769 Template:
1768
1770
1769 The following keywords are supported. See also :hg:`help templates`.
1771 The following keywords are supported. See also :hg:`help templates`.
1770
1772
1771 :name: String. Config name.
1773 :name: String. Config name.
1772 :source: String. Filename and line number where the item is defined.
1774 :source: String. Filename and line number where the item is defined.
1773 :value: String. Config value.
1775 :value: String. Config value.
1774
1776
1775 Returns 0 on success, 1 if NAME does not exist.
1777 Returns 0 on success, 1 if NAME does not exist.
1776
1778
1777 """
1779 """
1778
1780
1779 opts = pycompat.byteskwargs(opts)
1781 opts = pycompat.byteskwargs(opts)
1780 if opts.get('edit') or opts.get('local') or opts.get('global'):
1782 if opts.get('edit') or opts.get('local') or opts.get('global'):
1781 if opts.get('local') and opts.get('global'):
1783 if opts.get('local') and opts.get('global'):
1782 raise error.Abort(_("can't use --local and --global together"))
1784 raise error.Abort(_("can't use --local and --global together"))
1783
1785
1784 if opts.get('local'):
1786 if opts.get('local'):
1785 if not repo:
1787 if not repo:
1786 raise error.Abort(_("can't use --local outside a repository"))
1788 raise error.Abort(_("can't use --local outside a repository"))
1787 paths = [repo.vfs.join('hgrc')]
1789 paths = [repo.vfs.join('hgrc')]
1788 elif opts.get('global'):
1790 elif opts.get('global'):
1789 paths = rcutil.systemrcpath()
1791 paths = rcutil.systemrcpath()
1790 else:
1792 else:
1791 paths = rcutil.userrcpath()
1793 paths = rcutil.userrcpath()
1792
1794
1793 for f in paths:
1795 for f in paths:
1794 if os.path.exists(f):
1796 if os.path.exists(f):
1795 break
1797 break
1796 else:
1798 else:
1797 if opts.get('global'):
1799 if opts.get('global'):
1798 samplehgrc = uimod.samplehgrcs['global']
1800 samplehgrc = uimod.samplehgrcs['global']
1799 elif opts.get('local'):
1801 elif opts.get('local'):
1800 samplehgrc = uimod.samplehgrcs['local']
1802 samplehgrc = uimod.samplehgrcs['local']
1801 else:
1803 else:
1802 samplehgrc = uimod.samplehgrcs['user']
1804 samplehgrc = uimod.samplehgrcs['user']
1803
1805
1804 f = paths[0]
1806 f = paths[0]
1805 fp = open(f, "wb")
1807 fp = open(f, "wb")
1806 fp.write(util.tonativeeol(samplehgrc))
1808 fp.write(util.tonativeeol(samplehgrc))
1807 fp.close()
1809 fp.close()
1808
1810
1809 editor = ui.geteditor()
1811 editor = ui.geteditor()
1810 ui.system("%s \"%s\"" % (editor, f),
1812 ui.system("%s \"%s\"" % (editor, f),
1811 onerr=error.Abort, errprefix=_("edit failed"),
1813 onerr=error.Abort, errprefix=_("edit failed"),
1812 blockedtag='config_edit')
1814 blockedtag='config_edit')
1813 return
1815 return
1814 ui.pager('config')
1816 ui.pager('config')
1815 fm = ui.formatter('config', opts)
1817 fm = ui.formatter('config', opts)
1816 for t, f in rcutil.rccomponents():
1818 for t, f in rcutil.rccomponents():
1817 if t == 'path':
1819 if t == 'path':
1818 ui.debug('read config from: %s\n' % f)
1820 ui.debug('read config from: %s\n' % f)
1819 elif t == 'items':
1821 elif t == 'items':
1820 for section, name, value, source in f:
1822 for section, name, value, source in f:
1821 ui.debug('set config by: %s\n' % source)
1823 ui.debug('set config by: %s\n' % source)
1822 else:
1824 else:
1823 raise error.ProgrammingError('unknown rctype: %s' % t)
1825 raise error.ProgrammingError('unknown rctype: %s' % t)
1824 untrusted = bool(opts.get('untrusted'))
1826 untrusted = bool(opts.get('untrusted'))
1825
1827
1826 selsections = selentries = []
1828 selsections = selentries = []
1827 if values:
1829 if values:
1828 selsections = [v for v in values if '.' not in v]
1830 selsections = [v for v in values if '.' not in v]
1829 selentries = [v for v in values if '.' in v]
1831 selentries = [v for v in values if '.' in v]
1830 uniquesel = (len(selentries) == 1 and not selsections)
1832 uniquesel = (len(selentries) == 1 and not selsections)
1831 selsections = set(selsections)
1833 selsections = set(selsections)
1832 selentries = set(selentries)
1834 selentries = set(selentries)
1833
1835
1834 matched = False
1836 matched = False
1835 for section, name, value in ui.walkconfig(untrusted=untrusted):
1837 for section, name, value in ui.walkconfig(untrusted=untrusted):
1836 source = ui.configsource(section, name, untrusted)
1838 source = ui.configsource(section, name, untrusted)
1837 value = pycompat.bytestr(value)
1839 value = pycompat.bytestr(value)
1838 if fm.isplain():
1840 if fm.isplain():
1839 source = source or 'none'
1841 source = source or 'none'
1840 value = value.replace('\n', '\\n')
1842 value = value.replace('\n', '\\n')
1841 entryname = section + '.' + name
1843 entryname = section + '.' + name
1842 if values and not (section in selsections or entryname in selentries):
1844 if values and not (section in selsections or entryname in selentries):
1843 continue
1845 continue
1844 fm.startitem()
1846 fm.startitem()
1845 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1847 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1846 if uniquesel:
1848 if uniquesel:
1847 fm.data(name=entryname)
1849 fm.data(name=entryname)
1848 fm.write('value', '%s\n', value)
1850 fm.write('value', '%s\n', value)
1849 else:
1851 else:
1850 fm.write('name value', '%s=%s\n', entryname, value)
1852 fm.write('name value', '%s=%s\n', entryname, value)
1851 matched = True
1853 matched = True
1852 fm.end()
1854 fm.end()
1853 if matched:
1855 if matched:
1854 return 0
1856 return 0
1855 return 1
1857 return 1
1856
1858
1857 @command('copy|cp',
1859 @command('copy|cp',
1858 [('A', 'after', None, _('record a copy that has already occurred')),
1860 [('A', 'after', None, _('record a copy that has already occurred')),
1859 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1861 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1860 ] + walkopts + dryrunopts,
1862 ] + walkopts + dryrunopts,
1861 _('[OPTION]... [SOURCE]... DEST'),
1863 _('[OPTION]... [SOURCE]... DEST'),
1862 helpcategory=command.CATEGORY_FILE_CONTENTS)
1864 helpcategory=command.CATEGORY_FILE_CONTENTS)
1863 def copy(ui, repo, *pats, **opts):
1865 def copy(ui, repo, *pats, **opts):
1864 """mark files as copied for the next commit
1866 """mark files as copied for the next commit
1865
1867
1866 Mark dest as having copies of source files. If dest is a
1868 Mark dest as having copies of source files. If dest is a
1867 directory, copies are put in that directory. If dest is a file,
1869 directory, copies are put in that directory. If dest is a file,
1868 the source must be a single file.
1870 the source must be a single file.
1869
1871
1870 By default, this command copies the contents of files as they
1872 By default, this command copies the contents of files as they
1871 exist in the working directory. If invoked with -A/--after, the
1873 exist in the working directory. If invoked with -A/--after, the
1872 operation is recorded, but no copying is performed.
1874 operation is recorded, but no copying is performed.
1873
1875
1874 This command takes effect with the next commit. To undo a copy
1876 This command takes effect with the next commit. To undo a copy
1875 before that, see :hg:`revert`.
1877 before that, see :hg:`revert`.
1876
1878
1877 Returns 0 on success, 1 if errors are encountered.
1879 Returns 0 on success, 1 if errors are encountered.
1878 """
1880 """
1879 opts = pycompat.byteskwargs(opts)
1881 opts = pycompat.byteskwargs(opts)
1880 with repo.wlock(False):
1882 with repo.wlock(False):
1881 return cmdutil.copy(ui, repo, pats, opts)
1883 return cmdutil.copy(ui, repo, pats, opts)
1882
1884
1883 @command(
1885 @command(
1884 'debugcommands', [], _('[COMMAND]'),
1886 'debugcommands', [], _('[COMMAND]'),
1885 helpcategory=command.CATEGORY_HELP,
1887 helpcategory=command.CATEGORY_HELP,
1886 norepo=True)
1888 norepo=True)
1887 def debugcommands(ui, cmd='', *args):
1889 def debugcommands(ui, cmd='', *args):
1888 """list all available commands and options"""
1890 """list all available commands and options"""
1889 for cmd, vals in sorted(table.iteritems()):
1891 for cmd, vals in sorted(table.iteritems()):
1890 cmd = cmd.split('|')[0]
1892 cmd = cmd.split('|')[0]
1891 opts = ', '.join([i[1] for i in vals[1]])
1893 opts = ', '.join([i[1] for i in vals[1]])
1892 ui.write('%s: %s\n' % (cmd, opts))
1894 ui.write('%s: %s\n' % (cmd, opts))
1893
1895
1894 @command('debugcomplete',
1896 @command('debugcomplete',
1895 [('o', 'options', None, _('show the command options'))],
1897 [('o', 'options', None, _('show the command options'))],
1896 _('[-o] CMD'),
1898 _('[-o] CMD'),
1897 helpcategory=command.CATEGORY_HELP,
1899 helpcategory=command.CATEGORY_HELP,
1898 norepo=True)
1900 norepo=True)
1899 def debugcomplete(ui, cmd='', **opts):
1901 def debugcomplete(ui, cmd='', **opts):
1900 """returns the completion list associated with the given command"""
1902 """returns the completion list associated with the given command"""
1901
1903
1902 if opts.get(r'options'):
1904 if opts.get(r'options'):
1903 options = []
1905 options = []
1904 otables = [globalopts]
1906 otables = [globalopts]
1905 if cmd:
1907 if cmd:
1906 aliases, entry = cmdutil.findcmd(cmd, table, False)
1908 aliases, entry = cmdutil.findcmd(cmd, table, False)
1907 otables.append(entry[1])
1909 otables.append(entry[1])
1908 for t in otables:
1910 for t in otables:
1909 for o in t:
1911 for o in t:
1910 if "(DEPRECATED)" in o[3]:
1912 if "(DEPRECATED)" in o[3]:
1911 continue
1913 continue
1912 if o[0]:
1914 if o[0]:
1913 options.append('-%s' % o[0])
1915 options.append('-%s' % o[0])
1914 options.append('--%s' % o[1])
1916 options.append('--%s' % o[1])
1915 ui.write("%s\n" % "\n".join(options))
1917 ui.write("%s\n" % "\n".join(options))
1916 return
1918 return
1917
1919
1918 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1920 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1919 if ui.verbose:
1921 if ui.verbose:
1920 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1922 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1921 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1923 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1922
1924
1923 @command('diff',
1925 @command('diff',
1924 [('r', 'rev', [], _('revision'), _('REV')),
1926 [('r', 'rev', [], _('revision'), _('REV')),
1925 ('c', 'change', '', _('change made by revision'), _('REV'))
1927 ('c', 'change', '', _('change made by revision'), _('REV'))
1926 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1928 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1927 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1929 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1928 helpcategory=command.CATEGORY_FILE_CONTENTS,
1930 helpcategory=command.CATEGORY_FILE_CONTENTS,
1929 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1931 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1930 def diff(ui, repo, *pats, **opts):
1932 def diff(ui, repo, *pats, **opts):
1931 """diff repository (or selected files)
1933 """diff repository (or selected files)
1932
1934
1933 Show differences between revisions for the specified files.
1935 Show differences between revisions for the specified files.
1934
1936
1935 Differences between files are shown using the unified diff format.
1937 Differences between files are shown using the unified diff format.
1936
1938
1937 .. note::
1939 .. note::
1938
1940
1939 :hg:`diff` may generate unexpected results for merges, as it will
1941 :hg:`diff` may generate unexpected results for merges, as it will
1940 default to comparing against the working directory's first
1942 default to comparing against the working directory's first
1941 parent changeset if no revisions are specified.
1943 parent changeset if no revisions are specified.
1942
1944
1943 When two revision arguments are given, then changes are shown
1945 When two revision arguments are given, then changes are shown
1944 between those revisions. If only one revision is specified then
1946 between those revisions. If only one revision is specified then
1945 that revision is compared to the working directory, and, when no
1947 that revision is compared to the working directory, and, when no
1946 revisions are specified, the working directory files are compared
1948 revisions are specified, the working directory files are compared
1947 to its first parent.
1949 to its first parent.
1948
1950
1949 Alternatively you can specify -c/--change with a revision to see
1951 Alternatively you can specify -c/--change with a revision to see
1950 the changes in that changeset relative to its first parent.
1952 the changes in that changeset relative to its first parent.
1951
1953
1952 Without the -a/--text option, diff will avoid generating diffs of
1954 Without the -a/--text option, diff will avoid generating diffs of
1953 files it detects as binary. With -a, diff will generate a diff
1955 files it detects as binary. With -a, diff will generate a diff
1954 anyway, probably with undesirable results.
1956 anyway, probably with undesirable results.
1955
1957
1956 Use the -g/--git option to generate diffs in the git extended diff
1958 Use the -g/--git option to generate diffs in the git extended diff
1957 format. For more information, read :hg:`help diffs`.
1959 format. For more information, read :hg:`help diffs`.
1958
1960
1959 .. container:: verbose
1961 .. container:: verbose
1960
1962
1961 Examples:
1963 Examples:
1962
1964
1963 - compare a file in the current working directory to its parent::
1965 - compare a file in the current working directory to its parent::
1964
1966
1965 hg diff foo.c
1967 hg diff foo.c
1966
1968
1967 - compare two historical versions of a directory, with rename info::
1969 - compare two historical versions of a directory, with rename info::
1968
1970
1969 hg diff --git -r 1.0:1.2 lib/
1971 hg diff --git -r 1.0:1.2 lib/
1970
1972
1971 - get change stats relative to the last change on some date::
1973 - get change stats relative to the last change on some date::
1972
1974
1973 hg diff --stat -r "date('may 2')"
1975 hg diff --stat -r "date('may 2')"
1974
1976
1975 - diff all newly-added files that contain a keyword::
1977 - diff all newly-added files that contain a keyword::
1976
1978
1977 hg diff "set:added() and grep(GNU)"
1979 hg diff "set:added() and grep(GNU)"
1978
1980
1979 - compare a revision and its parents::
1981 - compare a revision and its parents::
1980
1982
1981 hg diff -c 9353 # compare against first parent
1983 hg diff -c 9353 # compare against first parent
1982 hg diff -r 9353^:9353 # same using revset syntax
1984 hg diff -r 9353^:9353 # same using revset syntax
1983 hg diff -r 9353^2:9353 # compare against the second parent
1985 hg diff -r 9353^2:9353 # compare against the second parent
1984
1986
1985 Returns 0 on success.
1987 Returns 0 on success.
1986 """
1988 """
1987
1989
1988 opts = pycompat.byteskwargs(opts)
1990 opts = pycompat.byteskwargs(opts)
1989 revs = opts.get('rev')
1991 revs = opts.get('rev')
1990 change = opts.get('change')
1992 change = opts.get('change')
1991 stat = opts.get('stat')
1993 stat = opts.get('stat')
1992 reverse = opts.get('reverse')
1994 reverse = opts.get('reverse')
1993
1995
1994 if revs and change:
1996 if revs and change:
1995 msg = _('cannot specify --rev and --change at the same time')
1997 msg = _('cannot specify --rev and --change at the same time')
1996 raise error.Abort(msg)
1998 raise error.Abort(msg)
1997 elif change:
1999 elif change:
1998 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
2000 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1999 ctx2 = scmutil.revsingle(repo, change, None)
2001 ctx2 = scmutil.revsingle(repo, change, None)
2000 ctx1 = ctx2.p1()
2002 ctx1 = ctx2.p1()
2001 else:
2003 else:
2002 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
2004 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
2003 ctx1, ctx2 = scmutil.revpair(repo, revs)
2005 ctx1, ctx2 = scmutil.revpair(repo, revs)
2004 node1, node2 = ctx1.node(), ctx2.node()
2006 node1, node2 = ctx1.node(), ctx2.node()
2005
2007
2006 if reverse:
2008 if reverse:
2007 node1, node2 = node2, node1
2009 node1, node2 = node2, node1
2008
2010
2009 diffopts = patch.diffallopts(ui, opts)
2011 diffopts = patch.diffallopts(ui, opts)
2010 m = scmutil.match(ctx2, pats, opts)
2012 m = scmutil.match(ctx2, pats, opts)
2011 m = repo.narrowmatch(m)
2013 m = repo.narrowmatch(m)
2012 ui.pager('diff')
2014 ui.pager('diff')
2013 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2015 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2014 listsubrepos=opts.get('subrepos'),
2016 listsubrepos=opts.get('subrepos'),
2015 root=opts.get('root'))
2017 root=opts.get('root'))
2016
2018
2017 @command('export',
2019 @command('export',
2018 [('B', 'bookmark', '',
2020 [('B', 'bookmark', '',
2019 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2021 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2020 ('o', 'output', '',
2022 ('o', 'output', '',
2021 _('print output to file with formatted name'), _('FORMAT')),
2023 _('print output to file with formatted name'), _('FORMAT')),
2022 ('', 'switch-parent', None, _('diff against the second parent')),
2024 ('', 'switch-parent', None, _('diff against the second parent')),
2023 ('r', 'rev', [], _('revisions to export'), _('REV')),
2025 ('r', 'rev', [], _('revisions to export'), _('REV')),
2024 ] + diffopts + formatteropts,
2026 ] + diffopts + formatteropts,
2025 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2027 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2026 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2028 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2027 helpbasic=True, intents={INTENT_READONLY})
2029 helpbasic=True, intents={INTENT_READONLY})
2028 def export(ui, repo, *changesets, **opts):
2030 def export(ui, repo, *changesets, **opts):
2029 """dump the header and diffs for one or more changesets
2031 """dump the header and diffs for one or more changesets
2030
2032
2031 Print the changeset header and diffs for one or more revisions.
2033 Print the changeset header and diffs for one or more revisions.
2032 If no revision is given, the parent of the working directory is used.
2034 If no revision is given, the parent of the working directory is used.
2033
2035
2034 The information shown in the changeset header is: author, date,
2036 The information shown in the changeset header is: author, date,
2035 branch name (if non-default), changeset hash, parent(s) and commit
2037 branch name (if non-default), changeset hash, parent(s) and commit
2036 comment.
2038 comment.
2037
2039
2038 .. note::
2040 .. note::
2039
2041
2040 :hg:`export` may generate unexpected diff output for merge
2042 :hg:`export` may generate unexpected diff output for merge
2041 changesets, as it will compare the merge changeset against its
2043 changesets, as it will compare the merge changeset against its
2042 first parent only.
2044 first parent only.
2043
2045
2044 Output may be to a file, in which case the name of the file is
2046 Output may be to a file, in which case the name of the file is
2045 given using a template string. See :hg:`help templates`. In addition
2047 given using a template string. See :hg:`help templates`. In addition
2046 to the common template keywords, the following formatting rules are
2048 to the common template keywords, the following formatting rules are
2047 supported:
2049 supported:
2048
2050
2049 :``%%``: literal "%" character
2051 :``%%``: literal "%" character
2050 :``%H``: changeset hash (40 hexadecimal digits)
2052 :``%H``: changeset hash (40 hexadecimal digits)
2051 :``%N``: number of patches being generated
2053 :``%N``: number of patches being generated
2052 :``%R``: changeset revision number
2054 :``%R``: changeset revision number
2053 :``%b``: basename of the exporting repository
2055 :``%b``: basename of the exporting repository
2054 :``%h``: short-form changeset hash (12 hexadecimal digits)
2056 :``%h``: short-form changeset hash (12 hexadecimal digits)
2055 :``%m``: first line of the commit message (only alphanumeric characters)
2057 :``%m``: first line of the commit message (only alphanumeric characters)
2056 :``%n``: zero-padded sequence number, starting at 1
2058 :``%n``: zero-padded sequence number, starting at 1
2057 :``%r``: zero-padded changeset revision number
2059 :``%r``: zero-padded changeset revision number
2058 :``\\``: literal "\\" character
2060 :``\\``: literal "\\" character
2059
2061
2060 Without the -a/--text option, export will avoid generating diffs
2062 Without the -a/--text option, export will avoid generating diffs
2061 of files it detects as binary. With -a, export will generate a
2063 of files it detects as binary. With -a, export will generate a
2062 diff anyway, probably with undesirable results.
2064 diff anyway, probably with undesirable results.
2063
2065
2064 With -B/--bookmark changesets reachable by the given bookmark are
2066 With -B/--bookmark changesets reachable by the given bookmark are
2065 selected.
2067 selected.
2066
2068
2067 Use the -g/--git option to generate diffs in the git extended diff
2069 Use the -g/--git option to generate diffs in the git extended diff
2068 format. See :hg:`help diffs` for more information.
2070 format. See :hg:`help diffs` for more information.
2069
2071
2070 With the --switch-parent option, the diff will be against the
2072 With the --switch-parent option, the diff will be against the
2071 second parent. It can be useful to review a merge.
2073 second parent. It can be useful to review a merge.
2072
2074
2073 .. container:: verbose
2075 .. container:: verbose
2074
2076
2075 Template:
2077 Template:
2076
2078
2077 The following keywords are supported in addition to the common template
2079 The following keywords are supported in addition to the common template
2078 keywords and functions. See also :hg:`help templates`.
2080 keywords and functions. See also :hg:`help templates`.
2079
2081
2080 :diff: String. Diff content.
2082 :diff: String. Diff content.
2081 :parents: List of strings. Parent nodes of the changeset.
2083 :parents: List of strings. Parent nodes of the changeset.
2082
2084
2083 Examples:
2085 Examples:
2084
2086
2085 - use export and import to transplant a bugfix to the current
2087 - use export and import to transplant a bugfix to the current
2086 branch::
2088 branch::
2087
2089
2088 hg export -r 9353 | hg import -
2090 hg export -r 9353 | hg import -
2089
2091
2090 - export all the changesets between two revisions to a file with
2092 - export all the changesets between two revisions to a file with
2091 rename information::
2093 rename information::
2092
2094
2093 hg export --git -r 123:150 > changes.txt
2095 hg export --git -r 123:150 > changes.txt
2094
2096
2095 - split outgoing changes into a series of patches with
2097 - split outgoing changes into a series of patches with
2096 descriptive names::
2098 descriptive names::
2097
2099
2098 hg export -r "outgoing()" -o "%n-%m.patch"
2100 hg export -r "outgoing()" -o "%n-%m.patch"
2099
2101
2100 Returns 0 on success.
2102 Returns 0 on success.
2101 """
2103 """
2102 opts = pycompat.byteskwargs(opts)
2104 opts = pycompat.byteskwargs(opts)
2103 bookmark = opts.get('bookmark')
2105 bookmark = opts.get('bookmark')
2104 changesets += tuple(opts.get('rev', []))
2106 changesets += tuple(opts.get('rev', []))
2105
2107
2106 if bookmark and changesets:
2108 if bookmark and changesets:
2107 raise error.Abort(_("-r and -B are mutually exclusive"))
2109 raise error.Abort(_("-r and -B are mutually exclusive"))
2108
2110
2109 if bookmark:
2111 if bookmark:
2110 if bookmark not in repo._bookmarks:
2112 if bookmark not in repo._bookmarks:
2111 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2113 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2112
2114
2113 revs = scmutil.bookmarkrevs(repo, bookmark)
2115 revs = scmutil.bookmarkrevs(repo, bookmark)
2114 else:
2116 else:
2115 if not changesets:
2117 if not changesets:
2116 changesets = ['.']
2118 changesets = ['.']
2117
2119
2118 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2120 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2119 revs = scmutil.revrange(repo, changesets)
2121 revs = scmutil.revrange(repo, changesets)
2120
2122
2121 if not revs:
2123 if not revs:
2122 raise error.Abort(_("export requires at least one changeset"))
2124 raise error.Abort(_("export requires at least one changeset"))
2123 if len(revs) > 1:
2125 if len(revs) > 1:
2124 ui.note(_('exporting patches:\n'))
2126 ui.note(_('exporting patches:\n'))
2125 else:
2127 else:
2126 ui.note(_('exporting patch:\n'))
2128 ui.note(_('exporting patch:\n'))
2127
2129
2128 fntemplate = opts.get('output')
2130 fntemplate = opts.get('output')
2129 if cmdutil.isstdiofilename(fntemplate):
2131 if cmdutil.isstdiofilename(fntemplate):
2130 fntemplate = ''
2132 fntemplate = ''
2131
2133
2132 if fntemplate:
2134 if fntemplate:
2133 fm = formatter.nullformatter(ui, 'export', opts)
2135 fm = formatter.nullformatter(ui, 'export', opts)
2134 else:
2136 else:
2135 ui.pager('export')
2137 ui.pager('export')
2136 fm = ui.formatter('export', opts)
2138 fm = ui.formatter('export', opts)
2137 with fm:
2139 with fm:
2138 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2140 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2139 switch_parent=opts.get('switch_parent'),
2141 switch_parent=opts.get('switch_parent'),
2140 opts=patch.diffallopts(ui, opts))
2142 opts=patch.diffallopts(ui, opts))
2141
2143
2142 @command('files',
2144 @command('files',
2143 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2145 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2144 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2146 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2145 ] + walkopts + formatteropts + subrepoopts,
2147 ] + walkopts + formatteropts + subrepoopts,
2146 _('[OPTION]... [FILE]...'),
2148 _('[OPTION]... [FILE]...'),
2147 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2149 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2148 intents={INTENT_READONLY})
2150 intents={INTENT_READONLY})
2149 def files(ui, repo, *pats, **opts):
2151 def files(ui, repo, *pats, **opts):
2150 """list tracked files
2152 """list tracked files
2151
2153
2152 Print files under Mercurial control in the working directory or
2154 Print files under Mercurial control in the working directory or
2153 specified revision for given files (excluding removed files).
2155 specified revision for given files (excluding removed files).
2154 Files can be specified as filenames or filesets.
2156 Files can be specified as filenames or filesets.
2155
2157
2156 If no files are given to match, this command prints the names
2158 If no files are given to match, this command prints the names
2157 of all files under Mercurial control.
2159 of all files under Mercurial control.
2158
2160
2159 .. container:: verbose
2161 .. container:: verbose
2160
2162
2161 Template:
2163 Template:
2162
2164
2163 The following keywords are supported in addition to the common template
2165 The following keywords are supported in addition to the common template
2164 keywords and functions. See also :hg:`help templates`.
2166 keywords and functions. See also :hg:`help templates`.
2165
2167
2166 :flags: String. Character denoting file's symlink and executable bits.
2168 :flags: String. Character denoting file's symlink and executable bits.
2167 :path: String. Repository-absolute path of the file.
2169 :path: String. Repository-absolute path of the file.
2168 :size: Integer. Size of the file in bytes.
2170 :size: Integer. Size of the file in bytes.
2169
2171
2170 Examples:
2172 Examples:
2171
2173
2172 - list all files under the current directory::
2174 - list all files under the current directory::
2173
2175
2174 hg files .
2176 hg files .
2175
2177
2176 - shows sizes and flags for current revision::
2178 - shows sizes and flags for current revision::
2177
2179
2178 hg files -vr .
2180 hg files -vr .
2179
2181
2180 - list all files named README::
2182 - list all files named README::
2181
2183
2182 hg files -I "**/README"
2184 hg files -I "**/README"
2183
2185
2184 - list all binary files::
2186 - list all binary files::
2185
2187
2186 hg files "set:binary()"
2188 hg files "set:binary()"
2187
2189
2188 - find files containing a regular expression::
2190 - find files containing a regular expression::
2189
2191
2190 hg files "set:grep('bob')"
2192 hg files "set:grep('bob')"
2191
2193
2192 - search tracked file contents with xargs and grep::
2194 - search tracked file contents with xargs and grep::
2193
2195
2194 hg files -0 | xargs -0 grep foo
2196 hg files -0 | xargs -0 grep foo
2195
2197
2196 See :hg:`help patterns` and :hg:`help filesets` for more information
2198 See :hg:`help patterns` and :hg:`help filesets` for more information
2197 on specifying file patterns.
2199 on specifying file patterns.
2198
2200
2199 Returns 0 if a match is found, 1 otherwise.
2201 Returns 0 if a match is found, 1 otherwise.
2200
2202
2201 """
2203 """
2202
2204
2203 opts = pycompat.byteskwargs(opts)
2205 opts = pycompat.byteskwargs(opts)
2204 rev = opts.get('rev')
2206 rev = opts.get('rev')
2205 if rev:
2207 if rev:
2206 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2208 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2207 ctx = scmutil.revsingle(repo, rev, None)
2209 ctx = scmutil.revsingle(repo, rev, None)
2208
2210
2209 end = '\n'
2211 end = '\n'
2210 if opts.get('print0'):
2212 if opts.get('print0'):
2211 end = '\0'
2213 end = '\0'
2212 fmt = '%s' + end
2214 fmt = '%s' + end
2213
2215
2214 m = scmutil.match(ctx, pats, opts)
2216 m = scmutil.match(ctx, pats, opts)
2215 ui.pager('files')
2217 ui.pager('files')
2216 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2218 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2217 with ui.formatter('files', opts) as fm:
2219 with ui.formatter('files', opts) as fm:
2218 return cmdutil.files(ui, ctx, m, uipathfn, fm, fmt,
2220 return cmdutil.files(ui, ctx, m, uipathfn, fm, fmt,
2219 opts.get('subrepos'))
2221 opts.get('subrepos'))
2220
2222
2221 @command(
2223 @command(
2222 'forget',
2224 'forget',
2223 [('i', 'interactive', None, _('use interactive mode')),
2225 [('i', 'interactive', None, _('use interactive mode')),
2224 ] + walkopts + dryrunopts,
2226 ] + walkopts + dryrunopts,
2225 _('[OPTION]... FILE...'),
2227 _('[OPTION]... FILE...'),
2226 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2228 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2227 helpbasic=True, inferrepo=True)
2229 helpbasic=True, inferrepo=True)
2228 def forget(ui, repo, *pats, **opts):
2230 def forget(ui, repo, *pats, **opts):
2229 """forget the specified files on the next commit
2231 """forget the specified files on the next commit
2230
2232
2231 Mark the specified files so they will no longer be tracked
2233 Mark the specified files so they will no longer be tracked
2232 after the next commit.
2234 after the next commit.
2233
2235
2234 This only removes files from the current branch, not from the
2236 This only removes files from the current branch, not from the
2235 entire project history, and it does not delete them from the
2237 entire project history, and it does not delete them from the
2236 working directory.
2238 working directory.
2237
2239
2238 To delete the file from the working directory, see :hg:`remove`.
2240 To delete the file from the working directory, see :hg:`remove`.
2239
2241
2240 To undo a forget before the next commit, see :hg:`add`.
2242 To undo a forget before the next commit, see :hg:`add`.
2241
2243
2242 .. container:: verbose
2244 .. container:: verbose
2243
2245
2244 Examples:
2246 Examples:
2245
2247
2246 - forget newly-added binary files::
2248 - forget newly-added binary files::
2247
2249
2248 hg forget "set:added() and binary()"
2250 hg forget "set:added() and binary()"
2249
2251
2250 - forget files that would be excluded by .hgignore::
2252 - forget files that would be excluded by .hgignore::
2251
2253
2252 hg forget "set:hgignore()"
2254 hg forget "set:hgignore()"
2253
2255
2254 Returns 0 on success.
2256 Returns 0 on success.
2255 """
2257 """
2256
2258
2257 opts = pycompat.byteskwargs(opts)
2259 opts = pycompat.byteskwargs(opts)
2258 if not pats:
2260 if not pats:
2259 raise error.Abort(_('no files specified'))
2261 raise error.Abort(_('no files specified'))
2260
2262
2261 m = scmutil.match(repo[None], pats, opts)
2263 m = scmutil.match(repo[None], pats, opts)
2262 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2264 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2263 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2265 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2264 rejected = cmdutil.forget(ui, repo, m, prefix="", uipathfn=uipathfn,
2266 rejected = cmdutil.forget(ui, repo, m, prefix="", uipathfn=uipathfn,
2265 explicitonly=False, dryrun=dryrun,
2267 explicitonly=False, dryrun=dryrun,
2266 interactive=interactive)[0]
2268 interactive=interactive)[0]
2267 return rejected and 1 or 0
2269 return rejected and 1 or 0
2268
2270
2269 @command(
2271 @command(
2270 'graft',
2272 'graft',
2271 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2273 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2272 ('', 'base', '',
2274 ('', 'base', '',
2273 _('base revision when doing the graft merge (ADVANCED)'), _('REV')),
2275 _('base revision when doing the graft merge (ADVANCED)'), _('REV')),
2274 ('c', 'continue', False, _('resume interrupted graft')),
2276 ('c', 'continue', False, _('resume interrupted graft')),
2275 ('', 'stop', False, _('stop interrupted graft')),
2277 ('', 'stop', False, _('stop interrupted graft')),
2276 ('', 'abort', False, _('abort interrupted graft')),
2278 ('', 'abort', False, _('abort interrupted graft')),
2277 ('e', 'edit', False, _('invoke editor on commit messages')),
2279 ('e', 'edit', False, _('invoke editor on commit messages')),
2278 ('', 'log', None, _('append graft info to log message')),
2280 ('', 'log', None, _('append graft info to log message')),
2279 ('', 'no-commit', None,
2281 ('', 'no-commit', None,
2280 _("don't commit, just apply the changes in working directory")),
2282 _("don't commit, just apply the changes in working directory")),
2281 ('f', 'force', False, _('force graft')),
2283 ('f', 'force', False, _('force graft')),
2282 ('D', 'currentdate', False,
2284 ('D', 'currentdate', False,
2283 _('record the current date as commit date')),
2285 _('record the current date as commit date')),
2284 ('U', 'currentuser', False,
2286 ('U', 'currentuser', False,
2285 _('record the current user as committer'))]
2287 _('record the current user as committer'))]
2286 + commitopts2 + mergetoolopts + dryrunopts,
2288 + commitopts2 + mergetoolopts + dryrunopts,
2287 _('[OPTION]... [-r REV]... REV...'),
2289 _('[OPTION]... [-r REV]... REV...'),
2288 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2290 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2289 def graft(ui, repo, *revs, **opts):
2291 def graft(ui, repo, *revs, **opts):
2290 '''copy changes from other branches onto the current branch
2292 '''copy changes from other branches onto the current branch
2291
2293
2292 This command uses Mercurial's merge logic to copy individual
2294 This command uses Mercurial's merge logic to copy individual
2293 changes from other branches without merging branches in the
2295 changes from other branches without merging branches in the
2294 history graph. This is sometimes known as 'backporting' or
2296 history graph. This is sometimes known as 'backporting' or
2295 'cherry-picking'. By default, graft will copy user, date, and
2297 'cherry-picking'. By default, graft will copy user, date, and
2296 description from the source changesets.
2298 description from the source changesets.
2297
2299
2298 Changesets that are ancestors of the current revision, that have
2300 Changesets that are ancestors of the current revision, that have
2299 already been grafted, or that are merges will be skipped.
2301 already been grafted, or that are merges will be skipped.
2300
2302
2301 If --log is specified, log messages will have a comment appended
2303 If --log is specified, log messages will have a comment appended
2302 of the form::
2304 of the form::
2303
2305
2304 (grafted from CHANGESETHASH)
2306 (grafted from CHANGESETHASH)
2305
2307
2306 If --force is specified, revisions will be grafted even if they
2308 If --force is specified, revisions will be grafted even if they
2307 are already ancestors of, or have been grafted to, the destination.
2309 are already ancestors of, or have been grafted to, the destination.
2308 This is useful when the revisions have since been backed out.
2310 This is useful when the revisions have since been backed out.
2309
2311
2310 If a graft merge results in conflicts, the graft process is
2312 If a graft merge results in conflicts, the graft process is
2311 interrupted so that the current merge can be manually resolved.
2313 interrupted so that the current merge can be manually resolved.
2312 Once all conflicts are addressed, the graft process can be
2314 Once all conflicts are addressed, the graft process can be
2313 continued with the -c/--continue option.
2315 continued with the -c/--continue option.
2314
2316
2315 The -c/--continue option reapplies all the earlier options.
2317 The -c/--continue option reapplies all the earlier options.
2316
2318
2317 .. container:: verbose
2319 .. container:: verbose
2318
2320
2319 The --base option exposes more of how graft internally uses merge with a
2321 The --base option exposes more of how graft internally uses merge with a
2320 custom base revision. --base can be used to specify another ancestor than
2322 custom base revision. --base can be used to specify another ancestor than
2321 the first and only parent.
2323 the first and only parent.
2322
2324
2323 The command::
2325 The command::
2324
2326
2325 hg graft -r 345 --base 234
2327 hg graft -r 345 --base 234
2326
2328
2327 is thus pretty much the same as::
2329 is thus pretty much the same as::
2328
2330
2329 hg diff -r 234 -r 345 | hg import
2331 hg diff -r 234 -r 345 | hg import
2330
2332
2331 but using merge to resolve conflicts and track moved files.
2333 but using merge to resolve conflicts and track moved files.
2332
2334
2333 The result of a merge can thus be backported as a single commit by
2335 The result of a merge can thus be backported as a single commit by
2334 specifying one of the merge parents as base, and thus effectively
2336 specifying one of the merge parents as base, and thus effectively
2335 grafting the changes from the other side.
2337 grafting the changes from the other side.
2336
2338
2337 It is also possible to collapse multiple changesets and clean up history
2339 It is also possible to collapse multiple changesets and clean up history
2338 by specifying another ancestor as base, much like rebase --collapse
2340 by specifying another ancestor as base, much like rebase --collapse
2339 --keep.
2341 --keep.
2340
2342
2341 The commit message can be tweaked after the fact using commit --amend .
2343 The commit message can be tweaked after the fact using commit --amend .
2342
2344
2343 For using non-ancestors as the base to backout changes, see the backout
2345 For using non-ancestors as the base to backout changes, see the backout
2344 command and the hidden --parent option.
2346 command and the hidden --parent option.
2345
2347
2346 .. container:: verbose
2348 .. container:: verbose
2347
2349
2348 Examples:
2350 Examples:
2349
2351
2350 - copy a single change to the stable branch and edit its description::
2352 - copy a single change to the stable branch and edit its description::
2351
2353
2352 hg update stable
2354 hg update stable
2353 hg graft --edit 9393
2355 hg graft --edit 9393
2354
2356
2355 - graft a range of changesets with one exception, updating dates::
2357 - graft a range of changesets with one exception, updating dates::
2356
2358
2357 hg graft -D "2085::2093 and not 2091"
2359 hg graft -D "2085::2093 and not 2091"
2358
2360
2359 - continue a graft after resolving conflicts::
2361 - continue a graft after resolving conflicts::
2360
2362
2361 hg graft -c
2363 hg graft -c
2362
2364
2363 - show the source of a grafted changeset::
2365 - show the source of a grafted changeset::
2364
2366
2365 hg log --debug -r .
2367 hg log --debug -r .
2366
2368
2367 - show revisions sorted by date::
2369 - show revisions sorted by date::
2368
2370
2369 hg log -r "sort(all(), date)"
2371 hg log -r "sort(all(), date)"
2370
2372
2371 - backport the result of a merge as a single commit::
2373 - backport the result of a merge as a single commit::
2372
2374
2373 hg graft -r 123 --base 123^
2375 hg graft -r 123 --base 123^
2374
2376
2375 - land a feature branch as one changeset::
2377 - land a feature branch as one changeset::
2376
2378
2377 hg up -cr default
2379 hg up -cr default
2378 hg graft -r featureX --base "ancestor('featureX', 'default')"
2380 hg graft -r featureX --base "ancestor('featureX', 'default')"
2379
2381
2380 See :hg:`help revisions` for more about specifying revisions.
2382 See :hg:`help revisions` for more about specifying revisions.
2381
2383
2382 Returns 0 on successful completion.
2384 Returns 0 on successful completion.
2383 '''
2385 '''
2384 with repo.wlock():
2386 with repo.wlock():
2385 return _dograft(ui, repo, *revs, **opts)
2387 return _dograft(ui, repo, *revs, **opts)
2386
2388
2387 def _dograft(ui, repo, *revs, **opts):
2389 def _dograft(ui, repo, *revs, **opts):
2388 opts = pycompat.byteskwargs(opts)
2390 opts = pycompat.byteskwargs(opts)
2389 if revs and opts.get('rev'):
2391 if revs and opts.get('rev'):
2390 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2392 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2391 'revision ordering!\n'))
2393 'revision ordering!\n'))
2392
2394
2393 revs = list(revs)
2395 revs = list(revs)
2394 revs.extend(opts.get('rev'))
2396 revs.extend(opts.get('rev'))
2395 basectx = None
2397 basectx = None
2396 if opts.get('base'):
2398 if opts.get('base'):
2397 basectx = scmutil.revsingle(repo, opts['base'], None)
2399 basectx = scmutil.revsingle(repo, opts['base'], None)
2398 # a dict of data to be stored in state file
2400 # a dict of data to be stored in state file
2399 statedata = {}
2401 statedata = {}
2400 # list of new nodes created by ongoing graft
2402 # list of new nodes created by ongoing graft
2401 statedata['newnodes'] = []
2403 statedata['newnodes'] = []
2402
2404
2403 if opts.get('user') and opts.get('currentuser'):
2405 if opts.get('user') and opts.get('currentuser'):
2404 raise error.Abort(_('--user and --currentuser are mutually exclusive'))
2406 raise error.Abort(_('--user and --currentuser are mutually exclusive'))
2405 if opts.get('date') and opts.get('currentdate'):
2407 if opts.get('date') and opts.get('currentdate'):
2406 raise error.Abort(_('--date and --currentdate are mutually exclusive'))
2408 raise error.Abort(_('--date and --currentdate are mutually exclusive'))
2407 if not opts.get('user') and opts.get('currentuser'):
2409 if not opts.get('user') and opts.get('currentuser'):
2408 opts['user'] = ui.username()
2410 opts['user'] = ui.username()
2409 if not opts.get('date') and opts.get('currentdate'):
2411 if not opts.get('date') and opts.get('currentdate'):
2410 opts['date'] = "%d %d" % dateutil.makedate()
2412 opts['date'] = "%d %d" % dateutil.makedate()
2411
2413
2412 editor = cmdutil.getcommiteditor(editform='graft',
2414 editor = cmdutil.getcommiteditor(editform='graft',
2413 **pycompat.strkwargs(opts))
2415 **pycompat.strkwargs(opts))
2414
2416
2415 cont = False
2417 cont = False
2416 if opts.get('no_commit'):
2418 if opts.get('no_commit'):
2417 if opts.get('edit'):
2419 if opts.get('edit'):
2418 raise error.Abort(_("cannot specify --no-commit and "
2420 raise error.Abort(_("cannot specify --no-commit and "
2419 "--edit together"))
2421 "--edit together"))
2420 if opts.get('currentuser'):
2422 if opts.get('currentuser'):
2421 raise error.Abort(_("cannot specify --no-commit and "
2423 raise error.Abort(_("cannot specify --no-commit and "
2422 "--currentuser together"))
2424 "--currentuser together"))
2423 if opts.get('currentdate'):
2425 if opts.get('currentdate'):
2424 raise error.Abort(_("cannot specify --no-commit and "
2426 raise error.Abort(_("cannot specify --no-commit and "
2425 "--currentdate together"))
2427 "--currentdate together"))
2426 if opts.get('log'):
2428 if opts.get('log'):
2427 raise error.Abort(_("cannot specify --no-commit and "
2429 raise error.Abort(_("cannot specify --no-commit and "
2428 "--log together"))
2430 "--log together"))
2429
2431
2430 graftstate = statemod.cmdstate(repo, 'graftstate')
2432 graftstate = statemod.cmdstate(repo, 'graftstate')
2431
2433
2432 if opts.get('stop'):
2434 if opts.get('stop'):
2433 if opts.get('continue'):
2435 if opts.get('continue'):
2434 raise error.Abort(_("cannot use '--continue' and "
2436 raise error.Abort(_("cannot use '--continue' and "
2435 "'--stop' together"))
2437 "'--stop' together"))
2436 if opts.get('abort'):
2438 if opts.get('abort'):
2437 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2439 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2438
2440
2439 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2441 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2440 opts.get('date'), opts.get('currentdate'),
2442 opts.get('date'), opts.get('currentdate'),
2441 opts.get('currentuser'), opts.get('rev'))):
2443 opts.get('currentuser'), opts.get('rev'))):
2442 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2444 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2443 return _stopgraft(ui, repo, graftstate)
2445 return _stopgraft(ui, repo, graftstate)
2444 elif opts.get('abort'):
2446 elif opts.get('abort'):
2445 if opts.get('continue'):
2447 if opts.get('continue'):
2446 raise error.Abort(_("cannot use '--continue' and "
2448 raise error.Abort(_("cannot use '--continue' and "
2447 "'--abort' together"))
2449 "'--abort' together"))
2448 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2450 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2449 opts.get('date'), opts.get('currentdate'),
2451 opts.get('date'), opts.get('currentdate'),
2450 opts.get('currentuser'), opts.get('rev'))):
2452 opts.get('currentuser'), opts.get('rev'))):
2451 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2453 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2452
2454
2453 return _abortgraft(ui, repo, graftstate)
2455 return _abortgraft(ui, repo, graftstate)
2454 elif opts.get('continue'):
2456 elif opts.get('continue'):
2455 cont = True
2457 cont = True
2456 if revs:
2458 if revs:
2457 raise error.Abort(_("can't specify --continue and revisions"))
2459 raise error.Abort(_("can't specify --continue and revisions"))
2458 # read in unfinished revisions
2460 # read in unfinished revisions
2459 if graftstate.exists():
2461 if graftstate.exists():
2460 statedata = _readgraftstate(repo, graftstate)
2462 statedata = _readgraftstate(repo, graftstate)
2461 if statedata.get('date'):
2463 if statedata.get('date'):
2462 opts['date'] = statedata['date']
2464 opts['date'] = statedata['date']
2463 if statedata.get('user'):
2465 if statedata.get('user'):
2464 opts['user'] = statedata['user']
2466 opts['user'] = statedata['user']
2465 if statedata.get('log'):
2467 if statedata.get('log'):
2466 opts['log'] = True
2468 opts['log'] = True
2467 if statedata.get('no_commit'):
2469 if statedata.get('no_commit'):
2468 opts['no_commit'] = statedata.get('no_commit')
2470 opts['no_commit'] = statedata.get('no_commit')
2469 nodes = statedata['nodes']
2471 nodes = statedata['nodes']
2470 revs = [repo[node].rev() for node in nodes]
2472 revs = [repo[node].rev() for node in nodes]
2471 else:
2473 else:
2472 cmdutil.wrongtooltocontinue(repo, _('graft'))
2474 cmdutil.wrongtooltocontinue(repo, _('graft'))
2473 else:
2475 else:
2474 if not revs:
2476 if not revs:
2475 raise error.Abort(_('no revisions specified'))
2477 raise error.Abort(_('no revisions specified'))
2476 cmdutil.checkunfinished(repo)
2478 cmdutil.checkunfinished(repo)
2477 cmdutil.bailifchanged(repo)
2479 cmdutil.bailifchanged(repo)
2478 revs = scmutil.revrange(repo, revs)
2480 revs = scmutil.revrange(repo, revs)
2479
2481
2480 skipped = set()
2482 skipped = set()
2481 if basectx is None:
2483 if basectx is None:
2482 # check for merges
2484 # check for merges
2483 for rev in repo.revs('%ld and merge()', revs):
2485 for rev in repo.revs('%ld and merge()', revs):
2484 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2486 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2485 skipped.add(rev)
2487 skipped.add(rev)
2486 revs = [r for r in revs if r not in skipped]
2488 revs = [r for r in revs if r not in skipped]
2487 if not revs:
2489 if not revs:
2488 return -1
2490 return -1
2489 if basectx is not None and len(revs) != 1:
2491 if basectx is not None and len(revs) != 1:
2490 raise error.Abort(_('only one revision allowed with --base '))
2492 raise error.Abort(_('only one revision allowed with --base '))
2491
2493
2492 # Don't check in the --continue case, in effect retaining --force across
2494 # Don't check in the --continue case, in effect retaining --force across
2493 # --continues. That's because without --force, any revisions we decided to
2495 # --continues. That's because without --force, any revisions we decided to
2494 # skip would have been filtered out here, so they wouldn't have made their
2496 # skip would have been filtered out here, so they wouldn't have made their
2495 # way to the graftstate. With --force, any revisions we would have otherwise
2497 # way to the graftstate. With --force, any revisions we would have otherwise
2496 # skipped would not have been filtered out, and if they hadn't been applied
2498 # skipped would not have been filtered out, and if they hadn't been applied
2497 # already, they'd have been in the graftstate.
2499 # already, they'd have been in the graftstate.
2498 if not (cont or opts.get('force')) and basectx is None:
2500 if not (cont or opts.get('force')) and basectx is None:
2499 # check for ancestors of dest branch
2501 # check for ancestors of dest branch
2500 crev = repo['.'].rev()
2502 crev = repo['.'].rev()
2501 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2503 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2502 # XXX make this lazy in the future
2504 # XXX make this lazy in the future
2503 # don't mutate while iterating, create a copy
2505 # don't mutate while iterating, create a copy
2504 for rev in list(revs):
2506 for rev in list(revs):
2505 if rev in ancestors:
2507 if rev in ancestors:
2506 ui.warn(_('skipping ancestor revision %d:%s\n') %
2508 ui.warn(_('skipping ancestor revision %d:%s\n') %
2507 (rev, repo[rev]))
2509 (rev, repo[rev]))
2508 # XXX remove on list is slow
2510 # XXX remove on list is slow
2509 revs.remove(rev)
2511 revs.remove(rev)
2510 if not revs:
2512 if not revs:
2511 return -1
2513 return -1
2512
2514
2513 # analyze revs for earlier grafts
2515 # analyze revs for earlier grafts
2514 ids = {}
2516 ids = {}
2515 for ctx in repo.set("%ld", revs):
2517 for ctx in repo.set("%ld", revs):
2516 ids[ctx.hex()] = ctx.rev()
2518 ids[ctx.hex()] = ctx.rev()
2517 n = ctx.extra().get('source')
2519 n = ctx.extra().get('source')
2518 if n:
2520 if n:
2519 ids[n] = ctx.rev()
2521 ids[n] = ctx.rev()
2520
2522
2521 # check ancestors for earlier grafts
2523 # check ancestors for earlier grafts
2522 ui.debug('scanning for duplicate grafts\n')
2524 ui.debug('scanning for duplicate grafts\n')
2523
2525
2524 # The only changesets we can be sure doesn't contain grafts of any
2526 # The only changesets we can be sure doesn't contain grafts of any
2525 # revs, are the ones that are common ancestors of *all* revs:
2527 # revs, are the ones that are common ancestors of *all* revs:
2526 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2528 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2527 ctx = repo[rev]
2529 ctx = repo[rev]
2528 n = ctx.extra().get('source')
2530 n = ctx.extra().get('source')
2529 if n in ids:
2531 if n in ids:
2530 try:
2532 try:
2531 r = repo[n].rev()
2533 r = repo[n].rev()
2532 except error.RepoLookupError:
2534 except error.RepoLookupError:
2533 r = None
2535 r = None
2534 if r in revs:
2536 if r in revs:
2535 ui.warn(_('skipping revision %d:%s '
2537 ui.warn(_('skipping revision %d:%s '
2536 '(already grafted to %d:%s)\n')
2538 '(already grafted to %d:%s)\n')
2537 % (r, repo[r], rev, ctx))
2539 % (r, repo[r], rev, ctx))
2538 revs.remove(r)
2540 revs.remove(r)
2539 elif ids[n] in revs:
2541 elif ids[n] in revs:
2540 if r is None:
2542 if r is None:
2541 ui.warn(_('skipping already grafted revision %d:%s '
2543 ui.warn(_('skipping already grafted revision %d:%s '
2542 '(%d:%s also has unknown origin %s)\n')
2544 '(%d:%s also has unknown origin %s)\n')
2543 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2545 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2544 else:
2546 else:
2545 ui.warn(_('skipping already grafted revision %d:%s '
2547 ui.warn(_('skipping already grafted revision %d:%s '
2546 '(%d:%s also has origin %d:%s)\n')
2548 '(%d:%s also has origin %d:%s)\n')
2547 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2549 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2548 revs.remove(ids[n])
2550 revs.remove(ids[n])
2549 elif ctx.hex() in ids:
2551 elif ctx.hex() in ids:
2550 r = ids[ctx.hex()]
2552 r = ids[ctx.hex()]
2551 if r in revs:
2553 if r in revs:
2552 ui.warn(_('skipping already grafted revision %d:%s '
2554 ui.warn(_('skipping already grafted revision %d:%s '
2553 '(was grafted from %d:%s)\n') %
2555 '(was grafted from %d:%s)\n') %
2554 (r, repo[r], rev, ctx))
2556 (r, repo[r], rev, ctx))
2555 revs.remove(r)
2557 revs.remove(r)
2556 if not revs:
2558 if not revs:
2557 return -1
2559 return -1
2558
2560
2559 if opts.get('no_commit'):
2561 if opts.get('no_commit'):
2560 statedata['no_commit'] = True
2562 statedata['no_commit'] = True
2561 for pos, ctx in enumerate(repo.set("%ld", revs)):
2563 for pos, ctx in enumerate(repo.set("%ld", revs)):
2562 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2564 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2563 ctx.description().split('\n', 1)[0])
2565 ctx.description().split('\n', 1)[0])
2564 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2566 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2565 if names:
2567 if names:
2566 desc += ' (%s)' % ' '.join(names)
2568 desc += ' (%s)' % ' '.join(names)
2567 ui.status(_('grafting %s\n') % desc)
2569 ui.status(_('grafting %s\n') % desc)
2568 if opts.get('dry_run'):
2570 if opts.get('dry_run'):
2569 continue
2571 continue
2570
2572
2571 source = ctx.extra().get('source')
2573 source = ctx.extra().get('source')
2572 extra = {}
2574 extra = {}
2573 if source:
2575 if source:
2574 extra['source'] = source
2576 extra['source'] = source
2575 extra['intermediate-source'] = ctx.hex()
2577 extra['intermediate-source'] = ctx.hex()
2576 else:
2578 else:
2577 extra['source'] = ctx.hex()
2579 extra['source'] = ctx.hex()
2578 user = ctx.user()
2580 user = ctx.user()
2579 if opts.get('user'):
2581 if opts.get('user'):
2580 user = opts['user']
2582 user = opts['user']
2581 statedata['user'] = user
2583 statedata['user'] = user
2582 date = ctx.date()
2584 date = ctx.date()
2583 if opts.get('date'):
2585 if opts.get('date'):
2584 date = opts['date']
2586 date = opts['date']
2585 statedata['date'] = date
2587 statedata['date'] = date
2586 message = ctx.description()
2588 message = ctx.description()
2587 if opts.get('log'):
2589 if opts.get('log'):
2588 message += '\n(grafted from %s)' % ctx.hex()
2590 message += '\n(grafted from %s)' % ctx.hex()
2589 statedata['log'] = True
2591 statedata['log'] = True
2590
2592
2591 # we don't merge the first commit when continuing
2593 # we don't merge the first commit when continuing
2592 if not cont:
2594 if not cont:
2593 # perform the graft merge with p1(rev) as 'ancestor'
2595 # perform the graft merge with p1(rev) as 'ancestor'
2594 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2596 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2595 base = ctx.p1() if basectx is None else basectx
2597 base = ctx.p1() if basectx is None else basectx
2596 with ui.configoverride(overrides, 'graft'):
2598 with ui.configoverride(overrides, 'graft'):
2597 stats = mergemod.graft(repo, ctx, base, ['local', 'graft'])
2599 stats = mergemod.graft(repo, ctx, base, ['local', 'graft'])
2598 # report any conflicts
2600 # report any conflicts
2599 if stats.unresolvedcount > 0:
2601 if stats.unresolvedcount > 0:
2600 # write out state for --continue
2602 # write out state for --continue
2601 nodes = [repo[rev].hex() for rev in revs[pos:]]
2603 nodes = [repo[rev].hex() for rev in revs[pos:]]
2602 statedata['nodes'] = nodes
2604 statedata['nodes'] = nodes
2603 stateversion = 1
2605 stateversion = 1
2604 graftstate.save(stateversion, statedata)
2606 graftstate.save(stateversion, statedata)
2605 hint = _("use 'hg resolve' and 'hg graft --continue'")
2607 hint = _("use 'hg resolve' and 'hg graft --continue'")
2606 raise error.Abort(
2608 raise error.Abort(
2607 _("unresolved conflicts, can't continue"),
2609 _("unresolved conflicts, can't continue"),
2608 hint=hint)
2610 hint=hint)
2609 else:
2611 else:
2610 cont = False
2612 cont = False
2611
2613
2612 # commit if --no-commit is false
2614 # commit if --no-commit is false
2613 if not opts.get('no_commit'):
2615 if not opts.get('no_commit'):
2614 node = repo.commit(text=message, user=user, date=date, extra=extra,
2616 node = repo.commit(text=message, user=user, date=date, extra=extra,
2615 editor=editor)
2617 editor=editor)
2616 if node is None:
2618 if node is None:
2617 ui.warn(
2619 ui.warn(
2618 _('note: graft of %d:%s created no changes to commit\n') %
2620 _('note: graft of %d:%s created no changes to commit\n') %
2619 (ctx.rev(), ctx))
2621 (ctx.rev(), ctx))
2620 # checking that newnodes exist because old state files won't have it
2622 # checking that newnodes exist because old state files won't have it
2621 elif statedata.get('newnodes') is not None:
2623 elif statedata.get('newnodes') is not None:
2622 statedata['newnodes'].append(node)
2624 statedata['newnodes'].append(node)
2623
2625
2624 # remove state when we complete successfully
2626 # remove state when we complete successfully
2625 if not opts.get('dry_run'):
2627 if not opts.get('dry_run'):
2626 graftstate.delete()
2628 graftstate.delete()
2627
2629
2628 return 0
2630 return 0
2629
2631
2630 def _abortgraft(ui, repo, graftstate):
2632 def _abortgraft(ui, repo, graftstate):
2631 """abort the interrupted graft and rollbacks to the state before interrupted
2633 """abort the interrupted graft and rollbacks to the state before interrupted
2632 graft"""
2634 graft"""
2633 if not graftstate.exists():
2635 if not graftstate.exists():
2634 raise error.Abort(_("no interrupted graft to abort"))
2636 raise error.Abort(_("no interrupted graft to abort"))
2635 statedata = _readgraftstate(repo, graftstate)
2637 statedata = _readgraftstate(repo, graftstate)
2636 newnodes = statedata.get('newnodes')
2638 newnodes = statedata.get('newnodes')
2637 if newnodes is None:
2639 if newnodes is None:
2638 # and old graft state which does not have all the data required to abort
2640 # and old graft state which does not have all the data required to abort
2639 # the graft
2641 # the graft
2640 raise error.Abort(_("cannot abort using an old graftstate"))
2642 raise error.Abort(_("cannot abort using an old graftstate"))
2641
2643
2642 # changeset from which graft operation was started
2644 # changeset from which graft operation was started
2643 if len(newnodes) > 0:
2645 if len(newnodes) > 0:
2644 startctx = repo[newnodes[0]].p1()
2646 startctx = repo[newnodes[0]].p1()
2645 else:
2647 else:
2646 startctx = repo['.']
2648 startctx = repo['.']
2647 # whether to strip or not
2649 # whether to strip or not
2648 cleanup = False
2650 cleanup = False
2649 if newnodes:
2651 if newnodes:
2650 newnodes = [repo[r].rev() for r in newnodes]
2652 newnodes = [repo[r].rev() for r in newnodes]
2651 cleanup = True
2653 cleanup = True
2652 # checking that none of the newnodes turned public or is public
2654 # checking that none of the newnodes turned public or is public
2653 immutable = [c for c in newnodes if not repo[c].mutable()]
2655 immutable = [c for c in newnodes if not repo[c].mutable()]
2654 if immutable:
2656 if immutable:
2655 repo.ui.warn(_("cannot clean up public changesets %s\n")
2657 repo.ui.warn(_("cannot clean up public changesets %s\n")
2656 % ', '.join(bytes(repo[r]) for r in immutable),
2658 % ', '.join(bytes(repo[r]) for r in immutable),
2657 hint=_("see 'hg help phases' for details"))
2659 hint=_("see 'hg help phases' for details"))
2658 cleanup = False
2660 cleanup = False
2659
2661
2660 # checking that no new nodes are created on top of grafted revs
2662 # checking that no new nodes are created on top of grafted revs
2661 desc = set(repo.changelog.descendants(newnodes))
2663 desc = set(repo.changelog.descendants(newnodes))
2662 if desc - set(newnodes):
2664 if desc - set(newnodes):
2663 repo.ui.warn(_("new changesets detected on destination "
2665 repo.ui.warn(_("new changesets detected on destination "
2664 "branch, can't strip\n"))
2666 "branch, can't strip\n"))
2665 cleanup = False
2667 cleanup = False
2666
2668
2667 if cleanup:
2669 if cleanup:
2668 with repo.wlock(), repo.lock():
2670 with repo.wlock(), repo.lock():
2669 hg.updaterepo(repo, startctx.node(), overwrite=True)
2671 hg.updaterepo(repo, startctx.node(), overwrite=True)
2670 # stripping the new nodes created
2672 # stripping the new nodes created
2671 strippoints = [c.node() for c in repo.set("roots(%ld)",
2673 strippoints = [c.node() for c in repo.set("roots(%ld)",
2672 newnodes)]
2674 newnodes)]
2673 repair.strip(repo.ui, repo, strippoints, backup=False)
2675 repair.strip(repo.ui, repo, strippoints, backup=False)
2674
2676
2675 if not cleanup:
2677 if not cleanup:
2676 # we don't update to the startnode if we can't strip
2678 # we don't update to the startnode if we can't strip
2677 startctx = repo['.']
2679 startctx = repo['.']
2678 hg.updaterepo(repo, startctx.node(), overwrite=True)
2680 hg.updaterepo(repo, startctx.node(), overwrite=True)
2679
2681
2680 ui.status(_("graft aborted\n"))
2682 ui.status(_("graft aborted\n"))
2681 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2683 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2682 graftstate.delete()
2684 graftstate.delete()
2683 return 0
2685 return 0
2684
2686
2685 def _readgraftstate(repo, graftstate):
2687 def _readgraftstate(repo, graftstate):
2686 """read the graft state file and return a dict of the data stored in it"""
2688 """read the graft state file and return a dict of the data stored in it"""
2687 try:
2689 try:
2688 return graftstate.read()
2690 return graftstate.read()
2689 except error.CorruptedState:
2691 except error.CorruptedState:
2690 nodes = repo.vfs.read('graftstate').splitlines()
2692 nodes = repo.vfs.read('graftstate').splitlines()
2691 return {'nodes': nodes}
2693 return {'nodes': nodes}
2692
2694
2693 def _stopgraft(ui, repo, graftstate):
2695 def _stopgraft(ui, repo, graftstate):
2694 """stop the interrupted graft"""
2696 """stop the interrupted graft"""
2695 if not graftstate.exists():
2697 if not graftstate.exists():
2696 raise error.Abort(_("no interrupted graft found"))
2698 raise error.Abort(_("no interrupted graft found"))
2697 pctx = repo['.']
2699 pctx = repo['.']
2698 hg.updaterepo(repo, pctx.node(), overwrite=True)
2700 hg.updaterepo(repo, pctx.node(), overwrite=True)
2699 graftstate.delete()
2701 graftstate.delete()
2700 ui.status(_("stopped the interrupted graft\n"))
2702 ui.status(_("stopped the interrupted graft\n"))
2701 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2703 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2702 return 0
2704 return 0
2703
2705
2704 @command('grep',
2706 @command('grep',
2705 [('0', 'print0', None, _('end fields with NUL')),
2707 [('0', 'print0', None, _('end fields with NUL')),
2706 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2708 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2707 ('', 'diff', None, _('print all revisions when the term was introduced '
2709 ('', 'diff', None, _('print all revisions when the term was introduced '
2708 'or removed')),
2710 'or removed')),
2709 ('a', 'text', None, _('treat all files as text')),
2711 ('a', 'text', None, _('treat all files as text')),
2710 ('f', 'follow', None,
2712 ('f', 'follow', None,
2711 _('follow changeset history,'
2713 _('follow changeset history,'
2712 ' or file history across copies and renames')),
2714 ' or file history across copies and renames')),
2713 ('i', 'ignore-case', None, _('ignore case when matching')),
2715 ('i', 'ignore-case', None, _('ignore case when matching')),
2714 ('l', 'files-with-matches', None,
2716 ('l', 'files-with-matches', None,
2715 _('print only filenames and revisions that match')),
2717 _('print only filenames and revisions that match')),
2716 ('n', 'line-number', None, _('print matching line numbers')),
2718 ('n', 'line-number', None, _('print matching line numbers')),
2717 ('r', 'rev', [],
2719 ('r', 'rev', [],
2718 _('only search files changed within revision range'), _('REV')),
2720 _('only search files changed within revision range'), _('REV')),
2719 ('', 'all-files', None,
2721 ('', 'all-files', None,
2720 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2722 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2721 ('u', 'user', None, _('list the author (long with -v)')),
2723 ('u', 'user', None, _('list the author (long with -v)')),
2722 ('d', 'date', None, _('list the date (short with -q)')),
2724 ('d', 'date', None, _('list the date (short with -q)')),
2723 ] + formatteropts + walkopts,
2725 ] + formatteropts + walkopts,
2724 _('[OPTION]... PATTERN [FILE]...'),
2726 _('[OPTION]... PATTERN [FILE]...'),
2725 helpcategory=command.CATEGORY_FILE_CONTENTS,
2727 helpcategory=command.CATEGORY_FILE_CONTENTS,
2726 inferrepo=True,
2728 inferrepo=True,
2727 intents={INTENT_READONLY})
2729 intents={INTENT_READONLY})
2728 def grep(ui, repo, pattern, *pats, **opts):
2730 def grep(ui, repo, pattern, *pats, **opts):
2729 """search revision history for a pattern in specified files
2731 """search revision history for a pattern in specified files
2730
2732
2731 Search revision history for a regular expression in the specified
2733 Search revision history for a regular expression in the specified
2732 files or the entire project.
2734 files or the entire project.
2733
2735
2734 By default, grep prints the most recent revision number for each
2736 By default, grep prints the most recent revision number for each
2735 file in which it finds a match. To get it to print every revision
2737 file in which it finds a match. To get it to print every revision
2736 that contains a change in match status ("-" for a match that becomes
2738 that contains a change in match status ("-" for a match that becomes
2737 a non-match, or "+" for a non-match that becomes a match), use the
2739 a non-match, or "+" for a non-match that becomes a match), use the
2738 --diff flag.
2740 --diff flag.
2739
2741
2740 PATTERN can be any Python (roughly Perl-compatible) regular
2742 PATTERN can be any Python (roughly Perl-compatible) regular
2741 expression.
2743 expression.
2742
2744
2743 If no FILEs are specified (and -f/--follow isn't set), all files in
2745 If no FILEs are specified (and -f/--follow isn't set), all files in
2744 the repository are searched, including those that don't exist in the
2746 the repository are searched, including those that don't exist in the
2745 current branch or have been deleted in a prior changeset.
2747 current branch or have been deleted in a prior changeset.
2746
2748
2747 .. container:: verbose
2749 .. container:: verbose
2748
2750
2749 Template:
2751 Template:
2750
2752
2751 The following keywords are supported in addition to the common template
2753 The following keywords are supported in addition to the common template
2752 keywords and functions. See also :hg:`help templates`.
2754 keywords and functions. See also :hg:`help templates`.
2753
2755
2754 :change: String. Character denoting insertion ``+`` or removal ``-``.
2756 :change: String. Character denoting insertion ``+`` or removal ``-``.
2755 Available if ``--diff`` is specified.
2757 Available if ``--diff`` is specified.
2756 :lineno: Integer. Line number of the match.
2758 :lineno: Integer. Line number of the match.
2757 :path: String. Repository-absolute path of the file.
2759 :path: String. Repository-absolute path of the file.
2758 :texts: List of text chunks.
2760 :texts: List of text chunks.
2759
2761
2760 And each entry of ``{texts}`` provides the following sub-keywords.
2762 And each entry of ``{texts}`` provides the following sub-keywords.
2761
2763
2762 :matched: Boolean. True if the chunk matches the specified pattern.
2764 :matched: Boolean. True if the chunk matches the specified pattern.
2763 :text: String. Chunk content.
2765 :text: String. Chunk content.
2764
2766
2765 See :hg:`help templates.operators` for the list expansion syntax.
2767 See :hg:`help templates.operators` for the list expansion syntax.
2766
2768
2767 Returns 0 if a match is found, 1 otherwise.
2769 Returns 0 if a match is found, 1 otherwise.
2768 """
2770 """
2769 opts = pycompat.byteskwargs(opts)
2771 opts = pycompat.byteskwargs(opts)
2770 diff = opts.get('all') or opts.get('diff')
2772 diff = opts.get('all') or opts.get('diff')
2771 all_files = opts.get('all_files')
2773 all_files = opts.get('all_files')
2772 if diff and opts.get('all_files'):
2774 if diff and opts.get('all_files'):
2773 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2775 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2774 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2776 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2775 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2777 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2776 # experimental config: commands.grep.all-files
2778 # experimental config: commands.grep.all-files
2777 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2779 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2778 plaingrep = opts.get('all_files') and not opts.get('rev')
2780 plaingrep = opts.get('all_files') and not opts.get('rev')
2779 if plaingrep:
2781 if plaingrep:
2780 opts['rev'] = ['wdir()']
2782 opts['rev'] = ['wdir()']
2781
2783
2782 reflags = re.M
2784 reflags = re.M
2783 if opts.get('ignore_case'):
2785 if opts.get('ignore_case'):
2784 reflags |= re.I
2786 reflags |= re.I
2785 try:
2787 try:
2786 regexp = util.re.compile(pattern, reflags)
2788 regexp = util.re.compile(pattern, reflags)
2787 except re.error as inst:
2789 except re.error as inst:
2788 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2790 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2789 return 1
2791 return 1
2790 sep, eol = ':', '\n'
2792 sep, eol = ':', '\n'
2791 if opts.get('print0'):
2793 if opts.get('print0'):
2792 sep = eol = '\0'
2794 sep = eol = '\0'
2793
2795
2794 getfile = util.lrucachefunc(repo.file)
2796 getfile = util.lrucachefunc(repo.file)
2795
2797
2796 def matchlines(body):
2798 def matchlines(body):
2797 begin = 0
2799 begin = 0
2798 linenum = 0
2800 linenum = 0
2799 while begin < len(body):
2801 while begin < len(body):
2800 match = regexp.search(body, begin)
2802 match = regexp.search(body, begin)
2801 if not match:
2803 if not match:
2802 break
2804 break
2803 mstart, mend = match.span()
2805 mstart, mend = match.span()
2804 linenum += body.count('\n', begin, mstart) + 1
2806 linenum += body.count('\n', begin, mstart) + 1
2805 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2807 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2806 begin = body.find('\n', mend) + 1 or len(body) + 1
2808 begin = body.find('\n', mend) + 1 or len(body) + 1
2807 lend = begin - 1
2809 lend = begin - 1
2808 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2810 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2809
2811
2810 class linestate(object):
2812 class linestate(object):
2811 def __init__(self, line, linenum, colstart, colend):
2813 def __init__(self, line, linenum, colstart, colend):
2812 self.line = line
2814 self.line = line
2813 self.linenum = linenum
2815 self.linenum = linenum
2814 self.colstart = colstart
2816 self.colstart = colstart
2815 self.colend = colend
2817 self.colend = colend
2816
2818
2817 def __hash__(self):
2819 def __hash__(self):
2818 return hash((self.linenum, self.line))
2820 return hash((self.linenum, self.line))
2819
2821
2820 def __eq__(self, other):
2822 def __eq__(self, other):
2821 return self.line == other.line
2823 return self.line == other.line
2822
2824
2823 def findpos(self):
2825 def findpos(self):
2824 """Iterate all (start, end) indices of matches"""
2826 """Iterate all (start, end) indices of matches"""
2825 yield self.colstart, self.colend
2827 yield self.colstart, self.colend
2826 p = self.colend
2828 p = self.colend
2827 while p < len(self.line):
2829 while p < len(self.line):
2828 m = regexp.search(self.line, p)
2830 m = regexp.search(self.line, p)
2829 if not m:
2831 if not m:
2830 break
2832 break
2831 yield m.span()
2833 yield m.span()
2832 p = m.end()
2834 p = m.end()
2833
2835
2834 matches = {}
2836 matches = {}
2835 copies = {}
2837 copies = {}
2836 def grepbody(fn, rev, body):
2838 def grepbody(fn, rev, body):
2837 matches[rev].setdefault(fn, [])
2839 matches[rev].setdefault(fn, [])
2838 m = matches[rev][fn]
2840 m = matches[rev][fn]
2839 for lnum, cstart, cend, line in matchlines(body):
2841 for lnum, cstart, cend, line in matchlines(body):
2840 s = linestate(line, lnum, cstart, cend)
2842 s = linestate(line, lnum, cstart, cend)
2841 m.append(s)
2843 m.append(s)
2842
2844
2843 def difflinestates(a, b):
2845 def difflinestates(a, b):
2844 sm = difflib.SequenceMatcher(None, a, b)
2846 sm = difflib.SequenceMatcher(None, a, b)
2845 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2847 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2846 if tag == r'insert':
2848 if tag == r'insert':
2847 for i in pycompat.xrange(blo, bhi):
2849 for i in pycompat.xrange(blo, bhi):
2848 yield ('+', b[i])
2850 yield ('+', b[i])
2849 elif tag == r'delete':
2851 elif tag == r'delete':
2850 for i in pycompat.xrange(alo, ahi):
2852 for i in pycompat.xrange(alo, ahi):
2851 yield ('-', a[i])
2853 yield ('-', a[i])
2852 elif tag == r'replace':
2854 elif tag == r'replace':
2853 for i in pycompat.xrange(alo, ahi):
2855 for i in pycompat.xrange(alo, ahi):
2854 yield ('-', a[i])
2856 yield ('-', a[i])
2855 for i in pycompat.xrange(blo, bhi):
2857 for i in pycompat.xrange(blo, bhi):
2856 yield ('+', b[i])
2858 yield ('+', b[i])
2857
2859
2858 uipathfn = scmutil.getuipathfn(repo)
2860 uipathfn = scmutil.getuipathfn(repo)
2859 def display(fm, fn, ctx, pstates, states):
2861 def display(fm, fn, ctx, pstates, states):
2860 rev = scmutil.intrev(ctx)
2862 rev = scmutil.intrev(ctx)
2861 if fm.isplain():
2863 if fm.isplain():
2862 formatuser = ui.shortuser
2864 formatuser = ui.shortuser
2863 else:
2865 else:
2864 formatuser = pycompat.bytestr
2866 formatuser = pycompat.bytestr
2865 if ui.quiet:
2867 if ui.quiet:
2866 datefmt = '%Y-%m-%d'
2868 datefmt = '%Y-%m-%d'
2867 else:
2869 else:
2868 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2870 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2869 found = False
2871 found = False
2870 @util.cachefunc
2872 @util.cachefunc
2871 def binary():
2873 def binary():
2872 flog = getfile(fn)
2874 flog = getfile(fn)
2873 try:
2875 try:
2874 return stringutil.binary(flog.read(ctx.filenode(fn)))
2876 return stringutil.binary(flog.read(ctx.filenode(fn)))
2875 except error.WdirUnsupported:
2877 except error.WdirUnsupported:
2876 return ctx[fn].isbinary()
2878 return ctx[fn].isbinary()
2877
2879
2878 fieldnamemap = {'linenumber': 'lineno'}
2880 fieldnamemap = {'linenumber': 'lineno'}
2879 if diff:
2881 if diff:
2880 iter = difflinestates(pstates, states)
2882 iter = difflinestates(pstates, states)
2881 else:
2883 else:
2882 iter = [('', l) for l in states]
2884 iter = [('', l) for l in states]
2883 for change, l in iter:
2885 for change, l in iter:
2884 fm.startitem()
2886 fm.startitem()
2885 fm.context(ctx=ctx)
2887 fm.context(ctx=ctx)
2886 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
2888 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
2887 fm.plain(uipathfn(fn), label='grep.filename')
2889 fm.plain(uipathfn(fn), label='grep.filename')
2888
2890
2889 cols = [
2891 cols = [
2890 ('rev', '%d', rev, not plaingrep, ''),
2892 ('rev', '%d', rev, not plaingrep, ''),
2891 ('linenumber', '%d', l.linenum, opts.get('line_number'), ''),
2893 ('linenumber', '%d', l.linenum, opts.get('line_number'), ''),
2892 ]
2894 ]
2893 if diff:
2895 if diff:
2894 cols.append(
2896 cols.append(
2895 ('change', '%s', change, True,
2897 ('change', '%s', change, True,
2896 'grep.inserted ' if change == '+' else 'grep.deleted ')
2898 'grep.inserted ' if change == '+' else 'grep.deleted ')
2897 )
2899 )
2898 cols.extend([
2900 cols.extend([
2899 ('user', '%s', formatuser(ctx.user()), opts.get('user'), ''),
2901 ('user', '%s', formatuser(ctx.user()), opts.get('user'), ''),
2900 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2902 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2901 opts.get('date'), ''),
2903 opts.get('date'), ''),
2902 ])
2904 ])
2903 for name, fmt, data, cond, extra_label in cols:
2905 for name, fmt, data, cond, extra_label in cols:
2904 if cond:
2906 if cond:
2905 fm.plain(sep, label='grep.sep')
2907 fm.plain(sep, label='grep.sep')
2906 field = fieldnamemap.get(name, name)
2908 field = fieldnamemap.get(name, name)
2907 label = extra_label + ('grep.%s' % name)
2909 label = extra_label + ('grep.%s' % name)
2908 fm.condwrite(cond, field, fmt, data, label=label)
2910 fm.condwrite(cond, field, fmt, data, label=label)
2909 if not opts.get('files_with_matches'):
2911 if not opts.get('files_with_matches'):
2910 fm.plain(sep, label='grep.sep')
2912 fm.plain(sep, label='grep.sep')
2911 if not opts.get('text') and binary():
2913 if not opts.get('text') and binary():
2912 fm.plain(_(" Binary file matches"))
2914 fm.plain(_(" Binary file matches"))
2913 else:
2915 else:
2914 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2916 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2915 fm.plain(eol)
2917 fm.plain(eol)
2916 found = True
2918 found = True
2917 if opts.get('files_with_matches'):
2919 if opts.get('files_with_matches'):
2918 break
2920 break
2919 return found
2921 return found
2920
2922
2921 def displaymatches(fm, l):
2923 def displaymatches(fm, l):
2922 p = 0
2924 p = 0
2923 for s, e in l.findpos():
2925 for s, e in l.findpos():
2924 if p < s:
2926 if p < s:
2925 fm.startitem()
2927 fm.startitem()
2926 fm.write('text', '%s', l.line[p:s])
2928 fm.write('text', '%s', l.line[p:s])
2927 fm.data(matched=False)
2929 fm.data(matched=False)
2928 fm.startitem()
2930 fm.startitem()
2929 fm.write('text', '%s', l.line[s:e], label='grep.match')
2931 fm.write('text', '%s', l.line[s:e], label='grep.match')
2930 fm.data(matched=True)
2932 fm.data(matched=True)
2931 p = e
2933 p = e
2932 if p < len(l.line):
2934 if p < len(l.line):
2933 fm.startitem()
2935 fm.startitem()
2934 fm.write('text', '%s', l.line[p:])
2936 fm.write('text', '%s', l.line[p:])
2935 fm.data(matched=False)
2937 fm.data(matched=False)
2936 fm.end()
2938 fm.end()
2937
2939
2938 skip = set()
2940 skip = set()
2939 revfiles = {}
2941 revfiles = {}
2940 match = scmutil.match(repo[None], pats, opts)
2942 match = scmutil.match(repo[None], pats, opts)
2941 found = False
2943 found = False
2942 follow = opts.get('follow')
2944 follow = opts.get('follow')
2943
2945
2944 getrenamed = scmutil.getrenamedfn(repo)
2946 getrenamed = scmutil.getrenamedfn(repo)
2945 def prep(ctx, fns):
2947 def prep(ctx, fns):
2946 rev = ctx.rev()
2948 rev = ctx.rev()
2947 pctx = ctx.p1()
2949 pctx = ctx.p1()
2948 parent = pctx.rev()
2950 parent = pctx.rev()
2949 matches.setdefault(rev, {})
2951 matches.setdefault(rev, {})
2950 matches.setdefault(parent, {})
2952 matches.setdefault(parent, {})
2951 files = revfiles.setdefault(rev, [])
2953 files = revfiles.setdefault(rev, [])
2952 for fn in fns:
2954 for fn in fns:
2953 flog = getfile(fn)
2955 flog = getfile(fn)
2954 try:
2956 try:
2955 fnode = ctx.filenode(fn)
2957 fnode = ctx.filenode(fn)
2956 except error.LookupError:
2958 except error.LookupError:
2957 continue
2959 continue
2958
2960
2959 copy = None
2961 copy = None
2960 if follow:
2962 if follow:
2961 copy = getrenamed(fn, rev)
2963 copy = getrenamed(fn, rev)
2962 if copy:
2964 if copy:
2963 copies.setdefault(rev, {})[fn] = copy
2965 copies.setdefault(rev, {})[fn] = copy
2964 if fn in skip:
2966 if fn in skip:
2965 skip.add(copy)
2967 skip.add(copy)
2966 if fn in skip:
2968 if fn in skip:
2967 continue
2969 continue
2968 files.append(fn)
2970 files.append(fn)
2969
2971
2970 if fn not in matches[rev]:
2972 if fn not in matches[rev]:
2971 try:
2973 try:
2972 content = flog.read(fnode)
2974 content = flog.read(fnode)
2973 except error.WdirUnsupported:
2975 except error.WdirUnsupported:
2974 content = ctx[fn].data()
2976 content = ctx[fn].data()
2975 grepbody(fn, rev, content)
2977 grepbody(fn, rev, content)
2976
2978
2977 pfn = copy or fn
2979 pfn = copy or fn
2978 if pfn not in matches[parent]:
2980 if pfn not in matches[parent]:
2979 try:
2981 try:
2980 fnode = pctx.filenode(pfn)
2982 fnode = pctx.filenode(pfn)
2981 grepbody(pfn, parent, flog.read(fnode))
2983 grepbody(pfn, parent, flog.read(fnode))
2982 except error.LookupError:
2984 except error.LookupError:
2983 pass
2985 pass
2984
2986
2985 ui.pager('grep')
2987 ui.pager('grep')
2986 fm = ui.formatter('grep', opts)
2988 fm = ui.formatter('grep', opts)
2987 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2989 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2988 rev = ctx.rev()
2990 rev = ctx.rev()
2989 parent = ctx.p1().rev()
2991 parent = ctx.p1().rev()
2990 for fn in sorted(revfiles.get(rev, [])):
2992 for fn in sorted(revfiles.get(rev, [])):
2991 states = matches[rev][fn]
2993 states = matches[rev][fn]
2992 copy = copies.get(rev, {}).get(fn)
2994 copy = copies.get(rev, {}).get(fn)
2993 if fn in skip:
2995 if fn in skip:
2994 if copy:
2996 if copy:
2995 skip.add(copy)
2997 skip.add(copy)
2996 continue
2998 continue
2997 pstates = matches.get(parent, {}).get(copy or fn, [])
2999 pstates = matches.get(parent, {}).get(copy or fn, [])
2998 if pstates or states:
3000 if pstates or states:
2999 r = display(fm, fn, ctx, pstates, states)
3001 r = display(fm, fn, ctx, pstates, states)
3000 found = found or r
3002 found = found or r
3001 if r and not diff and not all_files:
3003 if r and not diff and not all_files:
3002 skip.add(fn)
3004 skip.add(fn)
3003 if copy:
3005 if copy:
3004 skip.add(copy)
3006 skip.add(copy)
3005 del revfiles[rev]
3007 del revfiles[rev]
3006 # We will keep the matches dict for the duration of the window
3008 # We will keep the matches dict for the duration of the window
3007 # clear the matches dict once the window is over
3009 # clear the matches dict once the window is over
3008 if not revfiles:
3010 if not revfiles:
3009 matches.clear()
3011 matches.clear()
3010 fm.end()
3012 fm.end()
3011
3013
3012 return not found
3014 return not found
3013
3015
3014 @command('heads',
3016 @command('heads',
3015 [('r', 'rev', '',
3017 [('r', 'rev', '',
3016 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3018 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3017 ('t', 'topo', False, _('show topological heads only')),
3019 ('t', 'topo', False, _('show topological heads only')),
3018 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3020 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3019 ('c', 'closed', False, _('show normal and closed branch heads')),
3021 ('c', 'closed', False, _('show normal and closed branch heads')),
3020 ] + templateopts,
3022 ] + templateopts,
3021 _('[-ct] [-r STARTREV] [REV]...'),
3023 _('[-ct] [-r STARTREV] [REV]...'),
3022 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3024 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3023 intents={INTENT_READONLY})
3025 intents={INTENT_READONLY})
3024 def heads(ui, repo, *branchrevs, **opts):
3026 def heads(ui, repo, *branchrevs, **opts):
3025 """show branch heads
3027 """show branch heads
3026
3028
3027 With no arguments, show all open branch heads in the repository.
3029 With no arguments, show all open branch heads in the repository.
3028 Branch heads are changesets that have no descendants on the
3030 Branch heads are changesets that have no descendants on the
3029 same branch. They are where development generally takes place and
3031 same branch. They are where development generally takes place and
3030 are the usual targets for update and merge operations.
3032 are the usual targets for update and merge operations.
3031
3033
3032 If one or more REVs are given, only open branch heads on the
3034 If one or more REVs are given, only open branch heads on the
3033 branches associated with the specified changesets are shown. This
3035 branches associated with the specified changesets are shown. This
3034 means that you can use :hg:`heads .` to see the heads on the
3036 means that you can use :hg:`heads .` to see the heads on the
3035 currently checked-out branch.
3037 currently checked-out branch.
3036
3038
3037 If -c/--closed is specified, also show branch heads marked closed
3039 If -c/--closed is specified, also show branch heads marked closed
3038 (see :hg:`commit --close-branch`).
3040 (see :hg:`commit --close-branch`).
3039
3041
3040 If STARTREV is specified, only those heads that are descendants of
3042 If STARTREV is specified, only those heads that are descendants of
3041 STARTREV will be displayed.
3043 STARTREV will be displayed.
3042
3044
3043 If -t/--topo is specified, named branch mechanics will be ignored and only
3045 If -t/--topo is specified, named branch mechanics will be ignored and only
3044 topological heads (changesets with no children) will be shown.
3046 topological heads (changesets with no children) will be shown.
3045
3047
3046 Returns 0 if matching heads are found, 1 if not.
3048 Returns 0 if matching heads are found, 1 if not.
3047 """
3049 """
3048
3050
3049 opts = pycompat.byteskwargs(opts)
3051 opts = pycompat.byteskwargs(opts)
3050 start = None
3052 start = None
3051 rev = opts.get('rev')
3053 rev = opts.get('rev')
3052 if rev:
3054 if rev:
3053 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3055 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3054 start = scmutil.revsingle(repo, rev, None).node()
3056 start = scmutil.revsingle(repo, rev, None).node()
3055
3057
3056 if opts.get('topo'):
3058 if opts.get('topo'):
3057 heads = [repo[h] for h in repo.heads(start)]
3059 heads = [repo[h] for h in repo.heads(start)]
3058 else:
3060 else:
3059 heads = []
3061 heads = []
3060 for branch in repo.branchmap():
3062 for branch in repo.branchmap():
3061 heads += repo.branchheads(branch, start, opts.get('closed'))
3063 heads += repo.branchheads(branch, start, opts.get('closed'))
3062 heads = [repo[h] for h in heads]
3064 heads = [repo[h] for h in heads]
3063
3065
3064 if branchrevs:
3066 if branchrevs:
3065 branches = set(repo[r].branch()
3067 branches = set(repo[r].branch()
3066 for r in scmutil.revrange(repo, branchrevs))
3068 for r in scmutil.revrange(repo, branchrevs))
3067 heads = [h for h in heads if h.branch() in branches]
3069 heads = [h for h in heads if h.branch() in branches]
3068
3070
3069 if opts.get('active') and branchrevs:
3071 if opts.get('active') and branchrevs:
3070 dagheads = repo.heads(start)
3072 dagheads = repo.heads(start)
3071 heads = [h for h in heads if h.node() in dagheads]
3073 heads = [h for h in heads if h.node() in dagheads]
3072
3074
3073 if branchrevs:
3075 if branchrevs:
3074 haveheads = set(h.branch() for h in heads)
3076 haveheads = set(h.branch() for h in heads)
3075 if branches - haveheads:
3077 if branches - haveheads:
3076 headless = ', '.join(b for b in branches - haveheads)
3078 headless = ', '.join(b for b in branches - haveheads)
3077 msg = _('no open branch heads found on branches %s')
3079 msg = _('no open branch heads found on branches %s')
3078 if opts.get('rev'):
3080 if opts.get('rev'):
3079 msg += _(' (started at %s)') % opts['rev']
3081 msg += _(' (started at %s)') % opts['rev']
3080 ui.warn((msg + '\n') % headless)
3082 ui.warn((msg + '\n') % headless)
3081
3083
3082 if not heads:
3084 if not heads:
3083 return 1
3085 return 1
3084
3086
3085 ui.pager('heads')
3087 ui.pager('heads')
3086 heads = sorted(heads, key=lambda x: -x.rev())
3088 heads = sorted(heads, key=lambda x: -x.rev())
3087 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3089 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3088 for ctx in heads:
3090 for ctx in heads:
3089 displayer.show(ctx)
3091 displayer.show(ctx)
3090 displayer.close()
3092 displayer.close()
3091
3093
3092 @command('help',
3094 @command('help',
3093 [('e', 'extension', None, _('show only help for extensions')),
3095 [('e', 'extension', None, _('show only help for extensions')),
3094 ('c', 'command', None, _('show only help for commands')),
3096 ('c', 'command', None, _('show only help for commands')),
3095 ('k', 'keyword', None, _('show topics matching keyword')),
3097 ('k', 'keyword', None, _('show topics matching keyword')),
3096 ('s', 'system', [],
3098 ('s', 'system', [],
3097 _('show help for specific platform(s)'), _('PLATFORM')),
3099 _('show help for specific platform(s)'), _('PLATFORM')),
3098 ],
3100 ],
3099 _('[-eck] [-s PLATFORM] [TOPIC]'),
3101 _('[-eck] [-s PLATFORM] [TOPIC]'),
3100 helpcategory=command.CATEGORY_HELP,
3102 helpcategory=command.CATEGORY_HELP,
3101 norepo=True,
3103 norepo=True,
3102 intents={INTENT_READONLY})
3104 intents={INTENT_READONLY})
3103 def help_(ui, name=None, **opts):
3105 def help_(ui, name=None, **opts):
3104 """show help for a given topic or a help overview
3106 """show help for a given topic or a help overview
3105
3107
3106 With no arguments, print a list of commands with short help messages.
3108 With no arguments, print a list of commands with short help messages.
3107
3109
3108 Given a topic, extension, or command name, print help for that
3110 Given a topic, extension, or command name, print help for that
3109 topic.
3111 topic.
3110
3112
3111 Returns 0 if successful.
3113 Returns 0 if successful.
3112 """
3114 """
3113
3115
3114 keep = opts.get(r'system') or []
3116 keep = opts.get(r'system') or []
3115 if len(keep) == 0:
3117 if len(keep) == 0:
3116 if pycompat.sysplatform.startswith('win'):
3118 if pycompat.sysplatform.startswith('win'):
3117 keep.append('windows')
3119 keep.append('windows')
3118 elif pycompat.sysplatform == 'OpenVMS':
3120 elif pycompat.sysplatform == 'OpenVMS':
3119 keep.append('vms')
3121 keep.append('vms')
3120 elif pycompat.sysplatform == 'plan9':
3122 elif pycompat.sysplatform == 'plan9':
3121 keep.append('plan9')
3123 keep.append('plan9')
3122 else:
3124 else:
3123 keep.append('unix')
3125 keep.append('unix')
3124 keep.append(pycompat.sysplatform.lower())
3126 keep.append(pycompat.sysplatform.lower())
3125 if ui.verbose:
3127 if ui.verbose:
3126 keep.append('verbose')
3128 keep.append('verbose')
3127
3129
3128 commands = sys.modules[__name__]
3130 commands = sys.modules[__name__]
3129 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3131 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3130 ui.pager('help')
3132 ui.pager('help')
3131 ui.write(formatted)
3133 ui.write(formatted)
3132
3134
3133
3135
3134 @command('identify|id',
3136 @command('identify|id',
3135 [('r', 'rev', '',
3137 [('r', 'rev', '',
3136 _('identify the specified revision'), _('REV')),
3138 _('identify the specified revision'), _('REV')),
3137 ('n', 'num', None, _('show local revision number')),
3139 ('n', 'num', None, _('show local revision number')),
3138 ('i', 'id', None, _('show global revision id')),
3140 ('i', 'id', None, _('show global revision id')),
3139 ('b', 'branch', None, _('show branch')),
3141 ('b', 'branch', None, _('show branch')),
3140 ('t', 'tags', None, _('show tags')),
3142 ('t', 'tags', None, _('show tags')),
3141 ('B', 'bookmarks', None, _('show bookmarks')),
3143 ('B', 'bookmarks', None, _('show bookmarks')),
3142 ] + remoteopts + formatteropts,
3144 ] + remoteopts + formatteropts,
3143 _('[-nibtB] [-r REV] [SOURCE]'),
3145 _('[-nibtB] [-r REV] [SOURCE]'),
3144 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3146 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3145 optionalrepo=True,
3147 optionalrepo=True,
3146 intents={INTENT_READONLY})
3148 intents={INTENT_READONLY})
3147 def identify(ui, repo, source=None, rev=None,
3149 def identify(ui, repo, source=None, rev=None,
3148 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3150 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3149 """identify the working directory or specified revision
3151 """identify the working directory or specified revision
3150
3152
3151 Print a summary identifying the repository state at REV using one or
3153 Print a summary identifying the repository state at REV using one or
3152 two parent hash identifiers, followed by a "+" if the working
3154 two parent hash identifiers, followed by a "+" if the working
3153 directory has uncommitted changes, the branch name (if not default),
3155 directory has uncommitted changes, the branch name (if not default),
3154 a list of tags, and a list of bookmarks.
3156 a list of tags, and a list of bookmarks.
3155
3157
3156 When REV is not given, print a summary of the current state of the
3158 When REV is not given, print a summary of the current state of the
3157 repository including the working directory. Specify -r. to get information
3159 repository including the working directory. Specify -r. to get information
3158 of the working directory parent without scanning uncommitted changes.
3160 of the working directory parent without scanning uncommitted changes.
3159
3161
3160 Specifying a path to a repository root or Mercurial bundle will
3162 Specifying a path to a repository root or Mercurial bundle will
3161 cause lookup to operate on that repository/bundle.
3163 cause lookup to operate on that repository/bundle.
3162
3164
3163 .. container:: verbose
3165 .. container:: verbose
3164
3166
3165 Template:
3167 Template:
3166
3168
3167 The following keywords are supported in addition to the common template
3169 The following keywords are supported in addition to the common template
3168 keywords and functions. See also :hg:`help templates`.
3170 keywords and functions. See also :hg:`help templates`.
3169
3171
3170 :dirty: String. Character ``+`` denoting if the working directory has
3172 :dirty: String. Character ``+`` denoting if the working directory has
3171 uncommitted changes.
3173 uncommitted changes.
3172 :id: String. One or two nodes, optionally followed by ``+``.
3174 :id: String. One or two nodes, optionally followed by ``+``.
3173 :parents: List of strings. Parent nodes of the changeset.
3175 :parents: List of strings. Parent nodes of the changeset.
3174
3176
3175 Examples:
3177 Examples:
3176
3178
3177 - generate a build identifier for the working directory::
3179 - generate a build identifier for the working directory::
3178
3180
3179 hg id --id > build-id.dat
3181 hg id --id > build-id.dat
3180
3182
3181 - find the revision corresponding to a tag::
3183 - find the revision corresponding to a tag::
3182
3184
3183 hg id -n -r 1.3
3185 hg id -n -r 1.3
3184
3186
3185 - check the most recent revision of a remote repository::
3187 - check the most recent revision of a remote repository::
3186
3188
3187 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3189 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3188
3190
3189 See :hg:`log` for generating more information about specific revisions,
3191 See :hg:`log` for generating more information about specific revisions,
3190 including full hash identifiers.
3192 including full hash identifiers.
3191
3193
3192 Returns 0 if successful.
3194 Returns 0 if successful.
3193 """
3195 """
3194
3196
3195 opts = pycompat.byteskwargs(opts)
3197 opts = pycompat.byteskwargs(opts)
3196 if not repo and not source:
3198 if not repo and not source:
3197 raise error.Abort(_("there is no Mercurial repository here "
3199 raise error.Abort(_("there is no Mercurial repository here "
3198 "(.hg not found)"))
3200 "(.hg not found)"))
3199
3201
3200 default = not (num or id or branch or tags or bookmarks)
3202 default = not (num or id or branch or tags or bookmarks)
3201 output = []
3203 output = []
3202 revs = []
3204 revs = []
3203
3205
3204 if source:
3206 if source:
3205 source, branches = hg.parseurl(ui.expandpath(source))
3207 source, branches = hg.parseurl(ui.expandpath(source))
3206 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3208 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3207 repo = peer.local()
3209 repo = peer.local()
3208 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3210 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3209
3211
3210 fm = ui.formatter('identify', opts)
3212 fm = ui.formatter('identify', opts)
3211 fm.startitem()
3213 fm.startitem()
3212
3214
3213 if not repo:
3215 if not repo:
3214 if num or branch or tags:
3216 if num or branch or tags:
3215 raise error.Abort(
3217 raise error.Abort(
3216 _("can't query remote revision number, branch, or tags"))
3218 _("can't query remote revision number, branch, or tags"))
3217 if not rev and revs:
3219 if not rev and revs:
3218 rev = revs[0]
3220 rev = revs[0]
3219 if not rev:
3221 if not rev:
3220 rev = "tip"
3222 rev = "tip"
3221
3223
3222 remoterev = peer.lookup(rev)
3224 remoterev = peer.lookup(rev)
3223 hexrev = fm.hexfunc(remoterev)
3225 hexrev = fm.hexfunc(remoterev)
3224 if default or id:
3226 if default or id:
3225 output = [hexrev]
3227 output = [hexrev]
3226 fm.data(id=hexrev)
3228 fm.data(id=hexrev)
3227
3229
3228 @util.cachefunc
3230 @util.cachefunc
3229 def getbms():
3231 def getbms():
3230 bms = []
3232 bms = []
3231
3233
3232 if 'bookmarks' in peer.listkeys('namespaces'):
3234 if 'bookmarks' in peer.listkeys('namespaces'):
3233 hexremoterev = hex(remoterev)
3235 hexremoterev = hex(remoterev)
3234 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3236 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3235 if bmr == hexremoterev]
3237 if bmr == hexremoterev]
3236
3238
3237 return sorted(bms)
3239 return sorted(bms)
3238
3240
3239 if fm.isplain():
3241 if fm.isplain():
3240 if bookmarks:
3242 if bookmarks:
3241 output.extend(getbms())
3243 output.extend(getbms())
3242 elif default and not ui.quiet:
3244 elif default and not ui.quiet:
3243 # multiple bookmarks for a single parent separated by '/'
3245 # multiple bookmarks for a single parent separated by '/'
3244 bm = '/'.join(getbms())
3246 bm = '/'.join(getbms())
3245 if bm:
3247 if bm:
3246 output.append(bm)
3248 output.append(bm)
3247 else:
3249 else:
3248 fm.data(node=hex(remoterev))
3250 fm.data(node=hex(remoterev))
3249 if bookmarks or 'bookmarks' in fm.datahint():
3251 if bookmarks or 'bookmarks' in fm.datahint():
3250 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3252 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3251 else:
3253 else:
3252 if rev:
3254 if rev:
3253 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3255 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3254 ctx = scmutil.revsingle(repo, rev, None)
3256 ctx = scmutil.revsingle(repo, rev, None)
3255
3257
3256 if ctx.rev() is None:
3258 if ctx.rev() is None:
3257 ctx = repo[None]
3259 ctx = repo[None]
3258 parents = ctx.parents()
3260 parents = ctx.parents()
3259 taglist = []
3261 taglist = []
3260 for p in parents:
3262 for p in parents:
3261 taglist.extend(p.tags())
3263 taglist.extend(p.tags())
3262
3264
3263 dirty = ""
3265 dirty = ""
3264 if ctx.dirty(missing=True, merge=False, branch=False):
3266 if ctx.dirty(missing=True, merge=False, branch=False):
3265 dirty = '+'
3267 dirty = '+'
3266 fm.data(dirty=dirty)
3268 fm.data(dirty=dirty)
3267
3269
3268 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3270 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3269 if default or id:
3271 if default or id:
3270 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3272 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3271 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3273 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3272
3274
3273 if num:
3275 if num:
3274 numoutput = ["%d" % p.rev() for p in parents]
3276 numoutput = ["%d" % p.rev() for p in parents]
3275 output.append("%s%s" % ('+'.join(numoutput), dirty))
3277 output.append("%s%s" % ('+'.join(numoutput), dirty))
3276
3278
3277 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3279 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3278 for p in parents], name='node'))
3280 for p in parents], name='node'))
3279 else:
3281 else:
3280 hexoutput = fm.hexfunc(ctx.node())
3282 hexoutput = fm.hexfunc(ctx.node())
3281 if default or id:
3283 if default or id:
3282 output = [hexoutput]
3284 output = [hexoutput]
3283 fm.data(id=hexoutput)
3285 fm.data(id=hexoutput)
3284
3286
3285 if num:
3287 if num:
3286 output.append(pycompat.bytestr(ctx.rev()))
3288 output.append(pycompat.bytestr(ctx.rev()))
3287 taglist = ctx.tags()
3289 taglist = ctx.tags()
3288
3290
3289 if default and not ui.quiet:
3291 if default and not ui.quiet:
3290 b = ctx.branch()
3292 b = ctx.branch()
3291 if b != 'default':
3293 if b != 'default':
3292 output.append("(%s)" % b)
3294 output.append("(%s)" % b)
3293
3295
3294 # multiple tags for a single parent separated by '/'
3296 # multiple tags for a single parent separated by '/'
3295 t = '/'.join(taglist)
3297 t = '/'.join(taglist)
3296 if t:
3298 if t:
3297 output.append(t)
3299 output.append(t)
3298
3300
3299 # multiple bookmarks for a single parent separated by '/'
3301 # multiple bookmarks for a single parent separated by '/'
3300 bm = '/'.join(ctx.bookmarks())
3302 bm = '/'.join(ctx.bookmarks())
3301 if bm:
3303 if bm:
3302 output.append(bm)
3304 output.append(bm)
3303 else:
3305 else:
3304 if branch:
3306 if branch:
3305 output.append(ctx.branch())
3307 output.append(ctx.branch())
3306
3308
3307 if tags:
3309 if tags:
3308 output.extend(taglist)
3310 output.extend(taglist)
3309
3311
3310 if bookmarks:
3312 if bookmarks:
3311 output.extend(ctx.bookmarks())
3313 output.extend(ctx.bookmarks())
3312
3314
3313 fm.data(node=ctx.hex())
3315 fm.data(node=ctx.hex())
3314 fm.data(branch=ctx.branch())
3316 fm.data(branch=ctx.branch())
3315 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3317 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3316 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3318 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3317 fm.context(ctx=ctx)
3319 fm.context(ctx=ctx)
3318
3320
3319 fm.plain("%s\n" % ' '.join(output))
3321 fm.plain("%s\n" % ' '.join(output))
3320 fm.end()
3322 fm.end()
3321
3323
3322 @command('import|patch',
3324 @command('import|patch',
3323 [('p', 'strip', 1,
3325 [('p', 'strip', 1,
3324 _('directory strip option for patch. This has the same '
3326 _('directory strip option for patch. This has the same '
3325 'meaning as the corresponding patch option'), _('NUM')),
3327 'meaning as the corresponding patch option'), _('NUM')),
3326 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3328 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3327 ('e', 'edit', False, _('invoke editor on commit messages')),
3329 ('e', 'edit', False, _('invoke editor on commit messages')),
3328 ('f', 'force', None,
3330 ('f', 'force', None,
3329 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3331 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3330 ('', 'no-commit', None,
3332 ('', 'no-commit', None,
3331 _("don't commit, just update the working directory")),
3333 _("don't commit, just update the working directory")),
3332 ('', 'bypass', None,
3334 ('', 'bypass', None,
3333 _("apply patch without touching the working directory")),
3335 _("apply patch without touching the working directory")),
3334 ('', 'partial', None,
3336 ('', 'partial', None,
3335 _('commit even if some hunks fail')),
3337 _('commit even if some hunks fail')),
3336 ('', 'exact', None,
3338 ('', 'exact', None,
3337 _('abort if patch would apply lossily')),
3339 _('abort if patch would apply lossily')),
3338 ('', 'prefix', '',
3340 ('', 'prefix', '',
3339 _('apply patch to subdirectory'), _('DIR')),
3341 _('apply patch to subdirectory'), _('DIR')),
3340 ('', 'import-branch', None,
3342 ('', 'import-branch', None,
3341 _('use any branch information in patch (implied by --exact)'))] +
3343 _('use any branch information in patch (implied by --exact)'))] +
3342 commitopts + commitopts2 + similarityopts,
3344 commitopts + commitopts2 + similarityopts,
3343 _('[OPTION]... PATCH...'),
3345 _('[OPTION]... PATCH...'),
3344 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3346 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3345 def import_(ui, repo, patch1=None, *patches, **opts):
3347 def import_(ui, repo, patch1=None, *patches, **opts):
3346 """import an ordered set of patches
3348 """import an ordered set of patches
3347
3349
3348 Import a list of patches and commit them individually (unless
3350 Import a list of patches and commit them individually (unless
3349 --no-commit is specified).
3351 --no-commit is specified).
3350
3352
3351 To read a patch from standard input (stdin), use "-" as the patch
3353 To read a patch from standard input (stdin), use "-" as the patch
3352 name. If a URL is specified, the patch will be downloaded from
3354 name. If a URL is specified, the patch will be downloaded from
3353 there.
3355 there.
3354
3356
3355 Import first applies changes to the working directory (unless
3357 Import first applies changes to the working directory (unless
3356 --bypass is specified), import will abort if there are outstanding
3358 --bypass is specified), import will abort if there are outstanding
3357 changes.
3359 changes.
3358
3360
3359 Use --bypass to apply and commit patches directly to the
3361 Use --bypass to apply and commit patches directly to the
3360 repository, without affecting the working directory. Without
3362 repository, without affecting the working directory. Without
3361 --exact, patches will be applied on top of the working directory
3363 --exact, patches will be applied on top of the working directory
3362 parent revision.
3364 parent revision.
3363
3365
3364 You can import a patch straight from a mail message. Even patches
3366 You can import a patch straight from a mail message. Even patches
3365 as attachments work (to use the body part, it must have type
3367 as attachments work (to use the body part, it must have type
3366 text/plain or text/x-patch). From and Subject headers of email
3368 text/plain or text/x-patch). From and Subject headers of email
3367 message are used as default committer and commit message. All
3369 message are used as default committer and commit message. All
3368 text/plain body parts before first diff are added to the commit
3370 text/plain body parts before first diff are added to the commit
3369 message.
3371 message.
3370
3372
3371 If the imported patch was generated by :hg:`export`, user and
3373 If the imported patch was generated by :hg:`export`, user and
3372 description from patch override values from message headers and
3374 description from patch override values from message headers and
3373 body. Values given on command line with -m/--message and -u/--user
3375 body. Values given on command line with -m/--message and -u/--user
3374 override these.
3376 override these.
3375
3377
3376 If --exact is specified, import will set the working directory to
3378 If --exact is specified, import will set the working directory to
3377 the parent of each patch before applying it, and will abort if the
3379 the parent of each patch before applying it, and will abort if the
3378 resulting changeset has a different ID than the one recorded in
3380 resulting changeset has a different ID than the one recorded in
3379 the patch. This will guard against various ways that portable
3381 the patch. This will guard against various ways that portable
3380 patch formats and mail systems might fail to transfer Mercurial
3382 patch formats and mail systems might fail to transfer Mercurial
3381 data or metadata. See :hg:`bundle` for lossless transmission.
3383 data or metadata. See :hg:`bundle` for lossless transmission.
3382
3384
3383 Use --partial to ensure a changeset will be created from the patch
3385 Use --partial to ensure a changeset will be created from the patch
3384 even if some hunks fail to apply. Hunks that fail to apply will be
3386 even if some hunks fail to apply. Hunks that fail to apply will be
3385 written to a <target-file>.rej file. Conflicts can then be resolved
3387 written to a <target-file>.rej file. Conflicts can then be resolved
3386 by hand before :hg:`commit --amend` is run to update the created
3388 by hand before :hg:`commit --amend` is run to update the created
3387 changeset. This flag exists to let people import patches that
3389 changeset. This flag exists to let people import patches that
3388 partially apply without losing the associated metadata (author,
3390 partially apply without losing the associated metadata (author,
3389 date, description, ...).
3391 date, description, ...).
3390
3392
3391 .. note::
3393 .. note::
3392
3394
3393 When no hunks apply cleanly, :hg:`import --partial` will create
3395 When no hunks apply cleanly, :hg:`import --partial` will create
3394 an empty changeset, importing only the patch metadata.
3396 an empty changeset, importing only the patch metadata.
3395
3397
3396 With -s/--similarity, hg will attempt to discover renames and
3398 With -s/--similarity, hg will attempt to discover renames and
3397 copies in the patch in the same way as :hg:`addremove`.
3399 copies in the patch in the same way as :hg:`addremove`.
3398
3400
3399 It is possible to use external patch programs to perform the patch
3401 It is possible to use external patch programs to perform the patch
3400 by setting the ``ui.patch`` configuration option. For the default
3402 by setting the ``ui.patch`` configuration option. For the default
3401 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3403 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3402 See :hg:`help config` for more information about configuration
3404 See :hg:`help config` for more information about configuration
3403 files and how to use these options.
3405 files and how to use these options.
3404
3406
3405 See :hg:`help dates` for a list of formats valid for -d/--date.
3407 See :hg:`help dates` for a list of formats valid for -d/--date.
3406
3408
3407 .. container:: verbose
3409 .. container:: verbose
3408
3410
3409 Examples:
3411 Examples:
3410
3412
3411 - import a traditional patch from a website and detect renames::
3413 - import a traditional patch from a website and detect renames::
3412
3414
3413 hg import -s 80 http://example.com/bugfix.patch
3415 hg import -s 80 http://example.com/bugfix.patch
3414
3416
3415 - import a changeset from an hgweb server::
3417 - import a changeset from an hgweb server::
3416
3418
3417 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3419 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3418
3420
3419 - import all the patches in an Unix-style mbox::
3421 - import all the patches in an Unix-style mbox::
3420
3422
3421 hg import incoming-patches.mbox
3423 hg import incoming-patches.mbox
3422
3424
3423 - import patches from stdin::
3425 - import patches from stdin::
3424
3426
3425 hg import -
3427 hg import -
3426
3428
3427 - attempt to exactly restore an exported changeset (not always
3429 - attempt to exactly restore an exported changeset (not always
3428 possible)::
3430 possible)::
3429
3431
3430 hg import --exact proposed-fix.patch
3432 hg import --exact proposed-fix.patch
3431
3433
3432 - use an external tool to apply a patch which is too fuzzy for
3434 - use an external tool to apply a patch which is too fuzzy for
3433 the default internal tool.
3435 the default internal tool.
3434
3436
3435 hg import --config ui.patch="patch --merge" fuzzy.patch
3437 hg import --config ui.patch="patch --merge" fuzzy.patch
3436
3438
3437 - change the default fuzzing from 2 to a less strict 7
3439 - change the default fuzzing from 2 to a less strict 7
3438
3440
3439 hg import --config ui.fuzz=7 fuzz.patch
3441 hg import --config ui.fuzz=7 fuzz.patch
3440
3442
3441 Returns 0 on success, 1 on partial success (see --partial).
3443 Returns 0 on success, 1 on partial success (see --partial).
3442 """
3444 """
3443
3445
3444 opts = pycompat.byteskwargs(opts)
3446 opts = pycompat.byteskwargs(opts)
3445 if not patch1:
3447 if not patch1:
3446 raise error.Abort(_('need at least one patch to import'))
3448 raise error.Abort(_('need at least one patch to import'))
3447
3449
3448 patches = (patch1,) + patches
3450 patches = (patch1,) + patches
3449
3451
3450 date = opts.get('date')
3452 date = opts.get('date')
3451 if date:
3453 if date:
3452 opts['date'] = dateutil.parsedate(date)
3454 opts['date'] = dateutil.parsedate(date)
3453
3455
3454 exact = opts.get('exact')
3456 exact = opts.get('exact')
3455 update = not opts.get('bypass')
3457 update = not opts.get('bypass')
3456 if not update and opts.get('no_commit'):
3458 if not update and opts.get('no_commit'):
3457 raise error.Abort(_('cannot use --no-commit with --bypass'))
3459 raise error.Abort(_('cannot use --no-commit with --bypass'))
3458 try:
3460 try:
3459 sim = float(opts.get('similarity') or 0)
3461 sim = float(opts.get('similarity') or 0)
3460 except ValueError:
3462 except ValueError:
3461 raise error.Abort(_('similarity must be a number'))
3463 raise error.Abort(_('similarity must be a number'))
3462 if sim < 0 or sim > 100:
3464 if sim < 0 or sim > 100:
3463 raise error.Abort(_('similarity must be between 0 and 100'))
3465 raise error.Abort(_('similarity must be between 0 and 100'))
3464 if sim and not update:
3466 if sim and not update:
3465 raise error.Abort(_('cannot use --similarity with --bypass'))
3467 raise error.Abort(_('cannot use --similarity with --bypass'))
3466 if exact:
3468 if exact:
3467 if opts.get('edit'):
3469 if opts.get('edit'):
3468 raise error.Abort(_('cannot use --exact with --edit'))
3470 raise error.Abort(_('cannot use --exact with --edit'))
3469 if opts.get('prefix'):
3471 if opts.get('prefix'):
3470 raise error.Abort(_('cannot use --exact with --prefix'))
3472 raise error.Abort(_('cannot use --exact with --prefix'))
3471
3473
3472 base = opts["base"]
3474 base = opts["base"]
3473 msgs = []
3475 msgs = []
3474 ret = 0
3476 ret = 0
3475
3477
3476 with repo.wlock():
3478 with repo.wlock():
3477 if update:
3479 if update:
3478 cmdutil.checkunfinished(repo)
3480 cmdutil.checkunfinished(repo)
3479 if (exact or not opts.get('force')):
3481 if (exact or not opts.get('force')):
3480 cmdutil.bailifchanged(repo)
3482 cmdutil.bailifchanged(repo)
3481
3483
3482 if not opts.get('no_commit'):
3484 if not opts.get('no_commit'):
3483 lock = repo.lock
3485 lock = repo.lock
3484 tr = lambda: repo.transaction('import')
3486 tr = lambda: repo.transaction('import')
3485 dsguard = util.nullcontextmanager
3487 dsguard = util.nullcontextmanager
3486 else:
3488 else:
3487 lock = util.nullcontextmanager
3489 lock = util.nullcontextmanager
3488 tr = util.nullcontextmanager
3490 tr = util.nullcontextmanager
3489 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3491 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3490 with lock(), tr(), dsguard():
3492 with lock(), tr(), dsguard():
3491 parents = repo[None].parents()
3493 parents = repo[None].parents()
3492 for patchurl in patches:
3494 for patchurl in patches:
3493 if patchurl == '-':
3495 if patchurl == '-':
3494 ui.status(_('applying patch from stdin\n'))
3496 ui.status(_('applying patch from stdin\n'))
3495 patchfile = ui.fin
3497 patchfile = ui.fin
3496 patchurl = 'stdin' # for error message
3498 patchurl = 'stdin' # for error message
3497 else:
3499 else:
3498 patchurl = os.path.join(base, patchurl)
3500 patchurl = os.path.join(base, patchurl)
3499 ui.status(_('applying %s\n') % patchurl)
3501 ui.status(_('applying %s\n') % patchurl)
3500 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
3502 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
3501
3503
3502 haspatch = False
3504 haspatch = False
3503 for hunk in patch.split(patchfile):
3505 for hunk in patch.split(patchfile):
3504 with patch.extract(ui, hunk) as patchdata:
3506 with patch.extract(ui, hunk) as patchdata:
3505 msg, node, rej = cmdutil.tryimportone(ui, repo,
3507 msg, node, rej = cmdutil.tryimportone(ui, repo,
3506 patchdata,
3508 patchdata,
3507 parents, opts,
3509 parents, opts,
3508 msgs, hg.clean)
3510 msgs, hg.clean)
3509 if msg:
3511 if msg:
3510 haspatch = True
3512 haspatch = True
3511 ui.note(msg + '\n')
3513 ui.note(msg + '\n')
3512 if update or exact:
3514 if update or exact:
3513 parents = repo[None].parents()
3515 parents = repo[None].parents()
3514 else:
3516 else:
3515 parents = [repo[node]]
3517 parents = [repo[node]]
3516 if rej:
3518 if rej:
3517 ui.write_err(_("patch applied partially\n"))
3519 ui.write_err(_("patch applied partially\n"))
3518 ui.write_err(_("(fix the .rej files and run "
3520 ui.write_err(_("(fix the .rej files and run "
3519 "`hg commit --amend`)\n"))
3521 "`hg commit --amend`)\n"))
3520 ret = 1
3522 ret = 1
3521 break
3523 break
3522
3524
3523 if not haspatch:
3525 if not haspatch:
3524 raise error.Abort(_('%s: no diffs found') % patchurl)
3526 raise error.Abort(_('%s: no diffs found') % patchurl)
3525
3527
3526 if msgs:
3528 if msgs:
3527 repo.savecommitmessage('\n* * *\n'.join(msgs))
3529 repo.savecommitmessage('\n* * *\n'.join(msgs))
3528 return ret
3530 return ret
3529
3531
3530 @command('incoming|in',
3532 @command('incoming|in',
3531 [('f', 'force', None,
3533 [('f', 'force', None,
3532 _('run even if remote repository is unrelated')),
3534 _('run even if remote repository is unrelated')),
3533 ('n', 'newest-first', None, _('show newest record first')),
3535 ('n', 'newest-first', None, _('show newest record first')),
3534 ('', 'bundle', '',
3536 ('', 'bundle', '',
3535 _('file to store the bundles into'), _('FILE')),
3537 _('file to store the bundles into'), _('FILE')),
3536 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3538 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3537 ('B', 'bookmarks', False, _("compare bookmarks")),
3539 ('B', 'bookmarks', False, _("compare bookmarks")),
3538 ('b', 'branch', [],
3540 ('b', 'branch', [],
3539 _('a specific branch you would like to pull'), _('BRANCH')),
3541 _('a specific branch you would like to pull'), _('BRANCH')),
3540 ] + logopts + remoteopts + subrepoopts,
3542 ] + logopts + remoteopts + subrepoopts,
3541 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3543 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3542 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3544 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3543 def incoming(ui, repo, source="default", **opts):
3545 def incoming(ui, repo, source="default", **opts):
3544 """show new changesets found in source
3546 """show new changesets found in source
3545
3547
3546 Show new changesets found in the specified path/URL or the default
3548 Show new changesets found in the specified path/URL or the default
3547 pull location. These are the changesets that would have been pulled
3549 pull location. These are the changesets that would have been pulled
3548 by :hg:`pull` at the time you issued this command.
3550 by :hg:`pull` at the time you issued this command.
3549
3551
3550 See pull for valid source format details.
3552 See pull for valid source format details.
3551
3553
3552 .. container:: verbose
3554 .. container:: verbose
3553
3555
3554 With -B/--bookmarks, the result of bookmark comparison between
3556 With -B/--bookmarks, the result of bookmark comparison between
3555 local and remote repositories is displayed. With -v/--verbose,
3557 local and remote repositories is displayed. With -v/--verbose,
3556 status is also displayed for each bookmark like below::
3558 status is also displayed for each bookmark like below::
3557
3559
3558 BM1 01234567890a added
3560 BM1 01234567890a added
3559 BM2 1234567890ab advanced
3561 BM2 1234567890ab advanced
3560 BM3 234567890abc diverged
3562 BM3 234567890abc diverged
3561 BM4 34567890abcd changed
3563 BM4 34567890abcd changed
3562
3564
3563 The action taken locally when pulling depends on the
3565 The action taken locally when pulling depends on the
3564 status of each bookmark:
3566 status of each bookmark:
3565
3567
3566 :``added``: pull will create it
3568 :``added``: pull will create it
3567 :``advanced``: pull will update it
3569 :``advanced``: pull will update it
3568 :``diverged``: pull will create a divergent bookmark
3570 :``diverged``: pull will create a divergent bookmark
3569 :``changed``: result depends on remote changesets
3571 :``changed``: result depends on remote changesets
3570
3572
3571 From the point of view of pulling behavior, bookmark
3573 From the point of view of pulling behavior, bookmark
3572 existing only in the remote repository are treated as ``added``,
3574 existing only in the remote repository are treated as ``added``,
3573 even if it is in fact locally deleted.
3575 even if it is in fact locally deleted.
3574
3576
3575 .. container:: verbose
3577 .. container:: verbose
3576
3578
3577 For remote repository, using --bundle avoids downloading the
3579 For remote repository, using --bundle avoids downloading the
3578 changesets twice if the incoming is followed by a pull.
3580 changesets twice if the incoming is followed by a pull.
3579
3581
3580 Examples:
3582 Examples:
3581
3583
3582 - show incoming changes with patches and full description::
3584 - show incoming changes with patches and full description::
3583
3585
3584 hg incoming -vp
3586 hg incoming -vp
3585
3587
3586 - show incoming changes excluding merges, store a bundle::
3588 - show incoming changes excluding merges, store a bundle::
3587
3589
3588 hg in -vpM --bundle incoming.hg
3590 hg in -vpM --bundle incoming.hg
3589 hg pull incoming.hg
3591 hg pull incoming.hg
3590
3592
3591 - briefly list changes inside a bundle::
3593 - briefly list changes inside a bundle::
3592
3594
3593 hg in changes.hg -T "{desc|firstline}\\n"
3595 hg in changes.hg -T "{desc|firstline}\\n"
3594
3596
3595 Returns 0 if there are incoming changes, 1 otherwise.
3597 Returns 0 if there are incoming changes, 1 otherwise.
3596 """
3598 """
3597 opts = pycompat.byteskwargs(opts)
3599 opts = pycompat.byteskwargs(opts)
3598 if opts.get('graph'):
3600 if opts.get('graph'):
3599 logcmdutil.checkunsupportedgraphflags([], opts)
3601 logcmdutil.checkunsupportedgraphflags([], opts)
3600 def display(other, chlist, displayer):
3602 def display(other, chlist, displayer):
3601 revdag = logcmdutil.graphrevs(other, chlist, opts)
3603 revdag = logcmdutil.graphrevs(other, chlist, opts)
3602 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3604 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3603 graphmod.asciiedges)
3605 graphmod.asciiedges)
3604
3606
3605 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3607 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3606 return 0
3608 return 0
3607
3609
3608 if opts.get('bundle') and opts.get('subrepos'):
3610 if opts.get('bundle') and opts.get('subrepos'):
3609 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3611 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3610
3612
3611 if opts.get('bookmarks'):
3613 if opts.get('bookmarks'):
3612 source, branches = hg.parseurl(ui.expandpath(source),
3614 source, branches = hg.parseurl(ui.expandpath(source),
3613 opts.get('branch'))
3615 opts.get('branch'))
3614 other = hg.peer(repo, opts, source)
3616 other = hg.peer(repo, opts, source)
3615 if 'bookmarks' not in other.listkeys('namespaces'):
3617 if 'bookmarks' not in other.listkeys('namespaces'):
3616 ui.warn(_("remote doesn't support bookmarks\n"))
3618 ui.warn(_("remote doesn't support bookmarks\n"))
3617 return 0
3619 return 0
3618 ui.pager('incoming')
3620 ui.pager('incoming')
3619 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3621 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3620 return bookmarks.incoming(ui, repo, other)
3622 return bookmarks.incoming(ui, repo, other)
3621
3623
3622 repo._subtoppath = ui.expandpath(source)
3624 repo._subtoppath = ui.expandpath(source)
3623 try:
3625 try:
3624 return hg.incoming(ui, repo, source, opts)
3626 return hg.incoming(ui, repo, source, opts)
3625 finally:
3627 finally:
3626 del repo._subtoppath
3628 del repo._subtoppath
3627
3629
3628
3630
3629 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3631 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3630 helpcategory=command.CATEGORY_REPO_CREATION,
3632 helpcategory=command.CATEGORY_REPO_CREATION,
3631 helpbasic=True, norepo=True)
3633 helpbasic=True, norepo=True)
3632 def init(ui, dest=".", **opts):
3634 def init(ui, dest=".", **opts):
3633 """create a new repository in the given directory
3635 """create a new repository in the given directory
3634
3636
3635 Initialize a new repository in the given directory. If the given
3637 Initialize a new repository in the given directory. If the given
3636 directory does not exist, it will be created.
3638 directory does not exist, it will be created.
3637
3639
3638 If no directory is given, the current directory is used.
3640 If no directory is given, the current directory is used.
3639
3641
3640 It is possible to specify an ``ssh://`` URL as the destination.
3642 It is possible to specify an ``ssh://`` URL as the destination.
3641 See :hg:`help urls` for more information.
3643 See :hg:`help urls` for more information.
3642
3644
3643 Returns 0 on success.
3645 Returns 0 on success.
3644 """
3646 """
3645 opts = pycompat.byteskwargs(opts)
3647 opts = pycompat.byteskwargs(opts)
3646 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3648 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3647
3649
3648 @command('locate',
3650 @command('locate',
3649 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3651 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3650 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3652 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3651 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3653 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3652 ] + walkopts,
3654 ] + walkopts,
3653 _('[OPTION]... [PATTERN]...'),
3655 _('[OPTION]... [PATTERN]...'),
3654 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3656 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3655 def locate(ui, repo, *pats, **opts):
3657 def locate(ui, repo, *pats, **opts):
3656 """locate files matching specific patterns (DEPRECATED)
3658 """locate files matching specific patterns (DEPRECATED)
3657
3659
3658 Print files under Mercurial control in the working directory whose
3660 Print files under Mercurial control in the working directory whose
3659 names match the given patterns.
3661 names match the given patterns.
3660
3662
3661 By default, this command searches all directories in the working
3663 By default, this command searches all directories in the working
3662 directory. To search just the current directory and its
3664 directory. To search just the current directory and its
3663 subdirectories, use "--include .".
3665 subdirectories, use "--include .".
3664
3666
3665 If no patterns are given to match, this command prints the names
3667 If no patterns are given to match, this command prints the names
3666 of all files under Mercurial control in the working directory.
3668 of all files under Mercurial control in the working directory.
3667
3669
3668 If you want to feed the output of this command into the "xargs"
3670 If you want to feed the output of this command into the "xargs"
3669 command, use the -0 option to both this command and "xargs". This
3671 command, use the -0 option to both this command and "xargs". This
3670 will avoid the problem of "xargs" treating single filenames that
3672 will avoid the problem of "xargs" treating single filenames that
3671 contain whitespace as multiple filenames.
3673 contain whitespace as multiple filenames.
3672
3674
3673 See :hg:`help files` for a more versatile command.
3675 See :hg:`help files` for a more versatile command.
3674
3676
3675 Returns 0 if a match is found, 1 otherwise.
3677 Returns 0 if a match is found, 1 otherwise.
3676 """
3678 """
3677 opts = pycompat.byteskwargs(opts)
3679 opts = pycompat.byteskwargs(opts)
3678 if opts.get('print0'):
3680 if opts.get('print0'):
3679 end = '\0'
3681 end = '\0'
3680 else:
3682 else:
3681 end = '\n'
3683 end = '\n'
3682 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3684 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3683
3685
3684 ret = 1
3686 ret = 1
3685 m = scmutil.match(ctx, pats, opts, default='relglob',
3687 m = scmutil.match(ctx, pats, opts, default='relglob',
3686 badfn=lambda x, y: False)
3688 badfn=lambda x, y: False)
3687
3689
3688 ui.pager('locate')
3690 ui.pager('locate')
3689 if ctx.rev() is None:
3691 if ctx.rev() is None:
3690 # When run on the working copy, "locate" includes removed files, so
3692 # When run on the working copy, "locate" includes removed files, so
3691 # we get the list of files from the dirstate.
3693 # we get the list of files from the dirstate.
3692 filesgen = sorted(repo.dirstate.matches(m))
3694 filesgen = sorted(repo.dirstate.matches(m))
3693 else:
3695 else:
3694 filesgen = ctx.matches(m)
3696 filesgen = ctx.matches(m)
3695 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
3697 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
3696 for abs in filesgen:
3698 for abs in filesgen:
3697 if opts.get('fullpath'):
3699 if opts.get('fullpath'):
3698 ui.write(repo.wjoin(abs), end)
3700 ui.write(repo.wjoin(abs), end)
3699 else:
3701 else:
3700 ui.write(uipathfn(abs), end)
3702 ui.write(uipathfn(abs), end)
3701 ret = 0
3703 ret = 0
3702
3704
3703 return ret
3705 return ret
3704
3706
3705 @command('log|history',
3707 @command('log|history',
3706 [('f', 'follow', None,
3708 [('f', 'follow', None,
3707 _('follow changeset history, or file history across copies and renames')),
3709 _('follow changeset history, or file history across copies and renames')),
3708 ('', 'follow-first', None,
3710 ('', 'follow-first', None,
3709 _('only follow the first parent of merge changesets (DEPRECATED)')),
3711 _('only follow the first parent of merge changesets (DEPRECATED)')),
3710 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3712 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3711 ('C', 'copies', None, _('show copied files')),
3713 ('C', 'copies', None, _('show copied files')),
3712 ('k', 'keyword', [],
3714 ('k', 'keyword', [],
3713 _('do case-insensitive search for a given text'), _('TEXT')),
3715 _('do case-insensitive search for a given text'), _('TEXT')),
3714 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3716 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3715 ('L', 'line-range', [],
3717 ('L', 'line-range', [],
3716 _('follow line range of specified file (EXPERIMENTAL)'),
3718 _('follow line range of specified file (EXPERIMENTAL)'),
3717 _('FILE,RANGE')),
3719 _('FILE,RANGE')),
3718 ('', 'removed', None, _('include revisions where files were removed')),
3720 ('', 'removed', None, _('include revisions where files were removed')),
3719 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3721 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3720 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3722 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3721 ('', 'only-branch', [],
3723 ('', 'only-branch', [],
3722 _('show only changesets within the given named branch (DEPRECATED)'),
3724 _('show only changesets within the given named branch (DEPRECATED)'),
3723 _('BRANCH')),
3725 _('BRANCH')),
3724 ('b', 'branch', [],
3726 ('b', 'branch', [],
3725 _('show changesets within the given named branch'), _('BRANCH')),
3727 _('show changesets within the given named branch'), _('BRANCH')),
3726 ('P', 'prune', [],
3728 ('P', 'prune', [],
3727 _('do not display revision or any of its ancestors'), _('REV')),
3729 _('do not display revision or any of its ancestors'), _('REV')),
3728 ] + logopts + walkopts,
3730 ] + logopts + walkopts,
3729 _('[OPTION]... [FILE]'),
3731 _('[OPTION]... [FILE]'),
3730 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3732 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3731 helpbasic=True, inferrepo=True,
3733 helpbasic=True, inferrepo=True,
3732 intents={INTENT_READONLY})
3734 intents={INTENT_READONLY})
3733 def log(ui, repo, *pats, **opts):
3735 def log(ui, repo, *pats, **opts):
3734 """show revision history of entire repository or files
3736 """show revision history of entire repository or files
3735
3737
3736 Print the revision history of the specified files or the entire
3738 Print the revision history of the specified files or the entire
3737 project.
3739 project.
3738
3740
3739 If no revision range is specified, the default is ``tip:0`` unless
3741 If no revision range is specified, the default is ``tip:0`` unless
3740 --follow is set, in which case the working directory parent is
3742 --follow is set, in which case the working directory parent is
3741 used as the starting revision.
3743 used as the starting revision.
3742
3744
3743 File history is shown without following rename or copy history of
3745 File history is shown without following rename or copy history of
3744 files. Use -f/--follow with a filename to follow history across
3746 files. Use -f/--follow with a filename to follow history across
3745 renames and copies. --follow without a filename will only show
3747 renames and copies. --follow without a filename will only show
3746 ancestors of the starting revision.
3748 ancestors of the starting revision.
3747
3749
3748 By default this command prints revision number and changeset id,
3750 By default this command prints revision number and changeset id,
3749 tags, non-trivial parents, user, date and time, and a summary for
3751 tags, non-trivial parents, user, date and time, and a summary for
3750 each commit. When the -v/--verbose switch is used, the list of
3752 each commit. When the -v/--verbose switch is used, the list of
3751 changed files and full commit message are shown.
3753 changed files and full commit message are shown.
3752
3754
3753 With --graph the revisions are shown as an ASCII art DAG with the most
3755 With --graph the revisions are shown as an ASCII art DAG with the most
3754 recent changeset at the top.
3756 recent changeset at the top.
3755 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3757 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3756 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3758 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3757 changeset from the lines below is a parent of the 'o' merge on the same
3759 changeset from the lines below is a parent of the 'o' merge on the same
3758 line.
3760 line.
3759 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3761 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3760 of a '|' indicates one or more revisions in a path are omitted.
3762 of a '|' indicates one or more revisions in a path are omitted.
3761
3763
3762 .. container:: verbose
3764 .. container:: verbose
3763
3765
3764 Use -L/--line-range FILE,M:N options to follow the history of lines
3766 Use -L/--line-range FILE,M:N options to follow the history of lines
3765 from M to N in FILE. With -p/--patch only diff hunks affecting
3767 from M to N in FILE. With -p/--patch only diff hunks affecting
3766 specified line range will be shown. This option requires --follow;
3768 specified line range will be shown. This option requires --follow;
3767 it can be specified multiple times. Currently, this option is not
3769 it can be specified multiple times. Currently, this option is not
3768 compatible with --graph. This option is experimental.
3770 compatible with --graph. This option is experimental.
3769
3771
3770 .. note::
3772 .. note::
3771
3773
3772 :hg:`log --patch` may generate unexpected diff output for merge
3774 :hg:`log --patch` may generate unexpected diff output for merge
3773 changesets, as it will only compare the merge changeset against
3775 changesets, as it will only compare the merge changeset against
3774 its first parent. Also, only files different from BOTH parents
3776 its first parent. Also, only files different from BOTH parents
3775 will appear in files:.
3777 will appear in files:.
3776
3778
3777 .. note::
3779 .. note::
3778
3780
3779 For performance reasons, :hg:`log FILE` may omit duplicate changes
3781 For performance reasons, :hg:`log FILE` may omit duplicate changes
3780 made on branches and will not show removals or mode changes. To
3782 made on branches and will not show removals or mode changes. To
3781 see all such changes, use the --removed switch.
3783 see all such changes, use the --removed switch.
3782
3784
3783 .. container:: verbose
3785 .. container:: verbose
3784
3786
3785 .. note::
3787 .. note::
3786
3788
3787 The history resulting from -L/--line-range options depends on diff
3789 The history resulting from -L/--line-range options depends on diff
3788 options; for instance if white-spaces are ignored, respective changes
3790 options; for instance if white-spaces are ignored, respective changes
3789 with only white-spaces in specified line range will not be listed.
3791 with only white-spaces in specified line range will not be listed.
3790
3792
3791 .. container:: verbose
3793 .. container:: verbose
3792
3794
3793 Some examples:
3795 Some examples:
3794
3796
3795 - changesets with full descriptions and file lists::
3797 - changesets with full descriptions and file lists::
3796
3798
3797 hg log -v
3799 hg log -v
3798
3800
3799 - changesets ancestral to the working directory::
3801 - changesets ancestral to the working directory::
3800
3802
3801 hg log -f
3803 hg log -f
3802
3804
3803 - last 10 commits on the current branch::
3805 - last 10 commits on the current branch::
3804
3806
3805 hg log -l 10 -b .
3807 hg log -l 10 -b .
3806
3808
3807 - changesets showing all modifications of a file, including removals::
3809 - changesets showing all modifications of a file, including removals::
3808
3810
3809 hg log --removed file.c
3811 hg log --removed file.c
3810
3812
3811 - all changesets that touch a directory, with diffs, excluding merges::
3813 - all changesets that touch a directory, with diffs, excluding merges::
3812
3814
3813 hg log -Mp lib/
3815 hg log -Mp lib/
3814
3816
3815 - all revision numbers that match a keyword::
3817 - all revision numbers that match a keyword::
3816
3818
3817 hg log -k bug --template "{rev}\\n"
3819 hg log -k bug --template "{rev}\\n"
3818
3820
3819 - the full hash identifier of the working directory parent::
3821 - the full hash identifier of the working directory parent::
3820
3822
3821 hg log -r . --template "{node}\\n"
3823 hg log -r . --template "{node}\\n"
3822
3824
3823 - list available log templates::
3825 - list available log templates::
3824
3826
3825 hg log -T list
3827 hg log -T list
3826
3828
3827 - check if a given changeset is included in a tagged release::
3829 - check if a given changeset is included in a tagged release::
3828
3830
3829 hg log -r "a21ccf and ancestor(1.9)"
3831 hg log -r "a21ccf and ancestor(1.9)"
3830
3832
3831 - find all changesets by some user in a date range::
3833 - find all changesets by some user in a date range::
3832
3834
3833 hg log -k alice -d "may 2008 to jul 2008"
3835 hg log -k alice -d "may 2008 to jul 2008"
3834
3836
3835 - summary of all changesets after the last tag::
3837 - summary of all changesets after the last tag::
3836
3838
3837 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3839 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3838
3840
3839 - changesets touching lines 13 to 23 for file.c::
3841 - changesets touching lines 13 to 23 for file.c::
3840
3842
3841 hg log -L file.c,13:23
3843 hg log -L file.c,13:23
3842
3844
3843 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3845 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3844 main.c with patch::
3846 main.c with patch::
3845
3847
3846 hg log -L file.c,13:23 -L main.c,2:6 -p
3848 hg log -L file.c,13:23 -L main.c,2:6 -p
3847
3849
3848 See :hg:`help dates` for a list of formats valid for -d/--date.
3850 See :hg:`help dates` for a list of formats valid for -d/--date.
3849
3851
3850 See :hg:`help revisions` for more about specifying and ordering
3852 See :hg:`help revisions` for more about specifying and ordering
3851 revisions.
3853 revisions.
3852
3854
3853 See :hg:`help templates` for more about pre-packaged styles and
3855 See :hg:`help templates` for more about pre-packaged styles and
3854 specifying custom templates. The default template used by the log
3856 specifying custom templates. The default template used by the log
3855 command can be customized via the ``ui.logtemplate`` configuration
3857 command can be customized via the ``ui.logtemplate`` configuration
3856 setting.
3858 setting.
3857
3859
3858 Returns 0 on success.
3860 Returns 0 on success.
3859
3861
3860 """
3862 """
3861 opts = pycompat.byteskwargs(opts)
3863 opts = pycompat.byteskwargs(opts)
3862 linerange = opts.get('line_range')
3864 linerange = opts.get('line_range')
3863
3865
3864 if linerange and not opts.get('follow'):
3866 if linerange and not opts.get('follow'):
3865 raise error.Abort(_('--line-range requires --follow'))
3867 raise error.Abort(_('--line-range requires --follow'))
3866
3868
3867 if linerange and pats:
3869 if linerange and pats:
3868 # TODO: take pats as patterns with no line-range filter
3870 # TODO: take pats as patterns with no line-range filter
3869 raise error.Abort(
3871 raise error.Abort(
3870 _('FILE arguments are not compatible with --line-range option')
3872 _('FILE arguments are not compatible with --line-range option')
3871 )
3873 )
3872
3874
3873 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3875 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3874 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3876 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3875 if linerange:
3877 if linerange:
3876 # TODO: should follow file history from logcmdutil._initialrevs(),
3878 # TODO: should follow file history from logcmdutil._initialrevs(),
3877 # then filter the result by logcmdutil._makerevset() and --limit
3879 # then filter the result by logcmdutil._makerevset() and --limit
3878 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3880 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3879
3881
3880 getrenamed = None
3882 getrenamed = None
3881 if opts.get('copies'):
3883 if opts.get('copies'):
3882 endrev = None
3884 endrev = None
3883 if revs:
3885 if revs:
3884 endrev = revs.max() + 1
3886 endrev = revs.max() + 1
3885 getrenamed = scmutil.getrenamedfn(repo, endrev=endrev)
3887 getrenamed = scmutil.getrenamedfn(repo, endrev=endrev)
3886
3888
3887 ui.pager('log')
3889 ui.pager('log')
3888 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3890 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3889 buffered=True)
3891 buffered=True)
3890 if opts.get('graph'):
3892 if opts.get('graph'):
3891 displayfn = logcmdutil.displaygraphrevs
3893 displayfn = logcmdutil.displaygraphrevs
3892 else:
3894 else:
3893 displayfn = logcmdutil.displayrevs
3895 displayfn = logcmdutil.displayrevs
3894 displayfn(ui, repo, revs, displayer, getrenamed)
3896 displayfn(ui, repo, revs, displayer, getrenamed)
3895
3897
3896 @command('manifest',
3898 @command('manifest',
3897 [('r', 'rev', '', _('revision to display'), _('REV')),
3899 [('r', 'rev', '', _('revision to display'), _('REV')),
3898 ('', 'all', False, _("list files from all revisions"))]
3900 ('', 'all', False, _("list files from all revisions"))]
3899 + formatteropts,
3901 + formatteropts,
3900 _('[-r REV]'),
3902 _('[-r REV]'),
3901 helpcategory=command.CATEGORY_MAINTENANCE,
3903 helpcategory=command.CATEGORY_MAINTENANCE,
3902 intents={INTENT_READONLY})
3904 intents={INTENT_READONLY})
3903 def manifest(ui, repo, node=None, rev=None, **opts):
3905 def manifest(ui, repo, node=None, rev=None, **opts):
3904 """output the current or given revision of the project manifest
3906 """output the current or given revision of the project manifest
3905
3907
3906 Print a list of version controlled files for the given revision.
3908 Print a list of version controlled files for the given revision.
3907 If no revision is given, the first parent of the working directory
3909 If no revision is given, the first parent of the working directory
3908 is used, or the null revision if no revision is checked out.
3910 is used, or the null revision if no revision is checked out.
3909
3911
3910 With -v, print file permissions, symlink and executable bits.
3912 With -v, print file permissions, symlink and executable bits.
3911 With --debug, print file revision hashes.
3913 With --debug, print file revision hashes.
3912
3914
3913 If option --all is specified, the list of all files from all revisions
3915 If option --all is specified, the list of all files from all revisions
3914 is printed. This includes deleted and renamed files.
3916 is printed. This includes deleted and renamed files.
3915
3917
3916 Returns 0 on success.
3918 Returns 0 on success.
3917 """
3919 """
3918 opts = pycompat.byteskwargs(opts)
3920 opts = pycompat.byteskwargs(opts)
3919 fm = ui.formatter('manifest', opts)
3921 fm = ui.formatter('manifest', opts)
3920
3922
3921 if opts.get('all'):
3923 if opts.get('all'):
3922 if rev or node:
3924 if rev or node:
3923 raise error.Abort(_("can't specify a revision with --all"))
3925 raise error.Abort(_("can't specify a revision with --all"))
3924
3926
3925 res = set()
3927 res = set()
3926 for rev in repo:
3928 for rev in repo:
3927 ctx = repo[rev]
3929 ctx = repo[rev]
3928 res |= set(ctx.files())
3930 res |= set(ctx.files())
3929
3931
3930 ui.pager('manifest')
3932 ui.pager('manifest')
3931 for f in sorted(res):
3933 for f in sorted(res):
3932 fm.startitem()
3934 fm.startitem()
3933 fm.write("path", '%s\n', f)
3935 fm.write("path", '%s\n', f)
3934 fm.end()
3936 fm.end()
3935 return
3937 return
3936
3938
3937 if rev and node:
3939 if rev and node:
3938 raise error.Abort(_("please specify just one revision"))
3940 raise error.Abort(_("please specify just one revision"))
3939
3941
3940 if not node:
3942 if not node:
3941 node = rev
3943 node = rev
3942
3944
3943 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3945 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3944 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3946 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3945 if node:
3947 if node:
3946 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3948 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3947 ctx = scmutil.revsingle(repo, node)
3949 ctx = scmutil.revsingle(repo, node)
3948 mf = ctx.manifest()
3950 mf = ctx.manifest()
3949 ui.pager('manifest')
3951 ui.pager('manifest')
3950 for f in ctx:
3952 for f in ctx:
3951 fm.startitem()
3953 fm.startitem()
3952 fm.context(ctx=ctx)
3954 fm.context(ctx=ctx)
3953 fl = ctx[f].flags()
3955 fl = ctx[f].flags()
3954 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3956 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3955 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3957 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3956 fm.write('path', '%s\n', f)
3958 fm.write('path', '%s\n', f)
3957 fm.end()
3959 fm.end()
3958
3960
3959 @command('merge',
3961 @command('merge',
3960 [('f', 'force', None,
3962 [('f', 'force', None,
3961 _('force a merge including outstanding changes (DEPRECATED)')),
3963 _('force a merge including outstanding changes (DEPRECATED)')),
3962 ('r', 'rev', '', _('revision to merge'), _('REV')),
3964 ('r', 'rev', '', _('revision to merge'), _('REV')),
3963 ('P', 'preview', None,
3965 ('P', 'preview', None,
3964 _('review revisions to merge (no merge is performed)')),
3966 _('review revisions to merge (no merge is performed)')),
3965 ('', 'abort', None, _('abort the ongoing merge')),
3967 ('', 'abort', None, _('abort the ongoing merge')),
3966 ] + mergetoolopts,
3968 ] + mergetoolopts,
3967 _('[-P] [[-r] REV]'),
3969 _('[-P] [[-r] REV]'),
3968 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3970 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3969 def merge(ui, repo, node=None, **opts):
3971 def merge(ui, repo, node=None, **opts):
3970 """merge another revision into working directory
3972 """merge another revision into working directory
3971
3973
3972 The current working directory is updated with all changes made in
3974 The current working directory is updated with all changes made in
3973 the requested revision since the last common predecessor revision.
3975 the requested revision since the last common predecessor revision.
3974
3976
3975 Files that changed between either parent are marked as changed for
3977 Files that changed between either parent are marked as changed for
3976 the next commit and a commit must be performed before any further
3978 the next commit and a commit must be performed before any further
3977 updates to the repository are allowed. The next commit will have
3979 updates to the repository are allowed. The next commit will have
3978 two parents.
3980 two parents.
3979
3981
3980 ``--tool`` can be used to specify the merge tool used for file
3982 ``--tool`` can be used to specify the merge tool used for file
3981 merges. It overrides the HGMERGE environment variable and your
3983 merges. It overrides the HGMERGE environment variable and your
3982 configuration files. See :hg:`help merge-tools` for options.
3984 configuration files. See :hg:`help merge-tools` for options.
3983
3985
3984 If no revision is specified, the working directory's parent is a
3986 If no revision is specified, the working directory's parent is a
3985 head revision, and the current branch contains exactly one other
3987 head revision, and the current branch contains exactly one other
3986 head, the other head is merged with by default. Otherwise, an
3988 head, the other head is merged with by default. Otherwise, an
3987 explicit revision with which to merge with must be provided.
3989 explicit revision with which to merge with must be provided.
3988
3990
3989 See :hg:`help resolve` for information on handling file conflicts.
3991 See :hg:`help resolve` for information on handling file conflicts.
3990
3992
3991 To undo an uncommitted merge, use :hg:`merge --abort` which
3993 To undo an uncommitted merge, use :hg:`merge --abort` which
3992 will check out a clean copy of the original merge parent, losing
3994 will check out a clean copy of the original merge parent, losing
3993 all changes.
3995 all changes.
3994
3996
3995 Returns 0 on success, 1 if there are unresolved files.
3997 Returns 0 on success, 1 if there are unresolved files.
3996 """
3998 """
3997
3999
3998 opts = pycompat.byteskwargs(opts)
4000 opts = pycompat.byteskwargs(opts)
3999 abort = opts.get('abort')
4001 abort = opts.get('abort')
4000 if abort and repo.dirstate.p2() == nullid:
4002 if abort and repo.dirstate.p2() == nullid:
4001 cmdutil.wrongtooltocontinue(repo, _('merge'))
4003 cmdutil.wrongtooltocontinue(repo, _('merge'))
4002 if abort:
4004 if abort:
4003 if node:
4005 if node:
4004 raise error.Abort(_("cannot specify a node with --abort"))
4006 raise error.Abort(_("cannot specify a node with --abort"))
4005 if opts.get('rev'):
4007 if opts.get('rev'):
4006 raise error.Abort(_("cannot specify both --rev and --abort"))
4008 raise error.Abort(_("cannot specify both --rev and --abort"))
4007 if opts.get('preview'):
4009 if opts.get('preview'):
4008 raise error.Abort(_("cannot specify --preview with --abort"))
4010 raise error.Abort(_("cannot specify --preview with --abort"))
4009 if opts.get('rev') and node:
4011 if opts.get('rev') and node:
4010 raise error.Abort(_("please specify just one revision"))
4012 raise error.Abort(_("please specify just one revision"))
4011 if not node:
4013 if not node:
4012 node = opts.get('rev')
4014 node = opts.get('rev')
4013
4015
4014 if node:
4016 if node:
4015 node = scmutil.revsingle(repo, node).node()
4017 node = scmutil.revsingle(repo, node).node()
4016
4018
4017 if not node and not abort:
4019 if not node and not abort:
4018 node = repo[destutil.destmerge(repo)].node()
4020 node = repo[destutil.destmerge(repo)].node()
4019
4021
4020 if opts.get('preview'):
4022 if opts.get('preview'):
4021 # find nodes that are ancestors of p2 but not of p1
4023 # find nodes that are ancestors of p2 but not of p1
4022 p1 = repo.lookup('.')
4024 p1 = repo.lookup('.')
4023 p2 = node
4025 p2 = node
4024 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4026 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4025
4027
4026 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4028 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4027 for node in nodes:
4029 for node in nodes:
4028 displayer.show(repo[node])
4030 displayer.show(repo[node])
4029 displayer.close()
4031 displayer.close()
4030 return 0
4032 return 0
4031
4033
4032 # ui.forcemerge is an internal variable, do not document
4034 # ui.forcemerge is an internal variable, do not document
4033 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4035 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4034 with ui.configoverride(overrides, 'merge'):
4036 with ui.configoverride(overrides, 'merge'):
4035 force = opts.get('force')
4037 force = opts.get('force')
4036 labels = ['working copy', 'merge rev']
4038 labels = ['working copy', 'merge rev']
4037 return hg.merge(repo, node, force=force, mergeforce=force,
4039 return hg.merge(repo, node, force=force, mergeforce=force,
4038 labels=labels, abort=abort)
4040 labels=labels, abort=abort)
4039
4041
4040 @command('outgoing|out',
4042 @command('outgoing|out',
4041 [('f', 'force', None, _('run even when the destination is unrelated')),
4043 [('f', 'force', None, _('run even when the destination is unrelated')),
4042 ('r', 'rev', [],
4044 ('r', 'rev', [],
4043 _('a changeset intended to be included in the destination'), _('REV')),
4045 _('a changeset intended to be included in the destination'), _('REV')),
4044 ('n', 'newest-first', None, _('show newest record first')),
4046 ('n', 'newest-first', None, _('show newest record first')),
4045 ('B', 'bookmarks', False, _('compare bookmarks')),
4047 ('B', 'bookmarks', False, _('compare bookmarks')),
4046 ('b', 'branch', [], _('a specific branch you would like to push'),
4048 ('b', 'branch', [], _('a specific branch you would like to push'),
4047 _('BRANCH')),
4049 _('BRANCH')),
4048 ] + logopts + remoteopts + subrepoopts,
4050 ] + logopts + remoteopts + subrepoopts,
4049 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4051 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4050 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
4052 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
4051 def outgoing(ui, repo, dest=None, **opts):
4053 def outgoing(ui, repo, dest=None, **opts):
4052 """show changesets not found in the destination
4054 """show changesets not found in the destination
4053
4055
4054 Show changesets not found in the specified destination repository
4056 Show changesets not found in the specified destination repository
4055 or the default push location. These are the changesets that would
4057 or the default push location. These are the changesets that would
4056 be pushed if a push was requested.
4058 be pushed if a push was requested.
4057
4059
4058 See pull for details of valid destination formats.
4060 See pull for details of valid destination formats.
4059
4061
4060 .. container:: verbose
4062 .. container:: verbose
4061
4063
4062 With -B/--bookmarks, the result of bookmark comparison between
4064 With -B/--bookmarks, the result of bookmark comparison between
4063 local and remote repositories is displayed. With -v/--verbose,
4065 local and remote repositories is displayed. With -v/--verbose,
4064 status is also displayed for each bookmark like below::
4066 status is also displayed for each bookmark like below::
4065
4067
4066 BM1 01234567890a added
4068 BM1 01234567890a added
4067 BM2 deleted
4069 BM2 deleted
4068 BM3 234567890abc advanced
4070 BM3 234567890abc advanced
4069 BM4 34567890abcd diverged
4071 BM4 34567890abcd diverged
4070 BM5 4567890abcde changed
4072 BM5 4567890abcde changed
4071
4073
4072 The action taken when pushing depends on the
4074 The action taken when pushing depends on the
4073 status of each bookmark:
4075 status of each bookmark:
4074
4076
4075 :``added``: push with ``-B`` will create it
4077 :``added``: push with ``-B`` will create it
4076 :``deleted``: push with ``-B`` will delete it
4078 :``deleted``: push with ``-B`` will delete it
4077 :``advanced``: push will update it
4079 :``advanced``: push will update it
4078 :``diverged``: push with ``-B`` will update it
4080 :``diverged``: push with ``-B`` will update it
4079 :``changed``: push with ``-B`` will update it
4081 :``changed``: push with ``-B`` will update it
4080
4082
4081 From the point of view of pushing behavior, bookmarks
4083 From the point of view of pushing behavior, bookmarks
4082 existing only in the remote repository are treated as
4084 existing only in the remote repository are treated as
4083 ``deleted``, even if it is in fact added remotely.
4085 ``deleted``, even if it is in fact added remotely.
4084
4086
4085 Returns 0 if there are outgoing changes, 1 otherwise.
4087 Returns 0 if there are outgoing changes, 1 otherwise.
4086 """
4088 """
4087 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4089 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4088 # style URLs, so don't overwrite dest.
4090 # style URLs, so don't overwrite dest.
4089 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4091 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4090 if not path:
4092 if not path:
4091 raise error.Abort(_('default repository not configured!'),
4093 raise error.Abort(_('default repository not configured!'),
4092 hint=_("see 'hg help config.paths'"))
4094 hint=_("see 'hg help config.paths'"))
4093
4095
4094 opts = pycompat.byteskwargs(opts)
4096 opts = pycompat.byteskwargs(opts)
4095 if opts.get('graph'):
4097 if opts.get('graph'):
4096 logcmdutil.checkunsupportedgraphflags([], opts)
4098 logcmdutil.checkunsupportedgraphflags([], opts)
4097 o, other = hg._outgoing(ui, repo, dest, opts)
4099 o, other = hg._outgoing(ui, repo, dest, opts)
4098 if not o:
4100 if not o:
4099 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4101 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4100 return
4102 return
4101
4103
4102 revdag = logcmdutil.graphrevs(repo, o, opts)
4104 revdag = logcmdutil.graphrevs(repo, o, opts)
4103 ui.pager('outgoing')
4105 ui.pager('outgoing')
4104 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4106 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4105 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4107 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4106 graphmod.asciiedges)
4108 graphmod.asciiedges)
4107 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4109 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4108 return 0
4110 return 0
4109
4111
4110 if opts.get('bookmarks'):
4112 if opts.get('bookmarks'):
4111 dest = path.pushloc or path.loc
4113 dest = path.pushloc or path.loc
4112 other = hg.peer(repo, opts, dest)
4114 other = hg.peer(repo, opts, dest)
4113 if 'bookmarks' not in other.listkeys('namespaces'):
4115 if 'bookmarks' not in other.listkeys('namespaces'):
4114 ui.warn(_("remote doesn't support bookmarks\n"))
4116 ui.warn(_("remote doesn't support bookmarks\n"))
4115 return 0
4117 return 0
4116 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4118 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4117 ui.pager('outgoing')
4119 ui.pager('outgoing')
4118 return bookmarks.outgoing(ui, repo, other)
4120 return bookmarks.outgoing(ui, repo, other)
4119
4121
4120 repo._subtoppath = path.pushloc or path.loc
4122 repo._subtoppath = path.pushloc or path.loc
4121 try:
4123 try:
4122 return hg.outgoing(ui, repo, dest, opts)
4124 return hg.outgoing(ui, repo, dest, opts)
4123 finally:
4125 finally:
4124 del repo._subtoppath
4126 del repo._subtoppath
4125
4127
4126 @command('parents',
4128 @command('parents',
4127 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4129 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4128 ] + templateopts,
4130 ] + templateopts,
4129 _('[-r REV] [FILE]'),
4131 _('[-r REV] [FILE]'),
4130 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4132 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4131 inferrepo=True)
4133 inferrepo=True)
4132 def parents(ui, repo, file_=None, **opts):
4134 def parents(ui, repo, file_=None, **opts):
4133 """show the parents of the working directory or revision (DEPRECATED)
4135 """show the parents of the working directory or revision (DEPRECATED)
4134
4136
4135 Print the working directory's parent revisions. If a revision is
4137 Print the working directory's parent revisions. If a revision is
4136 given via -r/--rev, the parent of that revision will be printed.
4138 given via -r/--rev, the parent of that revision will be printed.
4137 If a file argument is given, the revision in which the file was
4139 If a file argument is given, the revision in which the file was
4138 last changed (before the working directory revision or the
4140 last changed (before the working directory revision or the
4139 argument to --rev if given) is printed.
4141 argument to --rev if given) is printed.
4140
4142
4141 This command is equivalent to::
4143 This command is equivalent to::
4142
4144
4143 hg log -r "p1()+p2()" or
4145 hg log -r "p1()+p2()" or
4144 hg log -r "p1(REV)+p2(REV)" or
4146 hg log -r "p1(REV)+p2(REV)" or
4145 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4147 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4146 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4148 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4147
4149
4148 See :hg:`summary` and :hg:`help revsets` for related information.
4150 See :hg:`summary` and :hg:`help revsets` for related information.
4149
4151
4150 Returns 0 on success.
4152 Returns 0 on success.
4151 """
4153 """
4152
4154
4153 opts = pycompat.byteskwargs(opts)
4155 opts = pycompat.byteskwargs(opts)
4154 rev = opts.get('rev')
4156 rev = opts.get('rev')
4155 if rev:
4157 if rev:
4156 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4158 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4157 ctx = scmutil.revsingle(repo, rev, None)
4159 ctx = scmutil.revsingle(repo, rev, None)
4158
4160
4159 if file_:
4161 if file_:
4160 m = scmutil.match(ctx, (file_,), opts)
4162 m = scmutil.match(ctx, (file_,), opts)
4161 if m.anypats() or len(m.files()) != 1:
4163 if m.anypats() or len(m.files()) != 1:
4162 raise error.Abort(_('can only specify an explicit filename'))
4164 raise error.Abort(_('can only specify an explicit filename'))
4163 file_ = m.files()[0]
4165 file_ = m.files()[0]
4164 filenodes = []
4166 filenodes = []
4165 for cp in ctx.parents():
4167 for cp in ctx.parents():
4166 if not cp:
4168 if not cp:
4167 continue
4169 continue
4168 try:
4170 try:
4169 filenodes.append(cp.filenode(file_))
4171 filenodes.append(cp.filenode(file_))
4170 except error.LookupError:
4172 except error.LookupError:
4171 pass
4173 pass
4172 if not filenodes:
4174 if not filenodes:
4173 raise error.Abort(_("'%s' not found in manifest!") % file_)
4175 raise error.Abort(_("'%s' not found in manifest!") % file_)
4174 p = []
4176 p = []
4175 for fn in filenodes:
4177 for fn in filenodes:
4176 fctx = repo.filectx(file_, fileid=fn)
4178 fctx = repo.filectx(file_, fileid=fn)
4177 p.append(fctx.node())
4179 p.append(fctx.node())
4178 else:
4180 else:
4179 p = [cp.node() for cp in ctx.parents()]
4181 p = [cp.node() for cp in ctx.parents()]
4180
4182
4181 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4183 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4182 for n in p:
4184 for n in p:
4183 if n != nullid:
4185 if n != nullid:
4184 displayer.show(repo[n])
4186 displayer.show(repo[n])
4185 displayer.close()
4187 displayer.close()
4186
4188
4187 @command('paths', formatteropts, _('[NAME]'),
4189 @command('paths', formatteropts, _('[NAME]'),
4188 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4190 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4189 optionalrepo=True, intents={INTENT_READONLY})
4191 optionalrepo=True, intents={INTENT_READONLY})
4190 def paths(ui, repo, search=None, **opts):
4192 def paths(ui, repo, search=None, **opts):
4191 """show aliases for remote repositories
4193 """show aliases for remote repositories
4192
4194
4193 Show definition of symbolic path name NAME. If no name is given,
4195 Show definition of symbolic path name NAME. If no name is given,
4194 show definition of all available names.
4196 show definition of all available names.
4195
4197
4196 Option -q/--quiet suppresses all output when searching for NAME
4198 Option -q/--quiet suppresses all output when searching for NAME
4197 and shows only the path names when listing all definitions.
4199 and shows only the path names when listing all definitions.
4198
4200
4199 Path names are defined in the [paths] section of your
4201 Path names are defined in the [paths] section of your
4200 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4202 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4201 repository, ``.hg/hgrc`` is used, too.
4203 repository, ``.hg/hgrc`` is used, too.
4202
4204
4203 The path names ``default`` and ``default-push`` have a special
4205 The path names ``default`` and ``default-push`` have a special
4204 meaning. When performing a push or pull operation, they are used
4206 meaning. When performing a push or pull operation, they are used
4205 as fallbacks if no location is specified on the command-line.
4207 as fallbacks if no location is specified on the command-line.
4206 When ``default-push`` is set, it will be used for push and
4208 When ``default-push`` is set, it will be used for push and
4207 ``default`` will be used for pull; otherwise ``default`` is used
4209 ``default`` will be used for pull; otherwise ``default`` is used
4208 as the fallback for both. When cloning a repository, the clone
4210 as the fallback for both. When cloning a repository, the clone
4209 source is written as ``default`` in ``.hg/hgrc``.
4211 source is written as ``default`` in ``.hg/hgrc``.
4210
4212
4211 .. note::
4213 .. note::
4212
4214
4213 ``default`` and ``default-push`` apply to all inbound (e.g.
4215 ``default`` and ``default-push`` apply to all inbound (e.g.
4214 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4216 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4215 and :hg:`bundle`) operations.
4217 and :hg:`bundle`) operations.
4216
4218
4217 See :hg:`help urls` for more information.
4219 See :hg:`help urls` for more information.
4218
4220
4219 .. container:: verbose
4221 .. container:: verbose
4220
4222
4221 Template:
4223 Template:
4222
4224
4223 The following keywords are supported. See also :hg:`help templates`.
4225 The following keywords are supported. See also :hg:`help templates`.
4224
4226
4225 :name: String. Symbolic name of the path alias.
4227 :name: String. Symbolic name of the path alias.
4226 :pushurl: String. URL for push operations.
4228 :pushurl: String. URL for push operations.
4227 :url: String. URL or directory path for the other operations.
4229 :url: String. URL or directory path for the other operations.
4228
4230
4229 Returns 0 on success.
4231 Returns 0 on success.
4230 """
4232 """
4231
4233
4232 opts = pycompat.byteskwargs(opts)
4234 opts = pycompat.byteskwargs(opts)
4233 ui.pager('paths')
4235 ui.pager('paths')
4234 if search:
4236 if search:
4235 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4237 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4236 if name == search]
4238 if name == search]
4237 else:
4239 else:
4238 pathitems = sorted(ui.paths.iteritems())
4240 pathitems = sorted(ui.paths.iteritems())
4239
4241
4240 fm = ui.formatter('paths', opts)
4242 fm = ui.formatter('paths', opts)
4241 if fm.isplain():
4243 if fm.isplain():
4242 hidepassword = util.hidepassword
4244 hidepassword = util.hidepassword
4243 else:
4245 else:
4244 hidepassword = bytes
4246 hidepassword = bytes
4245 if ui.quiet:
4247 if ui.quiet:
4246 namefmt = '%s\n'
4248 namefmt = '%s\n'
4247 else:
4249 else:
4248 namefmt = '%s = '
4250 namefmt = '%s = '
4249 showsubopts = not search and not ui.quiet
4251 showsubopts = not search and not ui.quiet
4250
4252
4251 for name, path in pathitems:
4253 for name, path in pathitems:
4252 fm.startitem()
4254 fm.startitem()
4253 fm.condwrite(not search, 'name', namefmt, name)
4255 fm.condwrite(not search, 'name', namefmt, name)
4254 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4256 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4255 for subopt, value in sorted(path.suboptions.items()):
4257 for subopt, value in sorted(path.suboptions.items()):
4256 assert subopt not in ('name', 'url')
4258 assert subopt not in ('name', 'url')
4257 if showsubopts:
4259 if showsubopts:
4258 fm.plain('%s:%s = ' % (name, subopt))
4260 fm.plain('%s:%s = ' % (name, subopt))
4259 fm.condwrite(showsubopts, subopt, '%s\n', value)
4261 fm.condwrite(showsubopts, subopt, '%s\n', value)
4260
4262
4261 fm.end()
4263 fm.end()
4262
4264
4263 if search and not pathitems:
4265 if search and not pathitems:
4264 if not ui.quiet:
4266 if not ui.quiet:
4265 ui.warn(_("not found!\n"))
4267 ui.warn(_("not found!\n"))
4266 return 1
4268 return 1
4267 else:
4269 else:
4268 return 0
4270 return 0
4269
4271
4270 @command('phase',
4272 @command('phase',
4271 [('p', 'public', False, _('set changeset phase to public')),
4273 [('p', 'public', False, _('set changeset phase to public')),
4272 ('d', 'draft', False, _('set changeset phase to draft')),
4274 ('d', 'draft', False, _('set changeset phase to draft')),
4273 ('s', 'secret', False, _('set changeset phase to secret')),
4275 ('s', 'secret', False, _('set changeset phase to secret')),
4274 ('f', 'force', False, _('allow to move boundary backward')),
4276 ('f', 'force', False, _('allow to move boundary backward')),
4275 ('r', 'rev', [], _('target revision'), _('REV')),
4277 ('r', 'rev', [], _('target revision'), _('REV')),
4276 ],
4278 ],
4277 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4279 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4278 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4280 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4279 def phase(ui, repo, *revs, **opts):
4281 def phase(ui, repo, *revs, **opts):
4280 """set or show the current phase name
4282 """set or show the current phase name
4281
4283
4282 With no argument, show the phase name of the current revision(s).
4284 With no argument, show the phase name of the current revision(s).
4283
4285
4284 With one of -p/--public, -d/--draft or -s/--secret, change the
4286 With one of -p/--public, -d/--draft or -s/--secret, change the
4285 phase value of the specified revisions.
4287 phase value of the specified revisions.
4286
4288
4287 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4289 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4288 lower phase to a higher phase. Phases are ordered as follows::
4290 lower phase to a higher phase. Phases are ordered as follows::
4289
4291
4290 public < draft < secret
4292 public < draft < secret
4291
4293
4292 Returns 0 on success, 1 if some phases could not be changed.
4294 Returns 0 on success, 1 if some phases could not be changed.
4293
4295
4294 (For more information about the phases concept, see :hg:`help phases`.)
4296 (For more information about the phases concept, see :hg:`help phases`.)
4295 """
4297 """
4296 opts = pycompat.byteskwargs(opts)
4298 opts = pycompat.byteskwargs(opts)
4297 # search for a unique phase argument
4299 # search for a unique phase argument
4298 targetphase = None
4300 targetphase = None
4299 for idx, name in enumerate(phases.cmdphasenames):
4301 for idx, name in enumerate(phases.cmdphasenames):
4300 if opts[name]:
4302 if opts[name]:
4301 if targetphase is not None:
4303 if targetphase is not None:
4302 raise error.Abort(_('only one phase can be specified'))
4304 raise error.Abort(_('only one phase can be specified'))
4303 targetphase = idx
4305 targetphase = idx
4304
4306
4305 # look for specified revision
4307 # look for specified revision
4306 revs = list(revs)
4308 revs = list(revs)
4307 revs.extend(opts['rev'])
4309 revs.extend(opts['rev'])
4308 if not revs:
4310 if not revs:
4309 # display both parents as the second parent phase can influence
4311 # display both parents as the second parent phase can influence
4310 # the phase of a merge commit
4312 # the phase of a merge commit
4311 revs = [c.rev() for c in repo[None].parents()]
4313 revs = [c.rev() for c in repo[None].parents()]
4312
4314
4313 revs = scmutil.revrange(repo, revs)
4315 revs = scmutil.revrange(repo, revs)
4314
4316
4315 ret = 0
4317 ret = 0
4316 if targetphase is None:
4318 if targetphase is None:
4317 # display
4319 # display
4318 for r in revs:
4320 for r in revs:
4319 ctx = repo[r]
4321 ctx = repo[r]
4320 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4322 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4321 else:
4323 else:
4322 with repo.lock(), repo.transaction("phase") as tr:
4324 with repo.lock(), repo.transaction("phase") as tr:
4323 # set phase
4325 # set phase
4324 if not revs:
4326 if not revs:
4325 raise error.Abort(_('empty revision set'))
4327 raise error.Abort(_('empty revision set'))
4326 nodes = [repo[r].node() for r in revs]
4328 nodes = [repo[r].node() for r in revs]
4327 # moving revision from public to draft may hide them
4329 # moving revision from public to draft may hide them
4328 # We have to check result on an unfiltered repository
4330 # We have to check result on an unfiltered repository
4329 unfi = repo.unfiltered()
4331 unfi = repo.unfiltered()
4330 getphase = unfi._phasecache.phase
4332 getphase = unfi._phasecache.phase
4331 olddata = [getphase(unfi, r) for r in unfi]
4333 olddata = [getphase(unfi, r) for r in unfi]
4332 phases.advanceboundary(repo, tr, targetphase, nodes)
4334 phases.advanceboundary(repo, tr, targetphase, nodes)
4333 if opts['force']:
4335 if opts['force']:
4334 phases.retractboundary(repo, tr, targetphase, nodes)
4336 phases.retractboundary(repo, tr, targetphase, nodes)
4335 getphase = unfi._phasecache.phase
4337 getphase = unfi._phasecache.phase
4336 newdata = [getphase(unfi, r) for r in unfi]
4338 newdata = [getphase(unfi, r) for r in unfi]
4337 changes = sum(newdata[r] != olddata[r] for r in unfi)
4339 changes = sum(newdata[r] != olddata[r] for r in unfi)
4338 cl = unfi.changelog
4340 cl = unfi.changelog
4339 rejected = [n for n in nodes
4341 rejected = [n for n in nodes
4340 if newdata[cl.rev(n)] < targetphase]
4342 if newdata[cl.rev(n)] < targetphase]
4341 if rejected:
4343 if rejected:
4342 ui.warn(_('cannot move %i changesets to a higher '
4344 ui.warn(_('cannot move %i changesets to a higher '
4343 'phase, use --force\n') % len(rejected))
4345 'phase, use --force\n') % len(rejected))
4344 ret = 1
4346 ret = 1
4345 if changes:
4347 if changes:
4346 msg = _('phase changed for %i changesets\n') % changes
4348 msg = _('phase changed for %i changesets\n') % changes
4347 if ret:
4349 if ret:
4348 ui.status(msg)
4350 ui.status(msg)
4349 else:
4351 else:
4350 ui.note(msg)
4352 ui.note(msg)
4351 else:
4353 else:
4352 ui.warn(_('no phases changed\n'))
4354 ui.warn(_('no phases changed\n'))
4353 return ret
4355 return ret
4354
4356
4355 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4357 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4356 """Run after a changegroup has been added via pull/unbundle
4358 """Run after a changegroup has been added via pull/unbundle
4357
4359
4358 This takes arguments below:
4360 This takes arguments below:
4359
4361
4360 :modheads: change of heads by pull/unbundle
4362 :modheads: change of heads by pull/unbundle
4361 :optupdate: updating working directory is needed or not
4363 :optupdate: updating working directory is needed or not
4362 :checkout: update destination revision (or None to default destination)
4364 :checkout: update destination revision (or None to default destination)
4363 :brev: a name, which might be a bookmark to be activated after updating
4365 :brev: a name, which might be a bookmark to be activated after updating
4364 """
4366 """
4365 if modheads == 0:
4367 if modheads == 0:
4366 return
4368 return
4367 if optupdate:
4369 if optupdate:
4368 try:
4370 try:
4369 return hg.updatetotally(ui, repo, checkout, brev)
4371 return hg.updatetotally(ui, repo, checkout, brev)
4370 except error.UpdateAbort as inst:
4372 except error.UpdateAbort as inst:
4371 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4373 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4372 hint = inst.hint
4374 hint = inst.hint
4373 raise error.UpdateAbort(msg, hint=hint)
4375 raise error.UpdateAbort(msg, hint=hint)
4374 if modheads is not None and modheads > 1:
4376 if modheads is not None and modheads > 1:
4375 currentbranchheads = len(repo.branchheads())
4377 currentbranchheads = len(repo.branchheads())
4376 if currentbranchheads == modheads:
4378 if currentbranchheads == modheads:
4377 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4379 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4378 elif currentbranchheads > 1:
4380 elif currentbranchheads > 1:
4379 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4381 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4380 "merge)\n"))
4382 "merge)\n"))
4381 else:
4383 else:
4382 ui.status(_("(run 'hg heads' to see heads)\n"))
4384 ui.status(_("(run 'hg heads' to see heads)\n"))
4383 elif not ui.configbool('commands', 'update.requiredest'):
4385 elif not ui.configbool('commands', 'update.requiredest'):
4384 ui.status(_("(run 'hg update' to get a working copy)\n"))
4386 ui.status(_("(run 'hg update' to get a working copy)\n"))
4385
4387
4386 @command('pull',
4388 @command('pull',
4387 [('u', 'update', None,
4389 [('u', 'update', None,
4388 _('update to new branch head if new descendants were pulled')),
4390 _('update to new branch head if new descendants were pulled')),
4389 ('f', 'force', None, _('run even when remote repository is unrelated')),
4391 ('f', 'force', None, _('run even when remote repository is unrelated')),
4390 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4392 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4391 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4393 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4392 ('b', 'branch', [], _('a specific branch you would like to pull'),
4394 ('b', 'branch', [], _('a specific branch you would like to pull'),
4393 _('BRANCH')),
4395 _('BRANCH')),
4394 ] + remoteopts,
4396 ] + remoteopts,
4395 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4397 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4396 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4398 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4397 helpbasic=True)
4399 helpbasic=True)
4398 def pull(ui, repo, source="default", **opts):
4400 def pull(ui, repo, source="default", **opts):
4399 """pull changes from the specified source
4401 """pull changes from the specified source
4400
4402
4401 Pull changes from a remote repository to a local one.
4403 Pull changes from a remote repository to a local one.
4402
4404
4403 This finds all changes from the repository at the specified path
4405 This finds all changes from the repository at the specified path
4404 or URL and adds them to a local repository (the current one unless
4406 or URL and adds them to a local repository (the current one unless
4405 -R is specified). By default, this does not update the copy of the
4407 -R is specified). By default, this does not update the copy of the
4406 project in the working directory.
4408 project in the working directory.
4407
4409
4408 When cloning from servers that support it, Mercurial may fetch
4410 When cloning from servers that support it, Mercurial may fetch
4409 pre-generated data. When this is done, hooks operating on incoming
4411 pre-generated data. When this is done, hooks operating on incoming
4410 changesets and changegroups may fire more than once, once for each
4412 changesets and changegroups may fire more than once, once for each
4411 pre-generated bundle and as well as for any additional remaining
4413 pre-generated bundle and as well as for any additional remaining
4412 data. See :hg:`help -e clonebundles` for more.
4414 data. See :hg:`help -e clonebundles` for more.
4413
4415
4414 Use :hg:`incoming` if you want to see what would have been added
4416 Use :hg:`incoming` if you want to see what would have been added
4415 by a pull at the time you issued this command. If you then decide
4417 by a pull at the time you issued this command. If you then decide
4416 to add those changes to the repository, you should use :hg:`pull
4418 to add those changes to the repository, you should use :hg:`pull
4417 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4419 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4418
4420
4419 If SOURCE is omitted, the 'default' path will be used.
4421 If SOURCE is omitted, the 'default' path will be used.
4420 See :hg:`help urls` for more information.
4422 See :hg:`help urls` for more information.
4421
4423
4422 Specifying bookmark as ``.`` is equivalent to specifying the active
4424 Specifying bookmark as ``.`` is equivalent to specifying the active
4423 bookmark's name.
4425 bookmark's name.
4424
4426
4425 Returns 0 on success, 1 if an update had unresolved files.
4427 Returns 0 on success, 1 if an update had unresolved files.
4426 """
4428 """
4427
4429
4428 opts = pycompat.byteskwargs(opts)
4430 opts = pycompat.byteskwargs(opts)
4429 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4431 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4430 msg = _('update destination required by configuration')
4432 msg = _('update destination required by configuration')
4431 hint = _('use hg pull followed by hg update DEST')
4433 hint = _('use hg pull followed by hg update DEST')
4432 raise error.Abort(msg, hint=hint)
4434 raise error.Abort(msg, hint=hint)
4433
4435
4434 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4436 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4435 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4437 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4436 other = hg.peer(repo, opts, source)
4438 other = hg.peer(repo, opts, source)
4437 try:
4439 try:
4438 revs, checkout = hg.addbranchrevs(repo, other, branches,
4440 revs, checkout = hg.addbranchrevs(repo, other, branches,
4439 opts.get('rev'))
4441 opts.get('rev'))
4440
4442
4441 pullopargs = {}
4443 pullopargs = {}
4442
4444
4443 nodes = None
4445 nodes = None
4444 if opts.get('bookmark') or revs:
4446 if opts.get('bookmark') or revs:
4445 # The list of bookmark used here is the same used to actually update
4447 # The list of bookmark used here is the same used to actually update
4446 # the bookmark names, to avoid the race from issue 4689 and we do
4448 # the bookmark names, to avoid the race from issue 4689 and we do
4447 # all lookup and bookmark queries in one go so they see the same
4449 # all lookup and bookmark queries in one go so they see the same
4448 # version of the server state (issue 4700).
4450 # version of the server state (issue 4700).
4449 nodes = []
4451 nodes = []
4450 fnodes = []
4452 fnodes = []
4451 revs = revs or []
4453 revs = revs or []
4452 if revs and not other.capable('lookup'):
4454 if revs and not other.capable('lookup'):
4453 err = _("other repository doesn't support revision lookup, "
4455 err = _("other repository doesn't support revision lookup, "
4454 "so a rev cannot be specified.")
4456 "so a rev cannot be specified.")
4455 raise error.Abort(err)
4457 raise error.Abort(err)
4456 with other.commandexecutor() as e:
4458 with other.commandexecutor() as e:
4457 fremotebookmarks = e.callcommand('listkeys', {
4459 fremotebookmarks = e.callcommand('listkeys', {
4458 'namespace': 'bookmarks'
4460 'namespace': 'bookmarks'
4459 })
4461 })
4460 for r in revs:
4462 for r in revs:
4461 fnodes.append(e.callcommand('lookup', {'key': r}))
4463 fnodes.append(e.callcommand('lookup', {'key': r}))
4462 remotebookmarks = fremotebookmarks.result()
4464 remotebookmarks = fremotebookmarks.result()
4463 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4465 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4464 pullopargs['remotebookmarks'] = remotebookmarks
4466 pullopargs['remotebookmarks'] = remotebookmarks
4465 for b in opts.get('bookmark', []):
4467 for b in opts.get('bookmark', []):
4466 b = repo._bookmarks.expandname(b)
4468 b = repo._bookmarks.expandname(b)
4467 if b not in remotebookmarks:
4469 if b not in remotebookmarks:
4468 raise error.Abort(_('remote bookmark %s not found!') % b)
4470 raise error.Abort(_('remote bookmark %s not found!') % b)
4469 nodes.append(remotebookmarks[b])
4471 nodes.append(remotebookmarks[b])
4470 for i, rev in enumerate(revs):
4472 for i, rev in enumerate(revs):
4471 node = fnodes[i].result()
4473 node = fnodes[i].result()
4472 nodes.append(node)
4474 nodes.append(node)
4473 if rev == checkout:
4475 if rev == checkout:
4474 checkout = node
4476 checkout = node
4475
4477
4476 wlock = util.nullcontextmanager()
4478 wlock = util.nullcontextmanager()
4477 if opts.get('update'):
4479 if opts.get('update'):
4478 wlock = repo.wlock()
4480 wlock = repo.wlock()
4479 with wlock:
4481 with wlock:
4480 pullopargs.update(opts.get('opargs', {}))
4482 pullopargs.update(opts.get('opargs', {}))
4481 modheads = exchange.pull(repo, other, heads=nodes,
4483 modheads = exchange.pull(repo, other, heads=nodes,
4482 force=opts.get('force'),
4484 force=opts.get('force'),
4483 bookmarks=opts.get('bookmark', ()),
4485 bookmarks=opts.get('bookmark', ()),
4484 opargs=pullopargs).cgresult
4486 opargs=pullopargs).cgresult
4485
4487
4486 # brev is a name, which might be a bookmark to be activated at
4488 # brev is a name, which might be a bookmark to be activated at
4487 # the end of the update. In other words, it is an explicit
4489 # the end of the update. In other words, it is an explicit
4488 # destination of the update
4490 # destination of the update
4489 brev = None
4491 brev = None
4490
4492
4491 if checkout:
4493 if checkout:
4492 checkout = repo.unfiltered().changelog.rev(checkout)
4494 checkout = repo.unfiltered().changelog.rev(checkout)
4493
4495
4494 # order below depends on implementation of
4496 # order below depends on implementation of
4495 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4497 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4496 # because 'checkout' is determined without it.
4498 # because 'checkout' is determined without it.
4497 if opts.get('rev'):
4499 if opts.get('rev'):
4498 brev = opts['rev'][0]
4500 brev = opts['rev'][0]
4499 elif opts.get('branch'):
4501 elif opts.get('branch'):
4500 brev = opts['branch'][0]
4502 brev = opts['branch'][0]
4501 else:
4503 else:
4502 brev = branches[0]
4504 brev = branches[0]
4503 repo._subtoppath = source
4505 repo._subtoppath = source
4504 try:
4506 try:
4505 ret = postincoming(ui, repo, modheads, opts.get('update'),
4507 ret = postincoming(ui, repo, modheads, opts.get('update'),
4506 checkout, brev)
4508 checkout, brev)
4507 except error.FilteredRepoLookupError as exc:
4509 except error.FilteredRepoLookupError as exc:
4508 msg = _('cannot update to target: %s') % exc.args[0]
4510 msg = _('cannot update to target: %s') % exc.args[0]
4509 exc.args = (msg,) + exc.args[1:]
4511 exc.args = (msg,) + exc.args[1:]
4510 raise
4512 raise
4511 finally:
4513 finally:
4512 del repo._subtoppath
4514 del repo._subtoppath
4513
4515
4514 finally:
4516 finally:
4515 other.close()
4517 other.close()
4516 return ret
4518 return ret
4517
4519
4518 @command('push',
4520 @command('push',
4519 [('f', 'force', None, _('force push')),
4521 [('f', 'force', None, _('force push')),
4520 ('r', 'rev', [],
4522 ('r', 'rev', [],
4521 _('a changeset intended to be included in the destination'),
4523 _('a changeset intended to be included in the destination'),
4522 _('REV')),
4524 _('REV')),
4523 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4525 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4524 ('b', 'branch', [],
4526 ('b', 'branch', [],
4525 _('a specific branch you would like to push'), _('BRANCH')),
4527 _('a specific branch you would like to push'), _('BRANCH')),
4526 ('', 'new-branch', False, _('allow pushing a new branch')),
4528 ('', 'new-branch', False, _('allow pushing a new branch')),
4527 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4529 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4528 ('', 'publish', False, _('push the changeset as public (EXPERIMENTAL)')),
4530 ('', 'publish', False, _('push the changeset as public (EXPERIMENTAL)')),
4529 ] + remoteopts,
4531 ] + remoteopts,
4530 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4532 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4531 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4533 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4532 helpbasic=True)
4534 helpbasic=True)
4533 def push(ui, repo, dest=None, **opts):
4535 def push(ui, repo, dest=None, **opts):
4534 """push changes to the specified destination
4536 """push changes to the specified destination
4535
4537
4536 Push changesets from the local repository to the specified
4538 Push changesets from the local repository to the specified
4537 destination.
4539 destination.
4538
4540
4539 This operation is symmetrical to pull: it is identical to a pull
4541 This operation is symmetrical to pull: it is identical to a pull
4540 in the destination repository from the current one.
4542 in the destination repository from the current one.
4541
4543
4542 By default, push will not allow creation of new heads at the
4544 By default, push will not allow creation of new heads at the
4543 destination, since multiple heads would make it unclear which head
4545 destination, since multiple heads would make it unclear which head
4544 to use. In this situation, it is recommended to pull and merge
4546 to use. In this situation, it is recommended to pull and merge
4545 before pushing.
4547 before pushing.
4546
4548
4547 Use --new-branch if you want to allow push to create a new named
4549 Use --new-branch if you want to allow push to create a new named
4548 branch that is not present at the destination. This allows you to
4550 branch that is not present at the destination. This allows you to
4549 only create a new branch without forcing other changes.
4551 only create a new branch without forcing other changes.
4550
4552
4551 .. note::
4553 .. note::
4552
4554
4553 Extra care should be taken with the -f/--force option,
4555 Extra care should be taken with the -f/--force option,
4554 which will push all new heads on all branches, an action which will
4556 which will push all new heads on all branches, an action which will
4555 almost always cause confusion for collaborators.
4557 almost always cause confusion for collaborators.
4556
4558
4557 If -r/--rev is used, the specified revision and all its ancestors
4559 If -r/--rev is used, the specified revision and all its ancestors
4558 will be pushed to the remote repository.
4560 will be pushed to the remote repository.
4559
4561
4560 If -B/--bookmark is used, the specified bookmarked revision, its
4562 If -B/--bookmark is used, the specified bookmarked revision, its
4561 ancestors, and the bookmark will be pushed to the remote
4563 ancestors, and the bookmark will be pushed to the remote
4562 repository. Specifying ``.`` is equivalent to specifying the active
4564 repository. Specifying ``.`` is equivalent to specifying the active
4563 bookmark's name.
4565 bookmark's name.
4564
4566
4565 Please see :hg:`help urls` for important details about ``ssh://``
4567 Please see :hg:`help urls` for important details about ``ssh://``
4566 URLs. If DESTINATION is omitted, a default path will be used.
4568 URLs. If DESTINATION is omitted, a default path will be used.
4567
4569
4568 .. container:: verbose
4570 .. container:: verbose
4569
4571
4570 The --pushvars option sends strings to the server that become
4572 The --pushvars option sends strings to the server that become
4571 environment variables prepended with ``HG_USERVAR_``. For example,
4573 environment variables prepended with ``HG_USERVAR_``. For example,
4572 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4574 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4573 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4575 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4574
4576
4575 pushvars can provide for user-overridable hooks as well as set debug
4577 pushvars can provide for user-overridable hooks as well as set debug
4576 levels. One example is having a hook that blocks commits containing
4578 levels. One example is having a hook that blocks commits containing
4577 conflict markers, but enables the user to override the hook if the file
4579 conflict markers, but enables the user to override the hook if the file
4578 is using conflict markers for testing purposes or the file format has
4580 is using conflict markers for testing purposes or the file format has
4579 strings that look like conflict markers.
4581 strings that look like conflict markers.
4580
4582
4581 By default, servers will ignore `--pushvars`. To enable it add the
4583 By default, servers will ignore `--pushvars`. To enable it add the
4582 following to your configuration file::
4584 following to your configuration file::
4583
4585
4584 [push]
4586 [push]
4585 pushvars.server = true
4587 pushvars.server = true
4586
4588
4587 Returns 0 if push was successful, 1 if nothing to push.
4589 Returns 0 if push was successful, 1 if nothing to push.
4588 """
4590 """
4589
4591
4590 opts = pycompat.byteskwargs(opts)
4592 opts = pycompat.byteskwargs(opts)
4591 if opts.get('bookmark'):
4593 if opts.get('bookmark'):
4592 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4594 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4593 for b in opts['bookmark']:
4595 for b in opts['bookmark']:
4594 # translate -B options to -r so changesets get pushed
4596 # translate -B options to -r so changesets get pushed
4595 b = repo._bookmarks.expandname(b)
4597 b = repo._bookmarks.expandname(b)
4596 if b in repo._bookmarks:
4598 if b in repo._bookmarks:
4597 opts.setdefault('rev', []).append(b)
4599 opts.setdefault('rev', []).append(b)
4598 else:
4600 else:
4599 # if we try to push a deleted bookmark, translate it to null
4601 # if we try to push a deleted bookmark, translate it to null
4600 # this lets simultaneous -r, -b options continue working
4602 # this lets simultaneous -r, -b options continue working
4601 opts.setdefault('rev', []).append("null")
4603 opts.setdefault('rev', []).append("null")
4602
4604
4603 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4605 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4604 if not path:
4606 if not path:
4605 raise error.Abort(_('default repository not configured!'),
4607 raise error.Abort(_('default repository not configured!'),
4606 hint=_("see 'hg help config.paths'"))
4608 hint=_("see 'hg help config.paths'"))
4607 dest = path.pushloc or path.loc
4609 dest = path.pushloc or path.loc
4608 branches = (path.branch, opts.get('branch') or [])
4610 branches = (path.branch, opts.get('branch') or [])
4609 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4611 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4610 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4612 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4611 other = hg.peer(repo, opts, dest)
4613 other = hg.peer(repo, opts, dest)
4612
4614
4613 if revs:
4615 if revs:
4614 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4616 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4615 if not revs:
4617 if not revs:
4616 raise error.Abort(_("specified revisions evaluate to an empty set"),
4618 raise error.Abort(_("specified revisions evaluate to an empty set"),
4617 hint=_("use different revision arguments"))
4619 hint=_("use different revision arguments"))
4618 elif path.pushrev:
4620 elif path.pushrev:
4619 # It doesn't make any sense to specify ancestor revisions. So limit
4621 # It doesn't make any sense to specify ancestor revisions. So limit
4620 # to DAG heads to make discovery simpler.
4622 # to DAG heads to make discovery simpler.
4621 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4623 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4622 revs = scmutil.revrange(repo, [expr])
4624 revs = scmutil.revrange(repo, [expr])
4623 revs = [repo[rev].node() for rev in revs]
4625 revs = [repo[rev].node() for rev in revs]
4624 if not revs:
4626 if not revs:
4625 raise error.Abort(_('default push revset for path evaluates to an '
4627 raise error.Abort(_('default push revset for path evaluates to an '
4626 'empty set'))
4628 'empty set'))
4627
4629
4628 repo._subtoppath = dest
4630 repo._subtoppath = dest
4629 try:
4631 try:
4630 # push subrepos depth-first for coherent ordering
4632 # push subrepos depth-first for coherent ordering
4631 c = repo['.']
4633 c = repo['.']
4632 subs = c.substate # only repos that are committed
4634 subs = c.substate # only repos that are committed
4633 for s in sorted(subs):
4635 for s in sorted(subs):
4634 result = c.sub(s).push(opts)
4636 result = c.sub(s).push(opts)
4635 if result == 0:
4637 if result == 0:
4636 return not result
4638 return not result
4637 finally:
4639 finally:
4638 del repo._subtoppath
4640 del repo._subtoppath
4639
4641
4640 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4642 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4641 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4643 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4642
4644
4643 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4645 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4644 newbranch=opts.get('new_branch'),
4646 newbranch=opts.get('new_branch'),
4645 bookmarks=opts.get('bookmark', ()),
4647 bookmarks=opts.get('bookmark', ()),
4646 publish=opts.get('publish'),
4648 publish=opts.get('publish'),
4647 opargs=opargs)
4649 opargs=opargs)
4648
4650
4649 result = not pushop.cgresult
4651 result = not pushop.cgresult
4650
4652
4651 if pushop.bkresult is not None:
4653 if pushop.bkresult is not None:
4652 if pushop.bkresult == 2:
4654 if pushop.bkresult == 2:
4653 result = 2
4655 result = 2
4654 elif not result and pushop.bkresult:
4656 elif not result and pushop.bkresult:
4655 result = 2
4657 result = 2
4656
4658
4657 return result
4659 return result
4658
4660
4659 @command('recover',
4661 @command('recover',
4660 [('','verify', True, "run `hg verify` after succesful recover"),
4662 [('','verify', True, "run `hg verify` after succesful recover"),
4661 ],
4663 ],
4662 helpcategory=command.CATEGORY_MAINTENANCE)
4664 helpcategory=command.CATEGORY_MAINTENANCE)
4663 def recover(ui, repo, **opts):
4665 def recover(ui, repo, **opts):
4664 """roll back an interrupted transaction
4666 """roll back an interrupted transaction
4665
4667
4666 Recover from an interrupted commit or pull.
4668 Recover from an interrupted commit or pull.
4667
4669
4668 This command tries to fix the repository status after an
4670 This command tries to fix the repository status after an
4669 interrupted operation. It should only be necessary when Mercurial
4671 interrupted operation. It should only be necessary when Mercurial
4670 suggests it.
4672 suggests it.
4671
4673
4672 Returns 0 if successful, 1 if nothing to recover or verify fails.
4674 Returns 0 if successful, 1 if nothing to recover or verify fails.
4673 """
4675 """
4674 ret = repo.recover()
4676 ret = repo.recover()
4675 if ret:
4677 if ret:
4676 if opts['verify']:
4678 if opts['verify']:
4677 return hg.verify(repo)
4679 return hg.verify(repo)
4678 else:
4680 else:
4679 msg = _("(verify step skipped, run `hg verify` to check your "
4681 msg = _("(verify step skipped, run `hg verify` to check your "
4680 "repository content)\n")
4682 "repository content)\n")
4681 ui.warn(msg)
4683 ui.warn(msg)
4682 return 0
4684 return 0
4683 return 1
4685 return 1
4684
4686
4685 @command('remove|rm',
4687 @command('remove|rm',
4686 [('A', 'after', None, _('record delete for missing files')),
4688 [('A', 'after', None, _('record delete for missing files')),
4687 ('f', 'force', None,
4689 ('f', 'force', None,
4688 _('forget added files, delete modified files')),
4690 _('forget added files, delete modified files')),
4689 ] + subrepoopts + walkopts + dryrunopts,
4691 ] + subrepoopts + walkopts + dryrunopts,
4690 _('[OPTION]... FILE...'),
4692 _('[OPTION]... FILE...'),
4691 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4693 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4692 helpbasic=True, inferrepo=True)
4694 helpbasic=True, inferrepo=True)
4693 def remove(ui, repo, *pats, **opts):
4695 def remove(ui, repo, *pats, **opts):
4694 """remove the specified files on the next commit
4696 """remove the specified files on the next commit
4695
4697
4696 Schedule the indicated files for removal from the current branch.
4698 Schedule the indicated files for removal from the current branch.
4697
4699
4698 This command schedules the files to be removed at the next commit.
4700 This command schedules the files to be removed at the next commit.
4699 To undo a remove before that, see :hg:`revert`. To undo added
4701 To undo a remove before that, see :hg:`revert`. To undo added
4700 files, see :hg:`forget`.
4702 files, see :hg:`forget`.
4701
4703
4702 .. container:: verbose
4704 .. container:: verbose
4703
4705
4704 -A/--after can be used to remove only files that have already
4706 -A/--after can be used to remove only files that have already
4705 been deleted, -f/--force can be used to force deletion, and -Af
4707 been deleted, -f/--force can be used to force deletion, and -Af
4706 can be used to remove files from the next revision without
4708 can be used to remove files from the next revision without
4707 deleting them from the working directory.
4709 deleting them from the working directory.
4708
4710
4709 The following table details the behavior of remove for different
4711 The following table details the behavior of remove for different
4710 file states (columns) and option combinations (rows). The file
4712 file states (columns) and option combinations (rows). The file
4711 states are Added [A], Clean [C], Modified [M] and Missing [!]
4713 states are Added [A], Clean [C], Modified [M] and Missing [!]
4712 (as reported by :hg:`status`). The actions are Warn, Remove
4714 (as reported by :hg:`status`). The actions are Warn, Remove
4713 (from branch) and Delete (from disk):
4715 (from branch) and Delete (from disk):
4714
4716
4715 ========= == == == ==
4717 ========= == == == ==
4716 opt/state A C M !
4718 opt/state A C M !
4717 ========= == == == ==
4719 ========= == == == ==
4718 none W RD W R
4720 none W RD W R
4719 -f R RD RD R
4721 -f R RD RD R
4720 -A W W W R
4722 -A W W W R
4721 -Af R R R R
4723 -Af R R R R
4722 ========= == == == ==
4724 ========= == == == ==
4723
4725
4724 .. note::
4726 .. note::
4725
4727
4726 :hg:`remove` never deletes files in Added [A] state from the
4728 :hg:`remove` never deletes files in Added [A] state from the
4727 working directory, not even if ``--force`` is specified.
4729 working directory, not even if ``--force`` is specified.
4728
4730
4729 Returns 0 on success, 1 if any warnings encountered.
4731 Returns 0 on success, 1 if any warnings encountered.
4730 """
4732 """
4731
4733
4732 opts = pycompat.byteskwargs(opts)
4734 opts = pycompat.byteskwargs(opts)
4733 after, force = opts.get('after'), opts.get('force')
4735 after, force = opts.get('after'), opts.get('force')
4734 dryrun = opts.get('dry_run')
4736 dryrun = opts.get('dry_run')
4735 if not pats and not after:
4737 if not pats and not after:
4736 raise error.Abort(_('no files specified'))
4738 raise error.Abort(_('no files specified'))
4737
4739
4738 m = scmutil.match(repo[None], pats, opts)
4740 m = scmutil.match(repo[None], pats, opts)
4739 subrepos = opts.get('subrepos')
4741 subrepos = opts.get('subrepos')
4740 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
4742 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
4741 return cmdutil.remove(ui, repo, m, "", uipathfn, after, force, subrepos,
4743 return cmdutil.remove(ui, repo, m, "", uipathfn, after, force, subrepos,
4742 dryrun=dryrun)
4744 dryrun=dryrun)
4743
4745
4744 @command('rename|move|mv',
4746 @command('rename|move|mv',
4745 [('A', 'after', None, _('record a rename that has already occurred')),
4747 [('A', 'after', None, _('record a rename that has already occurred')),
4746 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4748 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4747 ] + walkopts + dryrunopts,
4749 ] + walkopts + dryrunopts,
4748 _('[OPTION]... SOURCE... DEST'),
4750 _('[OPTION]... SOURCE... DEST'),
4749 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4751 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4750 def rename(ui, repo, *pats, **opts):
4752 def rename(ui, repo, *pats, **opts):
4751 """rename files; equivalent of copy + remove
4753 """rename files; equivalent of copy + remove
4752
4754
4753 Mark dest as copies of sources; mark sources for deletion. If dest
4755 Mark dest as copies of sources; mark sources for deletion. If dest
4754 is a directory, copies are put in that directory. If dest is a
4756 is a directory, copies are put in that directory. If dest is a
4755 file, there can only be one source.
4757 file, there can only be one source.
4756
4758
4757 By default, this command copies the contents of files as they
4759 By default, this command copies the contents of files as they
4758 exist in the working directory. If invoked with -A/--after, the
4760 exist in the working directory. If invoked with -A/--after, the
4759 operation is recorded, but no copying is performed.
4761 operation is recorded, but no copying is performed.
4760
4762
4761 This command takes effect at the next commit. To undo a rename
4763 This command takes effect at the next commit. To undo a rename
4762 before that, see :hg:`revert`.
4764 before that, see :hg:`revert`.
4763
4765
4764 Returns 0 on success, 1 if errors are encountered.
4766 Returns 0 on success, 1 if errors are encountered.
4765 """
4767 """
4766 opts = pycompat.byteskwargs(opts)
4768 opts = pycompat.byteskwargs(opts)
4767 with repo.wlock(False):
4769 with repo.wlock(False):
4768 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4770 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4769
4771
4770 @command('resolve',
4772 @command('resolve',
4771 [('a', 'all', None, _('select all unresolved files')),
4773 [('a', 'all', None, _('select all unresolved files')),
4772 ('l', 'list', None, _('list state of files needing merge')),
4774 ('l', 'list', None, _('list state of files needing merge')),
4773 ('m', 'mark', None, _('mark files as resolved')),
4775 ('m', 'mark', None, _('mark files as resolved')),
4774 ('u', 'unmark', None, _('mark files as unresolved')),
4776 ('u', 'unmark', None, _('mark files as unresolved')),
4775 ('n', 'no-status', None, _('hide status prefix')),
4777 ('n', 'no-status', None, _('hide status prefix')),
4776 ('', 're-merge', None, _('re-merge files'))]
4778 ('', 're-merge', None, _('re-merge files'))]
4777 + mergetoolopts + walkopts + formatteropts,
4779 + mergetoolopts + walkopts + formatteropts,
4778 _('[OPTION]... [FILE]...'),
4780 _('[OPTION]... [FILE]...'),
4779 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4781 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4780 inferrepo=True)
4782 inferrepo=True)
4781 def resolve(ui, repo, *pats, **opts):
4783 def resolve(ui, repo, *pats, **opts):
4782 """redo merges or set/view the merge status of files
4784 """redo merges or set/view the merge status of files
4783
4785
4784 Merges with unresolved conflicts are often the result of
4786 Merges with unresolved conflicts are often the result of
4785 non-interactive merging using the ``internal:merge`` configuration
4787 non-interactive merging using the ``internal:merge`` configuration
4786 setting, or a command-line merge tool like ``diff3``. The resolve
4788 setting, or a command-line merge tool like ``diff3``. The resolve
4787 command is used to manage the files involved in a merge, after
4789 command is used to manage the files involved in a merge, after
4788 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4790 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4789 working directory must have two parents). See :hg:`help
4791 working directory must have two parents). See :hg:`help
4790 merge-tools` for information on configuring merge tools.
4792 merge-tools` for information on configuring merge tools.
4791
4793
4792 The resolve command can be used in the following ways:
4794 The resolve command can be used in the following ways:
4793
4795
4794 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4796 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4795 the specified files, discarding any previous merge attempts. Re-merging
4797 the specified files, discarding any previous merge attempts. Re-merging
4796 is not performed for files already marked as resolved. Use ``--all/-a``
4798 is not performed for files already marked as resolved. Use ``--all/-a``
4797 to select all unresolved files. ``--tool`` can be used to specify
4799 to select all unresolved files. ``--tool`` can be used to specify
4798 the merge tool used for the given files. It overrides the HGMERGE
4800 the merge tool used for the given files. It overrides the HGMERGE
4799 environment variable and your configuration files. Previous file
4801 environment variable and your configuration files. Previous file
4800 contents are saved with a ``.orig`` suffix.
4802 contents are saved with a ``.orig`` suffix.
4801
4803
4802 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4804 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4803 (e.g. after having manually fixed-up the files). The default is
4805 (e.g. after having manually fixed-up the files). The default is
4804 to mark all unresolved files.
4806 to mark all unresolved files.
4805
4807
4806 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4808 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4807 default is to mark all resolved files.
4809 default is to mark all resolved files.
4808
4810
4809 - :hg:`resolve -l`: list files which had or still have conflicts.
4811 - :hg:`resolve -l`: list files which had or still have conflicts.
4810 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4812 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4811 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4813 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4812 the list. See :hg:`help filesets` for details.
4814 the list. See :hg:`help filesets` for details.
4813
4815
4814 .. note::
4816 .. note::
4815
4817
4816 Mercurial will not let you commit files with unresolved merge
4818 Mercurial will not let you commit files with unresolved merge
4817 conflicts. You must use :hg:`resolve -m ...` before you can
4819 conflicts. You must use :hg:`resolve -m ...` before you can
4818 commit after a conflicting merge.
4820 commit after a conflicting merge.
4819
4821
4820 .. container:: verbose
4822 .. container:: verbose
4821
4823
4822 Template:
4824 Template:
4823
4825
4824 The following keywords are supported in addition to the common template
4826 The following keywords are supported in addition to the common template
4825 keywords and functions. See also :hg:`help templates`.
4827 keywords and functions. See also :hg:`help templates`.
4826
4828
4827 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4829 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4828 :path: String. Repository-absolute path of the file.
4830 :path: String. Repository-absolute path of the file.
4829
4831
4830 Returns 0 on success, 1 if any files fail a resolve attempt.
4832 Returns 0 on success, 1 if any files fail a resolve attempt.
4831 """
4833 """
4832
4834
4833 opts = pycompat.byteskwargs(opts)
4835 opts = pycompat.byteskwargs(opts)
4834 confirm = ui.configbool('commands', 'resolve.confirm')
4836 confirm = ui.configbool('commands', 'resolve.confirm')
4835 flaglist = 'all mark unmark list no_status re_merge'.split()
4837 flaglist = 'all mark unmark list no_status re_merge'.split()
4836 all, mark, unmark, show, nostatus, remerge = [
4838 all, mark, unmark, show, nostatus, remerge = [
4837 opts.get(o) for o in flaglist]
4839 opts.get(o) for o in flaglist]
4838
4840
4839 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4841 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4840 if actioncount > 1:
4842 if actioncount > 1:
4841 raise error.Abort(_("too many actions specified"))
4843 raise error.Abort(_("too many actions specified"))
4842 elif (actioncount == 0
4844 elif (actioncount == 0
4843 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4845 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4844 hint = _('use --mark, --unmark, --list or --re-merge')
4846 hint = _('use --mark, --unmark, --list or --re-merge')
4845 raise error.Abort(_('no action specified'), hint=hint)
4847 raise error.Abort(_('no action specified'), hint=hint)
4846 if pats and all:
4848 if pats and all:
4847 raise error.Abort(_("can't specify --all and patterns"))
4849 raise error.Abort(_("can't specify --all and patterns"))
4848 if not (all or pats or show or mark or unmark):
4850 if not (all or pats or show or mark or unmark):
4849 raise error.Abort(_('no files or directories specified'),
4851 raise error.Abort(_('no files or directories specified'),
4850 hint=('use --all to re-merge all unresolved files'))
4852 hint=('use --all to re-merge all unresolved files'))
4851
4853
4852 if confirm:
4854 if confirm:
4853 if all:
4855 if all:
4854 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4856 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4855 b'$$ &Yes $$ &No')):
4857 b'$$ &Yes $$ &No')):
4856 raise error.Abort(_('user quit'))
4858 raise error.Abort(_('user quit'))
4857 if mark and not pats:
4859 if mark and not pats:
4858 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4860 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4859 b'$$ &Yes $$ &No')):
4861 b'$$ &Yes $$ &No')):
4860 raise error.Abort(_('user quit'))
4862 raise error.Abort(_('user quit'))
4861 if unmark and not pats:
4863 if unmark and not pats:
4862 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4864 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4863 b'$$ &Yes $$ &No')):
4865 b'$$ &Yes $$ &No')):
4864 raise error.Abort(_('user quit'))
4866 raise error.Abort(_('user quit'))
4865
4867
4866 uipathfn = scmutil.getuipathfn(repo)
4868 uipathfn = scmutil.getuipathfn(repo)
4867
4869
4868 if show:
4870 if show:
4869 ui.pager('resolve')
4871 ui.pager('resolve')
4870 fm = ui.formatter('resolve', opts)
4872 fm = ui.formatter('resolve', opts)
4871 ms = mergemod.mergestate.read(repo)
4873 ms = mergemod.mergestate.read(repo)
4872 wctx = repo[None]
4874 wctx = repo[None]
4873 m = scmutil.match(wctx, pats, opts)
4875 m = scmutil.match(wctx, pats, opts)
4874
4876
4875 # Labels and keys based on merge state. Unresolved path conflicts show
4877 # Labels and keys based on merge state. Unresolved path conflicts show
4876 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4878 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4877 # resolved conflicts.
4879 # resolved conflicts.
4878 mergestateinfo = {
4880 mergestateinfo = {
4879 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4881 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4880 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4882 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4881 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4883 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4882 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4884 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4883 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4885 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4884 'D'),
4886 'D'),
4885 }
4887 }
4886
4888
4887 for f in ms:
4889 for f in ms:
4888 if not m(f):
4890 if not m(f):
4889 continue
4891 continue
4890
4892
4891 label, key = mergestateinfo[ms[f]]
4893 label, key = mergestateinfo[ms[f]]
4892 fm.startitem()
4894 fm.startitem()
4893 fm.context(ctx=wctx)
4895 fm.context(ctx=wctx)
4894 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4896 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4895 fm.data(path=f)
4897 fm.data(path=f)
4896 fm.plain('%s\n' % uipathfn(f), label=label)
4898 fm.plain('%s\n' % uipathfn(f), label=label)
4897 fm.end()
4899 fm.end()
4898 return 0
4900 return 0
4899
4901
4900 with repo.wlock():
4902 with repo.wlock():
4901 ms = mergemod.mergestate.read(repo)
4903 ms = mergemod.mergestate.read(repo)
4902
4904
4903 if not (ms.active() or repo.dirstate.p2() != nullid):
4905 if not (ms.active() or repo.dirstate.p2() != nullid):
4904 raise error.Abort(
4906 raise error.Abort(
4905 _('resolve command not applicable when not merging'))
4907 _('resolve command not applicable when not merging'))
4906
4908
4907 wctx = repo[None]
4909 wctx = repo[None]
4908
4910
4909 if (ms.mergedriver
4911 if (ms.mergedriver
4910 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4912 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4911 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4913 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4912 ms.commit()
4914 ms.commit()
4913 # allow mark and unmark to go through
4915 # allow mark and unmark to go through
4914 if not mark and not unmark and not proceed:
4916 if not mark and not unmark and not proceed:
4915 return 1
4917 return 1
4916
4918
4917 m = scmutil.match(wctx, pats, opts)
4919 m = scmutil.match(wctx, pats, opts)
4918 ret = 0
4920 ret = 0
4919 didwork = False
4921 didwork = False
4920 runconclude = False
4922 runconclude = False
4921
4923
4922 tocomplete = []
4924 tocomplete = []
4923 hasconflictmarkers = []
4925 hasconflictmarkers = []
4924 if mark:
4926 if mark:
4925 markcheck = ui.config('commands', 'resolve.mark-check')
4927 markcheck = ui.config('commands', 'resolve.mark-check')
4926 if markcheck not in ['warn', 'abort']:
4928 if markcheck not in ['warn', 'abort']:
4927 # Treat all invalid / unrecognized values as 'none'.
4929 # Treat all invalid / unrecognized values as 'none'.
4928 markcheck = False
4930 markcheck = False
4929 for f in ms:
4931 for f in ms:
4930 if not m(f):
4932 if not m(f):
4931 continue
4933 continue
4932
4934
4933 didwork = True
4935 didwork = True
4934
4936
4935 # don't let driver-resolved files be marked, and run the conclude
4937 # don't let driver-resolved files be marked, and run the conclude
4936 # step if asked to resolve
4938 # step if asked to resolve
4937 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4939 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4938 exact = m.exact(f)
4940 exact = m.exact(f)
4939 if mark:
4941 if mark:
4940 if exact:
4942 if exact:
4941 ui.warn(_('not marking %s as it is driver-resolved\n')
4943 ui.warn(_('not marking %s as it is driver-resolved\n')
4942 % uipathfn(f))
4944 % uipathfn(f))
4943 elif unmark:
4945 elif unmark:
4944 if exact:
4946 if exact:
4945 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4947 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4946 % uipathfn(f))
4948 % uipathfn(f))
4947 else:
4949 else:
4948 runconclude = True
4950 runconclude = True
4949 continue
4951 continue
4950
4952
4951 # path conflicts must be resolved manually
4953 # path conflicts must be resolved manually
4952 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4954 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4953 mergemod.MERGE_RECORD_RESOLVED_PATH):
4955 mergemod.MERGE_RECORD_RESOLVED_PATH):
4954 if mark:
4956 if mark:
4955 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4957 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4956 elif unmark:
4958 elif unmark:
4957 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4959 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4958 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4960 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4959 ui.warn(_('%s: path conflict must be resolved manually\n')
4961 ui.warn(_('%s: path conflict must be resolved manually\n')
4960 % uipathfn(f))
4962 % uipathfn(f))
4961 continue
4963 continue
4962
4964
4963 if mark:
4965 if mark:
4964 if markcheck:
4966 if markcheck:
4965 fdata = repo.wvfs.tryread(f)
4967 fdata = repo.wvfs.tryread(f)
4966 if (filemerge.hasconflictmarkers(fdata) and
4968 if (filemerge.hasconflictmarkers(fdata) and
4967 ms[f] != mergemod.MERGE_RECORD_RESOLVED):
4969 ms[f] != mergemod.MERGE_RECORD_RESOLVED):
4968 hasconflictmarkers.append(f)
4970 hasconflictmarkers.append(f)
4969 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4971 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4970 elif unmark:
4972 elif unmark:
4971 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4973 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4972 else:
4974 else:
4973 # backup pre-resolve (merge uses .orig for its own purposes)
4975 # backup pre-resolve (merge uses .orig for its own purposes)
4974 a = repo.wjoin(f)
4976 a = repo.wjoin(f)
4975 try:
4977 try:
4976 util.copyfile(a, a + ".resolve")
4978 util.copyfile(a, a + ".resolve")
4977 except (IOError, OSError) as inst:
4979 except (IOError, OSError) as inst:
4978 if inst.errno != errno.ENOENT:
4980 if inst.errno != errno.ENOENT:
4979 raise
4981 raise
4980
4982
4981 try:
4983 try:
4982 # preresolve file
4984 # preresolve file
4983 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4985 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4984 with ui.configoverride(overrides, 'resolve'):
4986 with ui.configoverride(overrides, 'resolve'):
4985 complete, r = ms.preresolve(f, wctx)
4987 complete, r = ms.preresolve(f, wctx)
4986 if not complete:
4988 if not complete:
4987 tocomplete.append(f)
4989 tocomplete.append(f)
4988 elif r:
4990 elif r:
4989 ret = 1
4991 ret = 1
4990 finally:
4992 finally:
4991 ms.commit()
4993 ms.commit()
4992
4994
4993 # replace filemerge's .orig file with our resolve file, but only
4995 # replace filemerge's .orig file with our resolve file, but only
4994 # for merges that are complete
4996 # for merges that are complete
4995 if complete:
4997 if complete:
4996 try:
4998 try:
4997 util.rename(a + ".resolve",
4999 util.rename(a + ".resolve",
4998 scmutil.backuppath(ui, repo, f))
5000 scmutil.backuppath(ui, repo, f))
4999 except OSError as inst:
5001 except OSError as inst:
5000 if inst.errno != errno.ENOENT:
5002 if inst.errno != errno.ENOENT:
5001 raise
5003 raise
5002
5004
5003 if hasconflictmarkers:
5005 if hasconflictmarkers:
5004 ui.warn(_('warning: the following files still have conflict '
5006 ui.warn(_('warning: the following files still have conflict '
5005 'markers:\n') + ''.join(' ' + uipathfn(f) + '\n'
5007 'markers:\n') + ''.join(' ' + uipathfn(f) + '\n'
5006 for f in hasconflictmarkers))
5008 for f in hasconflictmarkers))
5007 if markcheck == 'abort' and not all and not pats:
5009 if markcheck == 'abort' and not all and not pats:
5008 raise error.Abort(_('conflict markers detected'),
5010 raise error.Abort(_('conflict markers detected'),
5009 hint=_('use --all to mark anyway'))
5011 hint=_('use --all to mark anyway'))
5010
5012
5011 for f in tocomplete:
5013 for f in tocomplete:
5012 try:
5014 try:
5013 # resolve file
5015 # resolve file
5014 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
5016 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
5015 with ui.configoverride(overrides, 'resolve'):
5017 with ui.configoverride(overrides, 'resolve'):
5016 r = ms.resolve(f, wctx)
5018 r = ms.resolve(f, wctx)
5017 if r:
5019 if r:
5018 ret = 1
5020 ret = 1
5019 finally:
5021 finally:
5020 ms.commit()
5022 ms.commit()
5021
5023
5022 # replace filemerge's .orig file with our resolve file
5024 # replace filemerge's .orig file with our resolve file
5023 a = repo.wjoin(f)
5025 a = repo.wjoin(f)
5024 try:
5026 try:
5025 util.rename(a + ".resolve", scmutil.backuppath(ui, repo, f))
5027 util.rename(a + ".resolve", scmutil.backuppath(ui, repo, f))
5026 except OSError as inst:
5028 except OSError as inst:
5027 if inst.errno != errno.ENOENT:
5029 if inst.errno != errno.ENOENT:
5028 raise
5030 raise
5029
5031
5030 ms.commit()
5032 ms.commit()
5031 ms.recordactions()
5033 ms.recordactions()
5032
5034
5033 if not didwork and pats:
5035 if not didwork and pats:
5034 hint = None
5036 hint = None
5035 if not any([p for p in pats if p.find(':') >= 0]):
5037 if not any([p for p in pats if p.find(':') >= 0]):
5036 pats = ['path:%s' % p for p in pats]
5038 pats = ['path:%s' % p for p in pats]
5037 m = scmutil.match(wctx, pats, opts)
5039 m = scmutil.match(wctx, pats, opts)
5038 for f in ms:
5040 for f in ms:
5039 if not m(f):
5041 if not m(f):
5040 continue
5042 continue
5041 def flag(o):
5043 def flag(o):
5042 if o == 're_merge':
5044 if o == 're_merge':
5043 return '--re-merge '
5045 return '--re-merge '
5044 return '-%s ' % o[0:1]
5046 return '-%s ' % o[0:1]
5045 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
5047 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
5046 hint = _("(try: hg resolve %s%s)\n") % (
5048 hint = _("(try: hg resolve %s%s)\n") % (
5047 flags,
5049 flags,
5048 ' '.join(pats))
5050 ' '.join(pats))
5049 break
5051 break
5050 ui.warn(_("arguments do not match paths that need resolving\n"))
5052 ui.warn(_("arguments do not match paths that need resolving\n"))
5051 if hint:
5053 if hint:
5052 ui.warn(hint)
5054 ui.warn(hint)
5053 elif ms.mergedriver and ms.mdstate() != 's':
5055 elif ms.mergedriver and ms.mdstate() != 's':
5054 # run conclude step when either a driver-resolved file is requested
5056 # run conclude step when either a driver-resolved file is requested
5055 # or there are no driver-resolved files
5057 # or there are no driver-resolved files
5056 # we can't use 'ret' to determine whether any files are unresolved
5058 # we can't use 'ret' to determine whether any files are unresolved
5057 # because we might not have tried to resolve some
5059 # because we might not have tried to resolve some
5058 if ((runconclude or not list(ms.driverresolved()))
5060 if ((runconclude or not list(ms.driverresolved()))
5059 and not list(ms.unresolved())):
5061 and not list(ms.unresolved())):
5060 proceed = mergemod.driverconclude(repo, ms, wctx)
5062 proceed = mergemod.driverconclude(repo, ms, wctx)
5061 ms.commit()
5063 ms.commit()
5062 if not proceed:
5064 if not proceed:
5063 return 1
5065 return 1
5064
5066
5065 # Nudge users into finishing an unfinished operation
5067 # Nudge users into finishing an unfinished operation
5066 unresolvedf = list(ms.unresolved())
5068 unresolvedf = list(ms.unresolved())
5067 driverresolvedf = list(ms.driverresolved())
5069 driverresolvedf = list(ms.driverresolved())
5068 if not unresolvedf and not driverresolvedf:
5070 if not unresolvedf and not driverresolvedf:
5069 ui.status(_('(no more unresolved files)\n'))
5071 ui.status(_('(no more unresolved files)\n'))
5070 cmdutil.checkafterresolved(repo)
5072 cmdutil.checkafterresolved(repo)
5071 elif not unresolvedf:
5073 elif not unresolvedf:
5072 ui.status(_('(no more unresolved files -- '
5074 ui.status(_('(no more unresolved files -- '
5073 'run "hg resolve --all" to conclude)\n'))
5075 'run "hg resolve --all" to conclude)\n'))
5074
5076
5075 return ret
5077 return ret
5076
5078
5077 @command('revert',
5079 @command('revert',
5078 [('a', 'all', None, _('revert all changes when no arguments given')),
5080 [('a', 'all', None, _('revert all changes when no arguments given')),
5079 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5081 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5080 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5082 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5081 ('C', 'no-backup', None, _('do not save backup copies of files')),
5083 ('C', 'no-backup', None, _('do not save backup copies of files')),
5082 ('i', 'interactive', None, _('interactively select the changes')),
5084 ('i', 'interactive', None, _('interactively select the changes')),
5083 ] + walkopts + dryrunopts,
5085 ] + walkopts + dryrunopts,
5084 _('[OPTION]... [-r REV] [NAME]...'),
5086 _('[OPTION]... [-r REV] [NAME]...'),
5085 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5087 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5086 def revert(ui, repo, *pats, **opts):
5088 def revert(ui, repo, *pats, **opts):
5087 """restore files to their checkout state
5089 """restore files to their checkout state
5088
5090
5089 .. note::
5091 .. note::
5090
5092
5091 To check out earlier revisions, you should use :hg:`update REV`.
5093 To check out earlier revisions, you should use :hg:`update REV`.
5092 To cancel an uncommitted merge (and lose your changes),
5094 To cancel an uncommitted merge (and lose your changes),
5093 use :hg:`merge --abort`.
5095 use :hg:`merge --abort`.
5094
5096
5095 With no revision specified, revert the specified files or directories
5097 With no revision specified, revert the specified files or directories
5096 to the contents they had in the parent of the working directory.
5098 to the contents they had in the parent of the working directory.
5097 This restores the contents of files to an unmodified
5099 This restores the contents of files to an unmodified
5098 state and unschedules adds, removes, copies, and renames. If the
5100 state and unschedules adds, removes, copies, and renames. If the
5099 working directory has two parents, you must explicitly specify a
5101 working directory has two parents, you must explicitly specify a
5100 revision.
5102 revision.
5101
5103
5102 Using the -r/--rev or -d/--date options, revert the given files or
5104 Using the -r/--rev or -d/--date options, revert the given files or
5103 directories to their states as of a specific revision. Because
5105 directories to their states as of a specific revision. Because
5104 revert does not change the working directory parents, this will
5106 revert does not change the working directory parents, this will
5105 cause these files to appear modified. This can be helpful to "back
5107 cause these files to appear modified. This can be helpful to "back
5106 out" some or all of an earlier change. See :hg:`backout` for a
5108 out" some or all of an earlier change. See :hg:`backout` for a
5107 related method.
5109 related method.
5108
5110
5109 Modified files are saved with a .orig suffix before reverting.
5111 Modified files are saved with a .orig suffix before reverting.
5110 To disable these backups, use --no-backup. It is possible to store
5112 To disable these backups, use --no-backup. It is possible to store
5111 the backup files in a custom directory relative to the root of the
5113 the backup files in a custom directory relative to the root of the
5112 repository by setting the ``ui.origbackuppath`` configuration
5114 repository by setting the ``ui.origbackuppath`` configuration
5113 option.
5115 option.
5114
5116
5115 See :hg:`help dates` for a list of formats valid for -d/--date.
5117 See :hg:`help dates` for a list of formats valid for -d/--date.
5116
5118
5117 See :hg:`help backout` for a way to reverse the effect of an
5119 See :hg:`help backout` for a way to reverse the effect of an
5118 earlier changeset.
5120 earlier changeset.
5119
5121
5120 Returns 0 on success.
5122 Returns 0 on success.
5121 """
5123 """
5122
5124
5123 opts = pycompat.byteskwargs(opts)
5125 opts = pycompat.byteskwargs(opts)
5124 if opts.get("date"):
5126 if opts.get("date"):
5125 if opts.get("rev"):
5127 if opts.get("rev"):
5126 raise error.Abort(_("you can't specify a revision and a date"))
5128 raise error.Abort(_("you can't specify a revision and a date"))
5127 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5129 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5128
5130
5129 parent, p2 = repo.dirstate.parents()
5131 parent, p2 = repo.dirstate.parents()
5130 if not opts.get('rev') and p2 != nullid:
5132 if not opts.get('rev') and p2 != nullid:
5131 # revert after merge is a trap for new users (issue2915)
5133 # revert after merge is a trap for new users (issue2915)
5132 raise error.Abort(_('uncommitted merge with no revision specified'),
5134 raise error.Abort(_('uncommitted merge with no revision specified'),
5133 hint=_("use 'hg update' or see 'hg help revert'"))
5135 hint=_("use 'hg update' or see 'hg help revert'"))
5134
5136
5135 rev = opts.get('rev')
5137 rev = opts.get('rev')
5136 if rev:
5138 if rev:
5137 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5139 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5138 ctx = scmutil.revsingle(repo, rev)
5140 ctx = scmutil.revsingle(repo, rev)
5139
5141
5140 if (not (pats or opts.get('include') or opts.get('exclude') or
5142 if (not (pats or opts.get('include') or opts.get('exclude') or
5141 opts.get('all') or opts.get('interactive'))):
5143 opts.get('all') or opts.get('interactive'))):
5142 msg = _("no files or directories specified")
5144 msg = _("no files or directories specified")
5143 if p2 != nullid:
5145 if p2 != nullid:
5144 hint = _("uncommitted merge, use --all to discard all changes,"
5146 hint = _("uncommitted merge, use --all to discard all changes,"
5145 " or 'hg update -C .' to abort the merge")
5147 " or 'hg update -C .' to abort the merge")
5146 raise error.Abort(msg, hint=hint)
5148 raise error.Abort(msg, hint=hint)
5147 dirty = any(repo.status())
5149 dirty = any(repo.status())
5148 node = ctx.node()
5150 node = ctx.node()
5149 if node != parent:
5151 if node != parent:
5150 if dirty:
5152 if dirty:
5151 hint = _("uncommitted changes, use --all to discard all"
5153 hint = _("uncommitted changes, use --all to discard all"
5152 " changes, or 'hg update %d' to update") % ctx.rev()
5154 " changes, or 'hg update %d' to update") % ctx.rev()
5153 else:
5155 else:
5154 hint = _("use --all to revert all files,"
5156 hint = _("use --all to revert all files,"
5155 " or 'hg update %d' to update") % ctx.rev()
5157 " or 'hg update %d' to update") % ctx.rev()
5156 elif dirty:
5158 elif dirty:
5157 hint = _("uncommitted changes, use --all to discard all changes")
5159 hint = _("uncommitted changes, use --all to discard all changes")
5158 else:
5160 else:
5159 hint = _("use --all to revert all files")
5161 hint = _("use --all to revert all files")
5160 raise error.Abort(msg, hint=hint)
5162 raise error.Abort(msg, hint=hint)
5161
5163
5162 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5164 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5163 **pycompat.strkwargs(opts))
5165 **pycompat.strkwargs(opts))
5164
5166
5165 @command(
5167 @command(
5166 'rollback',
5168 'rollback',
5167 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5169 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5168 helpcategory=command.CATEGORY_MAINTENANCE)
5170 helpcategory=command.CATEGORY_MAINTENANCE)
5169 def rollback(ui, repo, **opts):
5171 def rollback(ui, repo, **opts):
5170 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5172 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5171
5173
5172 Please use :hg:`commit --amend` instead of rollback to correct
5174 Please use :hg:`commit --amend` instead of rollback to correct
5173 mistakes in the last commit.
5175 mistakes in the last commit.
5174
5176
5175 This command should be used with care. There is only one level of
5177 This command should be used with care. There is only one level of
5176 rollback, and there is no way to undo a rollback. It will also
5178 rollback, and there is no way to undo a rollback. It will also
5177 restore the dirstate at the time of the last transaction, losing
5179 restore the dirstate at the time of the last transaction, losing
5178 any dirstate changes since that time. This command does not alter
5180 any dirstate changes since that time. This command does not alter
5179 the working directory.
5181 the working directory.
5180
5182
5181 Transactions are used to encapsulate the effects of all commands
5183 Transactions are used to encapsulate the effects of all commands
5182 that create new changesets or propagate existing changesets into a
5184 that create new changesets or propagate existing changesets into a
5183 repository.
5185 repository.
5184
5186
5185 .. container:: verbose
5187 .. container:: verbose
5186
5188
5187 For example, the following commands are transactional, and their
5189 For example, the following commands are transactional, and their
5188 effects can be rolled back:
5190 effects can be rolled back:
5189
5191
5190 - commit
5192 - commit
5191 - import
5193 - import
5192 - pull
5194 - pull
5193 - push (with this repository as the destination)
5195 - push (with this repository as the destination)
5194 - unbundle
5196 - unbundle
5195
5197
5196 To avoid permanent data loss, rollback will refuse to rollback a
5198 To avoid permanent data loss, rollback will refuse to rollback a
5197 commit transaction if it isn't checked out. Use --force to
5199 commit transaction if it isn't checked out. Use --force to
5198 override this protection.
5200 override this protection.
5199
5201
5200 The rollback command can be entirely disabled by setting the
5202 The rollback command can be entirely disabled by setting the
5201 ``ui.rollback`` configuration setting to false. If you're here
5203 ``ui.rollback`` configuration setting to false. If you're here
5202 because you want to use rollback and it's disabled, you can
5204 because you want to use rollback and it's disabled, you can
5203 re-enable the command by setting ``ui.rollback`` to true.
5205 re-enable the command by setting ``ui.rollback`` to true.
5204
5206
5205 This command is not intended for use on public repositories. Once
5207 This command is not intended for use on public repositories. Once
5206 changes are visible for pull by other users, rolling a transaction
5208 changes are visible for pull by other users, rolling a transaction
5207 back locally is ineffective (someone else may already have pulled
5209 back locally is ineffective (someone else may already have pulled
5208 the changes). Furthermore, a race is possible with readers of the
5210 the changes). Furthermore, a race is possible with readers of the
5209 repository; for example an in-progress pull from the repository
5211 repository; for example an in-progress pull from the repository
5210 may fail if a rollback is performed.
5212 may fail if a rollback is performed.
5211
5213
5212 Returns 0 on success, 1 if no rollback data is available.
5214 Returns 0 on success, 1 if no rollback data is available.
5213 """
5215 """
5214 if not ui.configbool('ui', 'rollback'):
5216 if not ui.configbool('ui', 'rollback'):
5215 raise error.Abort(_('rollback is disabled because it is unsafe'),
5217 raise error.Abort(_('rollback is disabled because it is unsafe'),
5216 hint=('see `hg help -v rollback` for information'))
5218 hint=('see `hg help -v rollback` for information'))
5217 return repo.rollback(dryrun=opts.get(r'dry_run'),
5219 return repo.rollback(dryrun=opts.get(r'dry_run'),
5218 force=opts.get(r'force'))
5220 force=opts.get(r'force'))
5219
5221
5220 @command(
5222 @command(
5221 'root', [], intents={INTENT_READONLY},
5223 'root', [], intents={INTENT_READONLY},
5222 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5224 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5223 def root(ui, repo):
5225 def root(ui, repo):
5224 """print the root (top) of the current working directory
5226 """print the root (top) of the current working directory
5225
5227
5226 Print the root directory of the current repository.
5228 Print the root directory of the current repository.
5227
5229
5228 Returns 0 on success.
5230 Returns 0 on success.
5229 """
5231 """
5230 ui.write(repo.root + "\n")
5232 ui.write(repo.root + "\n")
5231
5233
5232 @command('serve',
5234 @command('serve',
5233 [('A', 'accesslog', '', _('name of access log file to write to'),
5235 [('A', 'accesslog', '', _('name of access log file to write to'),
5234 _('FILE')),
5236 _('FILE')),
5235 ('d', 'daemon', None, _('run server in background')),
5237 ('d', 'daemon', None, _('run server in background')),
5236 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5238 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5237 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5239 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5238 # use string type, then we can check if something was passed
5240 # use string type, then we can check if something was passed
5239 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5241 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5240 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5242 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5241 _('ADDR')),
5243 _('ADDR')),
5242 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5244 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5243 _('PREFIX')),
5245 _('PREFIX')),
5244 ('n', 'name', '',
5246 ('n', 'name', '',
5245 _('name to show in web pages (default: working directory)'), _('NAME')),
5247 _('name to show in web pages (default: working directory)'), _('NAME')),
5246 ('', 'web-conf', '',
5248 ('', 'web-conf', '',
5247 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5249 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5248 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5250 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5249 _('FILE')),
5251 _('FILE')),
5250 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5252 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5251 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5253 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5252 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5254 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5253 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5255 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5254 ('', 'style', '', _('template style to use'), _('STYLE')),
5256 ('', 'style', '', _('template style to use'), _('STYLE')),
5255 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5257 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5256 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5258 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5257 ('', 'print-url', None, _('start and print only the URL'))]
5259 ('', 'print-url', None, _('start and print only the URL'))]
5258 + subrepoopts,
5260 + subrepoopts,
5259 _('[OPTION]...'),
5261 _('[OPTION]...'),
5260 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5262 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5261 helpbasic=True, optionalrepo=True)
5263 helpbasic=True, optionalrepo=True)
5262 def serve(ui, repo, **opts):
5264 def serve(ui, repo, **opts):
5263 """start stand-alone webserver
5265 """start stand-alone webserver
5264
5266
5265 Start a local HTTP repository browser and pull server. You can use
5267 Start a local HTTP repository browser and pull server. You can use
5266 this for ad-hoc sharing and browsing of repositories. It is
5268 this for ad-hoc sharing and browsing of repositories. It is
5267 recommended to use a real web server to serve a repository for
5269 recommended to use a real web server to serve a repository for
5268 longer periods of time.
5270 longer periods of time.
5269
5271
5270 Please note that the server does not implement access control.
5272 Please note that the server does not implement access control.
5271 This means that, by default, anybody can read from the server and
5273 This means that, by default, anybody can read from the server and
5272 nobody can write to it by default. Set the ``web.allow-push``
5274 nobody can write to it by default. Set the ``web.allow-push``
5273 option to ``*`` to allow everybody to push to the server. You
5275 option to ``*`` to allow everybody to push to the server. You
5274 should use a real web server if you need to authenticate users.
5276 should use a real web server if you need to authenticate users.
5275
5277
5276 By default, the server logs accesses to stdout and errors to
5278 By default, the server logs accesses to stdout and errors to
5277 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5279 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5278 files.
5280 files.
5279
5281
5280 To have the server choose a free port number to listen on, specify
5282 To have the server choose a free port number to listen on, specify
5281 a port number of 0; in this case, the server will print the port
5283 a port number of 0; in this case, the server will print the port
5282 number it uses.
5284 number it uses.
5283
5285
5284 Returns 0 on success.
5286 Returns 0 on success.
5285 """
5287 """
5286
5288
5287 opts = pycompat.byteskwargs(opts)
5289 opts = pycompat.byteskwargs(opts)
5288 if opts["stdio"] and opts["cmdserver"]:
5290 if opts["stdio"] and opts["cmdserver"]:
5289 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5291 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5290 if opts["print_url"] and ui.verbose:
5292 if opts["print_url"] and ui.verbose:
5291 raise error.Abort(_("cannot use --print-url with --verbose"))
5293 raise error.Abort(_("cannot use --print-url with --verbose"))
5292
5294
5293 if opts["stdio"]:
5295 if opts["stdio"]:
5294 if repo is None:
5296 if repo is None:
5295 raise error.RepoError(_("there is no Mercurial repository here"
5297 raise error.RepoError(_("there is no Mercurial repository here"
5296 " (.hg not found)"))
5298 " (.hg not found)"))
5297 s = wireprotoserver.sshserver(ui, repo)
5299 s = wireprotoserver.sshserver(ui, repo)
5298 s.serve_forever()
5300 s.serve_forever()
5299
5301
5300 service = server.createservice(ui, repo, opts)
5302 service = server.createservice(ui, repo, opts)
5301 return server.runservice(opts, initfn=service.init, runfn=service.run)
5303 return server.runservice(opts, initfn=service.init, runfn=service.run)
5302
5304
5303 _NOTTERSE = 'nothing'
5305 _NOTTERSE = 'nothing'
5304
5306
5305 @command('status|st',
5307 @command('status|st',
5306 [('A', 'all', None, _('show status of all files')),
5308 [('A', 'all', None, _('show status of all files')),
5307 ('m', 'modified', None, _('show only modified files')),
5309 ('m', 'modified', None, _('show only modified files')),
5308 ('a', 'added', None, _('show only added files')),
5310 ('a', 'added', None, _('show only added files')),
5309 ('r', 'removed', None, _('show only removed files')),
5311 ('r', 'removed', None, _('show only removed files')),
5310 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5312 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5311 ('c', 'clean', None, _('show only files without changes')),
5313 ('c', 'clean', None, _('show only files without changes')),
5312 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5314 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5313 ('i', 'ignored', None, _('show only ignored files')),
5315 ('i', 'ignored', None, _('show only ignored files')),
5314 ('n', 'no-status', None, _('hide status prefix')),
5316 ('n', 'no-status', None, _('hide status prefix')),
5315 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5317 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5316 ('C', 'copies', None, _('show source of copied files')),
5318 ('C', 'copies', None, _('show source of copied files')),
5317 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5319 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5318 ('', 'rev', [], _('show difference from revision'), _('REV')),
5320 ('', 'rev', [], _('show difference from revision'), _('REV')),
5319 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5321 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5320 ] + walkopts + subrepoopts + formatteropts,
5322 ] + walkopts + subrepoopts + formatteropts,
5321 _('[OPTION]... [FILE]...'),
5323 _('[OPTION]... [FILE]...'),
5322 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5324 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5323 helpbasic=True, inferrepo=True,
5325 helpbasic=True, inferrepo=True,
5324 intents={INTENT_READONLY})
5326 intents={INTENT_READONLY})
5325 def status(ui, repo, *pats, **opts):
5327 def status(ui, repo, *pats, **opts):
5326 """show changed files in the working directory
5328 """show changed files in the working directory
5327
5329
5328 Show status of files in the repository. If names are given, only
5330 Show status of files in the repository. If names are given, only
5329 files that match are shown. Files that are clean or ignored or
5331 files that match are shown. Files that are clean or ignored or
5330 the source of a copy/move operation, are not listed unless
5332 the source of a copy/move operation, are not listed unless
5331 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5333 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5332 Unless options described with "show only ..." are given, the
5334 Unless options described with "show only ..." are given, the
5333 options -mardu are used.
5335 options -mardu are used.
5334
5336
5335 Option -q/--quiet hides untracked (unknown and ignored) files
5337 Option -q/--quiet hides untracked (unknown and ignored) files
5336 unless explicitly requested with -u/--unknown or -i/--ignored.
5338 unless explicitly requested with -u/--unknown or -i/--ignored.
5337
5339
5338 .. note::
5340 .. note::
5339
5341
5340 :hg:`status` may appear to disagree with diff if permissions have
5342 :hg:`status` may appear to disagree with diff if permissions have
5341 changed or a merge has occurred. The standard diff format does
5343 changed or a merge has occurred. The standard diff format does
5342 not report permission changes and diff only reports changes
5344 not report permission changes and diff only reports changes
5343 relative to one merge parent.
5345 relative to one merge parent.
5344
5346
5345 If one revision is given, it is used as the base revision.
5347 If one revision is given, it is used as the base revision.
5346 If two revisions are given, the differences between them are
5348 If two revisions are given, the differences between them are
5347 shown. The --change option can also be used as a shortcut to list
5349 shown. The --change option can also be used as a shortcut to list
5348 the changed files of a revision from its first parent.
5350 the changed files of a revision from its first parent.
5349
5351
5350 The codes used to show the status of files are::
5352 The codes used to show the status of files are::
5351
5353
5352 M = modified
5354 M = modified
5353 A = added
5355 A = added
5354 R = removed
5356 R = removed
5355 C = clean
5357 C = clean
5356 ! = missing (deleted by non-hg command, but still tracked)
5358 ! = missing (deleted by non-hg command, but still tracked)
5357 ? = not tracked
5359 ? = not tracked
5358 I = ignored
5360 I = ignored
5359 = origin of the previous file (with --copies)
5361 = origin of the previous file (with --copies)
5360
5362
5361 .. container:: verbose
5363 .. container:: verbose
5362
5364
5363 The -t/--terse option abbreviates the output by showing only the directory
5365 The -t/--terse option abbreviates the output by showing only the directory
5364 name if all the files in it share the same status. The option takes an
5366 name if all the files in it share the same status. The option takes an
5365 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5367 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5366 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5368 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5367 for 'ignored' and 'c' for clean.
5369 for 'ignored' and 'c' for clean.
5368
5370
5369 It abbreviates only those statuses which are passed. Note that clean and
5371 It abbreviates only those statuses which are passed. Note that clean and
5370 ignored files are not displayed with '--terse ic' unless the -c/--clean
5372 ignored files are not displayed with '--terse ic' unless the -c/--clean
5371 and -i/--ignored options are also used.
5373 and -i/--ignored options are also used.
5372
5374
5373 The -v/--verbose option shows information when the repository is in an
5375 The -v/--verbose option shows information when the repository is in an
5374 unfinished merge, shelve, rebase state etc. You can have this behavior
5376 unfinished merge, shelve, rebase state etc. You can have this behavior
5375 turned on by default by enabling the ``commands.status.verbose`` option.
5377 turned on by default by enabling the ``commands.status.verbose`` option.
5376
5378
5377 You can skip displaying some of these states by setting
5379 You can skip displaying some of these states by setting
5378 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5380 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5379 'histedit', 'merge', 'rebase', or 'unshelve'.
5381 'histedit', 'merge', 'rebase', or 'unshelve'.
5380
5382
5381 Template:
5383 Template:
5382
5384
5383 The following keywords are supported in addition to the common template
5385 The following keywords are supported in addition to the common template
5384 keywords and functions. See also :hg:`help templates`.
5386 keywords and functions. See also :hg:`help templates`.
5385
5387
5386 :path: String. Repository-absolute path of the file.
5388 :path: String. Repository-absolute path of the file.
5387 :source: String. Repository-absolute path of the file originated from.
5389 :source: String. Repository-absolute path of the file originated from.
5388 Available if ``--copies`` is specified.
5390 Available if ``--copies`` is specified.
5389 :status: String. Character denoting file's status.
5391 :status: String. Character denoting file's status.
5390
5392
5391 Examples:
5393 Examples:
5392
5394
5393 - show changes in the working directory relative to a
5395 - show changes in the working directory relative to a
5394 changeset::
5396 changeset::
5395
5397
5396 hg status --rev 9353
5398 hg status --rev 9353
5397
5399
5398 - show changes in the working directory relative to the
5400 - show changes in the working directory relative to the
5399 current directory (see :hg:`help patterns` for more information)::
5401 current directory (see :hg:`help patterns` for more information)::
5400
5402
5401 hg status re:
5403 hg status re:
5402
5404
5403 - show all changes including copies in an existing changeset::
5405 - show all changes including copies in an existing changeset::
5404
5406
5405 hg status --copies --change 9353
5407 hg status --copies --change 9353
5406
5408
5407 - get a NUL separated list of added files, suitable for xargs::
5409 - get a NUL separated list of added files, suitable for xargs::
5408
5410
5409 hg status -an0
5411 hg status -an0
5410
5412
5411 - show more information about the repository status, abbreviating
5413 - show more information about the repository status, abbreviating
5412 added, removed, modified, deleted, and untracked paths::
5414 added, removed, modified, deleted, and untracked paths::
5413
5415
5414 hg status -v -t mardu
5416 hg status -v -t mardu
5415
5417
5416 Returns 0 on success.
5418 Returns 0 on success.
5417
5419
5418 """
5420 """
5419
5421
5420 opts = pycompat.byteskwargs(opts)
5422 opts = pycompat.byteskwargs(opts)
5421 revs = opts.get('rev')
5423 revs = opts.get('rev')
5422 change = opts.get('change')
5424 change = opts.get('change')
5423 terse = opts.get('terse')
5425 terse = opts.get('terse')
5424 if terse is _NOTTERSE:
5426 if terse is _NOTTERSE:
5425 if revs:
5427 if revs:
5426 terse = ''
5428 terse = ''
5427 else:
5429 else:
5428 terse = ui.config('commands', 'status.terse')
5430 terse = ui.config('commands', 'status.terse')
5429
5431
5430 if revs and change:
5432 if revs and change:
5431 msg = _('cannot specify --rev and --change at the same time')
5433 msg = _('cannot specify --rev and --change at the same time')
5432 raise error.Abort(msg)
5434 raise error.Abort(msg)
5433 elif revs and terse:
5435 elif revs and terse:
5434 msg = _('cannot use --terse with --rev')
5436 msg = _('cannot use --terse with --rev')
5435 raise error.Abort(msg)
5437 raise error.Abort(msg)
5436 elif change:
5438 elif change:
5437 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5439 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5438 ctx2 = scmutil.revsingle(repo, change, None)
5440 ctx2 = scmutil.revsingle(repo, change, None)
5439 ctx1 = ctx2.p1()
5441 ctx1 = ctx2.p1()
5440 else:
5442 else:
5441 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5443 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5442 ctx1, ctx2 = scmutil.revpair(repo, revs)
5444 ctx1, ctx2 = scmutil.revpair(repo, revs)
5443
5445
5444 forcerelativevalue = None
5446 forcerelativevalue = None
5445 if ui.hasconfig('commands', 'status.relative'):
5447 if ui.hasconfig('commands', 'status.relative'):
5446 forcerelativevalue = ui.configbool('commands', 'status.relative')
5448 forcerelativevalue = ui.configbool('commands', 'status.relative')
5447 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats),
5449 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats),
5448 forcerelativevalue=forcerelativevalue)
5450 forcerelativevalue=forcerelativevalue)
5449
5451
5450 if opts.get('print0'):
5452 if opts.get('print0'):
5451 end = '\0'
5453 end = '\0'
5452 else:
5454 else:
5453 end = '\n'
5455 end = '\n'
5454 copy = {}
5456 copy = {}
5455 states = 'modified added removed deleted unknown ignored clean'.split()
5457 states = 'modified added removed deleted unknown ignored clean'.split()
5456 show = [k for k in states if opts.get(k)]
5458 show = [k for k in states if opts.get(k)]
5457 if opts.get('all'):
5459 if opts.get('all'):
5458 show += ui.quiet and (states[:4] + ['clean']) or states
5460 show += ui.quiet and (states[:4] + ['clean']) or states
5459
5461
5460 if not show:
5462 if not show:
5461 if ui.quiet:
5463 if ui.quiet:
5462 show = states[:4]
5464 show = states[:4]
5463 else:
5465 else:
5464 show = states[:5]
5466 show = states[:5]
5465
5467
5466 m = scmutil.match(ctx2, pats, opts)
5468 m = scmutil.match(ctx2, pats, opts)
5467 if terse:
5469 if terse:
5468 # we need to compute clean and unknown to terse
5470 # we need to compute clean and unknown to terse
5469 stat = repo.status(ctx1.node(), ctx2.node(), m,
5471 stat = repo.status(ctx1.node(), ctx2.node(), m,
5470 'ignored' in show or 'i' in terse,
5472 'ignored' in show or 'i' in terse,
5471 clean=True, unknown=True,
5473 clean=True, unknown=True,
5472 listsubrepos=opts.get('subrepos'))
5474 listsubrepos=opts.get('subrepos'))
5473
5475
5474 stat = cmdutil.tersedir(stat, terse)
5476 stat = cmdutil.tersedir(stat, terse)
5475 else:
5477 else:
5476 stat = repo.status(ctx1.node(), ctx2.node(), m,
5478 stat = repo.status(ctx1.node(), ctx2.node(), m,
5477 'ignored' in show, 'clean' in show,
5479 'ignored' in show, 'clean' in show,
5478 'unknown' in show, opts.get('subrepos'))
5480 'unknown' in show, opts.get('subrepos'))
5479
5481
5480 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5482 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5481
5483
5482 if (opts.get('all') or opts.get('copies')
5484 if (opts.get('all') or opts.get('copies')
5483 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5485 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5484 copy = copies.pathcopies(ctx1, ctx2, m)
5486 copy = copies.pathcopies(ctx1, ctx2, m)
5485
5487
5486 ui.pager('status')
5488 ui.pager('status')
5487 fm = ui.formatter('status', opts)
5489 fm = ui.formatter('status', opts)
5488 fmt = '%s' + end
5490 fmt = '%s' + end
5489 showchar = not opts.get('no_status')
5491 showchar = not opts.get('no_status')
5490
5492
5491 for state, char, files in changestates:
5493 for state, char, files in changestates:
5492 if state in show:
5494 if state in show:
5493 label = 'status.' + state
5495 label = 'status.' + state
5494 for f in files:
5496 for f in files:
5495 fm.startitem()
5497 fm.startitem()
5496 fm.context(ctx=ctx2)
5498 fm.context(ctx=ctx2)
5497 fm.data(path=f)
5499 fm.data(path=f)
5498 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5500 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5499 fm.plain(fmt % uipathfn(f), label=label)
5501 fm.plain(fmt % uipathfn(f), label=label)
5500 if f in copy:
5502 if f in copy:
5501 fm.data(source=copy[f])
5503 fm.data(source=copy[f])
5502 fm.plain((' %s' + end) % uipathfn(copy[f]),
5504 fm.plain((' %s' + end) % uipathfn(copy[f]),
5503 label='status.copied')
5505 label='status.copied')
5504
5506
5505 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5507 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5506 and not ui.plain()):
5508 and not ui.plain()):
5507 cmdutil.morestatus(repo, fm)
5509 cmdutil.morestatus(repo, fm)
5508 fm.end()
5510 fm.end()
5509
5511
5510 @command('summary|sum',
5512 @command('summary|sum',
5511 [('', 'remote', None, _('check for push and pull'))],
5513 [('', 'remote', None, _('check for push and pull'))],
5512 '[--remote]',
5514 '[--remote]',
5513 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5515 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5514 helpbasic=True,
5516 helpbasic=True,
5515 intents={INTENT_READONLY})
5517 intents={INTENT_READONLY})
5516 def summary(ui, repo, **opts):
5518 def summary(ui, repo, **opts):
5517 """summarize working directory state
5519 """summarize working directory state
5518
5520
5519 This generates a brief summary of the working directory state,
5521 This generates a brief summary of the working directory state,
5520 including parents, branch, commit status, phase and available updates.
5522 including parents, branch, commit status, phase and available updates.
5521
5523
5522 With the --remote option, this will check the default paths for
5524 With the --remote option, this will check the default paths for
5523 incoming and outgoing changes. This can be time-consuming.
5525 incoming and outgoing changes. This can be time-consuming.
5524
5526
5525 Returns 0 on success.
5527 Returns 0 on success.
5526 """
5528 """
5527
5529
5528 opts = pycompat.byteskwargs(opts)
5530 opts = pycompat.byteskwargs(opts)
5529 ui.pager('summary')
5531 ui.pager('summary')
5530 ctx = repo[None]
5532 ctx = repo[None]
5531 parents = ctx.parents()
5533 parents = ctx.parents()
5532 pnode = parents[0].node()
5534 pnode = parents[0].node()
5533 marks = []
5535 marks = []
5534
5536
5535 try:
5537 try:
5536 ms = mergemod.mergestate.read(repo)
5538 ms = mergemod.mergestate.read(repo)
5537 except error.UnsupportedMergeRecords as e:
5539 except error.UnsupportedMergeRecords as e:
5538 s = ' '.join(e.recordtypes)
5540 s = ' '.join(e.recordtypes)
5539 ui.warn(
5541 ui.warn(
5540 _('warning: merge state has unsupported record types: %s\n') % s)
5542 _('warning: merge state has unsupported record types: %s\n') % s)
5541 unresolved = []
5543 unresolved = []
5542 else:
5544 else:
5543 unresolved = list(ms.unresolved())
5545 unresolved = list(ms.unresolved())
5544
5546
5545 for p in parents:
5547 for p in parents:
5546 # label with log.changeset (instead of log.parent) since this
5548 # label with log.changeset (instead of log.parent) since this
5547 # shows a working directory parent *changeset*:
5549 # shows a working directory parent *changeset*:
5548 # i18n: column positioning for "hg summary"
5550 # i18n: column positioning for "hg summary"
5549 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5551 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5550 label=logcmdutil.changesetlabels(p))
5552 label=logcmdutil.changesetlabels(p))
5551 ui.write(' '.join(p.tags()), label='log.tag')
5553 ui.write(' '.join(p.tags()), label='log.tag')
5552 if p.bookmarks():
5554 if p.bookmarks():
5553 marks.extend(p.bookmarks())
5555 marks.extend(p.bookmarks())
5554 if p.rev() == -1:
5556 if p.rev() == -1:
5555 if not len(repo):
5557 if not len(repo):
5556 ui.write(_(' (empty repository)'))
5558 ui.write(_(' (empty repository)'))
5557 else:
5559 else:
5558 ui.write(_(' (no revision checked out)'))
5560 ui.write(_(' (no revision checked out)'))
5559 if p.obsolete():
5561 if p.obsolete():
5560 ui.write(_(' (obsolete)'))
5562 ui.write(_(' (obsolete)'))
5561 if p.isunstable():
5563 if p.isunstable():
5562 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5564 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5563 for instability in p.instabilities())
5565 for instability in p.instabilities())
5564 ui.write(' ('
5566 ui.write(' ('
5565 + ', '.join(instabilities)
5567 + ', '.join(instabilities)
5566 + ')')
5568 + ')')
5567 ui.write('\n')
5569 ui.write('\n')
5568 if p.description():
5570 if p.description():
5569 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5571 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5570 label='log.summary')
5572 label='log.summary')
5571
5573
5572 branch = ctx.branch()
5574 branch = ctx.branch()
5573 bheads = repo.branchheads(branch)
5575 bheads = repo.branchheads(branch)
5574 # i18n: column positioning for "hg summary"
5576 # i18n: column positioning for "hg summary"
5575 m = _('branch: %s\n') % branch
5577 m = _('branch: %s\n') % branch
5576 if branch != 'default':
5578 if branch != 'default':
5577 ui.write(m, label='log.branch')
5579 ui.write(m, label='log.branch')
5578 else:
5580 else:
5579 ui.status(m, label='log.branch')
5581 ui.status(m, label='log.branch')
5580
5582
5581 if marks:
5583 if marks:
5582 active = repo._activebookmark
5584 active = repo._activebookmark
5583 # i18n: column positioning for "hg summary"
5585 # i18n: column positioning for "hg summary"
5584 ui.write(_('bookmarks:'), label='log.bookmark')
5586 ui.write(_('bookmarks:'), label='log.bookmark')
5585 if active is not None:
5587 if active is not None:
5586 if active in marks:
5588 if active in marks:
5587 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5589 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5588 marks.remove(active)
5590 marks.remove(active)
5589 else:
5591 else:
5590 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5592 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5591 for m in marks:
5593 for m in marks:
5592 ui.write(' ' + m, label='log.bookmark')
5594 ui.write(' ' + m, label='log.bookmark')
5593 ui.write('\n', label='log.bookmark')
5595 ui.write('\n', label='log.bookmark')
5594
5596
5595 status = repo.status(unknown=True)
5597 status = repo.status(unknown=True)
5596
5598
5597 c = repo.dirstate.copies()
5599 c = repo.dirstate.copies()
5598 copied, renamed = [], []
5600 copied, renamed = [], []
5599 for d, s in c.iteritems():
5601 for d, s in c.iteritems():
5600 if s in status.removed:
5602 if s in status.removed:
5601 status.removed.remove(s)
5603 status.removed.remove(s)
5602 renamed.append(d)
5604 renamed.append(d)
5603 else:
5605 else:
5604 copied.append(d)
5606 copied.append(d)
5605 if d in status.added:
5607 if d in status.added:
5606 status.added.remove(d)
5608 status.added.remove(d)
5607
5609
5608 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5610 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5609
5611
5610 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5612 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5611 (ui.label(_('%d added'), 'status.added'), status.added),
5613 (ui.label(_('%d added'), 'status.added'), status.added),
5612 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5614 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5613 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5615 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5614 (ui.label(_('%d copied'), 'status.copied'), copied),
5616 (ui.label(_('%d copied'), 'status.copied'), copied),
5615 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5617 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5616 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5618 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5617 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5619 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5618 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5620 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5619 t = []
5621 t = []
5620 for l, s in labels:
5622 for l, s in labels:
5621 if s:
5623 if s:
5622 t.append(l % len(s))
5624 t.append(l % len(s))
5623
5625
5624 t = ', '.join(t)
5626 t = ', '.join(t)
5625 cleanworkdir = False
5627 cleanworkdir = False
5626
5628
5627 if repo.vfs.exists('graftstate'):
5629 if repo.vfs.exists('graftstate'):
5628 t += _(' (graft in progress)')
5630 t += _(' (graft in progress)')
5629 if repo.vfs.exists('updatestate'):
5631 if repo.vfs.exists('updatestate'):
5630 t += _(' (interrupted update)')
5632 t += _(' (interrupted update)')
5631 elif len(parents) > 1:
5633 elif len(parents) > 1:
5632 t += _(' (merge)')
5634 t += _(' (merge)')
5633 elif branch != parents[0].branch():
5635 elif branch != parents[0].branch():
5634 t += _(' (new branch)')
5636 t += _(' (new branch)')
5635 elif (parents[0].closesbranch() and
5637 elif (parents[0].closesbranch() and
5636 pnode in repo.branchheads(branch, closed=True)):
5638 pnode in repo.branchheads(branch, closed=True)):
5637 t += _(' (head closed)')
5639 t += _(' (head closed)')
5638 elif not (status.modified or status.added or status.removed or renamed or
5640 elif not (status.modified or status.added or status.removed or renamed or
5639 copied or subs):
5641 copied or subs):
5640 t += _(' (clean)')
5642 t += _(' (clean)')
5641 cleanworkdir = True
5643 cleanworkdir = True
5642 elif pnode not in bheads:
5644 elif pnode not in bheads:
5643 t += _(' (new branch head)')
5645 t += _(' (new branch head)')
5644
5646
5645 if parents:
5647 if parents:
5646 pendingphase = max(p.phase() for p in parents)
5648 pendingphase = max(p.phase() for p in parents)
5647 else:
5649 else:
5648 pendingphase = phases.public
5650 pendingphase = phases.public
5649
5651
5650 if pendingphase > phases.newcommitphase(ui):
5652 if pendingphase > phases.newcommitphase(ui):
5651 t += ' (%s)' % phases.phasenames[pendingphase]
5653 t += ' (%s)' % phases.phasenames[pendingphase]
5652
5654
5653 if cleanworkdir:
5655 if cleanworkdir:
5654 # i18n: column positioning for "hg summary"
5656 # i18n: column positioning for "hg summary"
5655 ui.status(_('commit: %s\n') % t.strip())
5657 ui.status(_('commit: %s\n') % t.strip())
5656 else:
5658 else:
5657 # i18n: column positioning for "hg summary"
5659 # i18n: column positioning for "hg summary"
5658 ui.write(_('commit: %s\n') % t.strip())
5660 ui.write(_('commit: %s\n') % t.strip())
5659
5661
5660 # all ancestors of branch heads - all ancestors of parent = new csets
5662 # all ancestors of branch heads - all ancestors of parent = new csets
5661 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5663 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5662 bheads))
5664 bheads))
5663
5665
5664 if new == 0:
5666 if new == 0:
5665 # i18n: column positioning for "hg summary"
5667 # i18n: column positioning for "hg summary"
5666 ui.status(_('update: (current)\n'))
5668 ui.status(_('update: (current)\n'))
5667 elif pnode not in bheads:
5669 elif pnode not in bheads:
5668 # i18n: column positioning for "hg summary"
5670 # i18n: column positioning for "hg summary"
5669 ui.write(_('update: %d new changesets (update)\n') % new)
5671 ui.write(_('update: %d new changesets (update)\n') % new)
5670 else:
5672 else:
5671 # i18n: column positioning for "hg summary"
5673 # i18n: column positioning for "hg summary"
5672 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5674 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5673 (new, len(bheads)))
5675 (new, len(bheads)))
5674
5676
5675 t = []
5677 t = []
5676 draft = len(repo.revs('draft()'))
5678 draft = len(repo.revs('draft()'))
5677 if draft:
5679 if draft:
5678 t.append(_('%d draft') % draft)
5680 t.append(_('%d draft') % draft)
5679 secret = len(repo.revs('secret()'))
5681 secret = len(repo.revs('secret()'))
5680 if secret:
5682 if secret:
5681 t.append(_('%d secret') % secret)
5683 t.append(_('%d secret') % secret)
5682
5684
5683 if draft or secret:
5685 if draft or secret:
5684 ui.status(_('phases: %s\n') % ', '.join(t))
5686 ui.status(_('phases: %s\n') % ', '.join(t))
5685
5687
5686 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5688 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5687 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5689 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5688 numtrouble = len(repo.revs(trouble + "()"))
5690 numtrouble = len(repo.revs(trouble + "()"))
5689 # We write all the possibilities to ease translation
5691 # We write all the possibilities to ease translation
5690 troublemsg = {
5692 troublemsg = {
5691 "orphan": _("orphan: %d changesets"),
5693 "orphan": _("orphan: %d changesets"),
5692 "contentdivergent": _("content-divergent: %d changesets"),
5694 "contentdivergent": _("content-divergent: %d changesets"),
5693 "phasedivergent": _("phase-divergent: %d changesets"),
5695 "phasedivergent": _("phase-divergent: %d changesets"),
5694 }
5696 }
5695 if numtrouble > 0:
5697 if numtrouble > 0:
5696 ui.status(troublemsg[trouble] % numtrouble + "\n")
5698 ui.status(troublemsg[trouble] % numtrouble + "\n")
5697
5699
5698 cmdutil.summaryhooks(ui, repo)
5700 cmdutil.summaryhooks(ui, repo)
5699
5701
5700 if opts.get('remote'):
5702 if opts.get('remote'):
5701 needsincoming, needsoutgoing = True, True
5703 needsincoming, needsoutgoing = True, True
5702 else:
5704 else:
5703 needsincoming, needsoutgoing = False, False
5705 needsincoming, needsoutgoing = False, False
5704 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5706 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5705 if i:
5707 if i:
5706 needsincoming = True
5708 needsincoming = True
5707 if o:
5709 if o:
5708 needsoutgoing = True
5710 needsoutgoing = True
5709 if not needsincoming and not needsoutgoing:
5711 if not needsincoming and not needsoutgoing:
5710 return
5712 return
5711
5713
5712 def getincoming():
5714 def getincoming():
5713 source, branches = hg.parseurl(ui.expandpath('default'))
5715 source, branches = hg.parseurl(ui.expandpath('default'))
5714 sbranch = branches[0]
5716 sbranch = branches[0]
5715 try:
5717 try:
5716 other = hg.peer(repo, {}, source)
5718 other = hg.peer(repo, {}, source)
5717 except error.RepoError:
5719 except error.RepoError:
5718 if opts.get('remote'):
5720 if opts.get('remote'):
5719 raise
5721 raise
5720 return source, sbranch, None, None, None
5722 return source, sbranch, None, None, None
5721 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5723 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5722 if revs:
5724 if revs:
5723 revs = [other.lookup(rev) for rev in revs]
5725 revs = [other.lookup(rev) for rev in revs]
5724 ui.debug('comparing with %s\n' % util.hidepassword(source))
5726 ui.debug('comparing with %s\n' % util.hidepassword(source))
5725 repo.ui.pushbuffer()
5727 repo.ui.pushbuffer()
5726 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5728 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5727 repo.ui.popbuffer()
5729 repo.ui.popbuffer()
5728 return source, sbranch, other, commoninc, commoninc[1]
5730 return source, sbranch, other, commoninc, commoninc[1]
5729
5731
5730 if needsincoming:
5732 if needsincoming:
5731 source, sbranch, sother, commoninc, incoming = getincoming()
5733 source, sbranch, sother, commoninc, incoming = getincoming()
5732 else:
5734 else:
5733 source = sbranch = sother = commoninc = incoming = None
5735 source = sbranch = sother = commoninc = incoming = None
5734
5736
5735 def getoutgoing():
5737 def getoutgoing():
5736 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5738 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5737 dbranch = branches[0]
5739 dbranch = branches[0]
5738 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5740 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5739 if source != dest:
5741 if source != dest:
5740 try:
5742 try:
5741 dother = hg.peer(repo, {}, dest)
5743 dother = hg.peer(repo, {}, dest)
5742 except error.RepoError:
5744 except error.RepoError:
5743 if opts.get('remote'):
5745 if opts.get('remote'):
5744 raise
5746 raise
5745 return dest, dbranch, None, None
5747 return dest, dbranch, None, None
5746 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5748 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5747 elif sother is None:
5749 elif sother is None:
5748 # there is no explicit destination peer, but source one is invalid
5750 # there is no explicit destination peer, but source one is invalid
5749 return dest, dbranch, None, None
5751 return dest, dbranch, None, None
5750 else:
5752 else:
5751 dother = sother
5753 dother = sother
5752 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5754 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5753 common = None
5755 common = None
5754 else:
5756 else:
5755 common = commoninc
5757 common = commoninc
5756 if revs:
5758 if revs:
5757 revs = [repo.lookup(rev) for rev in revs]
5759 revs = [repo.lookup(rev) for rev in revs]
5758 repo.ui.pushbuffer()
5760 repo.ui.pushbuffer()
5759 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5761 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5760 commoninc=common)
5762 commoninc=common)
5761 repo.ui.popbuffer()
5763 repo.ui.popbuffer()
5762 return dest, dbranch, dother, outgoing
5764 return dest, dbranch, dother, outgoing
5763
5765
5764 if needsoutgoing:
5766 if needsoutgoing:
5765 dest, dbranch, dother, outgoing = getoutgoing()
5767 dest, dbranch, dother, outgoing = getoutgoing()
5766 else:
5768 else:
5767 dest = dbranch = dother = outgoing = None
5769 dest = dbranch = dother = outgoing = None
5768
5770
5769 if opts.get('remote'):
5771 if opts.get('remote'):
5770 t = []
5772 t = []
5771 if incoming:
5773 if incoming:
5772 t.append(_('1 or more incoming'))
5774 t.append(_('1 or more incoming'))
5773 o = outgoing.missing
5775 o = outgoing.missing
5774 if o:
5776 if o:
5775 t.append(_('%d outgoing') % len(o))
5777 t.append(_('%d outgoing') % len(o))
5776 other = dother or sother
5778 other = dother or sother
5777 if 'bookmarks' in other.listkeys('namespaces'):
5779 if 'bookmarks' in other.listkeys('namespaces'):
5778 counts = bookmarks.summary(repo, other)
5780 counts = bookmarks.summary(repo, other)
5779 if counts[0] > 0:
5781 if counts[0] > 0:
5780 t.append(_('%d incoming bookmarks') % counts[0])
5782 t.append(_('%d incoming bookmarks') % counts[0])
5781 if counts[1] > 0:
5783 if counts[1] > 0:
5782 t.append(_('%d outgoing bookmarks') % counts[1])
5784 t.append(_('%d outgoing bookmarks') % counts[1])
5783
5785
5784 if t:
5786 if t:
5785 # i18n: column positioning for "hg summary"
5787 # i18n: column positioning for "hg summary"
5786 ui.write(_('remote: %s\n') % (', '.join(t)))
5788 ui.write(_('remote: %s\n') % (', '.join(t)))
5787 else:
5789 else:
5788 # i18n: column positioning for "hg summary"
5790 # i18n: column positioning for "hg summary"
5789 ui.status(_('remote: (synced)\n'))
5791 ui.status(_('remote: (synced)\n'))
5790
5792
5791 cmdutil.summaryremotehooks(ui, repo, opts,
5793 cmdutil.summaryremotehooks(ui, repo, opts,
5792 ((source, sbranch, sother, commoninc),
5794 ((source, sbranch, sother, commoninc),
5793 (dest, dbranch, dother, outgoing)))
5795 (dest, dbranch, dother, outgoing)))
5794
5796
5795 @command('tag',
5797 @command('tag',
5796 [('f', 'force', None, _('force tag')),
5798 [('f', 'force', None, _('force tag')),
5797 ('l', 'local', None, _('make the tag local')),
5799 ('l', 'local', None, _('make the tag local')),
5798 ('r', 'rev', '', _('revision to tag'), _('REV')),
5800 ('r', 'rev', '', _('revision to tag'), _('REV')),
5799 ('', 'remove', None, _('remove a tag')),
5801 ('', 'remove', None, _('remove a tag')),
5800 # -l/--local is already there, commitopts cannot be used
5802 # -l/--local is already there, commitopts cannot be used
5801 ('e', 'edit', None, _('invoke editor on commit messages')),
5803 ('e', 'edit', None, _('invoke editor on commit messages')),
5802 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5804 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5803 ] + commitopts2,
5805 ] + commitopts2,
5804 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5806 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5805 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5807 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5806 def tag(ui, repo, name1, *names, **opts):
5808 def tag(ui, repo, name1, *names, **opts):
5807 """add one or more tags for the current or given revision
5809 """add one or more tags for the current or given revision
5808
5810
5809 Name a particular revision using <name>.
5811 Name a particular revision using <name>.
5810
5812
5811 Tags are used to name particular revisions of the repository and are
5813 Tags are used to name particular revisions of the repository and are
5812 very useful to compare different revisions, to go back to significant
5814 very useful to compare different revisions, to go back to significant
5813 earlier versions or to mark branch points as releases, etc. Changing
5815 earlier versions or to mark branch points as releases, etc. Changing
5814 an existing tag is normally disallowed; use -f/--force to override.
5816 an existing tag is normally disallowed; use -f/--force to override.
5815
5817
5816 If no revision is given, the parent of the working directory is
5818 If no revision is given, the parent of the working directory is
5817 used.
5819 used.
5818
5820
5819 To facilitate version control, distribution, and merging of tags,
5821 To facilitate version control, distribution, and merging of tags,
5820 they are stored as a file named ".hgtags" which is managed similarly
5822 they are stored as a file named ".hgtags" which is managed similarly
5821 to other project files and can be hand-edited if necessary. This
5823 to other project files and can be hand-edited if necessary. This
5822 also means that tagging creates a new commit. The file
5824 also means that tagging creates a new commit. The file
5823 ".hg/localtags" is used for local tags (not shared among
5825 ".hg/localtags" is used for local tags (not shared among
5824 repositories).
5826 repositories).
5825
5827
5826 Tag commits are usually made at the head of a branch. If the parent
5828 Tag commits are usually made at the head of a branch. If the parent
5827 of the working directory is not a branch head, :hg:`tag` aborts; use
5829 of the working directory is not a branch head, :hg:`tag` aborts; use
5828 -f/--force to force the tag commit to be based on a non-head
5830 -f/--force to force the tag commit to be based on a non-head
5829 changeset.
5831 changeset.
5830
5832
5831 See :hg:`help dates` for a list of formats valid for -d/--date.
5833 See :hg:`help dates` for a list of formats valid for -d/--date.
5832
5834
5833 Since tag names have priority over branch names during revision
5835 Since tag names have priority over branch names during revision
5834 lookup, using an existing branch name as a tag name is discouraged.
5836 lookup, using an existing branch name as a tag name is discouraged.
5835
5837
5836 Returns 0 on success.
5838 Returns 0 on success.
5837 """
5839 """
5838 opts = pycompat.byteskwargs(opts)
5840 opts = pycompat.byteskwargs(opts)
5839 with repo.wlock(), repo.lock():
5841 with repo.wlock(), repo.lock():
5840 rev_ = "."
5842 rev_ = "."
5841 names = [t.strip() for t in (name1,) + names]
5843 names = [t.strip() for t in (name1,) + names]
5842 if len(names) != len(set(names)):
5844 if len(names) != len(set(names)):
5843 raise error.Abort(_('tag names must be unique'))
5845 raise error.Abort(_('tag names must be unique'))
5844 for n in names:
5846 for n in names:
5845 scmutil.checknewlabel(repo, n, 'tag')
5847 scmutil.checknewlabel(repo, n, 'tag')
5846 if not n:
5848 if not n:
5847 raise error.Abort(_('tag names cannot consist entirely of '
5849 raise error.Abort(_('tag names cannot consist entirely of '
5848 'whitespace'))
5850 'whitespace'))
5849 if opts.get('rev') and opts.get('remove'):
5851 if opts.get('rev') and opts.get('remove'):
5850 raise error.Abort(_("--rev and --remove are incompatible"))
5852 raise error.Abort(_("--rev and --remove are incompatible"))
5851 if opts.get('rev'):
5853 if opts.get('rev'):
5852 rev_ = opts['rev']
5854 rev_ = opts['rev']
5853 message = opts.get('message')
5855 message = opts.get('message')
5854 if opts.get('remove'):
5856 if opts.get('remove'):
5855 if opts.get('local'):
5857 if opts.get('local'):
5856 expectedtype = 'local'
5858 expectedtype = 'local'
5857 else:
5859 else:
5858 expectedtype = 'global'
5860 expectedtype = 'global'
5859
5861
5860 for n in names:
5862 for n in names:
5861 if repo.tagtype(n) == 'global':
5863 if repo.tagtype(n) == 'global':
5862 alltags = tagsmod.findglobaltags(ui, repo)
5864 alltags = tagsmod.findglobaltags(ui, repo)
5863 if alltags[n][0] == nullid:
5865 if alltags[n][0] == nullid:
5864 raise error.Abort(_("tag '%s' is already removed") % n)
5866 raise error.Abort(_("tag '%s' is already removed") % n)
5865 if not repo.tagtype(n):
5867 if not repo.tagtype(n):
5866 raise error.Abort(_("tag '%s' does not exist") % n)
5868 raise error.Abort(_("tag '%s' does not exist") % n)
5867 if repo.tagtype(n) != expectedtype:
5869 if repo.tagtype(n) != expectedtype:
5868 if expectedtype == 'global':
5870 if expectedtype == 'global':
5869 raise error.Abort(_("tag '%s' is not a global tag") % n)
5871 raise error.Abort(_("tag '%s' is not a global tag") % n)
5870 else:
5872 else:
5871 raise error.Abort(_("tag '%s' is not a local tag") % n)
5873 raise error.Abort(_("tag '%s' is not a local tag") % n)
5872 rev_ = 'null'
5874 rev_ = 'null'
5873 if not message:
5875 if not message:
5874 # we don't translate commit messages
5876 # we don't translate commit messages
5875 message = 'Removed tag %s' % ', '.join(names)
5877 message = 'Removed tag %s' % ', '.join(names)
5876 elif not opts.get('force'):
5878 elif not opts.get('force'):
5877 for n in names:
5879 for n in names:
5878 if n in repo.tags():
5880 if n in repo.tags():
5879 raise error.Abort(_("tag '%s' already exists "
5881 raise error.Abort(_("tag '%s' already exists "
5880 "(use -f to force)") % n)
5882 "(use -f to force)") % n)
5881 if not opts.get('local'):
5883 if not opts.get('local'):
5882 p1, p2 = repo.dirstate.parents()
5884 p1, p2 = repo.dirstate.parents()
5883 if p2 != nullid:
5885 if p2 != nullid:
5884 raise error.Abort(_('uncommitted merge'))
5886 raise error.Abort(_('uncommitted merge'))
5885 bheads = repo.branchheads()
5887 bheads = repo.branchheads()
5886 if not opts.get('force') and bheads and p1 not in bheads:
5888 if not opts.get('force') and bheads and p1 not in bheads:
5887 raise error.Abort(_('working directory is not at a branch head '
5889 raise error.Abort(_('working directory is not at a branch head '
5888 '(use -f to force)'))
5890 '(use -f to force)'))
5889 node = scmutil.revsingle(repo, rev_).node()
5891 node = scmutil.revsingle(repo, rev_).node()
5890
5892
5891 if not message:
5893 if not message:
5892 # we don't translate commit messages
5894 # we don't translate commit messages
5893 message = ('Added tag %s for changeset %s' %
5895 message = ('Added tag %s for changeset %s' %
5894 (', '.join(names), short(node)))
5896 (', '.join(names), short(node)))
5895
5897
5896 date = opts.get('date')
5898 date = opts.get('date')
5897 if date:
5899 if date:
5898 date = dateutil.parsedate(date)
5900 date = dateutil.parsedate(date)
5899
5901
5900 if opts.get('remove'):
5902 if opts.get('remove'):
5901 editform = 'tag.remove'
5903 editform = 'tag.remove'
5902 else:
5904 else:
5903 editform = 'tag.add'
5905 editform = 'tag.add'
5904 editor = cmdutil.getcommiteditor(editform=editform,
5906 editor = cmdutil.getcommiteditor(editform=editform,
5905 **pycompat.strkwargs(opts))
5907 **pycompat.strkwargs(opts))
5906
5908
5907 # don't allow tagging the null rev
5909 # don't allow tagging the null rev
5908 if (not opts.get('remove') and
5910 if (not opts.get('remove') and
5909 scmutil.revsingle(repo, rev_).rev() == nullrev):
5911 scmutil.revsingle(repo, rev_).rev() == nullrev):
5910 raise error.Abort(_("cannot tag null revision"))
5912 raise error.Abort(_("cannot tag null revision"))
5911
5913
5912 tagsmod.tag(repo, names, node, message, opts.get('local'),
5914 tagsmod.tag(repo, names, node, message, opts.get('local'),
5913 opts.get('user'), date, editor=editor)
5915 opts.get('user'), date, editor=editor)
5914
5916
5915 @command(
5917 @command(
5916 'tags', formatteropts, '',
5918 'tags', formatteropts, '',
5917 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5919 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5918 intents={INTENT_READONLY})
5920 intents={INTENT_READONLY})
5919 def tags(ui, repo, **opts):
5921 def tags(ui, repo, **opts):
5920 """list repository tags
5922 """list repository tags
5921
5923
5922 This lists both regular and local tags. When the -v/--verbose
5924 This lists both regular and local tags. When the -v/--verbose
5923 switch is used, a third column "local" is printed for local tags.
5925 switch is used, a third column "local" is printed for local tags.
5924 When the -q/--quiet switch is used, only the tag name is printed.
5926 When the -q/--quiet switch is used, only the tag name is printed.
5925
5927
5926 .. container:: verbose
5928 .. container:: verbose
5927
5929
5928 Template:
5930 Template:
5929
5931
5930 The following keywords are supported in addition to the common template
5932 The following keywords are supported in addition to the common template
5931 keywords and functions such as ``{tag}``. See also
5933 keywords and functions such as ``{tag}``. See also
5932 :hg:`help templates`.
5934 :hg:`help templates`.
5933
5935
5934 :type: String. ``local`` for local tags.
5936 :type: String. ``local`` for local tags.
5935
5937
5936 Returns 0 on success.
5938 Returns 0 on success.
5937 """
5939 """
5938
5940
5939 opts = pycompat.byteskwargs(opts)
5941 opts = pycompat.byteskwargs(opts)
5940 ui.pager('tags')
5942 ui.pager('tags')
5941 fm = ui.formatter('tags', opts)
5943 fm = ui.formatter('tags', opts)
5942 hexfunc = fm.hexfunc
5944 hexfunc = fm.hexfunc
5943
5945
5944 for t, n in reversed(repo.tagslist()):
5946 for t, n in reversed(repo.tagslist()):
5945 hn = hexfunc(n)
5947 hn = hexfunc(n)
5946 label = 'tags.normal'
5948 label = 'tags.normal'
5947 tagtype = ''
5949 tagtype = ''
5948 if repo.tagtype(t) == 'local':
5950 if repo.tagtype(t) == 'local':
5949 label = 'tags.local'
5951 label = 'tags.local'
5950 tagtype = 'local'
5952 tagtype = 'local'
5951
5953
5952 fm.startitem()
5954 fm.startitem()
5953 fm.context(repo=repo)
5955 fm.context(repo=repo)
5954 fm.write('tag', '%s', t, label=label)
5956 fm.write('tag', '%s', t, label=label)
5955 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5957 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5956 fm.condwrite(not ui.quiet, 'rev node', fmt,
5958 fm.condwrite(not ui.quiet, 'rev node', fmt,
5957 repo.changelog.rev(n), hn, label=label)
5959 repo.changelog.rev(n), hn, label=label)
5958 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5960 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5959 tagtype, label=label)
5961 tagtype, label=label)
5960 fm.plain('\n')
5962 fm.plain('\n')
5961 fm.end()
5963 fm.end()
5962
5964
5963 @command('tip',
5965 @command('tip',
5964 [('p', 'patch', None, _('show patch')),
5966 [('p', 'patch', None, _('show patch')),
5965 ('g', 'git', None, _('use git extended diff format')),
5967 ('g', 'git', None, _('use git extended diff format')),
5966 ] + templateopts,
5968 ] + templateopts,
5967 _('[-p] [-g]'),
5969 _('[-p] [-g]'),
5968 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
5970 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
5969 def tip(ui, repo, **opts):
5971 def tip(ui, repo, **opts):
5970 """show the tip revision (DEPRECATED)
5972 """show the tip revision (DEPRECATED)
5971
5973
5972 The tip revision (usually just called the tip) is the changeset
5974 The tip revision (usually just called the tip) is the changeset
5973 most recently added to the repository (and therefore the most
5975 most recently added to the repository (and therefore the most
5974 recently changed head).
5976 recently changed head).
5975
5977
5976 If you have just made a commit, that commit will be the tip. If
5978 If you have just made a commit, that commit will be the tip. If
5977 you have just pulled changes from another repository, the tip of
5979 you have just pulled changes from another repository, the tip of
5978 that repository becomes the current tip. The "tip" tag is special
5980 that repository becomes the current tip. The "tip" tag is special
5979 and cannot be renamed or assigned to a different changeset.
5981 and cannot be renamed or assigned to a different changeset.
5980
5982
5981 This command is deprecated, please use :hg:`heads` instead.
5983 This command is deprecated, please use :hg:`heads` instead.
5982
5984
5983 Returns 0 on success.
5985 Returns 0 on success.
5984 """
5986 """
5985 opts = pycompat.byteskwargs(opts)
5987 opts = pycompat.byteskwargs(opts)
5986 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5988 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5987 displayer.show(repo['tip'])
5989 displayer.show(repo['tip'])
5988 displayer.close()
5990 displayer.close()
5989
5991
5990 @command('unbundle',
5992 @command('unbundle',
5991 [('u', 'update', None,
5993 [('u', 'update', None,
5992 _('update to new branch head if changesets were unbundled'))],
5994 _('update to new branch head if changesets were unbundled'))],
5993 _('[-u] FILE...'),
5995 _('[-u] FILE...'),
5994 helpcategory=command.CATEGORY_IMPORT_EXPORT)
5996 helpcategory=command.CATEGORY_IMPORT_EXPORT)
5995 def unbundle(ui, repo, fname1, *fnames, **opts):
5997 def unbundle(ui, repo, fname1, *fnames, **opts):
5996 """apply one or more bundle files
5998 """apply one or more bundle files
5997
5999
5998 Apply one or more bundle files generated by :hg:`bundle`.
6000 Apply one or more bundle files generated by :hg:`bundle`.
5999
6001
6000 Returns 0 on success, 1 if an update has unresolved files.
6002 Returns 0 on success, 1 if an update has unresolved files.
6001 """
6003 """
6002 fnames = (fname1,) + fnames
6004 fnames = (fname1,) + fnames
6003
6005
6004 with repo.lock():
6006 with repo.lock():
6005 for fname in fnames:
6007 for fname in fnames:
6006 f = hg.openpath(ui, fname)
6008 f = hg.openpath(ui, fname)
6007 gen = exchange.readbundle(ui, f, fname)
6009 gen = exchange.readbundle(ui, f, fname)
6008 if isinstance(gen, streamclone.streamcloneapplier):
6010 if isinstance(gen, streamclone.streamcloneapplier):
6009 raise error.Abort(
6011 raise error.Abort(
6010 _('packed bundles cannot be applied with '
6012 _('packed bundles cannot be applied with '
6011 '"hg unbundle"'),
6013 '"hg unbundle"'),
6012 hint=_('use "hg debugapplystreamclonebundle"'))
6014 hint=_('use "hg debugapplystreamclonebundle"'))
6013 url = 'bundle:' + fname
6015 url = 'bundle:' + fname
6014 try:
6016 try:
6015 txnname = 'unbundle'
6017 txnname = 'unbundle'
6016 if not isinstance(gen, bundle2.unbundle20):
6018 if not isinstance(gen, bundle2.unbundle20):
6017 txnname = 'unbundle\n%s' % util.hidepassword(url)
6019 txnname = 'unbundle\n%s' % util.hidepassword(url)
6018 with repo.transaction(txnname) as tr:
6020 with repo.transaction(txnname) as tr:
6019 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6021 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6020 url=url)
6022 url=url)
6021 except error.BundleUnknownFeatureError as exc:
6023 except error.BundleUnknownFeatureError as exc:
6022 raise error.Abort(
6024 raise error.Abort(
6023 _('%s: unknown bundle feature, %s') % (fname, exc),
6025 _('%s: unknown bundle feature, %s') % (fname, exc),
6024 hint=_("see https://mercurial-scm.org/"
6026 hint=_("see https://mercurial-scm.org/"
6025 "wiki/BundleFeature for more "
6027 "wiki/BundleFeature for more "
6026 "information"))
6028 "information"))
6027 modheads = bundle2.combinechangegroupresults(op)
6029 modheads = bundle2.combinechangegroupresults(op)
6028
6030
6029 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
6031 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
6030
6032
6031 @command('update|up|checkout|co',
6033 @command('update|up|checkout|co',
6032 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6034 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6033 ('c', 'check', None, _('require clean working directory')),
6035 ('c', 'check', None, _('require clean working directory')),
6034 ('m', 'merge', None, _('merge uncommitted changes')),
6036 ('m', 'merge', None, _('merge uncommitted changes')),
6035 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6037 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6036 ('r', 'rev', '', _('revision'), _('REV'))
6038 ('r', 'rev', '', _('revision'), _('REV'))
6037 ] + mergetoolopts,
6039 ] + mergetoolopts,
6038 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
6040 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
6039 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6041 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6040 helpbasic=True)
6042 helpbasic=True)
6041 def update(ui, repo, node=None, **opts):
6043 def update(ui, repo, node=None, **opts):
6042 """update working directory (or switch revisions)
6044 """update working directory (or switch revisions)
6043
6045
6044 Update the repository's working directory to the specified
6046 Update the repository's working directory to the specified
6045 changeset. If no changeset is specified, update to the tip of the
6047 changeset. If no changeset is specified, update to the tip of the
6046 current named branch and move the active bookmark (see :hg:`help
6048 current named branch and move the active bookmark (see :hg:`help
6047 bookmarks`).
6049 bookmarks`).
6048
6050
6049 Update sets the working directory's parent revision to the specified
6051 Update sets the working directory's parent revision to the specified
6050 changeset (see :hg:`help parents`).
6052 changeset (see :hg:`help parents`).
6051
6053
6052 If the changeset is not a descendant or ancestor of the working
6054 If the changeset is not a descendant or ancestor of the working
6053 directory's parent and there are uncommitted changes, the update is
6055 directory's parent and there are uncommitted changes, the update is
6054 aborted. With the -c/--check option, the working directory is checked
6056 aborted. With the -c/--check option, the working directory is checked
6055 for uncommitted changes; if none are found, the working directory is
6057 for uncommitted changes; if none are found, the working directory is
6056 updated to the specified changeset.
6058 updated to the specified changeset.
6057
6059
6058 .. container:: verbose
6060 .. container:: verbose
6059
6061
6060 The -C/--clean, -c/--check, and -m/--merge options control what
6062 The -C/--clean, -c/--check, and -m/--merge options control what
6061 happens if the working directory contains uncommitted changes.
6063 happens if the working directory contains uncommitted changes.
6062 At most of one of them can be specified.
6064 At most of one of them can be specified.
6063
6065
6064 1. If no option is specified, and if
6066 1. If no option is specified, and if
6065 the requested changeset is an ancestor or descendant of
6067 the requested changeset is an ancestor or descendant of
6066 the working directory's parent, the uncommitted changes
6068 the working directory's parent, the uncommitted changes
6067 are merged into the requested changeset and the merged
6069 are merged into the requested changeset and the merged
6068 result is left uncommitted. If the requested changeset is
6070 result is left uncommitted. If the requested changeset is
6069 not an ancestor or descendant (that is, it is on another
6071 not an ancestor or descendant (that is, it is on another
6070 branch), the update is aborted and the uncommitted changes
6072 branch), the update is aborted and the uncommitted changes
6071 are preserved.
6073 are preserved.
6072
6074
6073 2. With the -m/--merge option, the update is allowed even if the
6075 2. With the -m/--merge option, the update is allowed even if the
6074 requested changeset is not an ancestor or descendant of
6076 requested changeset is not an ancestor or descendant of
6075 the working directory's parent.
6077 the working directory's parent.
6076
6078
6077 3. With the -c/--check option, the update is aborted and the
6079 3. With the -c/--check option, the update is aborted and the
6078 uncommitted changes are preserved.
6080 uncommitted changes are preserved.
6079
6081
6080 4. With the -C/--clean option, uncommitted changes are discarded and
6082 4. With the -C/--clean option, uncommitted changes are discarded and
6081 the working directory is updated to the requested changeset.
6083 the working directory is updated to the requested changeset.
6082
6084
6083 To cancel an uncommitted merge (and lose your changes), use
6085 To cancel an uncommitted merge (and lose your changes), use
6084 :hg:`merge --abort`.
6086 :hg:`merge --abort`.
6085
6087
6086 Use null as the changeset to remove the working directory (like
6088 Use null as the changeset to remove the working directory (like
6087 :hg:`clone -U`).
6089 :hg:`clone -U`).
6088
6090
6089 If you want to revert just one file to an older revision, use
6091 If you want to revert just one file to an older revision, use
6090 :hg:`revert [-r REV] NAME`.
6092 :hg:`revert [-r REV] NAME`.
6091
6093
6092 See :hg:`help dates` for a list of formats valid for -d/--date.
6094 See :hg:`help dates` for a list of formats valid for -d/--date.
6093
6095
6094 Returns 0 on success, 1 if there are unresolved files.
6096 Returns 0 on success, 1 if there are unresolved files.
6095 """
6097 """
6096 rev = opts.get(r'rev')
6098 rev = opts.get(r'rev')
6097 date = opts.get(r'date')
6099 date = opts.get(r'date')
6098 clean = opts.get(r'clean')
6100 clean = opts.get(r'clean')
6099 check = opts.get(r'check')
6101 check = opts.get(r'check')
6100 merge = opts.get(r'merge')
6102 merge = opts.get(r'merge')
6101 if rev and node:
6103 if rev and node:
6102 raise error.Abort(_("please specify just one revision"))
6104 raise error.Abort(_("please specify just one revision"))
6103
6105
6104 if ui.configbool('commands', 'update.requiredest'):
6106 if ui.configbool('commands', 'update.requiredest'):
6105 if not node and not rev and not date:
6107 if not node and not rev and not date:
6106 raise error.Abort(_('you must specify a destination'),
6108 raise error.Abort(_('you must specify a destination'),
6107 hint=_('for example: hg update ".::"'))
6109 hint=_('for example: hg update ".::"'))
6108
6110
6109 if rev is None or rev == '':
6111 if rev is None or rev == '':
6110 rev = node
6112 rev = node
6111
6113
6112 if date and rev is not None:
6114 if date and rev is not None:
6113 raise error.Abort(_("you can't specify a revision and a date"))
6115 raise error.Abort(_("you can't specify a revision and a date"))
6114
6116
6115 if len([x for x in (clean, check, merge) if x]) > 1:
6117 if len([x for x in (clean, check, merge) if x]) > 1:
6116 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6118 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6117 "or -m/--merge"))
6119 "or -m/--merge"))
6118
6120
6119 updatecheck = None
6121 updatecheck = None
6120 if check:
6122 if check:
6121 updatecheck = 'abort'
6123 updatecheck = 'abort'
6122 elif merge:
6124 elif merge:
6123 updatecheck = 'none'
6125 updatecheck = 'none'
6124
6126
6125 with repo.wlock():
6127 with repo.wlock():
6126 cmdutil.clearunfinished(repo)
6128 cmdutil.clearunfinished(repo)
6127
6129
6128 if date:
6130 if date:
6129 rev = cmdutil.finddate(ui, repo, date)
6131 rev = cmdutil.finddate(ui, repo, date)
6130
6132
6131 # if we defined a bookmark, we have to remember the original name
6133 # if we defined a bookmark, we have to remember the original name
6132 brev = rev
6134 brev = rev
6133 if rev:
6135 if rev:
6134 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6136 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6135 ctx = scmutil.revsingle(repo, rev, default=None)
6137 ctx = scmutil.revsingle(repo, rev, default=None)
6136 rev = ctx.rev()
6138 rev = ctx.rev()
6137 hidden = ctx.hidden()
6139 hidden = ctx.hidden()
6138 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6140 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6139 with ui.configoverride(overrides, 'update'):
6141 with ui.configoverride(overrides, 'update'):
6140 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6142 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6141 updatecheck=updatecheck)
6143 updatecheck=updatecheck)
6142 if hidden:
6144 if hidden:
6143 ctxstr = ctx.hex()[:12]
6145 ctxstr = ctx.hex()[:12]
6144 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6146 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6145
6147
6146 if ctx.obsolete():
6148 if ctx.obsolete():
6147 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6149 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6148 ui.warn("(%s)\n" % obsfatemsg)
6150 ui.warn("(%s)\n" % obsfatemsg)
6149 return ret
6151 return ret
6150
6152
6151 @command('verify',
6153 @command('verify',
6152 [('', 'full', False, 'perform more checks (EXPERIMENTAL)')],
6154 [('', 'full', False, 'perform more checks (EXPERIMENTAL)')],
6153 helpcategory=command.CATEGORY_MAINTENANCE)
6155 helpcategory=command.CATEGORY_MAINTENANCE)
6154 def verify(ui, repo, **opts):
6156 def verify(ui, repo, **opts):
6155 """verify the integrity of the repository
6157 """verify the integrity of the repository
6156
6158
6157 Verify the integrity of the current repository.
6159 Verify the integrity of the current repository.
6158
6160
6159 This will perform an extensive check of the repository's
6161 This will perform an extensive check of the repository's
6160 integrity, validating the hashes and checksums of each entry in
6162 integrity, validating the hashes and checksums of each entry in
6161 the changelog, manifest, and tracked files, as well as the
6163 the changelog, manifest, and tracked files, as well as the
6162 integrity of their crosslinks and indices.
6164 integrity of their crosslinks and indices.
6163
6165
6164 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6166 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6165 for more information about recovery from corruption of the
6167 for more information about recovery from corruption of the
6166 repository.
6168 repository.
6167
6169
6168 Returns 0 on success, 1 if errors are encountered.
6170 Returns 0 on success, 1 if errors are encountered.
6169 """
6171 """
6170 opts = pycompat.byteskwargs(opts)
6172 opts = pycompat.byteskwargs(opts)
6171
6173
6172 level = None
6174 level = None
6173 if opts['full']:
6175 if opts['full']:
6174 level = verifymod.VERIFY_FULL
6176 level = verifymod.VERIFY_FULL
6175 return hg.verify(repo, level)
6177 return hg.verify(repo, level)
6176
6178
6177 @command(
6179 @command(
6178 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6180 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6179 norepo=True, intents={INTENT_READONLY})
6181 norepo=True, intents={INTENT_READONLY})
6180 def version_(ui, **opts):
6182 def version_(ui, **opts):
6181 """output version and copyright information
6183 """output version and copyright information
6182
6184
6183 .. container:: verbose
6185 .. container:: verbose
6184
6186
6185 Template:
6187 Template:
6186
6188
6187 The following keywords are supported. See also :hg:`help templates`.
6189 The following keywords are supported. See also :hg:`help templates`.
6188
6190
6189 :extensions: List of extensions.
6191 :extensions: List of extensions.
6190 :ver: String. Version number.
6192 :ver: String. Version number.
6191
6193
6192 And each entry of ``{extensions}`` provides the following sub-keywords
6194 And each entry of ``{extensions}`` provides the following sub-keywords
6193 in addition to ``{ver}``.
6195 in addition to ``{ver}``.
6194
6196
6195 :bundled: Boolean. True if included in the release.
6197 :bundled: Boolean. True if included in the release.
6196 :name: String. Extension name.
6198 :name: String. Extension name.
6197 """
6199 """
6198 opts = pycompat.byteskwargs(opts)
6200 opts = pycompat.byteskwargs(opts)
6199 if ui.verbose:
6201 if ui.verbose:
6200 ui.pager('version')
6202 ui.pager('version')
6201 fm = ui.formatter("version", opts)
6203 fm = ui.formatter("version", opts)
6202 fm.startitem()
6204 fm.startitem()
6203 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6205 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6204 util.version())
6206 util.version())
6205 license = _(
6207 license = _(
6206 "(see https://mercurial-scm.org for more information)\n"
6208 "(see https://mercurial-scm.org for more information)\n"
6207 "\nCopyright (C) 2005-2019 Matt Mackall and others\n"
6209 "\nCopyright (C) 2005-2019 Matt Mackall and others\n"
6208 "This is free software; see the source for copying conditions. "
6210 "This is free software; see the source for copying conditions. "
6209 "There is NO\nwarranty; "
6211 "There is NO\nwarranty; "
6210 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6212 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6211 )
6213 )
6212 if not ui.quiet:
6214 if not ui.quiet:
6213 fm.plain(license)
6215 fm.plain(license)
6214
6216
6215 if ui.verbose:
6217 if ui.verbose:
6216 fm.plain(_("\nEnabled extensions:\n\n"))
6218 fm.plain(_("\nEnabled extensions:\n\n"))
6217 # format names and versions into columns
6219 # format names and versions into columns
6218 names = []
6220 names = []
6219 vers = []
6221 vers = []
6220 isinternals = []
6222 isinternals = []
6221 for name, module in extensions.extensions():
6223 for name, module in extensions.extensions():
6222 names.append(name)
6224 names.append(name)
6223 vers.append(extensions.moduleversion(module) or None)
6225 vers.append(extensions.moduleversion(module) or None)
6224 isinternals.append(extensions.ismoduleinternal(module))
6226 isinternals.append(extensions.ismoduleinternal(module))
6225 fn = fm.nested("extensions", tmpl='{name}\n')
6227 fn = fm.nested("extensions", tmpl='{name}\n')
6226 if names:
6228 if names:
6227 namefmt = " %%-%ds " % max(len(n) for n in names)
6229 namefmt = " %%-%ds " % max(len(n) for n in names)
6228 places = [_("external"), _("internal")]
6230 places = [_("external"), _("internal")]
6229 for n, v, p in zip(names, vers, isinternals):
6231 for n, v, p in zip(names, vers, isinternals):
6230 fn.startitem()
6232 fn.startitem()
6231 fn.condwrite(ui.verbose, "name", namefmt, n)
6233 fn.condwrite(ui.verbose, "name", namefmt, n)
6232 if ui.verbose:
6234 if ui.verbose:
6233 fn.plain("%s " % places[p])
6235 fn.plain("%s " % places[p])
6234 fn.data(bundled=p)
6236 fn.data(bundled=p)
6235 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6237 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6236 if ui.verbose:
6238 if ui.verbose:
6237 fn.plain("\n")
6239 fn.plain("\n")
6238 fn.end()
6240 fn.end()
6239 fm.end()
6241 fm.end()
6240
6242
6241 def loadcmdtable(ui, name, cmdtable):
6243 def loadcmdtable(ui, name, cmdtable):
6242 """Load command functions from specified cmdtable
6244 """Load command functions from specified cmdtable
6243 """
6245 """
6244 cmdtable = cmdtable.copy()
6246 cmdtable = cmdtable.copy()
6245 for cmd in list(cmdtable):
6247 for cmd in list(cmdtable):
6246 if not cmd.startswith('^'):
6248 if not cmd.startswith('^'):
6247 continue
6249 continue
6248 ui.deprecwarn("old-style command registration '%s' in extension '%s'"
6250 ui.deprecwarn("old-style command registration '%s' in extension '%s'"
6249 % (cmd, name), '4.8')
6251 % (cmd, name), '4.8')
6250 entry = cmdtable.pop(cmd)
6252 entry = cmdtable.pop(cmd)
6251 entry[0].helpbasic = True
6253 entry[0].helpbasic = True
6252 cmdtable[cmd[1:]] = entry
6254 cmdtable[cmd[1:]] = entry
6253
6255
6254 overrides = [cmd for cmd in cmdtable if cmd in table]
6256 overrides = [cmd for cmd in cmdtable if cmd in table]
6255 if overrides:
6257 if overrides:
6256 ui.warn(_("extension '%s' overrides commands: %s\n")
6258 ui.warn(_("extension '%s' overrides commands: %s\n")
6257 % (name, " ".join(overrides)))
6259 % (name, " ".join(overrides)))
6258 table.update(cmdtable)
6260 table.update(cmdtable)
@@ -1,977 +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: can only close branch heads
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 XXX: it should have aborted here
960 $ hg ci -m "closing branch" --close-branch
959 $ hg ci -m "closing branch" --close-branch
961 created new head
960 abort: can only close branch heads
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 _ 3: 006876ddd20e closing branch
966 o 2: 155349b645be added c
967 | default
967 | default
968 |
968 |
969 | o 2: 155349b645be added c
970 |/ default
971 |
972 o 1: 5f6d8a4bf34a added b
969 o 1: 5f6d8a4bf34a added b
973 | default
970 | default
974 |
971 |
975 @ 0: 9092f1db7931 added a
972 @ 0: 9092f1db7931 added a
976 default
973 default
977
974
General Comments 0
You need to be logged in to leave comments. Login now