##// END OF EJS Templates
resolve: when resolve.mark-check=abort, downgrade to warning if pats specified...
Kyle Lippincott -
r40520:da2e874f stable
parent child Browse files
Show More
@@ -1,6156 +1,6156 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 templatekw,
64 templatekw,
65 ui as uimod,
65 ui as uimod,
66 util,
66 util,
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 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
183 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
184 return rejected and 1 or 0
184 return rejected and 1 or 0
185
185
186 @command('addremove',
186 @command('addremove',
187 similarityopts + subrepoopts + walkopts + dryrunopts,
187 similarityopts + subrepoopts + walkopts + dryrunopts,
188 _('[OPTION]... [FILE]...'),
188 _('[OPTION]... [FILE]...'),
189 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
189 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
190 inferrepo=True)
190 inferrepo=True)
191 def addremove(ui, repo, *pats, **opts):
191 def addremove(ui, repo, *pats, **opts):
192 """add all new files, delete all missing files
192 """add all new files, delete all missing files
193
193
194 Add all new files and remove all missing files from the
194 Add all new files and remove all missing files from the
195 repository.
195 repository.
196
196
197 Unless names are given, new files are ignored if they match any of
197 Unless names are given, new files are ignored if they match any of
198 the patterns in ``.hgignore``. As with add, these changes take
198 the patterns in ``.hgignore``. As with add, these changes take
199 effect at the next commit.
199 effect at the next commit.
200
200
201 Use the -s/--similarity option to detect renamed files. This
201 Use the -s/--similarity option to detect renamed files. This
202 option takes a percentage between 0 (disabled) and 100 (files must
202 option takes a percentage between 0 (disabled) and 100 (files must
203 be identical) as its parameter. With a parameter greater than 0,
203 be identical) as its parameter. With a parameter greater than 0,
204 this compares every removed file with every added file and records
204 this compares every removed file with every added file and records
205 those similar enough as renames. Detecting renamed files this way
205 those similar enough as renames. Detecting renamed files this way
206 can be expensive. After using this option, :hg:`status -C` can be
206 can be expensive. After using this option, :hg:`status -C` can be
207 used to check which files were identified as moved or renamed. If
207 used to check which files were identified as moved or renamed. If
208 not specified, -s/--similarity defaults to 100 and only renames of
208 not specified, -s/--similarity defaults to 100 and only renames of
209 identical files are detected.
209 identical files are detected.
210
210
211 .. container:: verbose
211 .. container:: verbose
212
212
213 Examples:
213 Examples:
214
214
215 - A number of files (bar.c and foo.c) are new,
215 - A number of files (bar.c and foo.c) are new,
216 while foobar.c has been removed (without using :hg:`remove`)
216 while foobar.c has been removed (without using :hg:`remove`)
217 from the repository::
217 from the repository::
218
218
219 $ ls
219 $ ls
220 bar.c foo.c
220 bar.c foo.c
221 $ hg status
221 $ hg status
222 ! foobar.c
222 ! foobar.c
223 ? bar.c
223 ? bar.c
224 ? foo.c
224 ? foo.c
225 $ hg addremove
225 $ hg addremove
226 adding bar.c
226 adding bar.c
227 adding foo.c
227 adding foo.c
228 removing foobar.c
228 removing foobar.c
229 $ hg status
229 $ hg status
230 A bar.c
230 A bar.c
231 A foo.c
231 A foo.c
232 R foobar.c
232 R foobar.c
233
233
234 - A file foobar.c was moved to foo.c without using :hg:`rename`.
234 - A file foobar.c was moved to foo.c without using :hg:`rename`.
235 Afterwards, it was edited slightly::
235 Afterwards, it was edited slightly::
236
236
237 $ ls
237 $ ls
238 foo.c
238 foo.c
239 $ hg status
239 $ hg status
240 ! foobar.c
240 ! foobar.c
241 ? foo.c
241 ? foo.c
242 $ hg addremove --similarity 90
242 $ hg addremove --similarity 90
243 removing foobar.c
243 removing foobar.c
244 adding foo.c
244 adding foo.c
245 recording removal of foobar.c as rename to foo.c (94% similar)
245 recording removal of foobar.c as rename to foo.c (94% similar)
246 $ hg status -C
246 $ hg status -C
247 A foo.c
247 A foo.c
248 foobar.c
248 foobar.c
249 R foobar.c
249 R foobar.c
250
250
251 Returns 0 if all files are successfully added.
251 Returns 0 if all files are successfully added.
252 """
252 """
253 opts = pycompat.byteskwargs(opts)
253 opts = pycompat.byteskwargs(opts)
254 if not opts.get('similarity'):
254 if not opts.get('similarity'):
255 opts['similarity'] = '100'
255 opts['similarity'] = '100'
256 matcher = scmutil.match(repo[None], pats, opts)
256 matcher = scmutil.match(repo[None], pats, opts)
257 return scmutil.addremove(repo, matcher, "", opts)
257 return scmutil.addremove(repo, matcher, "", opts)
258
258
259 @command('annotate|blame',
259 @command('annotate|blame',
260 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
260 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
261 ('', 'follow', None,
261 ('', 'follow', None,
262 _('follow copies/renames and list the filename (DEPRECATED)')),
262 _('follow copies/renames and list the filename (DEPRECATED)')),
263 ('', 'no-follow', None, _("don't follow copies and renames")),
263 ('', 'no-follow', None, _("don't follow copies and renames")),
264 ('a', 'text', None, _('treat all files as text')),
264 ('a', 'text', None, _('treat all files as text')),
265 ('u', 'user', None, _('list the author (long with -v)')),
265 ('u', 'user', None, _('list the author (long with -v)')),
266 ('f', 'file', None, _('list the filename')),
266 ('f', 'file', None, _('list the filename')),
267 ('d', 'date', None, _('list the date (short with -q)')),
267 ('d', 'date', None, _('list the date (short with -q)')),
268 ('n', 'number', None, _('list the revision number (default)')),
268 ('n', 'number', None, _('list the revision number (default)')),
269 ('c', 'changeset', None, _('list the changeset')),
269 ('c', 'changeset', None, _('list the changeset')),
270 ('l', 'line-number', None, _('show line number at the first appearance')),
270 ('l', 'line-number', None, _('show line number at the first appearance')),
271 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
271 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
272 ] + diffwsopts + walkopts + formatteropts,
272 ] + diffwsopts + walkopts + formatteropts,
273 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
273 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
274 helpcategory=command.CATEGORY_FILE_CONTENTS,
274 helpcategory=command.CATEGORY_FILE_CONTENTS,
275 helpbasic=True, inferrepo=True)
275 helpbasic=True, inferrepo=True)
276 def annotate(ui, repo, *pats, **opts):
276 def annotate(ui, repo, *pats, **opts):
277 """show changeset information by line for each file
277 """show changeset information by line for each file
278
278
279 List changes in files, showing the revision id responsible for
279 List changes in files, showing the revision id responsible for
280 each line.
280 each line.
281
281
282 This command is useful for discovering when a change was made and
282 This command is useful for discovering when a change was made and
283 by whom.
283 by whom.
284
284
285 If you include --file, --user, or --date, the revision number is
285 If you include --file, --user, or --date, the revision number is
286 suppressed unless you also include --number.
286 suppressed unless you also include --number.
287
287
288 Without the -a/--text option, annotate will avoid processing files
288 Without the -a/--text option, annotate will avoid processing files
289 it detects as binary. With -a, annotate will annotate the file
289 it detects as binary. With -a, annotate will annotate the file
290 anyway, although the results will probably be neither useful
290 anyway, although the results will probably be neither useful
291 nor desirable.
291 nor desirable.
292
292
293 .. container:: verbose
293 .. container:: verbose
294
294
295 Template:
295 Template:
296
296
297 The following keywords are supported in addition to the common template
297 The following keywords are supported in addition to the common template
298 keywords and functions. See also :hg:`help templates`.
298 keywords and functions. See also :hg:`help templates`.
299
299
300 :lines: List of lines with annotation data.
300 :lines: List of lines with annotation data.
301 :path: String. Repository-absolute path of the specified file.
301 :path: String. Repository-absolute path of the specified file.
302
302
303 And each entry of ``{lines}`` provides the following sub-keywords in
303 And each entry of ``{lines}`` provides the following sub-keywords in
304 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
304 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
305
305
306 :line: String. Line content.
306 :line: String. Line content.
307 :lineno: Integer. Line number at that revision.
307 :lineno: Integer. Line number at that revision.
308 :path: String. Repository-absolute path of the file at that revision.
308 :path: String. Repository-absolute path of the file at that revision.
309
309
310 See :hg:`help templates.operators` for the list expansion syntax.
310 See :hg:`help templates.operators` for the list expansion syntax.
311
311
312 Returns 0 on success.
312 Returns 0 on success.
313 """
313 """
314 opts = pycompat.byteskwargs(opts)
314 opts = pycompat.byteskwargs(opts)
315 if not pats:
315 if not pats:
316 raise error.Abort(_('at least one filename or pattern is required'))
316 raise error.Abort(_('at least one filename or pattern is required'))
317
317
318 if opts.get('follow'):
318 if opts.get('follow'):
319 # --follow is deprecated and now just an alias for -f/--file
319 # --follow is deprecated and now just an alias for -f/--file
320 # to mimic the behavior of Mercurial before version 1.5
320 # to mimic the behavior of Mercurial before version 1.5
321 opts['file'] = True
321 opts['file'] = True
322
322
323 rev = opts.get('rev')
323 rev = opts.get('rev')
324 if rev:
324 if rev:
325 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
325 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
326 ctx = scmutil.revsingle(repo, rev)
326 ctx = scmutil.revsingle(repo, rev)
327
327
328 rootfm = ui.formatter('annotate', opts)
328 rootfm = ui.formatter('annotate', opts)
329 if ui.debugflag:
329 if ui.debugflag:
330 shorthex = pycompat.identity
330 shorthex = pycompat.identity
331 else:
331 else:
332 def shorthex(h):
332 def shorthex(h):
333 return h[:12]
333 return h[:12]
334 if ui.quiet:
334 if ui.quiet:
335 datefunc = dateutil.shortdate
335 datefunc = dateutil.shortdate
336 else:
336 else:
337 datefunc = dateutil.datestr
337 datefunc = dateutil.datestr
338 if ctx.rev() is None:
338 if ctx.rev() is None:
339 if opts.get('changeset'):
339 if opts.get('changeset'):
340 # omit "+" suffix which is appended to node hex
340 # omit "+" suffix which is appended to node hex
341 def formatrev(rev):
341 def formatrev(rev):
342 if rev == wdirrev:
342 if rev == wdirrev:
343 return '%d' % ctx.p1().rev()
343 return '%d' % ctx.p1().rev()
344 else:
344 else:
345 return '%d' % rev
345 return '%d' % rev
346 else:
346 else:
347 def formatrev(rev):
347 def formatrev(rev):
348 if rev == wdirrev:
348 if rev == wdirrev:
349 return '%d+' % ctx.p1().rev()
349 return '%d+' % ctx.p1().rev()
350 else:
350 else:
351 return '%d ' % rev
351 return '%d ' % rev
352 def formathex(h):
352 def formathex(h):
353 if h == wdirhex:
353 if h == wdirhex:
354 return '%s+' % shorthex(hex(ctx.p1().node()))
354 return '%s+' % shorthex(hex(ctx.p1().node()))
355 else:
355 else:
356 return '%s ' % shorthex(h)
356 return '%s ' % shorthex(h)
357 else:
357 else:
358 formatrev = b'%d'.__mod__
358 formatrev = b'%d'.__mod__
359 formathex = shorthex
359 formathex = shorthex
360
360
361 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
361 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
362 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
362 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
363 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
363 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
364 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
364 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
365 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
365 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
366 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
366 ('lineno', ':', lambda x: x.lineno, pycompat.bytestr),
367 ]
367 ]
368 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file',
368 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file',
369 'lineno': 'line_number'}
369 'lineno': 'line_number'}
370
370
371 if (not opts.get('user') and not opts.get('changeset')
371 if (not opts.get('user') and not opts.get('changeset')
372 and not opts.get('date') and not opts.get('file')):
372 and not opts.get('date') and not opts.get('file')):
373 opts['number'] = True
373 opts['number'] = True
374
374
375 linenumber = opts.get('line_number') is not None
375 linenumber = opts.get('line_number') is not None
376 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
376 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
377 raise error.Abort(_('at least one of -n/-c is required for -l'))
377 raise error.Abort(_('at least one of -n/-c is required for -l'))
378
378
379 ui.pager('annotate')
379 ui.pager('annotate')
380
380
381 if rootfm.isplain():
381 if rootfm.isplain():
382 def makefunc(get, fmt):
382 def makefunc(get, fmt):
383 return lambda x: fmt(get(x))
383 return lambda x: fmt(get(x))
384 else:
384 else:
385 def makefunc(get, fmt):
385 def makefunc(get, fmt):
386 return get
386 return get
387 datahint = rootfm.datahint()
387 datahint = rootfm.datahint()
388 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
388 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
389 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
389 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
390 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
390 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
391 fields = ' '.join(fn for fn, sep, get, fmt in opmap
391 fields = ' '.join(fn for fn, sep, get, fmt in opmap
392 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
392 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
393
393
394 def bad(x, y):
394 def bad(x, y):
395 raise error.Abort("%s: %s" % (x, y))
395 raise error.Abort("%s: %s" % (x, y))
396
396
397 m = scmutil.match(ctx, pats, opts, badfn=bad)
397 m = scmutil.match(ctx, pats, opts, badfn=bad)
398
398
399 follow = not opts.get('no_follow')
399 follow = not opts.get('no_follow')
400 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
400 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
401 whitespace=True)
401 whitespace=True)
402 skiprevs = opts.get('skip')
402 skiprevs = opts.get('skip')
403 if skiprevs:
403 if skiprevs:
404 skiprevs = scmutil.revrange(repo, skiprevs)
404 skiprevs = scmutil.revrange(repo, skiprevs)
405
405
406 for abs in ctx.walk(m):
406 for abs in ctx.walk(m):
407 fctx = ctx[abs]
407 fctx = ctx[abs]
408 rootfm.startitem()
408 rootfm.startitem()
409 rootfm.data(path=abs)
409 rootfm.data(path=abs)
410 if not opts.get('text') and fctx.isbinary():
410 if not opts.get('text') and fctx.isbinary():
411 rootfm.plain(_("%s: binary file\n")
411 rootfm.plain(_("%s: binary file\n")
412 % ((pats and m.rel(abs)) or abs))
412 % ((pats and m.rel(abs)) or abs))
413 continue
413 continue
414
414
415 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
415 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
416 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
416 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
417 diffopts=diffopts)
417 diffopts=diffopts)
418 if not lines:
418 if not lines:
419 fm.end()
419 fm.end()
420 continue
420 continue
421 formats = []
421 formats = []
422 pieces = []
422 pieces = []
423
423
424 for f, sep in funcmap:
424 for f, sep in funcmap:
425 l = [f(n) for n in lines]
425 l = [f(n) for n in lines]
426 if fm.isplain():
426 if fm.isplain():
427 sizes = [encoding.colwidth(x) for x in l]
427 sizes = [encoding.colwidth(x) for x in l]
428 ml = max(sizes)
428 ml = max(sizes)
429 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
429 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
430 else:
430 else:
431 formats.append(['%s' for x in l])
431 formats.append(['%s' for x in l])
432 pieces.append(l)
432 pieces.append(l)
433
433
434 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
434 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
435 fm.startitem()
435 fm.startitem()
436 fm.context(fctx=n.fctx)
436 fm.context(fctx=n.fctx)
437 fm.write(fields, "".join(f), *p)
437 fm.write(fields, "".join(f), *p)
438 if n.skip:
438 if n.skip:
439 fmt = "* %s"
439 fmt = "* %s"
440 else:
440 else:
441 fmt = ": %s"
441 fmt = ": %s"
442 fm.write('line', fmt, n.text)
442 fm.write('line', fmt, n.text)
443
443
444 if not lines[-1].text.endswith('\n'):
444 if not lines[-1].text.endswith('\n'):
445 fm.plain('\n')
445 fm.plain('\n')
446 fm.end()
446 fm.end()
447
447
448 rootfm.end()
448 rootfm.end()
449
449
450 @command('archive',
450 @command('archive',
451 [('', 'no-decode', None, _('do not pass files through decoders')),
451 [('', 'no-decode', None, _('do not pass files through decoders')),
452 ('p', 'prefix', '', _('directory prefix for files in archive'),
452 ('p', 'prefix', '', _('directory prefix for files in archive'),
453 _('PREFIX')),
453 _('PREFIX')),
454 ('r', 'rev', '', _('revision to distribute'), _('REV')),
454 ('r', 'rev', '', _('revision to distribute'), _('REV')),
455 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
455 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
456 ] + subrepoopts + walkopts,
456 ] + subrepoopts + walkopts,
457 _('[OPTION]... DEST'),
457 _('[OPTION]... DEST'),
458 helpcategory=command.CATEGORY_IMPORT_EXPORT)
458 helpcategory=command.CATEGORY_IMPORT_EXPORT)
459 def archive(ui, repo, dest, **opts):
459 def archive(ui, repo, dest, **opts):
460 '''create an unversioned archive of a repository revision
460 '''create an unversioned archive of a repository revision
461
461
462 By default, the revision used is the parent of the working
462 By default, the revision used is the parent of the working
463 directory; use -r/--rev to specify a different revision.
463 directory; use -r/--rev to specify a different revision.
464
464
465 The archive type is automatically detected based on file
465 The archive type is automatically detected based on file
466 extension (to override, use -t/--type).
466 extension (to override, use -t/--type).
467
467
468 .. container:: verbose
468 .. container:: verbose
469
469
470 Examples:
470 Examples:
471
471
472 - create a zip file containing the 1.0 release::
472 - create a zip file containing the 1.0 release::
473
473
474 hg archive -r 1.0 project-1.0.zip
474 hg archive -r 1.0 project-1.0.zip
475
475
476 - create a tarball excluding .hg files::
476 - create a tarball excluding .hg files::
477
477
478 hg archive project.tar.gz -X ".hg*"
478 hg archive project.tar.gz -X ".hg*"
479
479
480 Valid types are:
480 Valid types are:
481
481
482 :``files``: a directory full of files (default)
482 :``files``: a directory full of files (default)
483 :``tar``: tar archive, uncompressed
483 :``tar``: tar archive, uncompressed
484 :``tbz2``: tar archive, compressed using bzip2
484 :``tbz2``: tar archive, compressed using bzip2
485 :``tgz``: tar archive, compressed using gzip
485 :``tgz``: tar archive, compressed using gzip
486 :``uzip``: zip archive, uncompressed
486 :``uzip``: zip archive, uncompressed
487 :``zip``: zip archive, compressed using deflate
487 :``zip``: zip archive, compressed using deflate
488
488
489 The exact name of the destination archive or directory is given
489 The exact name of the destination archive or directory is given
490 using a format string; see :hg:`help export` for details.
490 using a format string; see :hg:`help export` for details.
491
491
492 Each member added to an archive file has a directory prefix
492 Each member added to an archive file has a directory prefix
493 prepended. Use -p/--prefix to specify a format string for the
493 prepended. Use -p/--prefix to specify a format string for the
494 prefix. The default is the basename of the archive, with suffixes
494 prefix. The default is the basename of the archive, with suffixes
495 removed.
495 removed.
496
496
497 Returns 0 on success.
497 Returns 0 on success.
498 '''
498 '''
499
499
500 opts = pycompat.byteskwargs(opts)
500 opts = pycompat.byteskwargs(opts)
501 rev = opts.get('rev')
501 rev = opts.get('rev')
502 if rev:
502 if rev:
503 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
503 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
504 ctx = scmutil.revsingle(repo, rev)
504 ctx = scmutil.revsingle(repo, rev)
505 if not ctx:
505 if not ctx:
506 raise error.Abort(_('no working directory: please specify a revision'))
506 raise error.Abort(_('no working directory: please specify a revision'))
507 node = ctx.node()
507 node = ctx.node()
508 dest = cmdutil.makefilename(ctx, dest)
508 dest = cmdutil.makefilename(ctx, dest)
509 if os.path.realpath(dest) == repo.root:
509 if os.path.realpath(dest) == repo.root:
510 raise error.Abort(_('repository root cannot be destination'))
510 raise error.Abort(_('repository root cannot be destination'))
511
511
512 kind = opts.get('type') or archival.guesskind(dest) or 'files'
512 kind = opts.get('type') or archival.guesskind(dest) or 'files'
513 prefix = opts.get('prefix')
513 prefix = opts.get('prefix')
514
514
515 if dest == '-':
515 if dest == '-':
516 if kind == 'files':
516 if kind == 'files':
517 raise error.Abort(_('cannot archive plain files to stdout'))
517 raise error.Abort(_('cannot archive plain files to stdout'))
518 dest = cmdutil.makefileobj(ctx, dest)
518 dest = cmdutil.makefileobj(ctx, dest)
519 if not prefix:
519 if not prefix:
520 prefix = os.path.basename(repo.root) + '-%h'
520 prefix = os.path.basename(repo.root) + '-%h'
521
521
522 prefix = cmdutil.makefilename(ctx, prefix)
522 prefix = cmdutil.makefilename(ctx, prefix)
523 match = scmutil.match(ctx, [], opts)
523 match = scmutil.match(ctx, [], opts)
524 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
524 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
525 match, prefix, subrepos=opts.get('subrepos'))
525 match, prefix, subrepos=opts.get('subrepos'))
526
526
527 @command('backout',
527 @command('backout',
528 [('', 'merge', None, _('merge with old dirstate parent after backout')),
528 [('', 'merge', None, _('merge with old dirstate parent after backout')),
529 ('', 'commit', None,
529 ('', 'commit', None,
530 _('commit if no conflicts were encountered (DEPRECATED)')),
530 _('commit if no conflicts were encountered (DEPRECATED)')),
531 ('', 'no-commit', None, _('do not commit')),
531 ('', 'no-commit', None, _('do not commit')),
532 ('', 'parent', '',
532 ('', 'parent', '',
533 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
533 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
534 ('r', 'rev', '', _('revision to backout'), _('REV')),
534 ('r', 'rev', '', _('revision to backout'), _('REV')),
535 ('e', 'edit', False, _('invoke editor on commit messages')),
535 ('e', 'edit', False, _('invoke editor on commit messages')),
536 ] + mergetoolopts + walkopts + commitopts + commitopts2,
536 ] + mergetoolopts + walkopts + commitopts + commitopts2,
537 _('[OPTION]... [-r] REV'),
537 _('[OPTION]... [-r] REV'),
538 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
538 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
539 def backout(ui, repo, node=None, rev=None, **opts):
539 def backout(ui, repo, node=None, rev=None, **opts):
540 '''reverse effect of earlier changeset
540 '''reverse effect of earlier changeset
541
541
542 Prepare a new changeset with the effect of REV undone in the
542 Prepare a new changeset with the effect of REV undone in the
543 current working directory. If no conflicts were encountered,
543 current working directory. If no conflicts were encountered,
544 it will be committed immediately.
544 it will be committed immediately.
545
545
546 If REV is the parent of the working directory, then this new changeset
546 If REV is the parent of the working directory, then this new changeset
547 is committed automatically (unless --no-commit is specified).
547 is committed automatically (unless --no-commit is specified).
548
548
549 .. note::
549 .. note::
550
550
551 :hg:`backout` cannot be used to fix either an unwanted or
551 :hg:`backout` cannot be used to fix either an unwanted or
552 incorrect merge.
552 incorrect merge.
553
553
554 .. container:: verbose
554 .. container:: verbose
555
555
556 Examples:
556 Examples:
557
557
558 - Reverse the effect of the parent of the working directory.
558 - Reverse the effect of the parent of the working directory.
559 This backout will be committed immediately::
559 This backout will be committed immediately::
560
560
561 hg backout -r .
561 hg backout -r .
562
562
563 - Reverse the effect of previous bad revision 23::
563 - Reverse the effect of previous bad revision 23::
564
564
565 hg backout -r 23
565 hg backout -r 23
566
566
567 - Reverse the effect of previous bad revision 23 and
567 - Reverse the effect of previous bad revision 23 and
568 leave changes uncommitted::
568 leave changes uncommitted::
569
569
570 hg backout -r 23 --no-commit
570 hg backout -r 23 --no-commit
571 hg commit -m "Backout revision 23"
571 hg commit -m "Backout revision 23"
572
572
573 By default, the pending changeset will have one parent,
573 By default, the pending changeset will have one parent,
574 maintaining a linear history. With --merge, the pending
574 maintaining a linear history. With --merge, the pending
575 changeset will instead have two parents: the old parent of the
575 changeset will instead have two parents: the old parent of the
576 working directory and a new child of REV that simply undoes REV.
576 working directory and a new child of REV that simply undoes REV.
577
577
578 Before version 1.7, the behavior without --merge was equivalent
578 Before version 1.7, the behavior without --merge was equivalent
579 to specifying --merge followed by :hg:`update --clean .` to
579 to specifying --merge followed by :hg:`update --clean .` to
580 cancel the merge and leave the child of REV as a head to be
580 cancel the merge and leave the child of REV as a head to be
581 merged separately.
581 merged separately.
582
582
583 See :hg:`help dates` for a list of formats valid for -d/--date.
583 See :hg:`help dates` for a list of formats valid for -d/--date.
584
584
585 See :hg:`help revert` for a way to restore files to the state
585 See :hg:`help revert` for a way to restore files to the state
586 of another revision.
586 of another revision.
587
587
588 Returns 0 on success, 1 if nothing to backout or there are unresolved
588 Returns 0 on success, 1 if nothing to backout or there are unresolved
589 files.
589 files.
590 '''
590 '''
591 with repo.wlock(), repo.lock():
591 with repo.wlock(), repo.lock():
592 return _dobackout(ui, repo, node, rev, **opts)
592 return _dobackout(ui, repo, node, rev, **opts)
593
593
594 def _dobackout(ui, repo, node=None, rev=None, **opts):
594 def _dobackout(ui, repo, node=None, rev=None, **opts):
595 opts = pycompat.byteskwargs(opts)
595 opts = pycompat.byteskwargs(opts)
596 if opts.get('commit') and opts.get('no_commit'):
596 if opts.get('commit') and opts.get('no_commit'):
597 raise error.Abort(_("cannot use --commit with --no-commit"))
597 raise error.Abort(_("cannot use --commit with --no-commit"))
598 if opts.get('merge') and opts.get('no_commit'):
598 if opts.get('merge') and opts.get('no_commit'):
599 raise error.Abort(_("cannot use --merge with --no-commit"))
599 raise error.Abort(_("cannot use --merge with --no-commit"))
600
600
601 if rev and node:
601 if rev and node:
602 raise error.Abort(_("please specify just one revision"))
602 raise error.Abort(_("please specify just one revision"))
603
603
604 if not rev:
604 if not rev:
605 rev = node
605 rev = node
606
606
607 if not rev:
607 if not rev:
608 raise error.Abort(_("please specify a revision to backout"))
608 raise error.Abort(_("please specify a revision to backout"))
609
609
610 date = opts.get('date')
610 date = opts.get('date')
611 if date:
611 if date:
612 opts['date'] = dateutil.parsedate(date)
612 opts['date'] = dateutil.parsedate(date)
613
613
614 cmdutil.checkunfinished(repo)
614 cmdutil.checkunfinished(repo)
615 cmdutil.bailifchanged(repo)
615 cmdutil.bailifchanged(repo)
616 node = scmutil.revsingle(repo, rev).node()
616 node = scmutil.revsingle(repo, rev).node()
617
617
618 op1, op2 = repo.dirstate.parents()
618 op1, op2 = repo.dirstate.parents()
619 if not repo.changelog.isancestor(node, op1):
619 if not repo.changelog.isancestor(node, op1):
620 raise error.Abort(_('cannot backout change that is not an ancestor'))
620 raise error.Abort(_('cannot backout change that is not an ancestor'))
621
621
622 p1, p2 = repo.changelog.parents(node)
622 p1, p2 = repo.changelog.parents(node)
623 if p1 == nullid:
623 if p1 == nullid:
624 raise error.Abort(_('cannot backout a change with no parents'))
624 raise error.Abort(_('cannot backout a change with no parents'))
625 if p2 != nullid:
625 if p2 != nullid:
626 if not opts.get('parent'):
626 if not opts.get('parent'):
627 raise error.Abort(_('cannot backout a merge changeset'))
627 raise error.Abort(_('cannot backout a merge changeset'))
628 p = repo.lookup(opts['parent'])
628 p = repo.lookup(opts['parent'])
629 if p not in (p1, p2):
629 if p not in (p1, p2):
630 raise error.Abort(_('%s is not a parent of %s') %
630 raise error.Abort(_('%s is not a parent of %s') %
631 (short(p), short(node)))
631 (short(p), short(node)))
632 parent = p
632 parent = p
633 else:
633 else:
634 if opts.get('parent'):
634 if opts.get('parent'):
635 raise error.Abort(_('cannot use --parent on non-merge changeset'))
635 raise error.Abort(_('cannot use --parent on non-merge changeset'))
636 parent = p1
636 parent = p1
637
637
638 # the backout should appear on the same branch
638 # the backout should appear on the same branch
639 branch = repo.dirstate.branch()
639 branch = repo.dirstate.branch()
640 bheads = repo.branchheads(branch)
640 bheads = repo.branchheads(branch)
641 rctx = scmutil.revsingle(repo, hex(parent))
641 rctx = scmutil.revsingle(repo, hex(parent))
642 if not opts.get('merge') and op1 != node:
642 if not opts.get('merge') and op1 != node:
643 with dirstateguard.dirstateguard(repo, 'backout'):
643 with dirstateguard.dirstateguard(repo, 'backout'):
644 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
644 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
645 with ui.configoverride(overrides, 'backout'):
645 with ui.configoverride(overrides, 'backout'):
646 stats = mergemod.update(repo, parent, branchmerge=True,
646 stats = mergemod.update(repo, parent, branchmerge=True,
647 force=True, ancestor=node,
647 force=True, ancestor=node,
648 mergeancestor=False)
648 mergeancestor=False)
649 repo.setparents(op1, op2)
649 repo.setparents(op1, op2)
650 hg._showstats(repo, stats)
650 hg._showstats(repo, stats)
651 if stats.unresolvedcount:
651 if stats.unresolvedcount:
652 repo.ui.status(_("use 'hg resolve' to retry unresolved "
652 repo.ui.status(_("use 'hg resolve' to retry unresolved "
653 "file merges\n"))
653 "file merges\n"))
654 return 1
654 return 1
655 else:
655 else:
656 hg.clean(repo, node, show_stats=False)
656 hg.clean(repo, node, show_stats=False)
657 repo.dirstate.setbranch(branch)
657 repo.dirstate.setbranch(branch)
658 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
658 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
659
659
660 if opts.get('no_commit'):
660 if opts.get('no_commit'):
661 msg = _("changeset %s backed out, "
661 msg = _("changeset %s backed out, "
662 "don't forget to commit.\n")
662 "don't forget to commit.\n")
663 ui.status(msg % short(node))
663 ui.status(msg % short(node))
664 return 0
664 return 0
665
665
666 def commitfunc(ui, repo, message, match, opts):
666 def commitfunc(ui, repo, message, match, opts):
667 editform = 'backout'
667 editform = 'backout'
668 e = cmdutil.getcommiteditor(editform=editform,
668 e = cmdutil.getcommiteditor(editform=editform,
669 **pycompat.strkwargs(opts))
669 **pycompat.strkwargs(opts))
670 if not message:
670 if not message:
671 # we don't translate commit messages
671 # we don't translate commit messages
672 message = "Backed out changeset %s" % short(node)
672 message = "Backed out changeset %s" % short(node)
673 e = cmdutil.getcommiteditor(edit=True, editform=editform)
673 e = cmdutil.getcommiteditor(edit=True, editform=editform)
674 return repo.commit(message, opts.get('user'), opts.get('date'),
674 return repo.commit(message, opts.get('user'), opts.get('date'),
675 match, editor=e)
675 match, editor=e)
676 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
676 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
677 if not newnode:
677 if not newnode:
678 ui.status(_("nothing changed\n"))
678 ui.status(_("nothing changed\n"))
679 return 1
679 return 1
680 cmdutil.commitstatus(repo, newnode, branch, bheads)
680 cmdutil.commitstatus(repo, newnode, branch, bheads)
681
681
682 def nice(node):
682 def nice(node):
683 return '%d:%s' % (repo.changelog.rev(node), short(node))
683 return '%d:%s' % (repo.changelog.rev(node), short(node))
684 ui.status(_('changeset %s backs out changeset %s\n') %
684 ui.status(_('changeset %s backs out changeset %s\n') %
685 (nice(repo.changelog.tip()), nice(node)))
685 (nice(repo.changelog.tip()), nice(node)))
686 if opts.get('merge') and op1 != node:
686 if opts.get('merge') and op1 != node:
687 hg.clean(repo, op1, show_stats=False)
687 hg.clean(repo, op1, show_stats=False)
688 ui.status(_('merging with changeset %s\n')
688 ui.status(_('merging with changeset %s\n')
689 % nice(repo.changelog.tip()))
689 % nice(repo.changelog.tip()))
690 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
690 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
691 with ui.configoverride(overrides, 'backout'):
691 with ui.configoverride(overrides, 'backout'):
692 return hg.merge(repo, hex(repo.changelog.tip()))
692 return hg.merge(repo, hex(repo.changelog.tip()))
693 return 0
693 return 0
694
694
695 @command('bisect',
695 @command('bisect',
696 [('r', 'reset', False, _('reset bisect state')),
696 [('r', 'reset', False, _('reset bisect state')),
697 ('g', 'good', False, _('mark changeset good')),
697 ('g', 'good', False, _('mark changeset good')),
698 ('b', 'bad', False, _('mark changeset bad')),
698 ('b', 'bad', False, _('mark changeset bad')),
699 ('s', 'skip', False, _('skip testing changeset')),
699 ('s', 'skip', False, _('skip testing changeset')),
700 ('e', 'extend', False, _('extend the bisect range')),
700 ('e', 'extend', False, _('extend the bisect range')),
701 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
701 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
702 ('U', 'noupdate', False, _('do not update to target'))],
702 ('U', 'noupdate', False, _('do not update to target'))],
703 _("[-gbsr] [-U] [-c CMD] [REV]"),
703 _("[-gbsr] [-U] [-c CMD] [REV]"),
704 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
704 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
705 def bisect(ui, repo, rev=None, extra=None, command=None,
705 def bisect(ui, repo, rev=None, extra=None, command=None,
706 reset=None, good=None, bad=None, skip=None, extend=None,
706 reset=None, good=None, bad=None, skip=None, extend=None,
707 noupdate=None):
707 noupdate=None):
708 """subdivision search of changesets
708 """subdivision search of changesets
709
709
710 This command helps to find changesets which introduce problems. To
710 This command helps to find changesets which introduce problems. To
711 use, mark the earliest changeset you know exhibits the problem as
711 use, mark the earliest changeset you know exhibits the problem as
712 bad, then mark the latest changeset which is free from the problem
712 bad, then mark the latest changeset which is free from the problem
713 as good. Bisect will update your working directory to a revision
713 as good. Bisect will update your working directory to a revision
714 for testing (unless the -U/--noupdate option is specified). Once
714 for testing (unless the -U/--noupdate option is specified). Once
715 you have performed tests, mark the working directory as good or
715 you have performed tests, mark the working directory as good or
716 bad, and bisect will either update to another candidate changeset
716 bad, and bisect will either update to another candidate changeset
717 or announce that it has found the bad revision.
717 or announce that it has found the bad revision.
718
718
719 As a shortcut, you can also use the revision argument to mark a
719 As a shortcut, you can also use the revision argument to mark a
720 revision as good or bad without checking it out first.
720 revision as good or bad without checking it out first.
721
721
722 If you supply a command, it will be used for automatic bisection.
722 If you supply a command, it will be used for automatic bisection.
723 The environment variable HG_NODE will contain the ID of the
723 The environment variable HG_NODE will contain the ID of the
724 changeset being tested. The exit status of the command will be
724 changeset being tested. The exit status of the command will be
725 used to mark revisions as good or bad: status 0 means good, 125
725 used to mark revisions as good or bad: status 0 means good, 125
726 means to skip the revision, 127 (command not found) will abort the
726 means to skip the revision, 127 (command not found) will abort the
727 bisection, and any other non-zero exit status means the revision
727 bisection, and any other non-zero exit status means the revision
728 is bad.
728 is bad.
729
729
730 .. container:: verbose
730 .. container:: verbose
731
731
732 Some examples:
732 Some examples:
733
733
734 - start a bisection with known bad revision 34, and good revision 12::
734 - start a bisection with known bad revision 34, and good revision 12::
735
735
736 hg bisect --bad 34
736 hg bisect --bad 34
737 hg bisect --good 12
737 hg bisect --good 12
738
738
739 - advance the current bisection by marking current revision as good or
739 - advance the current bisection by marking current revision as good or
740 bad::
740 bad::
741
741
742 hg bisect --good
742 hg bisect --good
743 hg bisect --bad
743 hg bisect --bad
744
744
745 - mark the current revision, or a known revision, to be skipped (e.g. if
745 - mark the current revision, or a known revision, to be skipped (e.g. if
746 that revision is not usable because of another issue)::
746 that revision is not usable because of another issue)::
747
747
748 hg bisect --skip
748 hg bisect --skip
749 hg bisect --skip 23
749 hg bisect --skip 23
750
750
751 - skip all revisions that do not touch directories ``foo`` or ``bar``::
751 - skip all revisions that do not touch directories ``foo`` or ``bar``::
752
752
753 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
753 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
754
754
755 - forget the current bisection::
755 - forget the current bisection::
756
756
757 hg bisect --reset
757 hg bisect --reset
758
758
759 - use 'make && make tests' to automatically find the first broken
759 - use 'make && make tests' to automatically find the first broken
760 revision::
760 revision::
761
761
762 hg bisect --reset
762 hg bisect --reset
763 hg bisect --bad 34
763 hg bisect --bad 34
764 hg bisect --good 12
764 hg bisect --good 12
765 hg bisect --command "make && make tests"
765 hg bisect --command "make && make tests"
766
766
767 - see all changesets whose states are already known in the current
767 - see all changesets whose states are already known in the current
768 bisection::
768 bisection::
769
769
770 hg log -r "bisect(pruned)"
770 hg log -r "bisect(pruned)"
771
771
772 - see the changeset currently being bisected (especially useful
772 - see the changeset currently being bisected (especially useful
773 if running with -U/--noupdate)::
773 if running with -U/--noupdate)::
774
774
775 hg log -r "bisect(current)"
775 hg log -r "bisect(current)"
776
776
777 - see all changesets that took part in the current bisection::
777 - see all changesets that took part in the current bisection::
778
778
779 hg log -r "bisect(range)"
779 hg log -r "bisect(range)"
780
780
781 - you can even get a nice graph::
781 - you can even get a nice graph::
782
782
783 hg log --graph -r "bisect(range)"
783 hg log --graph -r "bisect(range)"
784
784
785 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
785 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
786
786
787 Returns 0 on success.
787 Returns 0 on success.
788 """
788 """
789 # backward compatibility
789 # backward compatibility
790 if rev in "good bad reset init".split():
790 if rev in "good bad reset init".split():
791 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
791 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
792 cmd, rev, extra = rev, extra, None
792 cmd, rev, extra = rev, extra, None
793 if cmd == "good":
793 if cmd == "good":
794 good = True
794 good = True
795 elif cmd == "bad":
795 elif cmd == "bad":
796 bad = True
796 bad = True
797 else:
797 else:
798 reset = True
798 reset = True
799 elif extra:
799 elif extra:
800 raise error.Abort(_('incompatible arguments'))
800 raise error.Abort(_('incompatible arguments'))
801
801
802 incompatibles = {
802 incompatibles = {
803 '--bad': bad,
803 '--bad': bad,
804 '--command': bool(command),
804 '--command': bool(command),
805 '--extend': extend,
805 '--extend': extend,
806 '--good': good,
806 '--good': good,
807 '--reset': reset,
807 '--reset': reset,
808 '--skip': skip,
808 '--skip': skip,
809 }
809 }
810
810
811 enabled = [x for x in incompatibles if incompatibles[x]]
811 enabled = [x for x in incompatibles if incompatibles[x]]
812
812
813 if len(enabled) > 1:
813 if len(enabled) > 1:
814 raise error.Abort(_('%s and %s are incompatible') %
814 raise error.Abort(_('%s and %s are incompatible') %
815 tuple(sorted(enabled)[0:2]))
815 tuple(sorted(enabled)[0:2]))
816
816
817 if reset:
817 if reset:
818 hbisect.resetstate(repo)
818 hbisect.resetstate(repo)
819 return
819 return
820
820
821 state = hbisect.load_state(repo)
821 state = hbisect.load_state(repo)
822
822
823 # update state
823 # update state
824 if good or bad or skip:
824 if good or bad or skip:
825 if rev:
825 if rev:
826 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
826 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
827 else:
827 else:
828 nodes = [repo.lookup('.')]
828 nodes = [repo.lookup('.')]
829 if good:
829 if good:
830 state['good'] += nodes
830 state['good'] += nodes
831 elif bad:
831 elif bad:
832 state['bad'] += nodes
832 state['bad'] += nodes
833 elif skip:
833 elif skip:
834 state['skip'] += nodes
834 state['skip'] += nodes
835 hbisect.save_state(repo, state)
835 hbisect.save_state(repo, state)
836 if not (state['good'] and state['bad']):
836 if not (state['good'] and state['bad']):
837 return
837 return
838
838
839 def mayupdate(repo, node, show_stats=True):
839 def mayupdate(repo, node, show_stats=True):
840 """common used update sequence"""
840 """common used update sequence"""
841 if noupdate:
841 if noupdate:
842 return
842 return
843 cmdutil.checkunfinished(repo)
843 cmdutil.checkunfinished(repo)
844 cmdutil.bailifchanged(repo)
844 cmdutil.bailifchanged(repo)
845 return hg.clean(repo, node, show_stats=show_stats)
845 return hg.clean(repo, node, show_stats=show_stats)
846
846
847 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
847 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
848
848
849 if command:
849 if command:
850 changesets = 1
850 changesets = 1
851 if noupdate:
851 if noupdate:
852 try:
852 try:
853 node = state['current'][0]
853 node = state['current'][0]
854 except LookupError:
854 except LookupError:
855 raise error.Abort(_('current bisect revision is unknown - '
855 raise error.Abort(_('current bisect revision is unknown - '
856 'start a new bisect to fix'))
856 'start a new bisect to fix'))
857 else:
857 else:
858 node, p2 = repo.dirstate.parents()
858 node, p2 = repo.dirstate.parents()
859 if p2 != nullid:
859 if p2 != nullid:
860 raise error.Abort(_('current bisect revision is a merge'))
860 raise error.Abort(_('current bisect revision is a merge'))
861 if rev:
861 if rev:
862 node = repo[scmutil.revsingle(repo, rev, node)].node()
862 node = repo[scmutil.revsingle(repo, rev, node)].node()
863 try:
863 try:
864 while changesets:
864 while changesets:
865 # update state
865 # update state
866 state['current'] = [node]
866 state['current'] = [node]
867 hbisect.save_state(repo, state)
867 hbisect.save_state(repo, state)
868 status = ui.system(command, environ={'HG_NODE': hex(node)},
868 status = ui.system(command, environ={'HG_NODE': hex(node)},
869 blockedtag='bisect_check')
869 blockedtag='bisect_check')
870 if status == 125:
870 if status == 125:
871 transition = "skip"
871 transition = "skip"
872 elif status == 0:
872 elif status == 0:
873 transition = "good"
873 transition = "good"
874 # status < 0 means process was killed
874 # status < 0 means process was killed
875 elif status == 127:
875 elif status == 127:
876 raise error.Abort(_("failed to execute %s") % command)
876 raise error.Abort(_("failed to execute %s") % command)
877 elif status < 0:
877 elif status < 0:
878 raise error.Abort(_("%s killed") % command)
878 raise error.Abort(_("%s killed") % command)
879 else:
879 else:
880 transition = "bad"
880 transition = "bad"
881 state[transition].append(node)
881 state[transition].append(node)
882 ctx = repo[node]
882 ctx = repo[node]
883 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
883 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
884 transition))
884 transition))
885 hbisect.checkstate(state)
885 hbisect.checkstate(state)
886 # bisect
886 # bisect
887 nodes, changesets, bgood = hbisect.bisect(repo, state)
887 nodes, changesets, bgood = hbisect.bisect(repo, state)
888 # update to next check
888 # update to next check
889 node = nodes[0]
889 node = nodes[0]
890 mayupdate(repo, node, show_stats=False)
890 mayupdate(repo, node, show_stats=False)
891 finally:
891 finally:
892 state['current'] = [node]
892 state['current'] = [node]
893 hbisect.save_state(repo, state)
893 hbisect.save_state(repo, state)
894 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
894 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
895 return
895 return
896
896
897 hbisect.checkstate(state)
897 hbisect.checkstate(state)
898
898
899 # actually bisect
899 # actually bisect
900 nodes, changesets, good = hbisect.bisect(repo, state)
900 nodes, changesets, good = hbisect.bisect(repo, state)
901 if extend:
901 if extend:
902 if not changesets:
902 if not changesets:
903 extendnode = hbisect.extendrange(repo, state, nodes, good)
903 extendnode = hbisect.extendrange(repo, state, nodes, good)
904 if extendnode is not None:
904 if extendnode is not None:
905 ui.write(_("Extending search to changeset %d:%s\n")
905 ui.write(_("Extending search to changeset %d:%s\n")
906 % (extendnode.rev(), extendnode))
906 % (extendnode.rev(), extendnode))
907 state['current'] = [extendnode.node()]
907 state['current'] = [extendnode.node()]
908 hbisect.save_state(repo, state)
908 hbisect.save_state(repo, state)
909 return mayupdate(repo, extendnode.node())
909 return mayupdate(repo, extendnode.node())
910 raise error.Abort(_("nothing to extend"))
910 raise error.Abort(_("nothing to extend"))
911
911
912 if changesets == 0:
912 if changesets == 0:
913 hbisect.printresult(ui, repo, state, displayer, nodes, good)
913 hbisect.printresult(ui, repo, state, displayer, nodes, good)
914 else:
914 else:
915 assert len(nodes) == 1 # only a single node can be tested next
915 assert len(nodes) == 1 # only a single node can be tested next
916 node = nodes[0]
916 node = nodes[0]
917 # compute the approximate number of remaining tests
917 # compute the approximate number of remaining tests
918 tests, size = 0, 2
918 tests, size = 0, 2
919 while size <= changesets:
919 while size <= changesets:
920 tests, size = tests + 1, size * 2
920 tests, size = tests + 1, size * 2
921 rev = repo.changelog.rev(node)
921 rev = repo.changelog.rev(node)
922 ui.write(_("Testing changeset %d:%s "
922 ui.write(_("Testing changeset %d:%s "
923 "(%d changesets remaining, ~%d tests)\n")
923 "(%d changesets remaining, ~%d tests)\n")
924 % (rev, short(node), changesets, tests))
924 % (rev, short(node), changesets, tests))
925 state['current'] = [node]
925 state['current'] = [node]
926 hbisect.save_state(repo, state)
926 hbisect.save_state(repo, state)
927 return mayupdate(repo, node)
927 return mayupdate(repo, node)
928
928
929 @command('bookmarks|bookmark',
929 @command('bookmarks|bookmark',
930 [('f', 'force', False, _('force')),
930 [('f', 'force', False, _('force')),
931 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
931 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
932 ('d', 'delete', False, _('delete a given bookmark')),
932 ('d', 'delete', False, _('delete a given bookmark')),
933 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
933 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
934 ('i', 'inactive', False, _('mark a bookmark inactive')),
934 ('i', 'inactive', False, _('mark a bookmark inactive')),
935 ('l', 'list', False, _('list existing bookmarks')),
935 ('l', 'list', False, _('list existing bookmarks')),
936 ] + formatteropts,
936 ] + formatteropts,
937 _('hg bookmarks [OPTIONS]... [NAME]...'),
937 _('hg bookmarks [OPTIONS]... [NAME]...'),
938 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
938 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
939 def bookmark(ui, repo, *names, **opts):
939 def bookmark(ui, repo, *names, **opts):
940 '''create a new bookmark or list existing bookmarks
940 '''create a new bookmark or list existing bookmarks
941
941
942 Bookmarks are labels on changesets to help track lines of development.
942 Bookmarks are labels on changesets to help track lines of development.
943 Bookmarks are unversioned and can be moved, renamed and deleted.
943 Bookmarks are unversioned and can be moved, renamed and deleted.
944 Deleting or moving a bookmark has no effect on the associated changesets.
944 Deleting or moving a bookmark has no effect on the associated changesets.
945
945
946 Creating or updating to a bookmark causes it to be marked as 'active'.
946 Creating or updating to a bookmark causes it to be marked as 'active'.
947 The active bookmark is indicated with a '*'.
947 The active bookmark is indicated with a '*'.
948 When a commit is made, the active bookmark will advance to the new commit.
948 When a commit is made, the active bookmark will advance to the new commit.
949 A plain :hg:`update` will also advance an active bookmark, if possible.
949 A plain :hg:`update` will also advance an active bookmark, if possible.
950 Updating away from a bookmark will cause it to be deactivated.
950 Updating away from a bookmark will cause it to be deactivated.
951
951
952 Bookmarks can be pushed and pulled between repositories (see
952 Bookmarks can be pushed and pulled between repositories (see
953 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
953 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
954 diverged, a new 'divergent bookmark' of the form 'name@path' will
954 diverged, a new 'divergent bookmark' of the form 'name@path' will
955 be created. Using :hg:`merge` will resolve the divergence.
955 be created. Using :hg:`merge` will resolve the divergence.
956
956
957 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
957 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
958 the active bookmark's name.
958 the active bookmark's name.
959
959
960 A bookmark named '@' has the special property that :hg:`clone` will
960 A bookmark named '@' has the special property that :hg:`clone` will
961 check it out by default if it exists.
961 check it out by default if it exists.
962
962
963 .. container:: verbose
963 .. container:: verbose
964
964
965 Template:
965 Template:
966
966
967 The following keywords are supported in addition to the common template
967 The following keywords are supported in addition to the common template
968 keywords and functions such as ``{bookmark}``. See also
968 keywords and functions such as ``{bookmark}``. See also
969 :hg:`help templates`.
969 :hg:`help templates`.
970
970
971 :active: Boolean. True if the bookmark is active.
971 :active: Boolean. True if the bookmark is active.
972
972
973 Examples:
973 Examples:
974
974
975 - create an active bookmark for a new line of development::
975 - create an active bookmark for a new line of development::
976
976
977 hg book new-feature
977 hg book new-feature
978
978
979 - create an inactive bookmark as a place marker::
979 - create an inactive bookmark as a place marker::
980
980
981 hg book -i reviewed
981 hg book -i reviewed
982
982
983 - create an inactive bookmark on another changeset::
983 - create an inactive bookmark on another changeset::
984
984
985 hg book -r .^ tested
985 hg book -r .^ tested
986
986
987 - rename bookmark turkey to dinner::
987 - rename bookmark turkey to dinner::
988
988
989 hg book -m turkey dinner
989 hg book -m turkey dinner
990
990
991 - move the '@' bookmark from another branch::
991 - move the '@' bookmark from another branch::
992
992
993 hg book -f @
993 hg book -f @
994
994
995 - print only the active bookmark name::
995 - print only the active bookmark name::
996
996
997 hg book -ql .
997 hg book -ql .
998 '''
998 '''
999 opts = pycompat.byteskwargs(opts)
999 opts = pycompat.byteskwargs(opts)
1000 force = opts.get('force')
1000 force = opts.get('force')
1001 rev = opts.get('rev')
1001 rev = opts.get('rev')
1002 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1002 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
1003
1003
1004 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
1004 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
1005 if len(selactions) > 1:
1005 if len(selactions) > 1:
1006 raise error.Abort(_('--%s and --%s are incompatible')
1006 raise error.Abort(_('--%s and --%s are incompatible')
1007 % tuple(selactions[:2]))
1007 % tuple(selactions[:2]))
1008 if selactions:
1008 if selactions:
1009 action = selactions[0]
1009 action = selactions[0]
1010 elif names or rev:
1010 elif names or rev:
1011 action = 'add'
1011 action = 'add'
1012 elif inactive:
1012 elif inactive:
1013 action = 'inactive' # meaning deactivate
1013 action = 'inactive' # meaning deactivate
1014 else:
1014 else:
1015 action = 'list'
1015 action = 'list'
1016
1016
1017 if rev and action in {'delete', 'rename', 'list'}:
1017 if rev and action in {'delete', 'rename', 'list'}:
1018 raise error.Abort(_("--rev is incompatible with --%s") % action)
1018 raise error.Abort(_("--rev is incompatible with --%s") % action)
1019 if inactive and action in {'delete', 'list'}:
1019 if inactive and action in {'delete', 'list'}:
1020 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1020 raise error.Abort(_("--inactive is incompatible with --%s") % action)
1021 if not names and action in {'add', 'delete'}:
1021 if not names and action in {'add', 'delete'}:
1022 raise error.Abort(_("bookmark name required"))
1022 raise error.Abort(_("bookmark name required"))
1023
1023
1024 if action in {'add', 'delete', 'rename', 'inactive'}:
1024 if action in {'add', 'delete', 'rename', 'inactive'}:
1025 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1025 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
1026 if action == 'delete':
1026 if action == 'delete':
1027 names = pycompat.maplist(repo._bookmarks.expandname, names)
1027 names = pycompat.maplist(repo._bookmarks.expandname, names)
1028 bookmarks.delete(repo, tr, names)
1028 bookmarks.delete(repo, tr, names)
1029 elif action == 'rename':
1029 elif action == 'rename':
1030 if not names:
1030 if not names:
1031 raise error.Abort(_("new bookmark name required"))
1031 raise error.Abort(_("new bookmark name required"))
1032 elif len(names) > 1:
1032 elif len(names) > 1:
1033 raise error.Abort(_("only one new bookmark name allowed"))
1033 raise error.Abort(_("only one new bookmark name allowed"))
1034 oldname = repo._bookmarks.expandname(opts['rename'])
1034 oldname = repo._bookmarks.expandname(opts['rename'])
1035 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1035 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1036 elif action == 'add':
1036 elif action == 'add':
1037 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1037 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1038 elif action == 'inactive':
1038 elif action == 'inactive':
1039 if len(repo._bookmarks) == 0:
1039 if len(repo._bookmarks) == 0:
1040 ui.status(_("no bookmarks set\n"))
1040 ui.status(_("no bookmarks set\n"))
1041 elif not repo._activebookmark:
1041 elif not repo._activebookmark:
1042 ui.status(_("no active bookmark\n"))
1042 ui.status(_("no active bookmark\n"))
1043 else:
1043 else:
1044 bookmarks.deactivate(repo)
1044 bookmarks.deactivate(repo)
1045 elif action == 'list':
1045 elif action == 'list':
1046 names = pycompat.maplist(repo._bookmarks.expandname, names)
1046 names = pycompat.maplist(repo._bookmarks.expandname, names)
1047 with ui.formatter('bookmarks', opts) as fm:
1047 with ui.formatter('bookmarks', opts) as fm:
1048 bookmarks.printbookmarks(ui, repo, fm, names)
1048 bookmarks.printbookmarks(ui, repo, fm, names)
1049 else:
1049 else:
1050 raise error.ProgrammingError('invalid action: %s' % action)
1050 raise error.ProgrammingError('invalid action: %s' % action)
1051
1051
1052 @command('branch',
1052 @command('branch',
1053 [('f', 'force', None,
1053 [('f', 'force', None,
1054 _('set branch name even if it shadows an existing branch')),
1054 _('set branch name even if it shadows an existing branch')),
1055 ('C', 'clean', None, _('reset branch name to parent branch name')),
1055 ('C', 'clean', None, _('reset branch name to parent branch name')),
1056 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1056 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1057 ],
1057 ],
1058 _('[-fC] [NAME]'),
1058 _('[-fC] [NAME]'),
1059 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
1059 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
1060 def branch(ui, repo, label=None, **opts):
1060 def branch(ui, repo, label=None, **opts):
1061 """set or show the current branch name
1061 """set or show the current branch name
1062
1062
1063 .. note::
1063 .. note::
1064
1064
1065 Branch names are permanent and global. Use :hg:`bookmark` to create a
1065 Branch names are permanent and global. Use :hg:`bookmark` to create a
1066 light-weight bookmark instead. See :hg:`help glossary` for more
1066 light-weight bookmark instead. See :hg:`help glossary` for more
1067 information about named branches and bookmarks.
1067 information about named branches and bookmarks.
1068
1068
1069 With no argument, show the current branch name. With one argument,
1069 With no argument, show the current branch name. With one argument,
1070 set the working directory branch name (the branch will not exist
1070 set the working directory branch name (the branch will not exist
1071 in the repository until the next commit). Standard practice
1071 in the repository until the next commit). Standard practice
1072 recommends that primary development take place on the 'default'
1072 recommends that primary development take place on the 'default'
1073 branch.
1073 branch.
1074
1074
1075 Unless -f/--force is specified, branch will not let you set a
1075 Unless -f/--force is specified, branch will not let you set a
1076 branch name that already exists.
1076 branch name that already exists.
1077
1077
1078 Use -C/--clean to reset the working directory branch to that of
1078 Use -C/--clean to reset the working directory branch to that of
1079 the parent of the working directory, negating a previous branch
1079 the parent of the working directory, negating a previous branch
1080 change.
1080 change.
1081
1081
1082 Use the command :hg:`update` to switch to an existing branch. Use
1082 Use the command :hg:`update` to switch to an existing branch. Use
1083 :hg:`commit --close-branch` to mark this branch head as closed.
1083 :hg:`commit --close-branch` to mark this branch head as closed.
1084 When all heads of a branch are closed, the branch will be
1084 When all heads of a branch are closed, the branch will be
1085 considered closed.
1085 considered closed.
1086
1086
1087 Returns 0 on success.
1087 Returns 0 on success.
1088 """
1088 """
1089 opts = pycompat.byteskwargs(opts)
1089 opts = pycompat.byteskwargs(opts)
1090 revs = opts.get('rev')
1090 revs = opts.get('rev')
1091 if label:
1091 if label:
1092 label = label.strip()
1092 label = label.strip()
1093
1093
1094 if not opts.get('clean') and not label:
1094 if not opts.get('clean') and not label:
1095 if revs:
1095 if revs:
1096 raise error.Abort(_("no branch name specified for the revisions"))
1096 raise error.Abort(_("no branch name specified for the revisions"))
1097 ui.write("%s\n" % repo.dirstate.branch())
1097 ui.write("%s\n" % repo.dirstate.branch())
1098 return
1098 return
1099
1099
1100 with repo.wlock():
1100 with repo.wlock():
1101 if opts.get('clean'):
1101 if opts.get('clean'):
1102 label = repo[None].p1().branch()
1102 label = repo[None].p1().branch()
1103 repo.dirstate.setbranch(label)
1103 repo.dirstate.setbranch(label)
1104 ui.status(_('reset working directory to branch %s\n') % label)
1104 ui.status(_('reset working directory to branch %s\n') % label)
1105 elif label:
1105 elif label:
1106
1106
1107 scmutil.checknewlabel(repo, label, 'branch')
1107 scmutil.checknewlabel(repo, label, 'branch')
1108 if revs:
1108 if revs:
1109 return cmdutil.changebranch(ui, repo, revs, label)
1109 return cmdutil.changebranch(ui, repo, revs, label)
1110
1110
1111 if not opts.get('force') and label in repo.branchmap():
1111 if not opts.get('force') and label in repo.branchmap():
1112 if label not in [p.branch() for p in repo[None].parents()]:
1112 if label not in [p.branch() for p in repo[None].parents()]:
1113 raise error.Abort(_('a branch of the same name already'
1113 raise error.Abort(_('a branch of the same name already'
1114 ' exists'),
1114 ' exists'),
1115 # i18n: "it" refers to an existing branch
1115 # i18n: "it" refers to an existing branch
1116 hint=_("use 'hg update' to switch to it"))
1116 hint=_("use 'hg update' to switch to it"))
1117
1117
1118 repo.dirstate.setbranch(label)
1118 repo.dirstate.setbranch(label)
1119 ui.status(_('marked working directory as branch %s\n') % label)
1119 ui.status(_('marked working directory as branch %s\n') % label)
1120
1120
1121 # find any open named branches aside from default
1121 # find any open named branches aside from default
1122 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1122 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1123 if n != "default" and not c]
1123 if n != "default" and not c]
1124 if not others:
1124 if not others:
1125 ui.status(_('(branches are permanent and global, '
1125 ui.status(_('(branches are permanent and global, '
1126 'did you want a bookmark?)\n'))
1126 'did you want a bookmark?)\n'))
1127
1127
1128 @command('branches',
1128 @command('branches',
1129 [('a', 'active', False,
1129 [('a', 'active', False,
1130 _('show only branches that have unmerged heads (DEPRECATED)')),
1130 _('show only branches that have unmerged heads (DEPRECATED)')),
1131 ('c', 'closed', False, _('show normal and closed branches')),
1131 ('c', 'closed', False, _('show normal and closed branches')),
1132 ] + formatteropts,
1132 ] + formatteropts,
1133 _('[-c]'),
1133 _('[-c]'),
1134 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1134 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1135 intents={INTENT_READONLY})
1135 intents={INTENT_READONLY})
1136 def branches(ui, repo, active=False, closed=False, **opts):
1136 def branches(ui, repo, active=False, closed=False, **opts):
1137 """list repository named branches
1137 """list repository named branches
1138
1138
1139 List the repository's named branches, indicating which ones are
1139 List the repository's named branches, indicating which ones are
1140 inactive. If -c/--closed is specified, also list branches which have
1140 inactive. If -c/--closed is specified, also list branches which have
1141 been marked closed (see :hg:`commit --close-branch`).
1141 been marked closed (see :hg:`commit --close-branch`).
1142
1142
1143 Use the command :hg:`update` to switch to an existing branch.
1143 Use the command :hg:`update` to switch to an existing branch.
1144
1144
1145 .. container:: verbose
1145 .. container:: verbose
1146
1146
1147 Template:
1147 Template:
1148
1148
1149 The following keywords are supported in addition to the common template
1149 The following keywords are supported in addition to the common template
1150 keywords and functions such as ``{branch}``. See also
1150 keywords and functions such as ``{branch}``. See also
1151 :hg:`help templates`.
1151 :hg:`help templates`.
1152
1152
1153 :active: Boolean. True if the branch is active.
1153 :active: Boolean. True if the branch is active.
1154 :closed: Boolean. True if the branch is closed.
1154 :closed: Boolean. True if the branch is closed.
1155 :current: Boolean. True if it is the current branch.
1155 :current: Boolean. True if it is the current branch.
1156
1156
1157 Returns 0.
1157 Returns 0.
1158 """
1158 """
1159
1159
1160 opts = pycompat.byteskwargs(opts)
1160 opts = pycompat.byteskwargs(opts)
1161 ui.pager('branches')
1161 ui.pager('branches')
1162 fm = ui.formatter('branches', opts)
1162 fm = ui.formatter('branches', opts)
1163 hexfunc = fm.hexfunc
1163 hexfunc = fm.hexfunc
1164
1164
1165 allheads = set(repo.heads())
1165 allheads = set(repo.heads())
1166 branches = []
1166 branches = []
1167 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1167 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1168 isactive = False
1168 isactive = False
1169 if not isclosed:
1169 if not isclosed:
1170 openheads = set(repo.branchmap().iteropen(heads))
1170 openheads = set(repo.branchmap().iteropen(heads))
1171 isactive = bool(openheads & allheads)
1171 isactive = bool(openheads & allheads)
1172 branches.append((tag, repo[tip], isactive, not isclosed))
1172 branches.append((tag, repo[tip], isactive, not isclosed))
1173 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1173 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1174 reverse=True)
1174 reverse=True)
1175
1175
1176 for tag, ctx, isactive, isopen in branches:
1176 for tag, ctx, isactive, isopen in branches:
1177 if active and not isactive:
1177 if active and not isactive:
1178 continue
1178 continue
1179 if isactive:
1179 if isactive:
1180 label = 'branches.active'
1180 label = 'branches.active'
1181 notice = ''
1181 notice = ''
1182 elif not isopen:
1182 elif not isopen:
1183 if not closed:
1183 if not closed:
1184 continue
1184 continue
1185 label = 'branches.closed'
1185 label = 'branches.closed'
1186 notice = _(' (closed)')
1186 notice = _(' (closed)')
1187 else:
1187 else:
1188 label = 'branches.inactive'
1188 label = 'branches.inactive'
1189 notice = _(' (inactive)')
1189 notice = _(' (inactive)')
1190 current = (tag == repo.dirstate.branch())
1190 current = (tag == repo.dirstate.branch())
1191 if current:
1191 if current:
1192 label = 'branches.current'
1192 label = 'branches.current'
1193
1193
1194 fm.startitem()
1194 fm.startitem()
1195 fm.write('branch', '%s', tag, label=label)
1195 fm.write('branch', '%s', tag, label=label)
1196 rev = ctx.rev()
1196 rev = ctx.rev()
1197 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1197 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1198 fmt = ' ' * padsize + ' %d:%s'
1198 fmt = ' ' * padsize + ' %d:%s'
1199 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1199 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1200 label='log.changeset changeset.%s' % ctx.phasestr())
1200 label='log.changeset changeset.%s' % ctx.phasestr())
1201 fm.context(ctx=ctx)
1201 fm.context(ctx=ctx)
1202 fm.data(active=isactive, closed=not isopen, current=current)
1202 fm.data(active=isactive, closed=not isopen, current=current)
1203 if not ui.quiet:
1203 if not ui.quiet:
1204 fm.plain(notice)
1204 fm.plain(notice)
1205 fm.plain('\n')
1205 fm.plain('\n')
1206 fm.end()
1206 fm.end()
1207
1207
1208 @command('bundle',
1208 @command('bundle',
1209 [('f', 'force', None, _('run even when the destination is unrelated')),
1209 [('f', 'force', None, _('run even when the destination is unrelated')),
1210 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1210 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1211 _('REV')),
1211 _('REV')),
1212 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1212 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1213 _('BRANCH')),
1213 _('BRANCH')),
1214 ('', 'base', [],
1214 ('', 'base', [],
1215 _('a base changeset assumed to be available at the destination'),
1215 _('a base changeset assumed to be available at the destination'),
1216 _('REV')),
1216 _('REV')),
1217 ('a', 'all', None, _('bundle all changesets in the repository')),
1217 ('a', 'all', None, _('bundle all changesets in the repository')),
1218 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1218 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1219 ] + remoteopts,
1219 ] + remoteopts,
1220 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1220 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1221 helpcategory=command.CATEGORY_IMPORT_EXPORT)
1221 helpcategory=command.CATEGORY_IMPORT_EXPORT)
1222 def bundle(ui, repo, fname, dest=None, **opts):
1222 def bundle(ui, repo, fname, dest=None, **opts):
1223 """create a bundle file
1223 """create a bundle file
1224
1224
1225 Generate a bundle file containing data to be transferred to another
1225 Generate a bundle file containing data to be transferred to another
1226 repository.
1226 repository.
1227
1227
1228 To create a bundle containing all changesets, use -a/--all
1228 To create a bundle containing all changesets, use -a/--all
1229 (or --base null). Otherwise, hg assumes the destination will have
1229 (or --base null). Otherwise, hg assumes the destination will have
1230 all the nodes you specify with --base parameters. Otherwise, hg
1230 all the nodes you specify with --base parameters. Otherwise, hg
1231 will assume the repository has all the nodes in destination, or
1231 will assume the repository has all the nodes in destination, or
1232 default-push/default if no destination is specified, where destination
1232 default-push/default if no destination is specified, where destination
1233 is the repository you provide through DEST option.
1233 is the repository you provide through DEST option.
1234
1234
1235 You can change bundle format with the -t/--type option. See
1235 You can change bundle format with the -t/--type option. See
1236 :hg:`help bundlespec` for documentation on this format. By default,
1236 :hg:`help bundlespec` for documentation on this format. By default,
1237 the most appropriate format is used and compression defaults to
1237 the most appropriate format is used and compression defaults to
1238 bzip2.
1238 bzip2.
1239
1239
1240 The bundle file can then be transferred using conventional means
1240 The bundle file can then be transferred using conventional means
1241 and applied to another repository with the unbundle or pull
1241 and applied to another repository with the unbundle or pull
1242 command. This is useful when direct push and pull are not
1242 command. This is useful when direct push and pull are not
1243 available or when exporting an entire repository is undesirable.
1243 available or when exporting an entire repository is undesirable.
1244
1244
1245 Applying bundles preserves all changeset contents including
1245 Applying bundles preserves all changeset contents including
1246 permissions, copy/rename information, and revision history.
1246 permissions, copy/rename information, and revision history.
1247
1247
1248 Returns 0 on success, 1 if no changes found.
1248 Returns 0 on success, 1 if no changes found.
1249 """
1249 """
1250 opts = pycompat.byteskwargs(opts)
1250 opts = pycompat.byteskwargs(opts)
1251 revs = None
1251 revs = None
1252 if 'rev' in opts:
1252 if 'rev' in opts:
1253 revstrings = opts['rev']
1253 revstrings = opts['rev']
1254 revs = scmutil.revrange(repo, revstrings)
1254 revs = scmutil.revrange(repo, revstrings)
1255 if revstrings and not revs:
1255 if revstrings and not revs:
1256 raise error.Abort(_('no commits to bundle'))
1256 raise error.Abort(_('no commits to bundle'))
1257
1257
1258 bundletype = opts.get('type', 'bzip2').lower()
1258 bundletype = opts.get('type', 'bzip2').lower()
1259 try:
1259 try:
1260 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1260 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1261 except error.UnsupportedBundleSpecification as e:
1261 except error.UnsupportedBundleSpecification as e:
1262 raise error.Abort(pycompat.bytestr(e),
1262 raise error.Abort(pycompat.bytestr(e),
1263 hint=_("see 'hg help bundlespec' for supported "
1263 hint=_("see 'hg help bundlespec' for supported "
1264 "values for --type"))
1264 "values for --type"))
1265 cgversion = bundlespec.contentopts["cg.version"]
1265 cgversion = bundlespec.contentopts["cg.version"]
1266
1266
1267 # Packed bundles are a pseudo bundle format for now.
1267 # Packed bundles are a pseudo bundle format for now.
1268 if cgversion == 's1':
1268 if cgversion == 's1':
1269 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1269 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1270 hint=_("use 'hg debugcreatestreamclonebundle'"))
1270 hint=_("use 'hg debugcreatestreamclonebundle'"))
1271
1271
1272 if opts.get('all'):
1272 if opts.get('all'):
1273 if dest:
1273 if dest:
1274 raise error.Abort(_("--all is incompatible with specifying "
1274 raise error.Abort(_("--all is incompatible with specifying "
1275 "a destination"))
1275 "a destination"))
1276 if opts.get('base'):
1276 if opts.get('base'):
1277 ui.warn(_("ignoring --base because --all was specified\n"))
1277 ui.warn(_("ignoring --base because --all was specified\n"))
1278 base = [nullrev]
1278 base = [nullrev]
1279 else:
1279 else:
1280 base = scmutil.revrange(repo, opts.get('base'))
1280 base = scmutil.revrange(repo, opts.get('base'))
1281 if cgversion not in changegroup.supportedoutgoingversions(repo):
1281 if cgversion not in changegroup.supportedoutgoingversions(repo):
1282 raise error.Abort(_("repository does not support bundle version %s") %
1282 raise error.Abort(_("repository does not support bundle version %s") %
1283 cgversion)
1283 cgversion)
1284
1284
1285 if base:
1285 if base:
1286 if dest:
1286 if dest:
1287 raise error.Abort(_("--base is incompatible with specifying "
1287 raise error.Abort(_("--base is incompatible with specifying "
1288 "a destination"))
1288 "a destination"))
1289 common = [repo[rev].node() for rev in base]
1289 common = [repo[rev].node() for rev in base]
1290 heads = [repo[r].node() for r in revs] if revs else None
1290 heads = [repo[r].node() for r in revs] if revs else None
1291 outgoing = discovery.outgoing(repo, common, heads)
1291 outgoing = discovery.outgoing(repo, common, heads)
1292 else:
1292 else:
1293 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1293 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1294 dest, branches = hg.parseurl(dest, opts.get('branch'))
1294 dest, branches = hg.parseurl(dest, opts.get('branch'))
1295 other = hg.peer(repo, opts, dest)
1295 other = hg.peer(repo, opts, dest)
1296 revs = [repo[r].hex() for r in revs]
1296 revs = [repo[r].hex() for r in revs]
1297 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1297 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1298 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1298 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1299 outgoing = discovery.findcommonoutgoing(repo, other,
1299 outgoing = discovery.findcommonoutgoing(repo, other,
1300 onlyheads=heads,
1300 onlyheads=heads,
1301 force=opts.get('force'),
1301 force=opts.get('force'),
1302 portable=True)
1302 portable=True)
1303
1303
1304 if not outgoing.missing:
1304 if not outgoing.missing:
1305 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1305 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1306 return 1
1306 return 1
1307
1307
1308 if cgversion == '01': #bundle1
1308 if cgversion == '01': #bundle1
1309 bversion = 'HG10' + bundlespec.wirecompression
1309 bversion = 'HG10' + bundlespec.wirecompression
1310 bcompression = None
1310 bcompression = None
1311 elif cgversion in ('02', '03'):
1311 elif cgversion in ('02', '03'):
1312 bversion = 'HG20'
1312 bversion = 'HG20'
1313 bcompression = bundlespec.wirecompression
1313 bcompression = bundlespec.wirecompression
1314 else:
1314 else:
1315 raise error.ProgrammingError(
1315 raise error.ProgrammingError(
1316 'bundle: unexpected changegroup version %s' % cgversion)
1316 'bundle: unexpected changegroup version %s' % cgversion)
1317
1317
1318 # TODO compression options should be derived from bundlespec parsing.
1318 # TODO compression options should be derived from bundlespec parsing.
1319 # This is a temporary hack to allow adjusting bundle compression
1319 # This is a temporary hack to allow adjusting bundle compression
1320 # level without a) formalizing the bundlespec changes to declare it
1320 # level without a) formalizing the bundlespec changes to declare it
1321 # b) introducing a command flag.
1321 # b) introducing a command flag.
1322 compopts = {}
1322 compopts = {}
1323 complevel = ui.configint('experimental',
1323 complevel = ui.configint('experimental',
1324 'bundlecomplevel.' + bundlespec.compression)
1324 'bundlecomplevel.' + bundlespec.compression)
1325 if complevel is None:
1325 if complevel is None:
1326 complevel = ui.configint('experimental', 'bundlecomplevel')
1326 complevel = ui.configint('experimental', 'bundlecomplevel')
1327 if complevel is not None:
1327 if complevel is not None:
1328 compopts['level'] = complevel
1328 compopts['level'] = complevel
1329
1329
1330 # Allow overriding the bundling of obsmarker in phases through
1330 # Allow overriding the bundling of obsmarker in phases through
1331 # configuration while we don't have a bundle version that include them
1331 # configuration while we don't have a bundle version that include them
1332 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1332 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1333 bundlespec.contentopts['obsolescence'] = True
1333 bundlespec.contentopts['obsolescence'] = True
1334 if repo.ui.configbool('experimental', 'bundle-phases'):
1334 if repo.ui.configbool('experimental', 'bundle-phases'):
1335 bundlespec.contentopts['phases'] = True
1335 bundlespec.contentopts['phases'] = True
1336
1336
1337 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1337 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1338 bundlespec.contentopts, compression=bcompression,
1338 bundlespec.contentopts, compression=bcompression,
1339 compopts=compopts)
1339 compopts=compopts)
1340
1340
1341 @command('cat',
1341 @command('cat',
1342 [('o', 'output', '',
1342 [('o', 'output', '',
1343 _('print output to file with formatted name'), _('FORMAT')),
1343 _('print output to file with formatted name'), _('FORMAT')),
1344 ('r', 'rev', '', _('print the given revision'), _('REV')),
1344 ('r', 'rev', '', _('print the given revision'), _('REV')),
1345 ('', 'decode', None, _('apply any matching decode filter')),
1345 ('', 'decode', None, _('apply any matching decode filter')),
1346 ] + walkopts + formatteropts,
1346 ] + walkopts + formatteropts,
1347 _('[OPTION]... FILE...'),
1347 _('[OPTION]... FILE...'),
1348 helpcategory=command.CATEGORY_FILE_CONTENTS,
1348 helpcategory=command.CATEGORY_FILE_CONTENTS,
1349 inferrepo=True,
1349 inferrepo=True,
1350 intents={INTENT_READONLY})
1350 intents={INTENT_READONLY})
1351 def cat(ui, repo, file1, *pats, **opts):
1351 def cat(ui, repo, file1, *pats, **opts):
1352 """output the current or given revision of files
1352 """output the current or given revision of files
1353
1353
1354 Print the specified files as they were at the given revision. If
1354 Print the specified files as they were at the given revision. If
1355 no revision is given, the parent of the working directory is used.
1355 no revision is given, the parent of the working directory is used.
1356
1356
1357 Output may be to a file, in which case the name of the file is
1357 Output may be to a file, in which case the name of the file is
1358 given using a template string. See :hg:`help templates`. In addition
1358 given using a template string. See :hg:`help templates`. In addition
1359 to the common template keywords, the following formatting rules are
1359 to the common template keywords, the following formatting rules are
1360 supported:
1360 supported:
1361
1361
1362 :``%%``: literal "%" character
1362 :``%%``: literal "%" character
1363 :``%s``: basename of file being printed
1363 :``%s``: basename of file being printed
1364 :``%d``: dirname of file being printed, or '.' if in repository root
1364 :``%d``: dirname of file being printed, or '.' if in repository root
1365 :``%p``: root-relative path name of file being printed
1365 :``%p``: root-relative path name of file being printed
1366 :``%H``: changeset hash (40 hexadecimal digits)
1366 :``%H``: changeset hash (40 hexadecimal digits)
1367 :``%R``: changeset revision number
1367 :``%R``: changeset revision number
1368 :``%h``: short-form changeset hash (12 hexadecimal digits)
1368 :``%h``: short-form changeset hash (12 hexadecimal digits)
1369 :``%r``: zero-padded changeset revision number
1369 :``%r``: zero-padded changeset revision number
1370 :``%b``: basename of the exporting repository
1370 :``%b``: basename of the exporting repository
1371 :``\\``: literal "\\" character
1371 :``\\``: literal "\\" character
1372
1372
1373 .. container:: verbose
1373 .. container:: verbose
1374
1374
1375 Template:
1375 Template:
1376
1376
1377 The following keywords are supported in addition to the common template
1377 The following keywords are supported in addition to the common template
1378 keywords and functions. See also :hg:`help templates`.
1378 keywords and functions. See also :hg:`help templates`.
1379
1379
1380 :data: String. File content.
1380 :data: String. File content.
1381 :path: String. Repository-absolute path of the file.
1381 :path: String. Repository-absolute path of the file.
1382
1382
1383 Returns 0 on success.
1383 Returns 0 on success.
1384 """
1384 """
1385 opts = pycompat.byteskwargs(opts)
1385 opts = pycompat.byteskwargs(opts)
1386 rev = opts.get('rev')
1386 rev = opts.get('rev')
1387 if rev:
1387 if rev:
1388 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1388 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1389 ctx = scmutil.revsingle(repo, rev)
1389 ctx = scmutil.revsingle(repo, rev)
1390 m = scmutil.match(ctx, (file1,) + pats, opts)
1390 m = scmutil.match(ctx, (file1,) + pats, opts)
1391 fntemplate = opts.pop('output', '')
1391 fntemplate = opts.pop('output', '')
1392 if cmdutil.isstdiofilename(fntemplate):
1392 if cmdutil.isstdiofilename(fntemplate):
1393 fntemplate = ''
1393 fntemplate = ''
1394
1394
1395 if fntemplate:
1395 if fntemplate:
1396 fm = formatter.nullformatter(ui, 'cat', opts)
1396 fm = formatter.nullformatter(ui, 'cat', opts)
1397 else:
1397 else:
1398 ui.pager('cat')
1398 ui.pager('cat')
1399 fm = ui.formatter('cat', opts)
1399 fm = ui.formatter('cat', opts)
1400 with fm:
1400 with fm:
1401 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1401 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1402 **pycompat.strkwargs(opts))
1402 **pycompat.strkwargs(opts))
1403
1403
1404 @command('clone',
1404 @command('clone',
1405 [('U', 'noupdate', None, _('the clone will include an empty working '
1405 [('U', 'noupdate', None, _('the clone will include an empty working '
1406 'directory (only a repository)')),
1406 'directory (only a repository)')),
1407 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1407 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1408 _('REV')),
1408 _('REV')),
1409 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1409 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1410 ' and its ancestors'), _('REV')),
1410 ' and its ancestors'), _('REV')),
1411 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1411 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1412 ' changesets and their ancestors'), _('BRANCH')),
1412 ' changesets and their ancestors'), _('BRANCH')),
1413 ('', 'pull', None, _('use pull protocol to copy metadata')),
1413 ('', 'pull', None, _('use pull protocol to copy metadata')),
1414 ('', 'uncompressed', None,
1414 ('', 'uncompressed', None,
1415 _('an alias to --stream (DEPRECATED)')),
1415 _('an alias to --stream (DEPRECATED)')),
1416 ('', 'stream', None,
1416 ('', 'stream', None,
1417 _('clone with minimal data processing')),
1417 _('clone with minimal data processing')),
1418 ] + remoteopts,
1418 ] + remoteopts,
1419 _('[OPTION]... SOURCE [DEST]'),
1419 _('[OPTION]... SOURCE [DEST]'),
1420 helpcategory=command.CATEGORY_REPO_CREATION,
1420 helpcategory=command.CATEGORY_REPO_CREATION,
1421 helpbasic=True, norepo=True)
1421 helpbasic=True, norepo=True)
1422 def clone(ui, source, dest=None, **opts):
1422 def clone(ui, source, dest=None, **opts):
1423 """make a copy of an existing repository
1423 """make a copy of an existing repository
1424
1424
1425 Create a copy of an existing repository in a new directory.
1425 Create a copy of an existing repository in a new directory.
1426
1426
1427 If no destination directory name is specified, it defaults to the
1427 If no destination directory name is specified, it defaults to the
1428 basename of the source.
1428 basename of the source.
1429
1429
1430 The location of the source is added to the new repository's
1430 The location of the source is added to the new repository's
1431 ``.hg/hgrc`` file, as the default to be used for future pulls.
1431 ``.hg/hgrc`` file, as the default to be used for future pulls.
1432
1432
1433 Only local paths and ``ssh://`` URLs are supported as
1433 Only local paths and ``ssh://`` URLs are supported as
1434 destinations. For ``ssh://`` destinations, no working directory or
1434 destinations. For ``ssh://`` destinations, no working directory or
1435 ``.hg/hgrc`` will be created on the remote side.
1435 ``.hg/hgrc`` will be created on the remote side.
1436
1436
1437 If the source repository has a bookmark called '@' set, that
1437 If the source repository has a bookmark called '@' set, that
1438 revision will be checked out in the new repository by default.
1438 revision will be checked out in the new repository by default.
1439
1439
1440 To check out a particular version, use -u/--update, or
1440 To check out a particular version, use -u/--update, or
1441 -U/--noupdate to create a clone with no working directory.
1441 -U/--noupdate to create a clone with no working directory.
1442
1442
1443 To pull only a subset of changesets, specify one or more revisions
1443 To pull only a subset of changesets, specify one or more revisions
1444 identifiers with -r/--rev or branches with -b/--branch. The
1444 identifiers with -r/--rev or branches with -b/--branch. The
1445 resulting clone will contain only the specified changesets and
1445 resulting clone will contain only the specified changesets and
1446 their ancestors. These options (or 'clone src#rev dest') imply
1446 their ancestors. These options (or 'clone src#rev dest') imply
1447 --pull, even for local source repositories.
1447 --pull, even for local source repositories.
1448
1448
1449 In normal clone mode, the remote normalizes repository data into a common
1449 In normal clone mode, the remote normalizes repository data into a common
1450 exchange format and the receiving end translates this data into its local
1450 exchange format and the receiving end translates this data into its local
1451 storage format. --stream activates a different clone mode that essentially
1451 storage format. --stream activates a different clone mode that essentially
1452 copies repository files from the remote with minimal data processing. This
1452 copies repository files from the remote with minimal data processing. This
1453 significantly reduces the CPU cost of a clone both remotely and locally.
1453 significantly reduces the CPU cost of a clone both remotely and locally.
1454 However, it often increases the transferred data size by 30-40%. This can
1454 However, it often increases the transferred data size by 30-40%. This can
1455 result in substantially faster clones where I/O throughput is plentiful,
1455 result in substantially faster clones where I/O throughput is plentiful,
1456 especially for larger repositories. A side-effect of --stream clones is
1456 especially for larger repositories. A side-effect of --stream clones is
1457 that storage settings and requirements on the remote are applied locally:
1457 that storage settings and requirements on the remote are applied locally:
1458 a modern client may inherit legacy or inefficient storage used by the
1458 a modern client may inherit legacy or inefficient storage used by the
1459 remote or a legacy Mercurial client may not be able to clone from a
1459 remote or a legacy Mercurial client may not be able to clone from a
1460 modern Mercurial remote.
1460 modern Mercurial remote.
1461
1461
1462 .. note::
1462 .. note::
1463
1463
1464 Specifying a tag will include the tagged changeset but not the
1464 Specifying a tag will include the tagged changeset but not the
1465 changeset containing the tag.
1465 changeset containing the tag.
1466
1466
1467 .. container:: verbose
1467 .. container:: verbose
1468
1468
1469 For efficiency, hardlinks are used for cloning whenever the
1469 For efficiency, hardlinks are used for cloning whenever the
1470 source and destination are on the same filesystem (note this
1470 source and destination are on the same filesystem (note this
1471 applies only to the repository data, not to the working
1471 applies only to the repository data, not to the working
1472 directory). Some filesystems, such as AFS, implement hardlinking
1472 directory). Some filesystems, such as AFS, implement hardlinking
1473 incorrectly, but do not report errors. In these cases, use the
1473 incorrectly, but do not report errors. In these cases, use the
1474 --pull option to avoid hardlinking.
1474 --pull option to avoid hardlinking.
1475
1475
1476 Mercurial will update the working directory to the first applicable
1476 Mercurial will update the working directory to the first applicable
1477 revision from this list:
1477 revision from this list:
1478
1478
1479 a) null if -U or the source repository has no changesets
1479 a) null if -U or the source repository has no changesets
1480 b) if -u . and the source repository is local, the first parent of
1480 b) if -u . and the source repository is local, the first parent of
1481 the source repository's working directory
1481 the source repository's working directory
1482 c) the changeset specified with -u (if a branch name, this means the
1482 c) the changeset specified with -u (if a branch name, this means the
1483 latest head of that branch)
1483 latest head of that branch)
1484 d) the changeset specified with -r
1484 d) the changeset specified with -r
1485 e) the tipmost head specified with -b
1485 e) the tipmost head specified with -b
1486 f) the tipmost head specified with the url#branch source syntax
1486 f) the tipmost head specified with the url#branch source syntax
1487 g) the revision marked with the '@' bookmark, if present
1487 g) the revision marked with the '@' bookmark, if present
1488 h) the tipmost head of the default branch
1488 h) the tipmost head of the default branch
1489 i) tip
1489 i) tip
1490
1490
1491 When cloning from servers that support it, Mercurial may fetch
1491 When cloning from servers that support it, Mercurial may fetch
1492 pre-generated data from a server-advertised URL or inline from the
1492 pre-generated data from a server-advertised URL or inline from the
1493 same stream. When this is done, hooks operating on incoming changesets
1493 same stream. When this is done, hooks operating on incoming changesets
1494 and changegroups may fire more than once, once for each pre-generated
1494 and changegroups may fire more than once, once for each pre-generated
1495 bundle and as well as for any additional remaining data. In addition,
1495 bundle and as well as for any additional remaining data. In addition,
1496 if an error occurs, the repository may be rolled back to a partial
1496 if an error occurs, the repository may be rolled back to a partial
1497 clone. This behavior may change in future releases.
1497 clone. This behavior may change in future releases.
1498 See :hg:`help -e clonebundles` for more.
1498 See :hg:`help -e clonebundles` for more.
1499
1499
1500 Examples:
1500 Examples:
1501
1501
1502 - clone a remote repository to a new directory named hg/::
1502 - clone a remote repository to a new directory named hg/::
1503
1503
1504 hg clone https://www.mercurial-scm.org/repo/hg/
1504 hg clone https://www.mercurial-scm.org/repo/hg/
1505
1505
1506 - create a lightweight local clone::
1506 - create a lightweight local clone::
1507
1507
1508 hg clone project/ project-feature/
1508 hg clone project/ project-feature/
1509
1509
1510 - clone from an absolute path on an ssh server (note double-slash)::
1510 - clone from an absolute path on an ssh server (note double-slash)::
1511
1511
1512 hg clone ssh://user@server//home/projects/alpha/
1512 hg clone ssh://user@server//home/projects/alpha/
1513
1513
1514 - do a streaming clone while checking out a specified version::
1514 - do a streaming clone while checking out a specified version::
1515
1515
1516 hg clone --stream http://server/repo -u 1.5
1516 hg clone --stream http://server/repo -u 1.5
1517
1517
1518 - create a repository without changesets after a particular revision::
1518 - create a repository without changesets after a particular revision::
1519
1519
1520 hg clone -r 04e544 experimental/ good/
1520 hg clone -r 04e544 experimental/ good/
1521
1521
1522 - clone (and track) a particular named branch::
1522 - clone (and track) a particular named branch::
1523
1523
1524 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1524 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1525
1525
1526 See :hg:`help urls` for details on specifying URLs.
1526 See :hg:`help urls` for details on specifying URLs.
1527
1527
1528 Returns 0 on success.
1528 Returns 0 on success.
1529 """
1529 """
1530 opts = pycompat.byteskwargs(opts)
1530 opts = pycompat.byteskwargs(opts)
1531 if opts.get('noupdate') and opts.get('updaterev'):
1531 if opts.get('noupdate') and opts.get('updaterev'):
1532 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1532 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1533
1533
1534 # --include/--exclude can come from narrow or sparse.
1534 # --include/--exclude can come from narrow or sparse.
1535 includepats, excludepats = None, None
1535 includepats, excludepats = None, None
1536
1536
1537 # hg.clone() differentiates between None and an empty set. So make sure
1537 # hg.clone() differentiates between None and an empty set. So make sure
1538 # patterns are sets if narrow is requested without patterns.
1538 # patterns are sets if narrow is requested without patterns.
1539 if opts.get('narrow'):
1539 if opts.get('narrow'):
1540 includepats = set()
1540 includepats = set()
1541 excludepats = set()
1541 excludepats = set()
1542
1542
1543 if opts.get('include'):
1543 if opts.get('include'):
1544 includepats = narrowspec.parsepatterns(opts.get('include'))
1544 includepats = narrowspec.parsepatterns(opts.get('include'))
1545 if opts.get('exclude'):
1545 if opts.get('exclude'):
1546 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1546 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1547
1547
1548 r = hg.clone(ui, opts, source, dest,
1548 r = hg.clone(ui, opts, source, dest,
1549 pull=opts.get('pull'),
1549 pull=opts.get('pull'),
1550 stream=opts.get('stream') or opts.get('uncompressed'),
1550 stream=opts.get('stream') or opts.get('uncompressed'),
1551 revs=opts.get('rev'),
1551 revs=opts.get('rev'),
1552 update=opts.get('updaterev') or not opts.get('noupdate'),
1552 update=opts.get('updaterev') or not opts.get('noupdate'),
1553 branch=opts.get('branch'),
1553 branch=opts.get('branch'),
1554 shareopts=opts.get('shareopts'),
1554 shareopts=opts.get('shareopts'),
1555 storeincludepats=includepats,
1555 storeincludepats=includepats,
1556 storeexcludepats=excludepats,
1556 storeexcludepats=excludepats,
1557 depth=opts.get('depth') or None)
1557 depth=opts.get('depth') or None)
1558
1558
1559 return r is None
1559 return r is None
1560
1560
1561 @command('commit|ci',
1561 @command('commit|ci',
1562 [('A', 'addremove', None,
1562 [('A', 'addremove', None,
1563 _('mark new/missing files as added/removed before committing')),
1563 _('mark new/missing files as added/removed before committing')),
1564 ('', 'close-branch', None,
1564 ('', 'close-branch', None,
1565 _('mark a branch head as closed')),
1565 _('mark a branch head as closed')),
1566 ('', 'amend', None, _('amend the parent of the working directory')),
1566 ('', 'amend', None, _('amend the parent of the working directory')),
1567 ('s', 'secret', None, _('use the secret phase for committing')),
1567 ('s', 'secret', None, _('use the secret phase for committing')),
1568 ('e', 'edit', None, _('invoke editor on commit messages')),
1568 ('e', 'edit', None, _('invoke editor on commit messages')),
1569 ('i', 'interactive', None, _('use interactive mode')),
1569 ('i', 'interactive', None, _('use interactive mode')),
1570 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1570 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1571 _('[OPTION]... [FILE]...'),
1571 _('[OPTION]... [FILE]...'),
1572 helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
1572 helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
1573 inferrepo=True)
1573 inferrepo=True)
1574 def commit(ui, repo, *pats, **opts):
1574 def commit(ui, repo, *pats, **opts):
1575 """commit the specified files or all outstanding changes
1575 """commit the specified files or all outstanding changes
1576
1576
1577 Commit changes to the given files into the repository. Unlike a
1577 Commit changes to the given files into the repository. Unlike a
1578 centralized SCM, this operation is a local operation. See
1578 centralized SCM, this operation is a local operation. See
1579 :hg:`push` for a way to actively distribute your changes.
1579 :hg:`push` for a way to actively distribute your changes.
1580
1580
1581 If a list of files is omitted, all changes reported by :hg:`status`
1581 If a list of files is omitted, all changes reported by :hg:`status`
1582 will be committed.
1582 will be committed.
1583
1583
1584 If you are committing the result of a merge, do not provide any
1584 If you are committing the result of a merge, do not provide any
1585 filenames or -I/-X filters.
1585 filenames or -I/-X filters.
1586
1586
1587 If no commit message is specified, Mercurial starts your
1587 If no commit message is specified, Mercurial starts your
1588 configured editor where you can enter a message. In case your
1588 configured editor where you can enter a message. In case your
1589 commit fails, you will find a backup of your message in
1589 commit fails, you will find a backup of your message in
1590 ``.hg/last-message.txt``.
1590 ``.hg/last-message.txt``.
1591
1591
1592 The --close-branch flag can be used to mark the current branch
1592 The --close-branch flag can be used to mark the current branch
1593 head closed. When all heads of a branch are closed, the branch
1593 head closed. When all heads of a branch are closed, the branch
1594 will be considered closed and no longer listed.
1594 will be considered closed and no longer listed.
1595
1595
1596 The --amend flag can be used to amend the parent of the
1596 The --amend flag can be used to amend the parent of the
1597 working directory with a new commit that contains the changes
1597 working directory with a new commit that contains the changes
1598 in the parent in addition to those currently reported by :hg:`status`,
1598 in the parent in addition to those currently reported by :hg:`status`,
1599 if there are any. The old commit is stored in a backup bundle in
1599 if there are any. The old commit is stored in a backup bundle in
1600 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1600 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1601 on how to restore it).
1601 on how to restore it).
1602
1602
1603 Message, user and date are taken from the amended commit unless
1603 Message, user and date are taken from the amended commit unless
1604 specified. When a message isn't specified on the command line,
1604 specified. When a message isn't specified on the command line,
1605 the editor will open with the message of the amended commit.
1605 the editor will open with the message of the amended commit.
1606
1606
1607 It is not possible to amend public changesets (see :hg:`help phases`)
1607 It is not possible to amend public changesets (see :hg:`help phases`)
1608 or changesets that have children.
1608 or changesets that have children.
1609
1609
1610 See :hg:`help dates` for a list of formats valid for -d/--date.
1610 See :hg:`help dates` for a list of formats valid for -d/--date.
1611
1611
1612 Returns 0 on success, 1 if nothing changed.
1612 Returns 0 on success, 1 if nothing changed.
1613
1613
1614 .. container:: verbose
1614 .. container:: verbose
1615
1615
1616 Examples:
1616 Examples:
1617
1617
1618 - commit all files ending in .py::
1618 - commit all files ending in .py::
1619
1619
1620 hg commit --include "set:**.py"
1620 hg commit --include "set:**.py"
1621
1621
1622 - commit all non-binary files::
1622 - commit all non-binary files::
1623
1623
1624 hg commit --exclude "set:binary()"
1624 hg commit --exclude "set:binary()"
1625
1625
1626 - amend the current commit and set the date to now::
1626 - amend the current commit and set the date to now::
1627
1627
1628 hg commit --amend --date now
1628 hg commit --amend --date now
1629 """
1629 """
1630 with repo.wlock(), repo.lock():
1630 with repo.wlock(), repo.lock():
1631 return _docommit(ui, repo, *pats, **opts)
1631 return _docommit(ui, repo, *pats, **opts)
1632
1632
1633 def _docommit(ui, repo, *pats, **opts):
1633 def _docommit(ui, repo, *pats, **opts):
1634 if opts.get(r'interactive'):
1634 if opts.get(r'interactive'):
1635 opts.pop(r'interactive')
1635 opts.pop(r'interactive')
1636 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1636 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1637 cmdutil.recordfilter, *pats,
1637 cmdutil.recordfilter, *pats,
1638 **opts)
1638 **opts)
1639 # ret can be 0 (no changes to record) or the value returned by
1639 # ret can be 0 (no changes to record) or the value returned by
1640 # commit(), 1 if nothing changed or None on success.
1640 # commit(), 1 if nothing changed or None on success.
1641 return 1 if ret == 0 else ret
1641 return 1 if ret == 0 else ret
1642
1642
1643 opts = pycompat.byteskwargs(opts)
1643 opts = pycompat.byteskwargs(opts)
1644 if opts.get('subrepos'):
1644 if opts.get('subrepos'):
1645 if opts.get('amend'):
1645 if opts.get('amend'):
1646 raise error.Abort(_('cannot amend with --subrepos'))
1646 raise error.Abort(_('cannot amend with --subrepos'))
1647 # Let --subrepos on the command line override config setting.
1647 # Let --subrepos on the command line override config setting.
1648 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1648 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1649
1649
1650 cmdutil.checkunfinished(repo, commit=True)
1650 cmdutil.checkunfinished(repo, commit=True)
1651
1651
1652 branch = repo[None].branch()
1652 branch = repo[None].branch()
1653 bheads = repo.branchheads(branch)
1653 bheads = repo.branchheads(branch)
1654
1654
1655 extra = {}
1655 extra = {}
1656 if opts.get('close_branch'):
1656 if opts.get('close_branch'):
1657 extra['close'] = '1'
1657 extra['close'] = '1'
1658
1658
1659 if not bheads:
1659 if not bheads:
1660 raise error.Abort(_('can only close branch heads'))
1660 raise error.Abort(_('can only close branch heads'))
1661 elif opts.get('amend'):
1661 elif opts.get('amend'):
1662 if repo[None].parents()[0].p1().branch() != branch and \
1662 if repo[None].parents()[0].p1().branch() != branch and \
1663 repo[None].parents()[0].p2().branch() != branch:
1663 repo[None].parents()[0].p2().branch() != branch:
1664 raise error.Abort(_('can only close branch heads'))
1664 raise error.Abort(_('can only close branch heads'))
1665
1665
1666 if opts.get('amend'):
1666 if opts.get('amend'):
1667 if ui.configbool('ui', 'commitsubrepos'):
1667 if ui.configbool('ui', 'commitsubrepos'):
1668 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1668 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1669
1669
1670 old = repo['.']
1670 old = repo['.']
1671 rewriteutil.precheck(repo, [old.rev()], 'amend')
1671 rewriteutil.precheck(repo, [old.rev()], 'amend')
1672
1672
1673 # Currently histedit gets confused if an amend happens while histedit
1673 # Currently histedit gets confused if an amend happens while histedit
1674 # is in progress. Since we have a checkunfinished command, we are
1674 # is in progress. Since we have a checkunfinished command, we are
1675 # temporarily honoring it.
1675 # temporarily honoring it.
1676 #
1676 #
1677 # Note: eventually this guard will be removed. Please do not expect
1677 # Note: eventually this guard will be removed. Please do not expect
1678 # this behavior to remain.
1678 # this behavior to remain.
1679 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1679 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1680 cmdutil.checkunfinished(repo)
1680 cmdutil.checkunfinished(repo)
1681
1681
1682 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1682 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1683 if node == old.node():
1683 if node == old.node():
1684 ui.status(_("nothing changed\n"))
1684 ui.status(_("nothing changed\n"))
1685 return 1
1685 return 1
1686 else:
1686 else:
1687 def commitfunc(ui, repo, message, match, opts):
1687 def commitfunc(ui, repo, message, match, opts):
1688 overrides = {}
1688 overrides = {}
1689 if opts.get('secret'):
1689 if opts.get('secret'):
1690 overrides[('phases', 'new-commit')] = 'secret'
1690 overrides[('phases', 'new-commit')] = 'secret'
1691
1691
1692 baseui = repo.baseui
1692 baseui = repo.baseui
1693 with baseui.configoverride(overrides, 'commit'):
1693 with baseui.configoverride(overrides, 'commit'):
1694 with ui.configoverride(overrides, 'commit'):
1694 with ui.configoverride(overrides, 'commit'):
1695 editform = cmdutil.mergeeditform(repo[None],
1695 editform = cmdutil.mergeeditform(repo[None],
1696 'commit.normal')
1696 'commit.normal')
1697 editor = cmdutil.getcommiteditor(
1697 editor = cmdutil.getcommiteditor(
1698 editform=editform, **pycompat.strkwargs(opts))
1698 editform=editform, **pycompat.strkwargs(opts))
1699 return repo.commit(message,
1699 return repo.commit(message,
1700 opts.get('user'),
1700 opts.get('user'),
1701 opts.get('date'),
1701 opts.get('date'),
1702 match,
1702 match,
1703 editor=editor,
1703 editor=editor,
1704 extra=extra)
1704 extra=extra)
1705
1705
1706 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1706 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1707
1707
1708 if not node:
1708 if not node:
1709 stat = cmdutil.postcommitstatus(repo, pats, opts)
1709 stat = cmdutil.postcommitstatus(repo, pats, opts)
1710 if stat[3]:
1710 if stat[3]:
1711 ui.status(_("nothing changed (%d missing files, see "
1711 ui.status(_("nothing changed (%d missing files, see "
1712 "'hg status')\n") % len(stat[3]))
1712 "'hg status')\n") % len(stat[3]))
1713 else:
1713 else:
1714 ui.status(_("nothing changed\n"))
1714 ui.status(_("nothing changed\n"))
1715 return 1
1715 return 1
1716
1716
1717 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1717 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1718
1718
1719 @command('config|showconfig|debugconfig',
1719 @command('config|showconfig|debugconfig',
1720 [('u', 'untrusted', None, _('show untrusted configuration options')),
1720 [('u', 'untrusted', None, _('show untrusted configuration options')),
1721 ('e', 'edit', None, _('edit user config')),
1721 ('e', 'edit', None, _('edit user config')),
1722 ('l', 'local', None, _('edit repository config')),
1722 ('l', 'local', None, _('edit repository config')),
1723 ('g', 'global', None, _('edit global config'))] + formatteropts,
1723 ('g', 'global', None, _('edit global config'))] + formatteropts,
1724 _('[-u] [NAME]...'),
1724 _('[-u] [NAME]...'),
1725 helpcategory=command.CATEGORY_HELP,
1725 helpcategory=command.CATEGORY_HELP,
1726 optionalrepo=True,
1726 optionalrepo=True,
1727 intents={INTENT_READONLY})
1727 intents={INTENT_READONLY})
1728 def config(ui, repo, *values, **opts):
1728 def config(ui, repo, *values, **opts):
1729 """show combined config settings from all hgrc files
1729 """show combined config settings from all hgrc files
1730
1730
1731 With no arguments, print names and values of all config items.
1731 With no arguments, print names and values of all config items.
1732
1732
1733 With one argument of the form section.name, print just the value
1733 With one argument of the form section.name, print just the value
1734 of that config item.
1734 of that config item.
1735
1735
1736 With multiple arguments, print names and values of all config
1736 With multiple arguments, print names and values of all config
1737 items with matching section names or section.names.
1737 items with matching section names or section.names.
1738
1738
1739 With --edit, start an editor on the user-level config file. With
1739 With --edit, start an editor on the user-level config file. With
1740 --global, edit the system-wide config file. With --local, edit the
1740 --global, edit the system-wide config file. With --local, edit the
1741 repository-level config file.
1741 repository-level config file.
1742
1742
1743 With --debug, the source (filename and line number) is printed
1743 With --debug, the source (filename and line number) is printed
1744 for each config item.
1744 for each config item.
1745
1745
1746 See :hg:`help config` for more information about config files.
1746 See :hg:`help config` for more information about config files.
1747
1747
1748 .. container:: verbose
1748 .. container:: verbose
1749
1749
1750 Template:
1750 Template:
1751
1751
1752 The following keywords are supported. See also :hg:`help templates`.
1752 The following keywords are supported. See also :hg:`help templates`.
1753
1753
1754 :name: String. Config name.
1754 :name: String. Config name.
1755 :source: String. Filename and line number where the item is defined.
1755 :source: String. Filename and line number where the item is defined.
1756 :value: String. Config value.
1756 :value: String. Config value.
1757
1757
1758 Returns 0 on success, 1 if NAME does not exist.
1758 Returns 0 on success, 1 if NAME does not exist.
1759
1759
1760 """
1760 """
1761
1761
1762 opts = pycompat.byteskwargs(opts)
1762 opts = pycompat.byteskwargs(opts)
1763 if opts.get('edit') or opts.get('local') or opts.get('global'):
1763 if opts.get('edit') or opts.get('local') or opts.get('global'):
1764 if opts.get('local') and opts.get('global'):
1764 if opts.get('local') and opts.get('global'):
1765 raise error.Abort(_("can't use --local and --global together"))
1765 raise error.Abort(_("can't use --local and --global together"))
1766
1766
1767 if opts.get('local'):
1767 if opts.get('local'):
1768 if not repo:
1768 if not repo:
1769 raise error.Abort(_("can't use --local outside a repository"))
1769 raise error.Abort(_("can't use --local outside a repository"))
1770 paths = [repo.vfs.join('hgrc')]
1770 paths = [repo.vfs.join('hgrc')]
1771 elif opts.get('global'):
1771 elif opts.get('global'):
1772 paths = rcutil.systemrcpath()
1772 paths = rcutil.systemrcpath()
1773 else:
1773 else:
1774 paths = rcutil.userrcpath()
1774 paths = rcutil.userrcpath()
1775
1775
1776 for f in paths:
1776 for f in paths:
1777 if os.path.exists(f):
1777 if os.path.exists(f):
1778 break
1778 break
1779 else:
1779 else:
1780 if opts.get('global'):
1780 if opts.get('global'):
1781 samplehgrc = uimod.samplehgrcs['global']
1781 samplehgrc = uimod.samplehgrcs['global']
1782 elif opts.get('local'):
1782 elif opts.get('local'):
1783 samplehgrc = uimod.samplehgrcs['local']
1783 samplehgrc = uimod.samplehgrcs['local']
1784 else:
1784 else:
1785 samplehgrc = uimod.samplehgrcs['user']
1785 samplehgrc = uimod.samplehgrcs['user']
1786
1786
1787 f = paths[0]
1787 f = paths[0]
1788 fp = open(f, "wb")
1788 fp = open(f, "wb")
1789 fp.write(util.tonativeeol(samplehgrc))
1789 fp.write(util.tonativeeol(samplehgrc))
1790 fp.close()
1790 fp.close()
1791
1791
1792 editor = ui.geteditor()
1792 editor = ui.geteditor()
1793 ui.system("%s \"%s\"" % (editor, f),
1793 ui.system("%s \"%s\"" % (editor, f),
1794 onerr=error.Abort, errprefix=_("edit failed"),
1794 onerr=error.Abort, errprefix=_("edit failed"),
1795 blockedtag='config_edit')
1795 blockedtag='config_edit')
1796 return
1796 return
1797 ui.pager('config')
1797 ui.pager('config')
1798 fm = ui.formatter('config', opts)
1798 fm = ui.formatter('config', opts)
1799 for t, f in rcutil.rccomponents():
1799 for t, f in rcutil.rccomponents():
1800 if t == 'path':
1800 if t == 'path':
1801 ui.debug('read config from: %s\n' % f)
1801 ui.debug('read config from: %s\n' % f)
1802 elif t == 'items':
1802 elif t == 'items':
1803 for section, name, value, source in f:
1803 for section, name, value, source in f:
1804 ui.debug('set config by: %s\n' % source)
1804 ui.debug('set config by: %s\n' % source)
1805 else:
1805 else:
1806 raise error.ProgrammingError('unknown rctype: %s' % t)
1806 raise error.ProgrammingError('unknown rctype: %s' % t)
1807 untrusted = bool(opts.get('untrusted'))
1807 untrusted = bool(opts.get('untrusted'))
1808
1808
1809 selsections = selentries = []
1809 selsections = selentries = []
1810 if values:
1810 if values:
1811 selsections = [v for v in values if '.' not in v]
1811 selsections = [v for v in values if '.' not in v]
1812 selentries = [v for v in values if '.' in v]
1812 selentries = [v for v in values if '.' in v]
1813 uniquesel = (len(selentries) == 1 and not selsections)
1813 uniquesel = (len(selentries) == 1 and not selsections)
1814 selsections = set(selsections)
1814 selsections = set(selsections)
1815 selentries = set(selentries)
1815 selentries = set(selentries)
1816
1816
1817 matched = False
1817 matched = False
1818 for section, name, value in ui.walkconfig(untrusted=untrusted):
1818 for section, name, value in ui.walkconfig(untrusted=untrusted):
1819 source = ui.configsource(section, name, untrusted)
1819 source = ui.configsource(section, name, untrusted)
1820 value = pycompat.bytestr(value)
1820 value = pycompat.bytestr(value)
1821 if fm.isplain():
1821 if fm.isplain():
1822 source = source or 'none'
1822 source = source or 'none'
1823 value = value.replace('\n', '\\n')
1823 value = value.replace('\n', '\\n')
1824 entryname = section + '.' + name
1824 entryname = section + '.' + name
1825 if values and not (section in selsections or entryname in selentries):
1825 if values and not (section in selsections or entryname in selentries):
1826 continue
1826 continue
1827 fm.startitem()
1827 fm.startitem()
1828 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1828 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1829 if uniquesel:
1829 if uniquesel:
1830 fm.data(name=entryname)
1830 fm.data(name=entryname)
1831 fm.write('value', '%s\n', value)
1831 fm.write('value', '%s\n', value)
1832 else:
1832 else:
1833 fm.write('name value', '%s=%s\n', entryname, value)
1833 fm.write('name value', '%s=%s\n', entryname, value)
1834 matched = True
1834 matched = True
1835 fm.end()
1835 fm.end()
1836 if matched:
1836 if matched:
1837 return 0
1837 return 0
1838 return 1
1838 return 1
1839
1839
1840 @command('copy|cp',
1840 @command('copy|cp',
1841 [('A', 'after', None, _('record a copy that has already occurred')),
1841 [('A', 'after', None, _('record a copy that has already occurred')),
1842 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1842 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1843 ] + walkopts + dryrunopts,
1843 ] + walkopts + dryrunopts,
1844 _('[OPTION]... [SOURCE]... DEST'),
1844 _('[OPTION]... [SOURCE]... DEST'),
1845 helpcategory=command.CATEGORY_FILE_CONTENTS)
1845 helpcategory=command.CATEGORY_FILE_CONTENTS)
1846 def copy(ui, repo, *pats, **opts):
1846 def copy(ui, repo, *pats, **opts):
1847 """mark files as copied for the next commit
1847 """mark files as copied for the next commit
1848
1848
1849 Mark dest as having copies of source files. If dest is a
1849 Mark dest as having copies of source files. If dest is a
1850 directory, copies are put in that directory. If dest is a file,
1850 directory, copies are put in that directory. If dest is a file,
1851 the source must be a single file.
1851 the source must be a single file.
1852
1852
1853 By default, this command copies the contents of files as they
1853 By default, this command copies the contents of files as they
1854 exist in the working directory. If invoked with -A/--after, the
1854 exist in the working directory. If invoked with -A/--after, the
1855 operation is recorded, but no copying is performed.
1855 operation is recorded, but no copying is performed.
1856
1856
1857 This command takes effect with the next commit. To undo a copy
1857 This command takes effect with the next commit. To undo a copy
1858 before that, see :hg:`revert`.
1858 before that, see :hg:`revert`.
1859
1859
1860 Returns 0 on success, 1 if errors are encountered.
1860 Returns 0 on success, 1 if errors are encountered.
1861 """
1861 """
1862 opts = pycompat.byteskwargs(opts)
1862 opts = pycompat.byteskwargs(opts)
1863 with repo.wlock(False):
1863 with repo.wlock(False):
1864 return cmdutil.copy(ui, repo, pats, opts)
1864 return cmdutil.copy(ui, repo, pats, opts)
1865
1865
1866 @command(
1866 @command(
1867 'debugcommands', [], _('[COMMAND]'),
1867 'debugcommands', [], _('[COMMAND]'),
1868 helpcategory=command.CATEGORY_HELP,
1868 helpcategory=command.CATEGORY_HELP,
1869 norepo=True)
1869 norepo=True)
1870 def debugcommands(ui, cmd='', *args):
1870 def debugcommands(ui, cmd='', *args):
1871 """list all available commands and options"""
1871 """list all available commands and options"""
1872 for cmd, vals in sorted(table.iteritems()):
1872 for cmd, vals in sorted(table.iteritems()):
1873 cmd = cmd.split('|')[0]
1873 cmd = cmd.split('|')[0]
1874 opts = ', '.join([i[1] for i in vals[1]])
1874 opts = ', '.join([i[1] for i in vals[1]])
1875 ui.write('%s: %s\n' % (cmd, opts))
1875 ui.write('%s: %s\n' % (cmd, opts))
1876
1876
1877 @command('debugcomplete',
1877 @command('debugcomplete',
1878 [('o', 'options', None, _('show the command options'))],
1878 [('o', 'options', None, _('show the command options'))],
1879 _('[-o] CMD'),
1879 _('[-o] CMD'),
1880 helpcategory=command.CATEGORY_HELP,
1880 helpcategory=command.CATEGORY_HELP,
1881 norepo=True)
1881 norepo=True)
1882 def debugcomplete(ui, cmd='', **opts):
1882 def debugcomplete(ui, cmd='', **opts):
1883 """returns the completion list associated with the given command"""
1883 """returns the completion list associated with the given command"""
1884
1884
1885 if opts.get(r'options'):
1885 if opts.get(r'options'):
1886 options = []
1886 options = []
1887 otables = [globalopts]
1887 otables = [globalopts]
1888 if cmd:
1888 if cmd:
1889 aliases, entry = cmdutil.findcmd(cmd, table, False)
1889 aliases, entry = cmdutil.findcmd(cmd, table, False)
1890 otables.append(entry[1])
1890 otables.append(entry[1])
1891 for t in otables:
1891 for t in otables:
1892 for o in t:
1892 for o in t:
1893 if "(DEPRECATED)" in o[3]:
1893 if "(DEPRECATED)" in o[3]:
1894 continue
1894 continue
1895 if o[0]:
1895 if o[0]:
1896 options.append('-%s' % o[0])
1896 options.append('-%s' % o[0])
1897 options.append('--%s' % o[1])
1897 options.append('--%s' % o[1])
1898 ui.write("%s\n" % "\n".join(options))
1898 ui.write("%s\n" % "\n".join(options))
1899 return
1899 return
1900
1900
1901 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1901 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1902 if ui.verbose:
1902 if ui.verbose:
1903 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1903 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1904 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1904 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1905
1905
1906 @command('diff',
1906 @command('diff',
1907 [('r', 'rev', [], _('revision'), _('REV')),
1907 [('r', 'rev', [], _('revision'), _('REV')),
1908 ('c', 'change', '', _('change made by revision'), _('REV'))
1908 ('c', 'change', '', _('change made by revision'), _('REV'))
1909 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1909 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1910 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1910 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1911 helpcategory=command.CATEGORY_FILE_CONTENTS,
1911 helpcategory=command.CATEGORY_FILE_CONTENTS,
1912 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1912 helpbasic=True, inferrepo=True, intents={INTENT_READONLY})
1913 def diff(ui, repo, *pats, **opts):
1913 def diff(ui, repo, *pats, **opts):
1914 """diff repository (or selected files)
1914 """diff repository (or selected files)
1915
1915
1916 Show differences between revisions for the specified files.
1916 Show differences between revisions for the specified files.
1917
1917
1918 Differences between files are shown using the unified diff format.
1918 Differences between files are shown using the unified diff format.
1919
1919
1920 .. note::
1920 .. note::
1921
1921
1922 :hg:`diff` may generate unexpected results for merges, as it will
1922 :hg:`diff` may generate unexpected results for merges, as it will
1923 default to comparing against the working directory's first
1923 default to comparing against the working directory's first
1924 parent changeset if no revisions are specified.
1924 parent changeset if no revisions are specified.
1925
1925
1926 When two revision arguments are given, then changes are shown
1926 When two revision arguments are given, then changes are shown
1927 between those revisions. If only one revision is specified then
1927 between those revisions. If only one revision is specified then
1928 that revision is compared to the working directory, and, when no
1928 that revision is compared to the working directory, and, when no
1929 revisions are specified, the working directory files are compared
1929 revisions are specified, the working directory files are compared
1930 to its first parent.
1930 to its first parent.
1931
1931
1932 Alternatively you can specify -c/--change with a revision to see
1932 Alternatively you can specify -c/--change with a revision to see
1933 the changes in that changeset relative to its first parent.
1933 the changes in that changeset relative to its first parent.
1934
1934
1935 Without the -a/--text option, diff will avoid generating diffs of
1935 Without the -a/--text option, diff will avoid generating diffs of
1936 files it detects as binary. With -a, diff will generate a diff
1936 files it detects as binary. With -a, diff will generate a diff
1937 anyway, probably with undesirable results.
1937 anyway, probably with undesirable results.
1938
1938
1939 Use the -g/--git option to generate diffs in the git extended diff
1939 Use the -g/--git option to generate diffs in the git extended diff
1940 format. For more information, read :hg:`help diffs`.
1940 format. For more information, read :hg:`help diffs`.
1941
1941
1942 .. container:: verbose
1942 .. container:: verbose
1943
1943
1944 Examples:
1944 Examples:
1945
1945
1946 - compare a file in the current working directory to its parent::
1946 - compare a file in the current working directory to its parent::
1947
1947
1948 hg diff foo.c
1948 hg diff foo.c
1949
1949
1950 - compare two historical versions of a directory, with rename info::
1950 - compare two historical versions of a directory, with rename info::
1951
1951
1952 hg diff --git -r 1.0:1.2 lib/
1952 hg diff --git -r 1.0:1.2 lib/
1953
1953
1954 - get change stats relative to the last change on some date::
1954 - get change stats relative to the last change on some date::
1955
1955
1956 hg diff --stat -r "date('may 2')"
1956 hg diff --stat -r "date('may 2')"
1957
1957
1958 - diff all newly-added files that contain a keyword::
1958 - diff all newly-added files that contain a keyword::
1959
1959
1960 hg diff "set:added() and grep(GNU)"
1960 hg diff "set:added() and grep(GNU)"
1961
1961
1962 - compare a revision and its parents::
1962 - compare a revision and its parents::
1963
1963
1964 hg diff -c 9353 # compare against first parent
1964 hg diff -c 9353 # compare against first parent
1965 hg diff -r 9353^:9353 # same using revset syntax
1965 hg diff -r 9353^:9353 # same using revset syntax
1966 hg diff -r 9353^2:9353 # compare against the second parent
1966 hg diff -r 9353^2:9353 # compare against the second parent
1967
1967
1968 Returns 0 on success.
1968 Returns 0 on success.
1969 """
1969 """
1970
1970
1971 opts = pycompat.byteskwargs(opts)
1971 opts = pycompat.byteskwargs(opts)
1972 revs = opts.get('rev')
1972 revs = opts.get('rev')
1973 change = opts.get('change')
1973 change = opts.get('change')
1974 stat = opts.get('stat')
1974 stat = opts.get('stat')
1975 reverse = opts.get('reverse')
1975 reverse = opts.get('reverse')
1976
1976
1977 if revs and change:
1977 if revs and change:
1978 msg = _('cannot specify --rev and --change at the same time')
1978 msg = _('cannot specify --rev and --change at the same time')
1979 raise error.Abort(msg)
1979 raise error.Abort(msg)
1980 elif change:
1980 elif change:
1981 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1981 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1982 ctx2 = scmutil.revsingle(repo, change, None)
1982 ctx2 = scmutil.revsingle(repo, change, None)
1983 ctx1 = ctx2.p1()
1983 ctx1 = ctx2.p1()
1984 else:
1984 else:
1985 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1985 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1986 ctx1, ctx2 = scmutil.revpair(repo, revs)
1986 ctx1, ctx2 = scmutil.revpair(repo, revs)
1987 node1, node2 = ctx1.node(), ctx2.node()
1987 node1, node2 = ctx1.node(), ctx2.node()
1988
1988
1989 if reverse:
1989 if reverse:
1990 node1, node2 = node2, node1
1990 node1, node2 = node2, node1
1991
1991
1992 diffopts = patch.diffallopts(ui, opts)
1992 diffopts = patch.diffallopts(ui, opts)
1993 m = scmutil.match(ctx2, pats, opts)
1993 m = scmutil.match(ctx2, pats, opts)
1994 m = repo.narrowmatch(m)
1994 m = repo.narrowmatch(m)
1995 ui.pager('diff')
1995 ui.pager('diff')
1996 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1996 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1997 listsubrepos=opts.get('subrepos'),
1997 listsubrepos=opts.get('subrepos'),
1998 root=opts.get('root'))
1998 root=opts.get('root'))
1999
1999
2000 @command('export',
2000 @command('export',
2001 [('B', 'bookmark', '',
2001 [('B', 'bookmark', '',
2002 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2002 _('export changes only reachable by given bookmark'), _('BOOKMARK')),
2003 ('o', 'output', '',
2003 ('o', 'output', '',
2004 _('print output to file with formatted name'), _('FORMAT')),
2004 _('print output to file with formatted name'), _('FORMAT')),
2005 ('', 'switch-parent', None, _('diff against the second parent')),
2005 ('', 'switch-parent', None, _('diff against the second parent')),
2006 ('r', 'rev', [], _('revisions to export'), _('REV')),
2006 ('r', 'rev', [], _('revisions to export'), _('REV')),
2007 ] + diffopts + formatteropts,
2007 ] + diffopts + formatteropts,
2008 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2008 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2009 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2009 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2010 helpbasic=True, intents={INTENT_READONLY})
2010 helpbasic=True, intents={INTENT_READONLY})
2011 def export(ui, repo, *changesets, **opts):
2011 def export(ui, repo, *changesets, **opts):
2012 """dump the header and diffs for one or more changesets
2012 """dump the header and diffs for one or more changesets
2013
2013
2014 Print the changeset header and diffs for one or more revisions.
2014 Print the changeset header and diffs for one or more revisions.
2015 If no revision is given, the parent of the working directory is used.
2015 If no revision is given, the parent of the working directory is used.
2016
2016
2017 The information shown in the changeset header is: author, date,
2017 The information shown in the changeset header is: author, date,
2018 branch name (if non-default), changeset hash, parent(s) and commit
2018 branch name (if non-default), changeset hash, parent(s) and commit
2019 comment.
2019 comment.
2020
2020
2021 .. note::
2021 .. note::
2022
2022
2023 :hg:`export` may generate unexpected diff output for merge
2023 :hg:`export` may generate unexpected diff output for merge
2024 changesets, as it will compare the merge changeset against its
2024 changesets, as it will compare the merge changeset against its
2025 first parent only.
2025 first parent only.
2026
2026
2027 Output may be to a file, in which case the name of the file is
2027 Output may be to a file, in which case the name of the file is
2028 given using a template string. See :hg:`help templates`. In addition
2028 given using a template string. See :hg:`help templates`. In addition
2029 to the common template keywords, the following formatting rules are
2029 to the common template keywords, the following formatting rules are
2030 supported:
2030 supported:
2031
2031
2032 :``%%``: literal "%" character
2032 :``%%``: literal "%" character
2033 :``%H``: changeset hash (40 hexadecimal digits)
2033 :``%H``: changeset hash (40 hexadecimal digits)
2034 :``%N``: number of patches being generated
2034 :``%N``: number of patches being generated
2035 :``%R``: changeset revision number
2035 :``%R``: changeset revision number
2036 :``%b``: basename of the exporting repository
2036 :``%b``: basename of the exporting repository
2037 :``%h``: short-form changeset hash (12 hexadecimal digits)
2037 :``%h``: short-form changeset hash (12 hexadecimal digits)
2038 :``%m``: first line of the commit message (only alphanumeric characters)
2038 :``%m``: first line of the commit message (only alphanumeric characters)
2039 :``%n``: zero-padded sequence number, starting at 1
2039 :``%n``: zero-padded sequence number, starting at 1
2040 :``%r``: zero-padded changeset revision number
2040 :``%r``: zero-padded changeset revision number
2041 :``\\``: literal "\\" character
2041 :``\\``: literal "\\" character
2042
2042
2043 Without the -a/--text option, export will avoid generating diffs
2043 Without the -a/--text option, export will avoid generating diffs
2044 of files it detects as binary. With -a, export will generate a
2044 of files it detects as binary. With -a, export will generate a
2045 diff anyway, probably with undesirable results.
2045 diff anyway, probably with undesirable results.
2046
2046
2047 With -B/--bookmark changesets reachable by the given bookmark are
2047 With -B/--bookmark changesets reachable by the given bookmark are
2048 selected.
2048 selected.
2049
2049
2050 Use the -g/--git option to generate diffs in the git extended diff
2050 Use the -g/--git option to generate diffs in the git extended diff
2051 format. See :hg:`help diffs` for more information.
2051 format. See :hg:`help diffs` for more information.
2052
2052
2053 With the --switch-parent option, the diff will be against the
2053 With the --switch-parent option, the diff will be against the
2054 second parent. It can be useful to review a merge.
2054 second parent. It can be useful to review a merge.
2055
2055
2056 .. container:: verbose
2056 .. container:: verbose
2057
2057
2058 Template:
2058 Template:
2059
2059
2060 The following keywords are supported in addition to the common template
2060 The following keywords are supported in addition to the common template
2061 keywords and functions. See also :hg:`help templates`.
2061 keywords and functions. See also :hg:`help templates`.
2062
2062
2063 :diff: String. Diff content.
2063 :diff: String. Diff content.
2064 :parents: List of strings. Parent nodes of the changeset.
2064 :parents: List of strings. Parent nodes of the changeset.
2065
2065
2066 Examples:
2066 Examples:
2067
2067
2068 - use export and import to transplant a bugfix to the current
2068 - use export and import to transplant a bugfix to the current
2069 branch::
2069 branch::
2070
2070
2071 hg export -r 9353 | hg import -
2071 hg export -r 9353 | hg import -
2072
2072
2073 - export all the changesets between two revisions to a file with
2073 - export all the changesets between two revisions to a file with
2074 rename information::
2074 rename information::
2075
2075
2076 hg export --git -r 123:150 > changes.txt
2076 hg export --git -r 123:150 > changes.txt
2077
2077
2078 - split outgoing changes into a series of patches with
2078 - split outgoing changes into a series of patches with
2079 descriptive names::
2079 descriptive names::
2080
2080
2081 hg export -r "outgoing()" -o "%n-%m.patch"
2081 hg export -r "outgoing()" -o "%n-%m.patch"
2082
2082
2083 Returns 0 on success.
2083 Returns 0 on success.
2084 """
2084 """
2085 opts = pycompat.byteskwargs(opts)
2085 opts = pycompat.byteskwargs(opts)
2086 bookmark = opts.get('bookmark')
2086 bookmark = opts.get('bookmark')
2087 changesets += tuple(opts.get('rev', []))
2087 changesets += tuple(opts.get('rev', []))
2088
2088
2089 if bookmark and changesets:
2089 if bookmark and changesets:
2090 raise error.Abort(_("-r and -B are mutually exclusive"))
2090 raise error.Abort(_("-r and -B are mutually exclusive"))
2091
2091
2092 if bookmark:
2092 if bookmark:
2093 if bookmark not in repo._bookmarks:
2093 if bookmark not in repo._bookmarks:
2094 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2094 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2095
2095
2096 revs = scmutil.bookmarkrevs(repo, bookmark)
2096 revs = scmutil.bookmarkrevs(repo, bookmark)
2097 else:
2097 else:
2098 if not changesets:
2098 if not changesets:
2099 changesets = ['.']
2099 changesets = ['.']
2100
2100
2101 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2101 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2102 revs = scmutil.revrange(repo, changesets)
2102 revs = scmutil.revrange(repo, changesets)
2103
2103
2104 if not revs:
2104 if not revs:
2105 raise error.Abort(_("export requires at least one changeset"))
2105 raise error.Abort(_("export requires at least one changeset"))
2106 if len(revs) > 1:
2106 if len(revs) > 1:
2107 ui.note(_('exporting patches:\n'))
2107 ui.note(_('exporting patches:\n'))
2108 else:
2108 else:
2109 ui.note(_('exporting patch:\n'))
2109 ui.note(_('exporting patch:\n'))
2110
2110
2111 fntemplate = opts.get('output')
2111 fntemplate = opts.get('output')
2112 if cmdutil.isstdiofilename(fntemplate):
2112 if cmdutil.isstdiofilename(fntemplate):
2113 fntemplate = ''
2113 fntemplate = ''
2114
2114
2115 if fntemplate:
2115 if fntemplate:
2116 fm = formatter.nullformatter(ui, 'export', opts)
2116 fm = formatter.nullformatter(ui, 'export', opts)
2117 else:
2117 else:
2118 ui.pager('export')
2118 ui.pager('export')
2119 fm = ui.formatter('export', opts)
2119 fm = ui.formatter('export', opts)
2120 with fm:
2120 with fm:
2121 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2121 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2122 switch_parent=opts.get('switch_parent'),
2122 switch_parent=opts.get('switch_parent'),
2123 opts=patch.diffallopts(ui, opts))
2123 opts=patch.diffallopts(ui, opts))
2124
2124
2125 @command('files',
2125 @command('files',
2126 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2126 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2127 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2127 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2128 ] + walkopts + formatteropts + subrepoopts,
2128 ] + walkopts + formatteropts + subrepoopts,
2129 _('[OPTION]... [FILE]...'),
2129 _('[OPTION]... [FILE]...'),
2130 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2130 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2131 intents={INTENT_READONLY})
2131 intents={INTENT_READONLY})
2132 def files(ui, repo, *pats, **opts):
2132 def files(ui, repo, *pats, **opts):
2133 """list tracked files
2133 """list tracked files
2134
2134
2135 Print files under Mercurial control in the working directory or
2135 Print files under Mercurial control in the working directory or
2136 specified revision for given files (excluding removed files).
2136 specified revision for given files (excluding removed files).
2137 Files can be specified as filenames or filesets.
2137 Files can be specified as filenames or filesets.
2138
2138
2139 If no files are given to match, this command prints the names
2139 If no files are given to match, this command prints the names
2140 of all files under Mercurial control.
2140 of all files under Mercurial control.
2141
2141
2142 .. container:: verbose
2142 .. container:: verbose
2143
2143
2144 Template:
2144 Template:
2145
2145
2146 The following keywords are supported in addition to the common template
2146 The following keywords are supported in addition to the common template
2147 keywords and functions. See also :hg:`help templates`.
2147 keywords and functions. See also :hg:`help templates`.
2148
2148
2149 :flags: String. Character denoting file's symlink and executable bits.
2149 :flags: String. Character denoting file's symlink and executable bits.
2150 :path: String. Repository-absolute path of the file.
2150 :path: String. Repository-absolute path of the file.
2151 :size: Integer. Size of the file in bytes.
2151 :size: Integer. Size of the file in bytes.
2152
2152
2153 Examples:
2153 Examples:
2154
2154
2155 - list all files under the current directory::
2155 - list all files under the current directory::
2156
2156
2157 hg files .
2157 hg files .
2158
2158
2159 - shows sizes and flags for current revision::
2159 - shows sizes and flags for current revision::
2160
2160
2161 hg files -vr .
2161 hg files -vr .
2162
2162
2163 - list all files named README::
2163 - list all files named README::
2164
2164
2165 hg files -I "**/README"
2165 hg files -I "**/README"
2166
2166
2167 - list all binary files::
2167 - list all binary files::
2168
2168
2169 hg files "set:binary()"
2169 hg files "set:binary()"
2170
2170
2171 - find files containing a regular expression::
2171 - find files containing a regular expression::
2172
2172
2173 hg files "set:grep('bob')"
2173 hg files "set:grep('bob')"
2174
2174
2175 - search tracked file contents with xargs and grep::
2175 - search tracked file contents with xargs and grep::
2176
2176
2177 hg files -0 | xargs -0 grep foo
2177 hg files -0 | xargs -0 grep foo
2178
2178
2179 See :hg:`help patterns` and :hg:`help filesets` for more information
2179 See :hg:`help patterns` and :hg:`help filesets` for more information
2180 on specifying file patterns.
2180 on specifying file patterns.
2181
2181
2182 Returns 0 if a match is found, 1 otherwise.
2182 Returns 0 if a match is found, 1 otherwise.
2183
2183
2184 """
2184 """
2185
2185
2186 opts = pycompat.byteskwargs(opts)
2186 opts = pycompat.byteskwargs(opts)
2187 rev = opts.get('rev')
2187 rev = opts.get('rev')
2188 if rev:
2188 if rev:
2189 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2189 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2190 ctx = scmutil.revsingle(repo, rev, None)
2190 ctx = scmutil.revsingle(repo, rev, None)
2191
2191
2192 end = '\n'
2192 end = '\n'
2193 if opts.get('print0'):
2193 if opts.get('print0'):
2194 end = '\0'
2194 end = '\0'
2195 fmt = '%s' + end
2195 fmt = '%s' + end
2196
2196
2197 m = scmutil.match(ctx, pats, opts)
2197 m = scmutil.match(ctx, pats, opts)
2198 ui.pager('files')
2198 ui.pager('files')
2199 with ui.formatter('files', opts) as fm:
2199 with ui.formatter('files', opts) as fm:
2200 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2200 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2201
2201
2202 @command(
2202 @command(
2203 'forget',
2203 'forget',
2204 [('i', 'interactive', None, _('use interactive mode')),
2204 [('i', 'interactive', None, _('use interactive mode')),
2205 ] + walkopts + dryrunopts,
2205 ] + walkopts + dryrunopts,
2206 _('[OPTION]... FILE...'),
2206 _('[OPTION]... FILE...'),
2207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2207 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2208 helpbasic=True, inferrepo=True)
2208 helpbasic=True, inferrepo=True)
2209 def forget(ui, repo, *pats, **opts):
2209 def forget(ui, repo, *pats, **opts):
2210 """forget the specified files on the next commit
2210 """forget the specified files on the next commit
2211
2211
2212 Mark the specified files so they will no longer be tracked
2212 Mark the specified files so they will no longer be tracked
2213 after the next commit.
2213 after the next commit.
2214
2214
2215 This only removes files from the current branch, not from the
2215 This only removes files from the current branch, not from the
2216 entire project history, and it does not delete them from the
2216 entire project history, and it does not delete them from the
2217 working directory.
2217 working directory.
2218
2218
2219 To delete the file from the working directory, see :hg:`remove`.
2219 To delete the file from the working directory, see :hg:`remove`.
2220
2220
2221 To undo a forget before the next commit, see :hg:`add`.
2221 To undo a forget before the next commit, see :hg:`add`.
2222
2222
2223 .. container:: verbose
2223 .. container:: verbose
2224
2224
2225 Examples:
2225 Examples:
2226
2226
2227 - forget newly-added binary files::
2227 - forget newly-added binary files::
2228
2228
2229 hg forget "set:added() and binary()"
2229 hg forget "set:added() and binary()"
2230
2230
2231 - forget files that would be excluded by .hgignore::
2231 - forget files that would be excluded by .hgignore::
2232
2232
2233 hg forget "set:hgignore()"
2233 hg forget "set:hgignore()"
2234
2234
2235 Returns 0 on success.
2235 Returns 0 on success.
2236 """
2236 """
2237
2237
2238 opts = pycompat.byteskwargs(opts)
2238 opts = pycompat.byteskwargs(opts)
2239 if not pats:
2239 if not pats:
2240 raise error.Abort(_('no files specified'))
2240 raise error.Abort(_('no files specified'))
2241
2241
2242 m = scmutil.match(repo[None], pats, opts)
2242 m = scmutil.match(repo[None], pats, opts)
2243 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2243 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2244 rejected = cmdutil.forget(ui, repo, m, prefix="",
2244 rejected = cmdutil.forget(ui, repo, m, prefix="",
2245 explicitonly=False, dryrun=dryrun,
2245 explicitonly=False, dryrun=dryrun,
2246 interactive=interactive)[0]
2246 interactive=interactive)[0]
2247 return rejected and 1 or 0
2247 return rejected and 1 or 0
2248
2248
2249 @command(
2249 @command(
2250 'graft',
2250 'graft',
2251 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2251 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2252 ('c', 'continue', False, _('resume interrupted graft')),
2252 ('c', 'continue', False, _('resume interrupted graft')),
2253 ('', 'stop', False, _('stop interrupted graft')),
2253 ('', 'stop', False, _('stop interrupted graft')),
2254 ('', 'abort', False, _('abort interrupted graft')),
2254 ('', 'abort', False, _('abort interrupted graft')),
2255 ('e', 'edit', False, _('invoke editor on commit messages')),
2255 ('e', 'edit', False, _('invoke editor on commit messages')),
2256 ('', 'log', None, _('append graft info to log message')),
2256 ('', 'log', None, _('append graft info to log message')),
2257 ('', 'no-commit', None,
2257 ('', 'no-commit', None,
2258 _("don't commit, just apply the changes in working directory")),
2258 _("don't commit, just apply the changes in working directory")),
2259 ('f', 'force', False, _('force graft')),
2259 ('f', 'force', False, _('force graft')),
2260 ('D', 'currentdate', False,
2260 ('D', 'currentdate', False,
2261 _('record the current date as commit date')),
2261 _('record the current date as commit date')),
2262 ('U', 'currentuser', False,
2262 ('U', 'currentuser', False,
2263 _('record the current user as committer'))]
2263 _('record the current user as committer'))]
2264 + commitopts2 + mergetoolopts + dryrunopts,
2264 + commitopts2 + mergetoolopts + dryrunopts,
2265 _('[OPTION]... [-r REV]... REV...'),
2265 _('[OPTION]... [-r REV]... REV...'),
2266 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2266 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
2267 def graft(ui, repo, *revs, **opts):
2267 def graft(ui, repo, *revs, **opts):
2268 '''copy changes from other branches onto the current branch
2268 '''copy changes from other branches onto the current branch
2269
2269
2270 This command uses Mercurial's merge logic to copy individual
2270 This command uses Mercurial's merge logic to copy individual
2271 changes from other branches without merging branches in the
2271 changes from other branches without merging branches in the
2272 history graph. This is sometimes known as 'backporting' or
2272 history graph. This is sometimes known as 'backporting' or
2273 'cherry-picking'. By default, graft will copy user, date, and
2273 'cherry-picking'. By default, graft will copy user, date, and
2274 description from the source changesets.
2274 description from the source changesets.
2275
2275
2276 Changesets that are ancestors of the current revision, that have
2276 Changesets that are ancestors of the current revision, that have
2277 already been grafted, or that are merges will be skipped.
2277 already been grafted, or that are merges will be skipped.
2278
2278
2279 If --log is specified, log messages will have a comment appended
2279 If --log is specified, log messages will have a comment appended
2280 of the form::
2280 of the form::
2281
2281
2282 (grafted from CHANGESETHASH)
2282 (grafted from CHANGESETHASH)
2283
2283
2284 If --force is specified, revisions will be grafted even if they
2284 If --force is specified, revisions will be grafted even if they
2285 are already ancestors of, or have been grafted to, the destination.
2285 are already ancestors of, or have been grafted to, the destination.
2286 This is useful when the revisions have since been backed out.
2286 This is useful when the revisions have since been backed out.
2287
2287
2288 If a graft merge results in conflicts, the graft process is
2288 If a graft merge results in conflicts, the graft process is
2289 interrupted so that the current merge can be manually resolved.
2289 interrupted so that the current merge can be manually resolved.
2290 Once all conflicts are addressed, the graft process can be
2290 Once all conflicts are addressed, the graft process can be
2291 continued with the -c/--continue option.
2291 continued with the -c/--continue option.
2292
2292
2293 The -c/--continue option reapplies all the earlier options.
2293 The -c/--continue option reapplies all the earlier options.
2294
2294
2295 .. container:: verbose
2295 .. container:: verbose
2296
2296
2297 Examples:
2297 Examples:
2298
2298
2299 - copy a single change to the stable branch and edit its description::
2299 - copy a single change to the stable branch and edit its description::
2300
2300
2301 hg update stable
2301 hg update stable
2302 hg graft --edit 9393
2302 hg graft --edit 9393
2303
2303
2304 - graft a range of changesets with one exception, updating dates::
2304 - graft a range of changesets with one exception, updating dates::
2305
2305
2306 hg graft -D "2085::2093 and not 2091"
2306 hg graft -D "2085::2093 and not 2091"
2307
2307
2308 - continue a graft after resolving conflicts::
2308 - continue a graft after resolving conflicts::
2309
2309
2310 hg graft -c
2310 hg graft -c
2311
2311
2312 - show the source of a grafted changeset::
2312 - show the source of a grafted changeset::
2313
2313
2314 hg log --debug -r .
2314 hg log --debug -r .
2315
2315
2316 - show revisions sorted by date::
2316 - show revisions sorted by date::
2317
2317
2318 hg log -r "sort(all(), date)"
2318 hg log -r "sort(all(), date)"
2319
2319
2320 See :hg:`help revisions` for more about specifying revisions.
2320 See :hg:`help revisions` for more about specifying revisions.
2321
2321
2322 Returns 0 on successful completion.
2322 Returns 0 on successful completion.
2323 '''
2323 '''
2324 with repo.wlock():
2324 with repo.wlock():
2325 return _dograft(ui, repo, *revs, **opts)
2325 return _dograft(ui, repo, *revs, **opts)
2326
2326
2327 def _dograft(ui, repo, *revs, **opts):
2327 def _dograft(ui, repo, *revs, **opts):
2328 opts = pycompat.byteskwargs(opts)
2328 opts = pycompat.byteskwargs(opts)
2329 if revs and opts.get('rev'):
2329 if revs and opts.get('rev'):
2330 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2330 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2331 'revision ordering!\n'))
2331 'revision ordering!\n'))
2332
2332
2333 revs = list(revs)
2333 revs = list(revs)
2334 revs.extend(opts.get('rev'))
2334 revs.extend(opts.get('rev'))
2335 # a dict of data to be stored in state file
2335 # a dict of data to be stored in state file
2336 statedata = {}
2336 statedata = {}
2337 # list of new nodes created by ongoing graft
2337 # list of new nodes created by ongoing graft
2338 statedata['newnodes'] = []
2338 statedata['newnodes'] = []
2339
2339
2340 if not opts.get('user') and opts.get('currentuser'):
2340 if not opts.get('user') and opts.get('currentuser'):
2341 opts['user'] = ui.username()
2341 opts['user'] = ui.username()
2342 if not opts.get('date') and opts.get('currentdate'):
2342 if not opts.get('date') and opts.get('currentdate'):
2343 opts['date'] = "%d %d" % dateutil.makedate()
2343 opts['date'] = "%d %d" % dateutil.makedate()
2344
2344
2345 editor = cmdutil.getcommiteditor(editform='graft',
2345 editor = cmdutil.getcommiteditor(editform='graft',
2346 **pycompat.strkwargs(opts))
2346 **pycompat.strkwargs(opts))
2347
2347
2348 cont = False
2348 cont = False
2349 if opts.get('no_commit'):
2349 if opts.get('no_commit'):
2350 if opts.get('edit'):
2350 if opts.get('edit'):
2351 raise error.Abort(_("cannot specify --no-commit and "
2351 raise error.Abort(_("cannot specify --no-commit and "
2352 "--edit together"))
2352 "--edit together"))
2353 if opts.get('currentuser'):
2353 if opts.get('currentuser'):
2354 raise error.Abort(_("cannot specify --no-commit and "
2354 raise error.Abort(_("cannot specify --no-commit and "
2355 "--currentuser together"))
2355 "--currentuser together"))
2356 if opts.get('currentdate'):
2356 if opts.get('currentdate'):
2357 raise error.Abort(_("cannot specify --no-commit and "
2357 raise error.Abort(_("cannot specify --no-commit and "
2358 "--currentdate together"))
2358 "--currentdate together"))
2359 if opts.get('log'):
2359 if opts.get('log'):
2360 raise error.Abort(_("cannot specify --no-commit and "
2360 raise error.Abort(_("cannot specify --no-commit and "
2361 "--log together"))
2361 "--log together"))
2362
2362
2363 graftstate = statemod.cmdstate(repo, 'graftstate')
2363 graftstate = statemod.cmdstate(repo, 'graftstate')
2364
2364
2365 if opts.get('stop'):
2365 if opts.get('stop'):
2366 if opts.get('continue'):
2366 if opts.get('continue'):
2367 raise error.Abort(_("cannot use '--continue' and "
2367 raise error.Abort(_("cannot use '--continue' and "
2368 "'--stop' together"))
2368 "'--stop' together"))
2369 if opts.get('abort'):
2369 if opts.get('abort'):
2370 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2370 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2371
2371
2372 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2372 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2373 opts.get('date'), opts.get('currentdate'),
2373 opts.get('date'), opts.get('currentdate'),
2374 opts.get('currentuser'), opts.get('rev'))):
2374 opts.get('currentuser'), opts.get('rev'))):
2375 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2375 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2376 return _stopgraft(ui, repo, graftstate)
2376 return _stopgraft(ui, repo, graftstate)
2377 elif opts.get('abort'):
2377 elif opts.get('abort'):
2378 if opts.get('continue'):
2378 if opts.get('continue'):
2379 raise error.Abort(_("cannot use '--continue' and "
2379 raise error.Abort(_("cannot use '--continue' and "
2380 "'--abort' together"))
2380 "'--abort' together"))
2381 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2381 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2382 opts.get('date'), opts.get('currentdate'),
2382 opts.get('date'), opts.get('currentdate'),
2383 opts.get('currentuser'), opts.get('rev'))):
2383 opts.get('currentuser'), opts.get('rev'))):
2384 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2384 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2385
2385
2386 return _abortgraft(ui, repo, graftstate)
2386 return _abortgraft(ui, repo, graftstate)
2387 elif opts.get('continue'):
2387 elif opts.get('continue'):
2388 cont = True
2388 cont = True
2389 if revs:
2389 if revs:
2390 raise error.Abort(_("can't specify --continue and revisions"))
2390 raise error.Abort(_("can't specify --continue and revisions"))
2391 # read in unfinished revisions
2391 # read in unfinished revisions
2392 if graftstate.exists():
2392 if graftstate.exists():
2393 statedata = _readgraftstate(repo, graftstate)
2393 statedata = _readgraftstate(repo, graftstate)
2394 if statedata.get('date'):
2394 if statedata.get('date'):
2395 opts['date'] = statedata['date']
2395 opts['date'] = statedata['date']
2396 if statedata.get('user'):
2396 if statedata.get('user'):
2397 opts['user'] = statedata['user']
2397 opts['user'] = statedata['user']
2398 if statedata.get('log'):
2398 if statedata.get('log'):
2399 opts['log'] = True
2399 opts['log'] = True
2400 if statedata.get('no_commit'):
2400 if statedata.get('no_commit'):
2401 opts['no_commit'] = statedata.get('no_commit')
2401 opts['no_commit'] = statedata.get('no_commit')
2402 nodes = statedata['nodes']
2402 nodes = statedata['nodes']
2403 revs = [repo[node].rev() for node in nodes]
2403 revs = [repo[node].rev() for node in nodes]
2404 else:
2404 else:
2405 cmdutil.wrongtooltocontinue(repo, _('graft'))
2405 cmdutil.wrongtooltocontinue(repo, _('graft'))
2406 else:
2406 else:
2407 if not revs:
2407 if not revs:
2408 raise error.Abort(_('no revisions specified'))
2408 raise error.Abort(_('no revisions specified'))
2409 cmdutil.checkunfinished(repo)
2409 cmdutil.checkunfinished(repo)
2410 cmdutil.bailifchanged(repo)
2410 cmdutil.bailifchanged(repo)
2411 revs = scmutil.revrange(repo, revs)
2411 revs = scmutil.revrange(repo, revs)
2412
2412
2413 skipped = set()
2413 skipped = set()
2414 # check for merges
2414 # check for merges
2415 for rev in repo.revs('%ld and merge()', revs):
2415 for rev in repo.revs('%ld and merge()', revs):
2416 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2416 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2417 skipped.add(rev)
2417 skipped.add(rev)
2418 revs = [r for r in revs if r not in skipped]
2418 revs = [r for r in revs if r not in skipped]
2419 if not revs:
2419 if not revs:
2420 return -1
2420 return -1
2421
2421
2422 # Don't check in the --continue case, in effect retaining --force across
2422 # Don't check in the --continue case, in effect retaining --force across
2423 # --continues. That's because without --force, any revisions we decided to
2423 # --continues. That's because without --force, any revisions we decided to
2424 # skip would have been filtered out here, so they wouldn't have made their
2424 # skip would have been filtered out here, so they wouldn't have made their
2425 # way to the graftstate. With --force, any revisions we would have otherwise
2425 # way to the graftstate. With --force, any revisions we would have otherwise
2426 # skipped would not have been filtered out, and if they hadn't been applied
2426 # skipped would not have been filtered out, and if they hadn't been applied
2427 # already, they'd have been in the graftstate.
2427 # already, they'd have been in the graftstate.
2428 if not (cont or opts.get('force')):
2428 if not (cont or opts.get('force')):
2429 # check for ancestors of dest branch
2429 # check for ancestors of dest branch
2430 crev = repo['.'].rev()
2430 crev = repo['.'].rev()
2431 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2431 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2432 # XXX make this lazy in the future
2432 # XXX make this lazy in the future
2433 # don't mutate while iterating, create a copy
2433 # don't mutate while iterating, create a copy
2434 for rev in list(revs):
2434 for rev in list(revs):
2435 if rev in ancestors:
2435 if rev in ancestors:
2436 ui.warn(_('skipping ancestor revision %d:%s\n') %
2436 ui.warn(_('skipping ancestor revision %d:%s\n') %
2437 (rev, repo[rev]))
2437 (rev, repo[rev]))
2438 # XXX remove on list is slow
2438 # XXX remove on list is slow
2439 revs.remove(rev)
2439 revs.remove(rev)
2440 if not revs:
2440 if not revs:
2441 return -1
2441 return -1
2442
2442
2443 # analyze revs for earlier grafts
2443 # analyze revs for earlier grafts
2444 ids = {}
2444 ids = {}
2445 for ctx in repo.set("%ld", revs):
2445 for ctx in repo.set("%ld", revs):
2446 ids[ctx.hex()] = ctx.rev()
2446 ids[ctx.hex()] = ctx.rev()
2447 n = ctx.extra().get('source')
2447 n = ctx.extra().get('source')
2448 if n:
2448 if n:
2449 ids[n] = ctx.rev()
2449 ids[n] = ctx.rev()
2450
2450
2451 # check ancestors for earlier grafts
2451 # check ancestors for earlier grafts
2452 ui.debug('scanning for duplicate grafts\n')
2452 ui.debug('scanning for duplicate grafts\n')
2453
2453
2454 # The only changesets we can be sure doesn't contain grafts of any
2454 # The only changesets we can be sure doesn't contain grafts of any
2455 # revs, are the ones that are common ancestors of *all* revs:
2455 # revs, are the ones that are common ancestors of *all* revs:
2456 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2456 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2457 ctx = repo[rev]
2457 ctx = repo[rev]
2458 n = ctx.extra().get('source')
2458 n = ctx.extra().get('source')
2459 if n in ids:
2459 if n in ids:
2460 try:
2460 try:
2461 r = repo[n].rev()
2461 r = repo[n].rev()
2462 except error.RepoLookupError:
2462 except error.RepoLookupError:
2463 r = None
2463 r = None
2464 if r in revs:
2464 if r in revs:
2465 ui.warn(_('skipping revision %d:%s '
2465 ui.warn(_('skipping revision %d:%s '
2466 '(already grafted to %d:%s)\n')
2466 '(already grafted to %d:%s)\n')
2467 % (r, repo[r], rev, ctx))
2467 % (r, repo[r], rev, ctx))
2468 revs.remove(r)
2468 revs.remove(r)
2469 elif ids[n] in revs:
2469 elif ids[n] in revs:
2470 if r is None:
2470 if r is None:
2471 ui.warn(_('skipping already grafted revision %d:%s '
2471 ui.warn(_('skipping already grafted revision %d:%s '
2472 '(%d:%s also has unknown origin %s)\n')
2472 '(%d:%s also has unknown origin %s)\n')
2473 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2473 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2474 else:
2474 else:
2475 ui.warn(_('skipping already grafted revision %d:%s '
2475 ui.warn(_('skipping already grafted revision %d:%s '
2476 '(%d:%s also has origin %d:%s)\n')
2476 '(%d:%s also has origin %d:%s)\n')
2477 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2477 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2478 revs.remove(ids[n])
2478 revs.remove(ids[n])
2479 elif ctx.hex() in ids:
2479 elif ctx.hex() in ids:
2480 r = ids[ctx.hex()]
2480 r = ids[ctx.hex()]
2481 ui.warn(_('skipping already grafted revision %d:%s '
2481 ui.warn(_('skipping already grafted revision %d:%s '
2482 '(was grafted from %d:%s)\n') %
2482 '(was grafted from %d:%s)\n') %
2483 (r, repo[r], rev, ctx))
2483 (r, repo[r], rev, ctx))
2484 revs.remove(r)
2484 revs.remove(r)
2485 if not revs:
2485 if not revs:
2486 return -1
2486 return -1
2487
2487
2488 if opts.get('no_commit'):
2488 if opts.get('no_commit'):
2489 statedata['no_commit'] = True
2489 statedata['no_commit'] = True
2490 for pos, ctx in enumerate(repo.set("%ld", revs)):
2490 for pos, ctx in enumerate(repo.set("%ld", revs)):
2491 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2491 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2492 ctx.description().split('\n', 1)[0])
2492 ctx.description().split('\n', 1)[0])
2493 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2493 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2494 if names:
2494 if names:
2495 desc += ' (%s)' % ' '.join(names)
2495 desc += ' (%s)' % ' '.join(names)
2496 ui.status(_('grafting %s\n') % desc)
2496 ui.status(_('grafting %s\n') % desc)
2497 if opts.get('dry_run'):
2497 if opts.get('dry_run'):
2498 continue
2498 continue
2499
2499
2500 source = ctx.extra().get('source')
2500 source = ctx.extra().get('source')
2501 extra = {}
2501 extra = {}
2502 if source:
2502 if source:
2503 extra['source'] = source
2503 extra['source'] = source
2504 extra['intermediate-source'] = ctx.hex()
2504 extra['intermediate-source'] = ctx.hex()
2505 else:
2505 else:
2506 extra['source'] = ctx.hex()
2506 extra['source'] = ctx.hex()
2507 user = ctx.user()
2507 user = ctx.user()
2508 if opts.get('user'):
2508 if opts.get('user'):
2509 user = opts['user']
2509 user = opts['user']
2510 statedata['user'] = user
2510 statedata['user'] = user
2511 date = ctx.date()
2511 date = ctx.date()
2512 if opts.get('date'):
2512 if opts.get('date'):
2513 date = opts['date']
2513 date = opts['date']
2514 statedata['date'] = date
2514 statedata['date'] = date
2515 message = ctx.description()
2515 message = ctx.description()
2516 if opts.get('log'):
2516 if opts.get('log'):
2517 message += '\n(grafted from %s)' % ctx.hex()
2517 message += '\n(grafted from %s)' % ctx.hex()
2518 statedata['log'] = True
2518 statedata['log'] = True
2519
2519
2520 # we don't merge the first commit when continuing
2520 # we don't merge the first commit when continuing
2521 if not cont:
2521 if not cont:
2522 # perform the graft merge with p1(rev) as 'ancestor'
2522 # perform the graft merge with p1(rev) as 'ancestor'
2523 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2523 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2524 with ui.configoverride(overrides, 'graft'):
2524 with ui.configoverride(overrides, 'graft'):
2525 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2525 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2526 # report any conflicts
2526 # report any conflicts
2527 if stats.unresolvedcount > 0:
2527 if stats.unresolvedcount > 0:
2528 # write out state for --continue
2528 # write out state for --continue
2529 nodes = [repo[rev].hex() for rev in revs[pos:]]
2529 nodes = [repo[rev].hex() for rev in revs[pos:]]
2530 statedata['nodes'] = nodes
2530 statedata['nodes'] = nodes
2531 stateversion = 1
2531 stateversion = 1
2532 graftstate.save(stateversion, statedata)
2532 graftstate.save(stateversion, statedata)
2533 hint = _("use 'hg resolve' and 'hg graft --continue'")
2533 hint = _("use 'hg resolve' and 'hg graft --continue'")
2534 raise error.Abort(
2534 raise error.Abort(
2535 _("unresolved conflicts, can't continue"),
2535 _("unresolved conflicts, can't continue"),
2536 hint=hint)
2536 hint=hint)
2537 else:
2537 else:
2538 cont = False
2538 cont = False
2539
2539
2540 # commit if --no-commit is false
2540 # commit if --no-commit is false
2541 if not opts.get('no_commit'):
2541 if not opts.get('no_commit'):
2542 node = repo.commit(text=message, user=user, date=date, extra=extra,
2542 node = repo.commit(text=message, user=user, date=date, extra=extra,
2543 editor=editor)
2543 editor=editor)
2544 if node is None:
2544 if node is None:
2545 ui.warn(
2545 ui.warn(
2546 _('note: graft of %d:%s created no changes to commit\n') %
2546 _('note: graft of %d:%s created no changes to commit\n') %
2547 (ctx.rev(), ctx))
2547 (ctx.rev(), ctx))
2548 # checking that newnodes exist because old state files won't have it
2548 # checking that newnodes exist because old state files won't have it
2549 elif statedata.get('newnodes') is not None:
2549 elif statedata.get('newnodes') is not None:
2550 statedata['newnodes'].append(node)
2550 statedata['newnodes'].append(node)
2551
2551
2552 # remove state when we complete successfully
2552 # remove state when we complete successfully
2553 if not opts.get('dry_run'):
2553 if not opts.get('dry_run'):
2554 graftstate.delete()
2554 graftstate.delete()
2555
2555
2556 return 0
2556 return 0
2557
2557
2558 def _abortgraft(ui, repo, graftstate):
2558 def _abortgraft(ui, repo, graftstate):
2559 """abort the interrupted graft and rollbacks to the state before interrupted
2559 """abort the interrupted graft and rollbacks to the state before interrupted
2560 graft"""
2560 graft"""
2561 if not graftstate.exists():
2561 if not graftstate.exists():
2562 raise error.Abort(_("no interrupted graft to abort"))
2562 raise error.Abort(_("no interrupted graft to abort"))
2563 statedata = _readgraftstate(repo, graftstate)
2563 statedata = _readgraftstate(repo, graftstate)
2564 newnodes = statedata.get('newnodes')
2564 newnodes = statedata.get('newnodes')
2565 if newnodes is None:
2565 if newnodes is None:
2566 # and old graft state which does not have all the data required to abort
2566 # and old graft state which does not have all the data required to abort
2567 # the graft
2567 # the graft
2568 raise error.Abort(_("cannot abort using an old graftstate"))
2568 raise error.Abort(_("cannot abort using an old graftstate"))
2569
2569
2570 # changeset from which graft operation was started
2570 # changeset from which graft operation was started
2571 startctx = None
2571 startctx = None
2572 if len(newnodes) > 0:
2572 if len(newnodes) > 0:
2573 startctx = repo[newnodes[0]].p1()
2573 startctx = repo[newnodes[0]].p1()
2574 else:
2574 else:
2575 startctx = repo['.']
2575 startctx = repo['.']
2576 # whether to strip or not
2576 # whether to strip or not
2577 cleanup = False
2577 cleanup = False
2578 if newnodes:
2578 if newnodes:
2579 newnodes = [repo[r].rev() for r in newnodes]
2579 newnodes = [repo[r].rev() for r in newnodes]
2580 cleanup = True
2580 cleanup = True
2581 # checking that none of the newnodes turned public or is public
2581 # checking that none of the newnodes turned public or is public
2582 immutable = [c for c in newnodes if not repo[c].mutable()]
2582 immutable = [c for c in newnodes if not repo[c].mutable()]
2583 if immutable:
2583 if immutable:
2584 repo.ui.warn(_("cannot clean up public changesets %s\n")
2584 repo.ui.warn(_("cannot clean up public changesets %s\n")
2585 % ', '.join(bytes(repo[r]) for r in immutable),
2585 % ', '.join(bytes(repo[r]) for r in immutable),
2586 hint=_("see 'hg help phases' for details"))
2586 hint=_("see 'hg help phases' for details"))
2587 cleanup = False
2587 cleanup = False
2588
2588
2589 # checking that no new nodes are created on top of grafted revs
2589 # checking that no new nodes are created on top of grafted revs
2590 desc = set(repo.changelog.descendants(newnodes))
2590 desc = set(repo.changelog.descendants(newnodes))
2591 if desc - set(newnodes):
2591 if desc - set(newnodes):
2592 repo.ui.warn(_("new changesets detected on destination "
2592 repo.ui.warn(_("new changesets detected on destination "
2593 "branch, can't strip\n"))
2593 "branch, can't strip\n"))
2594 cleanup = False
2594 cleanup = False
2595
2595
2596 if cleanup:
2596 if cleanup:
2597 with repo.wlock(), repo.lock():
2597 with repo.wlock(), repo.lock():
2598 hg.updaterepo(repo, startctx.node(), overwrite=True)
2598 hg.updaterepo(repo, startctx.node(), overwrite=True)
2599 # stripping the new nodes created
2599 # stripping the new nodes created
2600 strippoints = [c.node() for c in repo.set("roots(%ld)",
2600 strippoints = [c.node() for c in repo.set("roots(%ld)",
2601 newnodes)]
2601 newnodes)]
2602 repair.strip(repo.ui, repo, strippoints, backup=False)
2602 repair.strip(repo.ui, repo, strippoints, backup=False)
2603
2603
2604 if not cleanup:
2604 if not cleanup:
2605 # we don't update to the startnode if we can't strip
2605 # we don't update to the startnode if we can't strip
2606 startctx = repo['.']
2606 startctx = repo['.']
2607 hg.updaterepo(repo, startctx.node(), overwrite=True)
2607 hg.updaterepo(repo, startctx.node(), overwrite=True)
2608
2608
2609 ui.status(_("graft aborted\n"))
2609 ui.status(_("graft aborted\n"))
2610 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2610 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2611 graftstate.delete()
2611 graftstate.delete()
2612 return 0
2612 return 0
2613
2613
2614 def _readgraftstate(repo, graftstate):
2614 def _readgraftstate(repo, graftstate):
2615 """read the graft state file and return a dict of the data stored in it"""
2615 """read the graft state file and return a dict of the data stored in it"""
2616 try:
2616 try:
2617 return graftstate.read()
2617 return graftstate.read()
2618 except error.CorruptedState:
2618 except error.CorruptedState:
2619 nodes = repo.vfs.read('graftstate').splitlines()
2619 nodes = repo.vfs.read('graftstate').splitlines()
2620 return {'nodes': nodes}
2620 return {'nodes': nodes}
2621
2621
2622 def _stopgraft(ui, repo, graftstate):
2622 def _stopgraft(ui, repo, graftstate):
2623 """stop the interrupted graft"""
2623 """stop the interrupted graft"""
2624 if not graftstate.exists():
2624 if not graftstate.exists():
2625 raise error.Abort(_("no interrupted graft found"))
2625 raise error.Abort(_("no interrupted graft found"))
2626 pctx = repo['.']
2626 pctx = repo['.']
2627 hg.updaterepo(repo, pctx.node(), overwrite=True)
2627 hg.updaterepo(repo, pctx.node(), overwrite=True)
2628 graftstate.delete()
2628 graftstate.delete()
2629 ui.status(_("stopped the interrupted graft\n"))
2629 ui.status(_("stopped the interrupted graft\n"))
2630 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2630 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2631 return 0
2631 return 0
2632
2632
2633 @command('grep',
2633 @command('grep',
2634 [('0', 'print0', None, _('end fields with NUL')),
2634 [('0', 'print0', None, _('end fields with NUL')),
2635 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2635 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2636 ('', 'diff', None, _('print all revisions when the term was introduced '
2636 ('', 'diff', None, _('print all revisions when the term was introduced '
2637 'or removed')),
2637 'or removed')),
2638 ('a', 'text', None, _('treat all files as text')),
2638 ('a', 'text', None, _('treat all files as text')),
2639 ('f', 'follow', None,
2639 ('f', 'follow', None,
2640 _('follow changeset history,'
2640 _('follow changeset history,'
2641 ' or file history across copies and renames')),
2641 ' or file history across copies and renames')),
2642 ('i', 'ignore-case', None, _('ignore case when matching')),
2642 ('i', 'ignore-case', None, _('ignore case when matching')),
2643 ('l', 'files-with-matches', None,
2643 ('l', 'files-with-matches', None,
2644 _('print only filenames and revisions that match')),
2644 _('print only filenames and revisions that match')),
2645 ('n', 'line-number', None, _('print matching line numbers')),
2645 ('n', 'line-number', None, _('print matching line numbers')),
2646 ('r', 'rev', [],
2646 ('r', 'rev', [],
2647 _('only search files changed within revision range'), _('REV')),
2647 _('only search files changed within revision range'), _('REV')),
2648 ('', 'all-files', None,
2648 ('', 'all-files', None,
2649 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2649 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2650 ('u', 'user', None, _('list the author (long with -v)')),
2650 ('u', 'user', None, _('list the author (long with -v)')),
2651 ('d', 'date', None, _('list the date (short with -q)')),
2651 ('d', 'date', None, _('list the date (short with -q)')),
2652 ] + formatteropts + walkopts,
2652 ] + formatteropts + walkopts,
2653 _('[OPTION]... PATTERN [FILE]...'),
2653 _('[OPTION]... PATTERN [FILE]...'),
2654 helpcategory=command.CATEGORY_FILE_CONTENTS,
2654 helpcategory=command.CATEGORY_FILE_CONTENTS,
2655 inferrepo=True,
2655 inferrepo=True,
2656 intents={INTENT_READONLY})
2656 intents={INTENT_READONLY})
2657 def grep(ui, repo, pattern, *pats, **opts):
2657 def grep(ui, repo, pattern, *pats, **opts):
2658 """search revision history for a pattern in specified files
2658 """search revision history for a pattern in specified files
2659
2659
2660 Search revision history for a regular expression in the specified
2660 Search revision history for a regular expression in the specified
2661 files or the entire project.
2661 files or the entire project.
2662
2662
2663 By default, grep prints the most recent revision number for each
2663 By default, grep prints the most recent revision number for each
2664 file in which it finds a match. To get it to print every revision
2664 file in which it finds a match. To get it to print every revision
2665 that contains a change in match status ("-" for a match that becomes
2665 that contains a change in match status ("-" for a match that becomes
2666 a non-match, or "+" for a non-match that becomes a match), use the
2666 a non-match, or "+" for a non-match that becomes a match), use the
2667 --diff flag.
2667 --diff flag.
2668
2668
2669 PATTERN can be any Python (roughly Perl-compatible) regular
2669 PATTERN can be any Python (roughly Perl-compatible) regular
2670 expression.
2670 expression.
2671
2671
2672 If no FILEs are specified (and -f/--follow isn't set), all files in
2672 If no FILEs are specified (and -f/--follow isn't set), all files in
2673 the repository are searched, including those that don't exist in the
2673 the repository are searched, including those that don't exist in the
2674 current branch or have been deleted in a prior changeset.
2674 current branch or have been deleted in a prior changeset.
2675
2675
2676 .. container:: verbose
2676 .. container:: verbose
2677
2677
2678 Template:
2678 Template:
2679
2679
2680 The following keywords are supported in addition to the common template
2680 The following keywords are supported in addition to the common template
2681 keywords and functions. See also :hg:`help templates`.
2681 keywords and functions. See also :hg:`help templates`.
2682
2682
2683 :change: String. Character denoting insertion ``+`` or removal ``-``.
2683 :change: String. Character denoting insertion ``+`` or removal ``-``.
2684 Available if ``--diff`` is specified.
2684 Available if ``--diff`` is specified.
2685 :lineno: Integer. Line number of the match.
2685 :lineno: Integer. Line number of the match.
2686 :path: String. Repository-absolute path of the file.
2686 :path: String. Repository-absolute path of the file.
2687 :texts: List of text chunks.
2687 :texts: List of text chunks.
2688
2688
2689 And each entry of ``{texts}`` provides the following sub-keywords.
2689 And each entry of ``{texts}`` provides the following sub-keywords.
2690
2690
2691 :matched: Boolean. True if the chunk matches the specified pattern.
2691 :matched: Boolean. True if the chunk matches the specified pattern.
2692 :text: String. Chunk content.
2692 :text: String. Chunk content.
2693
2693
2694 See :hg:`help templates.operators` for the list expansion syntax.
2694 See :hg:`help templates.operators` for the list expansion syntax.
2695
2695
2696 Returns 0 if a match is found, 1 otherwise.
2696 Returns 0 if a match is found, 1 otherwise.
2697 """
2697 """
2698 opts = pycompat.byteskwargs(opts)
2698 opts = pycompat.byteskwargs(opts)
2699 diff = opts.get('all') or opts.get('diff')
2699 diff = opts.get('all') or opts.get('diff')
2700 all_files = opts.get('all_files')
2700 all_files = opts.get('all_files')
2701 if diff and opts.get('all_files'):
2701 if diff and opts.get('all_files'):
2702 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2702 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2703 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2703 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2704 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2704 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2705 # experimental config: commands.grep.all-files
2705 # experimental config: commands.grep.all-files
2706 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2706 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2707 plaingrep = opts.get('all_files') and not opts.get('rev')
2707 plaingrep = opts.get('all_files') and not opts.get('rev')
2708 if plaingrep:
2708 if plaingrep:
2709 opts['rev'] = ['wdir()']
2709 opts['rev'] = ['wdir()']
2710
2710
2711 reflags = re.M
2711 reflags = re.M
2712 if opts.get('ignore_case'):
2712 if opts.get('ignore_case'):
2713 reflags |= re.I
2713 reflags |= re.I
2714 try:
2714 try:
2715 regexp = util.re.compile(pattern, reflags)
2715 regexp = util.re.compile(pattern, reflags)
2716 except re.error as inst:
2716 except re.error as inst:
2717 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2717 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2718 return 1
2718 return 1
2719 sep, eol = ':', '\n'
2719 sep, eol = ':', '\n'
2720 if opts.get('print0'):
2720 if opts.get('print0'):
2721 sep = eol = '\0'
2721 sep = eol = '\0'
2722
2722
2723 getfile = util.lrucachefunc(repo.file)
2723 getfile = util.lrucachefunc(repo.file)
2724
2724
2725 def matchlines(body):
2725 def matchlines(body):
2726 begin = 0
2726 begin = 0
2727 linenum = 0
2727 linenum = 0
2728 while begin < len(body):
2728 while begin < len(body):
2729 match = regexp.search(body, begin)
2729 match = regexp.search(body, begin)
2730 if not match:
2730 if not match:
2731 break
2731 break
2732 mstart, mend = match.span()
2732 mstart, mend = match.span()
2733 linenum += body.count('\n', begin, mstart) + 1
2733 linenum += body.count('\n', begin, mstart) + 1
2734 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2734 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2735 begin = body.find('\n', mend) + 1 or len(body) + 1
2735 begin = body.find('\n', mend) + 1 or len(body) + 1
2736 lend = begin - 1
2736 lend = begin - 1
2737 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2737 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2738
2738
2739 class linestate(object):
2739 class linestate(object):
2740 def __init__(self, line, linenum, colstart, colend):
2740 def __init__(self, line, linenum, colstart, colend):
2741 self.line = line
2741 self.line = line
2742 self.linenum = linenum
2742 self.linenum = linenum
2743 self.colstart = colstart
2743 self.colstart = colstart
2744 self.colend = colend
2744 self.colend = colend
2745
2745
2746 def __hash__(self):
2746 def __hash__(self):
2747 return hash((self.linenum, self.line))
2747 return hash((self.linenum, self.line))
2748
2748
2749 def __eq__(self, other):
2749 def __eq__(self, other):
2750 return self.line == other.line
2750 return self.line == other.line
2751
2751
2752 def findpos(self):
2752 def findpos(self):
2753 """Iterate all (start, end) indices of matches"""
2753 """Iterate all (start, end) indices of matches"""
2754 yield self.colstart, self.colend
2754 yield self.colstart, self.colend
2755 p = self.colend
2755 p = self.colend
2756 while p < len(self.line):
2756 while p < len(self.line):
2757 m = regexp.search(self.line, p)
2757 m = regexp.search(self.line, p)
2758 if not m:
2758 if not m:
2759 break
2759 break
2760 yield m.span()
2760 yield m.span()
2761 p = m.end()
2761 p = m.end()
2762
2762
2763 matches = {}
2763 matches = {}
2764 copies = {}
2764 copies = {}
2765 def grepbody(fn, rev, body):
2765 def grepbody(fn, rev, body):
2766 matches[rev].setdefault(fn, [])
2766 matches[rev].setdefault(fn, [])
2767 m = matches[rev][fn]
2767 m = matches[rev][fn]
2768 for lnum, cstart, cend, line in matchlines(body):
2768 for lnum, cstart, cend, line in matchlines(body):
2769 s = linestate(line, lnum, cstart, cend)
2769 s = linestate(line, lnum, cstart, cend)
2770 m.append(s)
2770 m.append(s)
2771
2771
2772 def difflinestates(a, b):
2772 def difflinestates(a, b):
2773 sm = difflib.SequenceMatcher(None, a, b)
2773 sm = difflib.SequenceMatcher(None, a, b)
2774 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2774 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2775 if tag == r'insert':
2775 if tag == r'insert':
2776 for i in pycompat.xrange(blo, bhi):
2776 for i in pycompat.xrange(blo, bhi):
2777 yield ('+', b[i])
2777 yield ('+', b[i])
2778 elif tag == r'delete':
2778 elif tag == r'delete':
2779 for i in pycompat.xrange(alo, ahi):
2779 for i in pycompat.xrange(alo, ahi):
2780 yield ('-', a[i])
2780 yield ('-', a[i])
2781 elif tag == r'replace':
2781 elif tag == r'replace':
2782 for i in pycompat.xrange(alo, ahi):
2782 for i in pycompat.xrange(alo, ahi):
2783 yield ('-', a[i])
2783 yield ('-', a[i])
2784 for i in pycompat.xrange(blo, bhi):
2784 for i in pycompat.xrange(blo, bhi):
2785 yield ('+', b[i])
2785 yield ('+', b[i])
2786
2786
2787 def display(fm, fn, ctx, pstates, states):
2787 def display(fm, fn, ctx, pstates, states):
2788 rev = scmutil.intrev(ctx)
2788 rev = scmutil.intrev(ctx)
2789 if fm.isplain():
2789 if fm.isplain():
2790 formatuser = ui.shortuser
2790 formatuser = ui.shortuser
2791 else:
2791 else:
2792 formatuser = pycompat.bytestr
2792 formatuser = pycompat.bytestr
2793 if ui.quiet:
2793 if ui.quiet:
2794 datefmt = '%Y-%m-%d'
2794 datefmt = '%Y-%m-%d'
2795 else:
2795 else:
2796 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2796 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2797 found = False
2797 found = False
2798 @util.cachefunc
2798 @util.cachefunc
2799 def binary():
2799 def binary():
2800 flog = getfile(fn)
2800 flog = getfile(fn)
2801 try:
2801 try:
2802 return stringutil.binary(flog.read(ctx.filenode(fn)))
2802 return stringutil.binary(flog.read(ctx.filenode(fn)))
2803 except error.WdirUnsupported:
2803 except error.WdirUnsupported:
2804 return ctx[fn].isbinary()
2804 return ctx[fn].isbinary()
2805
2805
2806 fieldnamemap = {'filename': 'path', 'linenumber': 'lineno'}
2806 fieldnamemap = {'filename': 'path', 'linenumber': 'lineno'}
2807 if diff:
2807 if diff:
2808 iter = difflinestates(pstates, states)
2808 iter = difflinestates(pstates, states)
2809 else:
2809 else:
2810 iter = [('', l) for l in states]
2810 iter = [('', l) for l in states]
2811 for change, l in iter:
2811 for change, l in iter:
2812 fm.startitem()
2812 fm.startitem()
2813 fm.context(ctx=ctx)
2813 fm.context(ctx=ctx)
2814 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2814 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2815
2815
2816 cols = [
2816 cols = [
2817 ('filename', '%s', fn, True),
2817 ('filename', '%s', fn, True),
2818 ('rev', '%d', rev, not plaingrep),
2818 ('rev', '%d', rev, not plaingrep),
2819 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2819 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2820 ]
2820 ]
2821 if diff:
2821 if diff:
2822 cols.append(('change', '%s', change, True))
2822 cols.append(('change', '%s', change, True))
2823 cols.extend([
2823 cols.extend([
2824 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2824 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2825 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2825 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2826 opts.get('date')),
2826 opts.get('date')),
2827 ])
2827 ])
2828 lastcol = next(
2828 lastcol = next(
2829 name for name, fmt, data, cond in reversed(cols) if cond)
2829 name for name, fmt, data, cond in reversed(cols) if cond)
2830 for name, fmt, data, cond in cols:
2830 for name, fmt, data, cond in cols:
2831 field = fieldnamemap.get(name, name)
2831 field = fieldnamemap.get(name, name)
2832 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2832 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2833 if cond and name != lastcol:
2833 if cond and name != lastcol:
2834 fm.plain(sep, label='grep.sep')
2834 fm.plain(sep, label='grep.sep')
2835 if not opts.get('files_with_matches'):
2835 if not opts.get('files_with_matches'):
2836 fm.plain(sep, label='grep.sep')
2836 fm.plain(sep, label='grep.sep')
2837 if not opts.get('text') and binary():
2837 if not opts.get('text') and binary():
2838 fm.plain(_(" Binary file matches"))
2838 fm.plain(_(" Binary file matches"))
2839 else:
2839 else:
2840 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2840 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2841 fm.plain(eol)
2841 fm.plain(eol)
2842 found = True
2842 found = True
2843 if opts.get('files_with_matches'):
2843 if opts.get('files_with_matches'):
2844 break
2844 break
2845 return found
2845 return found
2846
2846
2847 def displaymatches(fm, l):
2847 def displaymatches(fm, l):
2848 p = 0
2848 p = 0
2849 for s, e in l.findpos():
2849 for s, e in l.findpos():
2850 if p < s:
2850 if p < s:
2851 fm.startitem()
2851 fm.startitem()
2852 fm.write('text', '%s', l.line[p:s])
2852 fm.write('text', '%s', l.line[p:s])
2853 fm.data(matched=False)
2853 fm.data(matched=False)
2854 fm.startitem()
2854 fm.startitem()
2855 fm.write('text', '%s', l.line[s:e], label='grep.match')
2855 fm.write('text', '%s', l.line[s:e], label='grep.match')
2856 fm.data(matched=True)
2856 fm.data(matched=True)
2857 p = e
2857 p = e
2858 if p < len(l.line):
2858 if p < len(l.line):
2859 fm.startitem()
2859 fm.startitem()
2860 fm.write('text', '%s', l.line[p:])
2860 fm.write('text', '%s', l.line[p:])
2861 fm.data(matched=False)
2861 fm.data(matched=False)
2862 fm.end()
2862 fm.end()
2863
2863
2864 skip = {}
2864 skip = {}
2865 revfiles = {}
2865 revfiles = {}
2866 match = scmutil.match(repo[None], pats, opts)
2866 match = scmutil.match(repo[None], pats, opts)
2867 found = False
2867 found = False
2868 follow = opts.get('follow')
2868 follow = opts.get('follow')
2869
2869
2870 def prep(ctx, fns):
2870 def prep(ctx, fns):
2871 rev = ctx.rev()
2871 rev = ctx.rev()
2872 pctx = ctx.p1()
2872 pctx = ctx.p1()
2873 parent = pctx.rev()
2873 parent = pctx.rev()
2874 matches.setdefault(rev, {})
2874 matches.setdefault(rev, {})
2875 matches.setdefault(parent, {})
2875 matches.setdefault(parent, {})
2876 files = revfiles.setdefault(rev, [])
2876 files = revfiles.setdefault(rev, [])
2877 for fn in fns:
2877 for fn in fns:
2878 flog = getfile(fn)
2878 flog = getfile(fn)
2879 try:
2879 try:
2880 fnode = ctx.filenode(fn)
2880 fnode = ctx.filenode(fn)
2881 except error.LookupError:
2881 except error.LookupError:
2882 continue
2882 continue
2883 try:
2883 try:
2884 copied = flog.renamed(fnode)
2884 copied = flog.renamed(fnode)
2885 except error.WdirUnsupported:
2885 except error.WdirUnsupported:
2886 copied = ctx[fn].renamed()
2886 copied = ctx[fn].renamed()
2887 copy = follow and copied and copied[0]
2887 copy = follow and copied and copied[0]
2888 if copy:
2888 if copy:
2889 copies.setdefault(rev, {})[fn] = copy
2889 copies.setdefault(rev, {})[fn] = copy
2890 if fn in skip:
2890 if fn in skip:
2891 if copy:
2891 if copy:
2892 skip[copy] = True
2892 skip[copy] = True
2893 continue
2893 continue
2894 files.append(fn)
2894 files.append(fn)
2895
2895
2896 if fn not in matches[rev]:
2896 if fn not in matches[rev]:
2897 try:
2897 try:
2898 content = flog.read(fnode)
2898 content = flog.read(fnode)
2899 except error.WdirUnsupported:
2899 except error.WdirUnsupported:
2900 content = ctx[fn].data()
2900 content = ctx[fn].data()
2901 grepbody(fn, rev, content)
2901 grepbody(fn, rev, content)
2902
2902
2903 pfn = copy or fn
2903 pfn = copy or fn
2904 if pfn not in matches[parent]:
2904 if pfn not in matches[parent]:
2905 try:
2905 try:
2906 fnode = pctx.filenode(pfn)
2906 fnode = pctx.filenode(pfn)
2907 grepbody(pfn, parent, flog.read(fnode))
2907 grepbody(pfn, parent, flog.read(fnode))
2908 except error.LookupError:
2908 except error.LookupError:
2909 pass
2909 pass
2910
2910
2911 ui.pager('grep')
2911 ui.pager('grep')
2912 fm = ui.formatter('grep', opts)
2912 fm = ui.formatter('grep', opts)
2913 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2913 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2914 rev = ctx.rev()
2914 rev = ctx.rev()
2915 parent = ctx.p1().rev()
2915 parent = ctx.p1().rev()
2916 for fn in sorted(revfiles.get(rev, [])):
2916 for fn in sorted(revfiles.get(rev, [])):
2917 states = matches[rev][fn]
2917 states = matches[rev][fn]
2918 copy = copies.get(rev, {}).get(fn)
2918 copy = copies.get(rev, {}).get(fn)
2919 if fn in skip:
2919 if fn in skip:
2920 if copy:
2920 if copy:
2921 skip[copy] = True
2921 skip[copy] = True
2922 continue
2922 continue
2923 pstates = matches.get(parent, {}).get(copy or fn, [])
2923 pstates = matches.get(parent, {}).get(copy or fn, [])
2924 if pstates or states:
2924 if pstates or states:
2925 r = display(fm, fn, ctx, pstates, states)
2925 r = display(fm, fn, ctx, pstates, states)
2926 found = found or r
2926 found = found or r
2927 if r and not diff and not all_files:
2927 if r and not diff and not all_files:
2928 skip[fn] = True
2928 skip[fn] = True
2929 if copy:
2929 if copy:
2930 skip[copy] = True
2930 skip[copy] = True
2931 del revfiles[rev]
2931 del revfiles[rev]
2932 # We will keep the matches dict for the duration of the window
2932 # We will keep the matches dict for the duration of the window
2933 # clear the matches dict once the window is over
2933 # clear the matches dict once the window is over
2934 if not revfiles:
2934 if not revfiles:
2935 matches.clear()
2935 matches.clear()
2936 fm.end()
2936 fm.end()
2937
2937
2938 return not found
2938 return not found
2939
2939
2940 @command('heads',
2940 @command('heads',
2941 [('r', 'rev', '',
2941 [('r', 'rev', '',
2942 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2942 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2943 ('t', 'topo', False, _('show topological heads only')),
2943 ('t', 'topo', False, _('show topological heads only')),
2944 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2944 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2945 ('c', 'closed', False, _('show normal and closed branch heads')),
2945 ('c', 'closed', False, _('show normal and closed branch heads')),
2946 ] + templateopts,
2946 ] + templateopts,
2947 _('[-ct] [-r STARTREV] [REV]...'),
2947 _('[-ct] [-r STARTREV] [REV]...'),
2948 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
2948 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
2949 intents={INTENT_READONLY})
2949 intents={INTENT_READONLY})
2950 def heads(ui, repo, *branchrevs, **opts):
2950 def heads(ui, repo, *branchrevs, **opts):
2951 """show branch heads
2951 """show branch heads
2952
2952
2953 With no arguments, show all open branch heads in the repository.
2953 With no arguments, show all open branch heads in the repository.
2954 Branch heads are changesets that have no descendants on the
2954 Branch heads are changesets that have no descendants on the
2955 same branch. They are where development generally takes place and
2955 same branch. They are where development generally takes place and
2956 are the usual targets for update and merge operations.
2956 are the usual targets for update and merge operations.
2957
2957
2958 If one or more REVs are given, only open branch heads on the
2958 If one or more REVs are given, only open branch heads on the
2959 branches associated with the specified changesets are shown. This
2959 branches associated with the specified changesets are shown. This
2960 means that you can use :hg:`heads .` to see the heads on the
2960 means that you can use :hg:`heads .` to see the heads on the
2961 currently checked-out branch.
2961 currently checked-out branch.
2962
2962
2963 If -c/--closed is specified, also show branch heads marked closed
2963 If -c/--closed is specified, also show branch heads marked closed
2964 (see :hg:`commit --close-branch`).
2964 (see :hg:`commit --close-branch`).
2965
2965
2966 If STARTREV is specified, only those heads that are descendants of
2966 If STARTREV is specified, only those heads that are descendants of
2967 STARTREV will be displayed.
2967 STARTREV will be displayed.
2968
2968
2969 If -t/--topo is specified, named branch mechanics will be ignored and only
2969 If -t/--topo is specified, named branch mechanics will be ignored and only
2970 topological heads (changesets with no children) will be shown.
2970 topological heads (changesets with no children) will be shown.
2971
2971
2972 Returns 0 if matching heads are found, 1 if not.
2972 Returns 0 if matching heads are found, 1 if not.
2973 """
2973 """
2974
2974
2975 opts = pycompat.byteskwargs(opts)
2975 opts = pycompat.byteskwargs(opts)
2976 start = None
2976 start = None
2977 rev = opts.get('rev')
2977 rev = opts.get('rev')
2978 if rev:
2978 if rev:
2979 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2979 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2980 start = scmutil.revsingle(repo, rev, None).node()
2980 start = scmutil.revsingle(repo, rev, None).node()
2981
2981
2982 if opts.get('topo'):
2982 if opts.get('topo'):
2983 heads = [repo[h] for h in repo.heads(start)]
2983 heads = [repo[h] for h in repo.heads(start)]
2984 else:
2984 else:
2985 heads = []
2985 heads = []
2986 for branch in repo.branchmap():
2986 for branch in repo.branchmap():
2987 heads += repo.branchheads(branch, start, opts.get('closed'))
2987 heads += repo.branchheads(branch, start, opts.get('closed'))
2988 heads = [repo[h] for h in heads]
2988 heads = [repo[h] for h in heads]
2989
2989
2990 if branchrevs:
2990 if branchrevs:
2991 branches = set(repo[r].branch()
2991 branches = set(repo[r].branch()
2992 for r in scmutil.revrange(repo, branchrevs))
2992 for r in scmutil.revrange(repo, branchrevs))
2993 heads = [h for h in heads if h.branch() in branches]
2993 heads = [h for h in heads if h.branch() in branches]
2994
2994
2995 if opts.get('active') and branchrevs:
2995 if opts.get('active') and branchrevs:
2996 dagheads = repo.heads(start)
2996 dagheads = repo.heads(start)
2997 heads = [h for h in heads if h.node() in dagheads]
2997 heads = [h for h in heads if h.node() in dagheads]
2998
2998
2999 if branchrevs:
2999 if branchrevs:
3000 haveheads = set(h.branch() for h in heads)
3000 haveheads = set(h.branch() for h in heads)
3001 if branches - haveheads:
3001 if branches - haveheads:
3002 headless = ', '.join(b for b in branches - haveheads)
3002 headless = ', '.join(b for b in branches - haveheads)
3003 msg = _('no open branch heads found on branches %s')
3003 msg = _('no open branch heads found on branches %s')
3004 if opts.get('rev'):
3004 if opts.get('rev'):
3005 msg += _(' (started at %s)') % opts['rev']
3005 msg += _(' (started at %s)') % opts['rev']
3006 ui.warn((msg + '\n') % headless)
3006 ui.warn((msg + '\n') % headless)
3007
3007
3008 if not heads:
3008 if not heads:
3009 return 1
3009 return 1
3010
3010
3011 ui.pager('heads')
3011 ui.pager('heads')
3012 heads = sorted(heads, key=lambda x: -x.rev())
3012 heads = sorted(heads, key=lambda x: -x.rev())
3013 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3013 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3014 for ctx in heads:
3014 for ctx in heads:
3015 displayer.show(ctx)
3015 displayer.show(ctx)
3016 displayer.close()
3016 displayer.close()
3017
3017
3018 @command('help',
3018 @command('help',
3019 [('e', 'extension', None, _('show only help for extensions')),
3019 [('e', 'extension', None, _('show only help for extensions')),
3020 ('c', 'command', None, _('show only help for commands')),
3020 ('c', 'command', None, _('show only help for commands')),
3021 ('k', 'keyword', None, _('show topics matching keyword')),
3021 ('k', 'keyword', None, _('show topics matching keyword')),
3022 ('s', 'system', [],
3022 ('s', 'system', [],
3023 _('show help for specific platform(s)'), _('PLATFORM')),
3023 _('show help for specific platform(s)'), _('PLATFORM')),
3024 ],
3024 ],
3025 _('[-eck] [-s PLATFORM] [TOPIC]'),
3025 _('[-eck] [-s PLATFORM] [TOPIC]'),
3026 helpcategory=command.CATEGORY_HELP,
3026 helpcategory=command.CATEGORY_HELP,
3027 norepo=True,
3027 norepo=True,
3028 intents={INTENT_READONLY})
3028 intents={INTENT_READONLY})
3029 def help_(ui, name=None, **opts):
3029 def help_(ui, name=None, **opts):
3030 """show help for a given topic or a help overview
3030 """show help for a given topic or a help overview
3031
3031
3032 With no arguments, print a list of commands with short help messages.
3032 With no arguments, print a list of commands with short help messages.
3033
3033
3034 Given a topic, extension, or command name, print help for that
3034 Given a topic, extension, or command name, print help for that
3035 topic.
3035 topic.
3036
3036
3037 Returns 0 if successful.
3037 Returns 0 if successful.
3038 """
3038 """
3039
3039
3040 keep = opts.get(r'system') or []
3040 keep = opts.get(r'system') or []
3041 if len(keep) == 0:
3041 if len(keep) == 0:
3042 if pycompat.sysplatform.startswith('win'):
3042 if pycompat.sysplatform.startswith('win'):
3043 keep.append('windows')
3043 keep.append('windows')
3044 elif pycompat.sysplatform == 'OpenVMS':
3044 elif pycompat.sysplatform == 'OpenVMS':
3045 keep.append('vms')
3045 keep.append('vms')
3046 elif pycompat.sysplatform == 'plan9':
3046 elif pycompat.sysplatform == 'plan9':
3047 keep.append('plan9')
3047 keep.append('plan9')
3048 else:
3048 else:
3049 keep.append('unix')
3049 keep.append('unix')
3050 keep.append(pycompat.sysplatform.lower())
3050 keep.append(pycompat.sysplatform.lower())
3051 if ui.verbose:
3051 if ui.verbose:
3052 keep.append('verbose')
3052 keep.append('verbose')
3053
3053
3054 commands = sys.modules[__name__]
3054 commands = sys.modules[__name__]
3055 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3055 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3056 ui.pager('help')
3056 ui.pager('help')
3057 ui.write(formatted)
3057 ui.write(formatted)
3058
3058
3059
3059
3060 @command('identify|id',
3060 @command('identify|id',
3061 [('r', 'rev', '',
3061 [('r', 'rev', '',
3062 _('identify the specified revision'), _('REV')),
3062 _('identify the specified revision'), _('REV')),
3063 ('n', 'num', None, _('show local revision number')),
3063 ('n', 'num', None, _('show local revision number')),
3064 ('i', 'id', None, _('show global revision id')),
3064 ('i', 'id', None, _('show global revision id')),
3065 ('b', 'branch', None, _('show branch')),
3065 ('b', 'branch', None, _('show branch')),
3066 ('t', 'tags', None, _('show tags')),
3066 ('t', 'tags', None, _('show tags')),
3067 ('B', 'bookmarks', None, _('show bookmarks')),
3067 ('B', 'bookmarks', None, _('show bookmarks')),
3068 ] + remoteopts + formatteropts,
3068 ] + remoteopts + formatteropts,
3069 _('[-nibtB] [-r REV] [SOURCE]'),
3069 _('[-nibtB] [-r REV] [SOURCE]'),
3070 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3070 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3071 optionalrepo=True,
3071 optionalrepo=True,
3072 intents={INTENT_READONLY})
3072 intents={INTENT_READONLY})
3073 def identify(ui, repo, source=None, rev=None,
3073 def identify(ui, repo, source=None, rev=None,
3074 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3074 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3075 """identify the working directory or specified revision
3075 """identify the working directory or specified revision
3076
3076
3077 Print a summary identifying the repository state at REV using one or
3077 Print a summary identifying the repository state at REV using one or
3078 two parent hash identifiers, followed by a "+" if the working
3078 two parent hash identifiers, followed by a "+" if the working
3079 directory has uncommitted changes, the branch name (if not default),
3079 directory has uncommitted changes, the branch name (if not default),
3080 a list of tags, and a list of bookmarks.
3080 a list of tags, and a list of bookmarks.
3081
3081
3082 When REV is not given, print a summary of the current state of the
3082 When REV is not given, print a summary of the current state of the
3083 repository including the working directory. Specify -r. to get information
3083 repository including the working directory. Specify -r. to get information
3084 of the working directory parent without scanning uncommitted changes.
3084 of the working directory parent without scanning uncommitted changes.
3085
3085
3086 Specifying a path to a repository root or Mercurial bundle will
3086 Specifying a path to a repository root or Mercurial bundle will
3087 cause lookup to operate on that repository/bundle.
3087 cause lookup to operate on that repository/bundle.
3088
3088
3089 .. container:: verbose
3089 .. container:: verbose
3090
3090
3091 Template:
3091 Template:
3092
3092
3093 The following keywords are supported in addition to the common template
3093 The following keywords are supported in addition to the common template
3094 keywords and functions. See also :hg:`help templates`.
3094 keywords and functions. See also :hg:`help templates`.
3095
3095
3096 :dirty: String. Character ``+`` denoting if the working directory has
3096 :dirty: String. Character ``+`` denoting if the working directory has
3097 uncommitted changes.
3097 uncommitted changes.
3098 :id: String. One or two nodes, optionally followed by ``+``.
3098 :id: String. One or two nodes, optionally followed by ``+``.
3099 :parents: List of strings. Parent nodes of the changeset.
3099 :parents: List of strings. Parent nodes of the changeset.
3100
3100
3101 Examples:
3101 Examples:
3102
3102
3103 - generate a build identifier for the working directory::
3103 - generate a build identifier for the working directory::
3104
3104
3105 hg id --id > build-id.dat
3105 hg id --id > build-id.dat
3106
3106
3107 - find the revision corresponding to a tag::
3107 - find the revision corresponding to a tag::
3108
3108
3109 hg id -n -r 1.3
3109 hg id -n -r 1.3
3110
3110
3111 - check the most recent revision of a remote repository::
3111 - check the most recent revision of a remote repository::
3112
3112
3113 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3113 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3114
3114
3115 See :hg:`log` for generating more information about specific revisions,
3115 See :hg:`log` for generating more information about specific revisions,
3116 including full hash identifiers.
3116 including full hash identifiers.
3117
3117
3118 Returns 0 if successful.
3118 Returns 0 if successful.
3119 """
3119 """
3120
3120
3121 opts = pycompat.byteskwargs(opts)
3121 opts = pycompat.byteskwargs(opts)
3122 if not repo and not source:
3122 if not repo and not source:
3123 raise error.Abort(_("there is no Mercurial repository here "
3123 raise error.Abort(_("there is no Mercurial repository here "
3124 "(.hg not found)"))
3124 "(.hg not found)"))
3125
3125
3126 default = not (num or id or branch or tags or bookmarks)
3126 default = not (num or id or branch or tags or bookmarks)
3127 output = []
3127 output = []
3128 revs = []
3128 revs = []
3129
3129
3130 if source:
3130 if source:
3131 source, branches = hg.parseurl(ui.expandpath(source))
3131 source, branches = hg.parseurl(ui.expandpath(source))
3132 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3132 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3133 repo = peer.local()
3133 repo = peer.local()
3134 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3134 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3135
3135
3136 fm = ui.formatter('identify', opts)
3136 fm = ui.formatter('identify', opts)
3137 fm.startitem()
3137 fm.startitem()
3138
3138
3139 if not repo:
3139 if not repo:
3140 if num or branch or tags:
3140 if num or branch or tags:
3141 raise error.Abort(
3141 raise error.Abort(
3142 _("can't query remote revision number, branch, or tags"))
3142 _("can't query remote revision number, branch, or tags"))
3143 if not rev and revs:
3143 if not rev and revs:
3144 rev = revs[0]
3144 rev = revs[0]
3145 if not rev:
3145 if not rev:
3146 rev = "tip"
3146 rev = "tip"
3147
3147
3148 remoterev = peer.lookup(rev)
3148 remoterev = peer.lookup(rev)
3149 hexrev = fm.hexfunc(remoterev)
3149 hexrev = fm.hexfunc(remoterev)
3150 if default or id:
3150 if default or id:
3151 output = [hexrev]
3151 output = [hexrev]
3152 fm.data(id=hexrev)
3152 fm.data(id=hexrev)
3153
3153
3154 @util.cachefunc
3154 @util.cachefunc
3155 def getbms():
3155 def getbms():
3156 bms = []
3156 bms = []
3157
3157
3158 if 'bookmarks' in peer.listkeys('namespaces'):
3158 if 'bookmarks' in peer.listkeys('namespaces'):
3159 hexremoterev = hex(remoterev)
3159 hexremoterev = hex(remoterev)
3160 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3160 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3161 if bmr == hexremoterev]
3161 if bmr == hexremoterev]
3162
3162
3163 return sorted(bms)
3163 return sorted(bms)
3164
3164
3165 if fm.isplain():
3165 if fm.isplain():
3166 if bookmarks:
3166 if bookmarks:
3167 output.extend(getbms())
3167 output.extend(getbms())
3168 elif default and not ui.quiet:
3168 elif default and not ui.quiet:
3169 # multiple bookmarks for a single parent separated by '/'
3169 # multiple bookmarks for a single parent separated by '/'
3170 bm = '/'.join(getbms())
3170 bm = '/'.join(getbms())
3171 if bm:
3171 if bm:
3172 output.append(bm)
3172 output.append(bm)
3173 else:
3173 else:
3174 fm.data(node=hex(remoterev))
3174 fm.data(node=hex(remoterev))
3175 if bookmarks or 'bookmarks' in fm.datahint():
3175 if bookmarks or 'bookmarks' in fm.datahint():
3176 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3176 fm.data(bookmarks=fm.formatlist(getbms(), name='bookmark'))
3177 else:
3177 else:
3178 if rev:
3178 if rev:
3179 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3179 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3180 ctx = scmutil.revsingle(repo, rev, None)
3180 ctx = scmutil.revsingle(repo, rev, None)
3181
3181
3182 if ctx.rev() is None:
3182 if ctx.rev() is None:
3183 ctx = repo[None]
3183 ctx = repo[None]
3184 parents = ctx.parents()
3184 parents = ctx.parents()
3185 taglist = []
3185 taglist = []
3186 for p in parents:
3186 for p in parents:
3187 taglist.extend(p.tags())
3187 taglist.extend(p.tags())
3188
3188
3189 dirty = ""
3189 dirty = ""
3190 if ctx.dirty(missing=True, merge=False, branch=False):
3190 if ctx.dirty(missing=True, merge=False, branch=False):
3191 dirty = '+'
3191 dirty = '+'
3192 fm.data(dirty=dirty)
3192 fm.data(dirty=dirty)
3193
3193
3194 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3194 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3195 if default or id:
3195 if default or id:
3196 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3196 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3197 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3197 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3198
3198
3199 if num:
3199 if num:
3200 numoutput = ["%d" % p.rev() for p in parents]
3200 numoutput = ["%d" % p.rev() for p in parents]
3201 output.append("%s%s" % ('+'.join(numoutput), dirty))
3201 output.append("%s%s" % ('+'.join(numoutput), dirty))
3202
3202
3203 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3203 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3204 for p in parents], name='node'))
3204 for p in parents], name='node'))
3205 else:
3205 else:
3206 hexoutput = fm.hexfunc(ctx.node())
3206 hexoutput = fm.hexfunc(ctx.node())
3207 if default or id:
3207 if default or id:
3208 output = [hexoutput]
3208 output = [hexoutput]
3209 fm.data(id=hexoutput)
3209 fm.data(id=hexoutput)
3210
3210
3211 if num:
3211 if num:
3212 output.append(pycompat.bytestr(ctx.rev()))
3212 output.append(pycompat.bytestr(ctx.rev()))
3213 taglist = ctx.tags()
3213 taglist = ctx.tags()
3214
3214
3215 if default and not ui.quiet:
3215 if default and not ui.quiet:
3216 b = ctx.branch()
3216 b = ctx.branch()
3217 if b != 'default':
3217 if b != 'default':
3218 output.append("(%s)" % b)
3218 output.append("(%s)" % b)
3219
3219
3220 # multiple tags for a single parent separated by '/'
3220 # multiple tags for a single parent separated by '/'
3221 t = '/'.join(taglist)
3221 t = '/'.join(taglist)
3222 if t:
3222 if t:
3223 output.append(t)
3223 output.append(t)
3224
3224
3225 # multiple bookmarks for a single parent separated by '/'
3225 # multiple bookmarks for a single parent separated by '/'
3226 bm = '/'.join(ctx.bookmarks())
3226 bm = '/'.join(ctx.bookmarks())
3227 if bm:
3227 if bm:
3228 output.append(bm)
3228 output.append(bm)
3229 else:
3229 else:
3230 if branch:
3230 if branch:
3231 output.append(ctx.branch())
3231 output.append(ctx.branch())
3232
3232
3233 if tags:
3233 if tags:
3234 output.extend(taglist)
3234 output.extend(taglist)
3235
3235
3236 if bookmarks:
3236 if bookmarks:
3237 output.extend(ctx.bookmarks())
3237 output.extend(ctx.bookmarks())
3238
3238
3239 fm.data(node=ctx.hex())
3239 fm.data(node=ctx.hex())
3240 fm.data(branch=ctx.branch())
3240 fm.data(branch=ctx.branch())
3241 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3241 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3242 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3242 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3243 fm.context(ctx=ctx)
3243 fm.context(ctx=ctx)
3244
3244
3245 fm.plain("%s\n" % ' '.join(output))
3245 fm.plain("%s\n" % ' '.join(output))
3246 fm.end()
3246 fm.end()
3247
3247
3248 @command('import|patch',
3248 @command('import|patch',
3249 [('p', 'strip', 1,
3249 [('p', 'strip', 1,
3250 _('directory strip option for patch. This has the same '
3250 _('directory strip option for patch. This has the same '
3251 'meaning as the corresponding patch option'), _('NUM')),
3251 'meaning as the corresponding patch option'), _('NUM')),
3252 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3252 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3253 ('e', 'edit', False, _('invoke editor on commit messages')),
3253 ('e', 'edit', False, _('invoke editor on commit messages')),
3254 ('f', 'force', None,
3254 ('f', 'force', None,
3255 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3255 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3256 ('', 'no-commit', None,
3256 ('', 'no-commit', None,
3257 _("don't commit, just update the working directory")),
3257 _("don't commit, just update the working directory")),
3258 ('', 'bypass', None,
3258 ('', 'bypass', None,
3259 _("apply patch without touching the working directory")),
3259 _("apply patch without touching the working directory")),
3260 ('', 'partial', None,
3260 ('', 'partial', None,
3261 _('commit even if some hunks fail')),
3261 _('commit even if some hunks fail')),
3262 ('', 'exact', None,
3262 ('', 'exact', None,
3263 _('abort if patch would apply lossily')),
3263 _('abort if patch would apply lossily')),
3264 ('', 'prefix', '',
3264 ('', 'prefix', '',
3265 _('apply patch to subdirectory'), _('DIR')),
3265 _('apply patch to subdirectory'), _('DIR')),
3266 ('', 'import-branch', None,
3266 ('', 'import-branch', None,
3267 _('use any branch information in patch (implied by --exact)'))] +
3267 _('use any branch information in patch (implied by --exact)'))] +
3268 commitopts + commitopts2 + similarityopts,
3268 commitopts + commitopts2 + similarityopts,
3269 _('[OPTION]... PATCH...'),
3269 _('[OPTION]... PATCH...'),
3270 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3270 helpcategory=command.CATEGORY_IMPORT_EXPORT)
3271 def import_(ui, repo, patch1=None, *patches, **opts):
3271 def import_(ui, repo, patch1=None, *patches, **opts):
3272 """import an ordered set of patches
3272 """import an ordered set of patches
3273
3273
3274 Import a list of patches and commit them individually (unless
3274 Import a list of patches and commit them individually (unless
3275 --no-commit is specified).
3275 --no-commit is specified).
3276
3276
3277 To read a patch from standard input (stdin), use "-" as the patch
3277 To read a patch from standard input (stdin), use "-" as the patch
3278 name. If a URL is specified, the patch will be downloaded from
3278 name. If a URL is specified, the patch will be downloaded from
3279 there.
3279 there.
3280
3280
3281 Import first applies changes to the working directory (unless
3281 Import first applies changes to the working directory (unless
3282 --bypass is specified), import will abort if there are outstanding
3282 --bypass is specified), import will abort if there are outstanding
3283 changes.
3283 changes.
3284
3284
3285 Use --bypass to apply and commit patches directly to the
3285 Use --bypass to apply and commit patches directly to the
3286 repository, without affecting the working directory. Without
3286 repository, without affecting the working directory. Without
3287 --exact, patches will be applied on top of the working directory
3287 --exact, patches will be applied on top of the working directory
3288 parent revision.
3288 parent revision.
3289
3289
3290 You can import a patch straight from a mail message. Even patches
3290 You can import a patch straight from a mail message. Even patches
3291 as attachments work (to use the body part, it must have type
3291 as attachments work (to use the body part, it must have type
3292 text/plain or text/x-patch). From and Subject headers of email
3292 text/plain or text/x-patch). From and Subject headers of email
3293 message are used as default committer and commit message. All
3293 message are used as default committer and commit message. All
3294 text/plain body parts before first diff are added to the commit
3294 text/plain body parts before first diff are added to the commit
3295 message.
3295 message.
3296
3296
3297 If the imported patch was generated by :hg:`export`, user and
3297 If the imported patch was generated by :hg:`export`, user and
3298 description from patch override values from message headers and
3298 description from patch override values from message headers and
3299 body. Values given on command line with -m/--message and -u/--user
3299 body. Values given on command line with -m/--message and -u/--user
3300 override these.
3300 override these.
3301
3301
3302 If --exact is specified, import will set the working directory to
3302 If --exact is specified, import will set the working directory to
3303 the parent of each patch before applying it, and will abort if the
3303 the parent of each patch before applying it, and will abort if the
3304 resulting changeset has a different ID than the one recorded in
3304 resulting changeset has a different ID than the one recorded in
3305 the patch. This will guard against various ways that portable
3305 the patch. This will guard against various ways that portable
3306 patch formats and mail systems might fail to transfer Mercurial
3306 patch formats and mail systems might fail to transfer Mercurial
3307 data or metadata. See :hg:`bundle` for lossless transmission.
3307 data or metadata. See :hg:`bundle` for lossless transmission.
3308
3308
3309 Use --partial to ensure a changeset will be created from the patch
3309 Use --partial to ensure a changeset will be created from the patch
3310 even if some hunks fail to apply. Hunks that fail to apply will be
3310 even if some hunks fail to apply. Hunks that fail to apply will be
3311 written to a <target-file>.rej file. Conflicts can then be resolved
3311 written to a <target-file>.rej file. Conflicts can then be resolved
3312 by hand before :hg:`commit --amend` is run to update the created
3312 by hand before :hg:`commit --amend` is run to update the created
3313 changeset. This flag exists to let people import patches that
3313 changeset. This flag exists to let people import patches that
3314 partially apply without losing the associated metadata (author,
3314 partially apply without losing the associated metadata (author,
3315 date, description, ...).
3315 date, description, ...).
3316
3316
3317 .. note::
3317 .. note::
3318
3318
3319 When no hunks apply cleanly, :hg:`import --partial` will create
3319 When no hunks apply cleanly, :hg:`import --partial` will create
3320 an empty changeset, importing only the patch metadata.
3320 an empty changeset, importing only the patch metadata.
3321
3321
3322 With -s/--similarity, hg will attempt to discover renames and
3322 With -s/--similarity, hg will attempt to discover renames and
3323 copies in the patch in the same way as :hg:`addremove`.
3323 copies in the patch in the same way as :hg:`addremove`.
3324
3324
3325 It is possible to use external patch programs to perform the patch
3325 It is possible to use external patch programs to perform the patch
3326 by setting the ``ui.patch`` configuration option. For the default
3326 by setting the ``ui.patch`` configuration option. For the default
3327 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3327 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3328 See :hg:`help config` for more information about configuration
3328 See :hg:`help config` for more information about configuration
3329 files and how to use these options.
3329 files and how to use these options.
3330
3330
3331 See :hg:`help dates` for a list of formats valid for -d/--date.
3331 See :hg:`help dates` for a list of formats valid for -d/--date.
3332
3332
3333 .. container:: verbose
3333 .. container:: verbose
3334
3334
3335 Examples:
3335 Examples:
3336
3336
3337 - import a traditional patch from a website and detect renames::
3337 - import a traditional patch from a website and detect renames::
3338
3338
3339 hg import -s 80 http://example.com/bugfix.patch
3339 hg import -s 80 http://example.com/bugfix.patch
3340
3340
3341 - import a changeset from an hgweb server::
3341 - import a changeset from an hgweb server::
3342
3342
3343 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3343 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3344
3344
3345 - import all the patches in an Unix-style mbox::
3345 - import all the patches in an Unix-style mbox::
3346
3346
3347 hg import incoming-patches.mbox
3347 hg import incoming-patches.mbox
3348
3348
3349 - import patches from stdin::
3349 - import patches from stdin::
3350
3350
3351 hg import -
3351 hg import -
3352
3352
3353 - attempt to exactly restore an exported changeset (not always
3353 - attempt to exactly restore an exported changeset (not always
3354 possible)::
3354 possible)::
3355
3355
3356 hg import --exact proposed-fix.patch
3356 hg import --exact proposed-fix.patch
3357
3357
3358 - use an external tool to apply a patch which is too fuzzy for
3358 - use an external tool to apply a patch which is too fuzzy for
3359 the default internal tool.
3359 the default internal tool.
3360
3360
3361 hg import --config ui.patch="patch --merge" fuzzy.patch
3361 hg import --config ui.patch="patch --merge" fuzzy.patch
3362
3362
3363 - change the default fuzzing from 2 to a less strict 7
3363 - change the default fuzzing from 2 to a less strict 7
3364
3364
3365 hg import --config ui.fuzz=7 fuzz.patch
3365 hg import --config ui.fuzz=7 fuzz.patch
3366
3366
3367 Returns 0 on success, 1 on partial success (see --partial).
3367 Returns 0 on success, 1 on partial success (see --partial).
3368 """
3368 """
3369
3369
3370 opts = pycompat.byteskwargs(opts)
3370 opts = pycompat.byteskwargs(opts)
3371 if not patch1:
3371 if not patch1:
3372 raise error.Abort(_('need at least one patch to import'))
3372 raise error.Abort(_('need at least one patch to import'))
3373
3373
3374 patches = (patch1,) + patches
3374 patches = (patch1,) + patches
3375
3375
3376 date = opts.get('date')
3376 date = opts.get('date')
3377 if date:
3377 if date:
3378 opts['date'] = dateutil.parsedate(date)
3378 opts['date'] = dateutil.parsedate(date)
3379
3379
3380 exact = opts.get('exact')
3380 exact = opts.get('exact')
3381 update = not opts.get('bypass')
3381 update = not opts.get('bypass')
3382 if not update and opts.get('no_commit'):
3382 if not update and opts.get('no_commit'):
3383 raise error.Abort(_('cannot use --no-commit with --bypass'))
3383 raise error.Abort(_('cannot use --no-commit with --bypass'))
3384 try:
3384 try:
3385 sim = float(opts.get('similarity') or 0)
3385 sim = float(opts.get('similarity') or 0)
3386 except ValueError:
3386 except ValueError:
3387 raise error.Abort(_('similarity must be a number'))
3387 raise error.Abort(_('similarity must be a number'))
3388 if sim < 0 or sim > 100:
3388 if sim < 0 or sim > 100:
3389 raise error.Abort(_('similarity must be between 0 and 100'))
3389 raise error.Abort(_('similarity must be between 0 and 100'))
3390 if sim and not update:
3390 if sim and not update:
3391 raise error.Abort(_('cannot use --similarity with --bypass'))
3391 raise error.Abort(_('cannot use --similarity with --bypass'))
3392 if exact:
3392 if exact:
3393 if opts.get('edit'):
3393 if opts.get('edit'):
3394 raise error.Abort(_('cannot use --exact with --edit'))
3394 raise error.Abort(_('cannot use --exact with --edit'))
3395 if opts.get('prefix'):
3395 if opts.get('prefix'):
3396 raise error.Abort(_('cannot use --exact with --prefix'))
3396 raise error.Abort(_('cannot use --exact with --prefix'))
3397
3397
3398 base = opts["base"]
3398 base = opts["base"]
3399 msgs = []
3399 msgs = []
3400 ret = 0
3400 ret = 0
3401
3401
3402 with repo.wlock():
3402 with repo.wlock():
3403 if update:
3403 if update:
3404 cmdutil.checkunfinished(repo)
3404 cmdutil.checkunfinished(repo)
3405 if (exact or not opts.get('force')):
3405 if (exact or not opts.get('force')):
3406 cmdutil.bailifchanged(repo)
3406 cmdutil.bailifchanged(repo)
3407
3407
3408 if not opts.get('no_commit'):
3408 if not opts.get('no_commit'):
3409 lock = repo.lock
3409 lock = repo.lock
3410 tr = lambda: repo.transaction('import')
3410 tr = lambda: repo.transaction('import')
3411 dsguard = util.nullcontextmanager
3411 dsguard = util.nullcontextmanager
3412 else:
3412 else:
3413 lock = util.nullcontextmanager
3413 lock = util.nullcontextmanager
3414 tr = util.nullcontextmanager
3414 tr = util.nullcontextmanager
3415 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3415 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3416 with lock(), tr(), dsguard():
3416 with lock(), tr(), dsguard():
3417 parents = repo[None].parents()
3417 parents = repo[None].parents()
3418 for patchurl in patches:
3418 for patchurl in patches:
3419 if patchurl == '-':
3419 if patchurl == '-':
3420 ui.status(_('applying patch from stdin\n'))
3420 ui.status(_('applying patch from stdin\n'))
3421 patchfile = ui.fin
3421 patchfile = ui.fin
3422 patchurl = 'stdin' # for error message
3422 patchurl = 'stdin' # for error message
3423 else:
3423 else:
3424 patchurl = os.path.join(base, patchurl)
3424 patchurl = os.path.join(base, patchurl)
3425 ui.status(_('applying %s\n') % patchurl)
3425 ui.status(_('applying %s\n') % patchurl)
3426 patchfile = hg.openpath(ui, patchurl)
3426 patchfile = hg.openpath(ui, patchurl)
3427
3427
3428 haspatch = False
3428 haspatch = False
3429 for hunk in patch.split(patchfile):
3429 for hunk in patch.split(patchfile):
3430 with patch.extract(ui, hunk) as patchdata:
3430 with patch.extract(ui, hunk) as patchdata:
3431 msg, node, rej = cmdutil.tryimportone(ui, repo,
3431 msg, node, rej = cmdutil.tryimportone(ui, repo,
3432 patchdata,
3432 patchdata,
3433 parents, opts,
3433 parents, opts,
3434 msgs, hg.clean)
3434 msgs, hg.clean)
3435 if msg:
3435 if msg:
3436 haspatch = True
3436 haspatch = True
3437 ui.note(msg + '\n')
3437 ui.note(msg + '\n')
3438 if update or exact:
3438 if update or exact:
3439 parents = repo[None].parents()
3439 parents = repo[None].parents()
3440 else:
3440 else:
3441 parents = [repo[node]]
3441 parents = [repo[node]]
3442 if rej:
3442 if rej:
3443 ui.write_err(_("patch applied partially\n"))
3443 ui.write_err(_("patch applied partially\n"))
3444 ui.write_err(_("(fix the .rej files and run "
3444 ui.write_err(_("(fix the .rej files and run "
3445 "`hg commit --amend`)\n"))
3445 "`hg commit --amend`)\n"))
3446 ret = 1
3446 ret = 1
3447 break
3447 break
3448
3448
3449 if not haspatch:
3449 if not haspatch:
3450 raise error.Abort(_('%s: no diffs found') % patchurl)
3450 raise error.Abort(_('%s: no diffs found') % patchurl)
3451
3451
3452 if msgs:
3452 if msgs:
3453 repo.savecommitmessage('\n* * *\n'.join(msgs))
3453 repo.savecommitmessage('\n* * *\n'.join(msgs))
3454 return ret
3454 return ret
3455
3455
3456 @command('incoming|in',
3456 @command('incoming|in',
3457 [('f', 'force', None,
3457 [('f', 'force', None,
3458 _('run even if remote repository is unrelated')),
3458 _('run even if remote repository is unrelated')),
3459 ('n', 'newest-first', None, _('show newest record first')),
3459 ('n', 'newest-first', None, _('show newest record first')),
3460 ('', 'bundle', '',
3460 ('', 'bundle', '',
3461 _('file to store the bundles into'), _('FILE')),
3461 _('file to store the bundles into'), _('FILE')),
3462 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3462 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3463 ('B', 'bookmarks', False, _("compare bookmarks")),
3463 ('B', 'bookmarks', False, _("compare bookmarks")),
3464 ('b', 'branch', [],
3464 ('b', 'branch', [],
3465 _('a specific branch you would like to pull'), _('BRANCH')),
3465 _('a specific branch you would like to pull'), _('BRANCH')),
3466 ] + logopts + remoteopts + subrepoopts,
3466 ] + logopts + remoteopts + subrepoopts,
3467 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3467 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
3468 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3468 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3469 def incoming(ui, repo, source="default", **opts):
3469 def incoming(ui, repo, source="default", **opts):
3470 """show new changesets found in source
3470 """show new changesets found in source
3471
3471
3472 Show new changesets found in the specified path/URL or the default
3472 Show new changesets found in the specified path/URL or the default
3473 pull location. These are the changesets that would have been pulled
3473 pull location. These are the changesets that would have been pulled
3474 by :hg:`pull` at the time you issued this command.
3474 by :hg:`pull` at the time you issued this command.
3475
3475
3476 See pull for valid source format details.
3476 See pull for valid source format details.
3477
3477
3478 .. container:: verbose
3478 .. container:: verbose
3479
3479
3480 With -B/--bookmarks, the result of bookmark comparison between
3480 With -B/--bookmarks, the result of bookmark comparison between
3481 local and remote repositories is displayed. With -v/--verbose,
3481 local and remote repositories is displayed. With -v/--verbose,
3482 status is also displayed for each bookmark like below::
3482 status is also displayed for each bookmark like below::
3483
3483
3484 BM1 01234567890a added
3484 BM1 01234567890a added
3485 BM2 1234567890ab advanced
3485 BM2 1234567890ab advanced
3486 BM3 234567890abc diverged
3486 BM3 234567890abc diverged
3487 BM4 34567890abcd changed
3487 BM4 34567890abcd changed
3488
3488
3489 The action taken locally when pulling depends on the
3489 The action taken locally when pulling depends on the
3490 status of each bookmark:
3490 status of each bookmark:
3491
3491
3492 :``added``: pull will create it
3492 :``added``: pull will create it
3493 :``advanced``: pull will update it
3493 :``advanced``: pull will update it
3494 :``diverged``: pull will create a divergent bookmark
3494 :``diverged``: pull will create a divergent bookmark
3495 :``changed``: result depends on remote changesets
3495 :``changed``: result depends on remote changesets
3496
3496
3497 From the point of view of pulling behavior, bookmark
3497 From the point of view of pulling behavior, bookmark
3498 existing only in the remote repository are treated as ``added``,
3498 existing only in the remote repository are treated as ``added``,
3499 even if it is in fact locally deleted.
3499 even if it is in fact locally deleted.
3500
3500
3501 .. container:: verbose
3501 .. container:: verbose
3502
3502
3503 For remote repository, using --bundle avoids downloading the
3503 For remote repository, using --bundle avoids downloading the
3504 changesets twice if the incoming is followed by a pull.
3504 changesets twice if the incoming is followed by a pull.
3505
3505
3506 Examples:
3506 Examples:
3507
3507
3508 - show incoming changes with patches and full description::
3508 - show incoming changes with patches and full description::
3509
3509
3510 hg incoming -vp
3510 hg incoming -vp
3511
3511
3512 - show incoming changes excluding merges, store a bundle::
3512 - show incoming changes excluding merges, store a bundle::
3513
3513
3514 hg in -vpM --bundle incoming.hg
3514 hg in -vpM --bundle incoming.hg
3515 hg pull incoming.hg
3515 hg pull incoming.hg
3516
3516
3517 - briefly list changes inside a bundle::
3517 - briefly list changes inside a bundle::
3518
3518
3519 hg in changes.hg -T "{desc|firstline}\\n"
3519 hg in changes.hg -T "{desc|firstline}\\n"
3520
3520
3521 Returns 0 if there are incoming changes, 1 otherwise.
3521 Returns 0 if there are incoming changes, 1 otherwise.
3522 """
3522 """
3523 opts = pycompat.byteskwargs(opts)
3523 opts = pycompat.byteskwargs(opts)
3524 if opts.get('graph'):
3524 if opts.get('graph'):
3525 logcmdutil.checkunsupportedgraphflags([], opts)
3525 logcmdutil.checkunsupportedgraphflags([], opts)
3526 def display(other, chlist, displayer):
3526 def display(other, chlist, displayer):
3527 revdag = logcmdutil.graphrevs(other, chlist, opts)
3527 revdag = logcmdutil.graphrevs(other, chlist, opts)
3528 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3528 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3529 graphmod.asciiedges)
3529 graphmod.asciiedges)
3530
3530
3531 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3531 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3532 return 0
3532 return 0
3533
3533
3534 if opts.get('bundle') and opts.get('subrepos'):
3534 if opts.get('bundle') and opts.get('subrepos'):
3535 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3535 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3536
3536
3537 if opts.get('bookmarks'):
3537 if opts.get('bookmarks'):
3538 source, branches = hg.parseurl(ui.expandpath(source),
3538 source, branches = hg.parseurl(ui.expandpath(source),
3539 opts.get('branch'))
3539 opts.get('branch'))
3540 other = hg.peer(repo, opts, source)
3540 other = hg.peer(repo, opts, source)
3541 if 'bookmarks' not in other.listkeys('namespaces'):
3541 if 'bookmarks' not in other.listkeys('namespaces'):
3542 ui.warn(_("remote doesn't support bookmarks\n"))
3542 ui.warn(_("remote doesn't support bookmarks\n"))
3543 return 0
3543 return 0
3544 ui.pager('incoming')
3544 ui.pager('incoming')
3545 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3545 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3546 return bookmarks.incoming(ui, repo, other)
3546 return bookmarks.incoming(ui, repo, other)
3547
3547
3548 repo._subtoppath = ui.expandpath(source)
3548 repo._subtoppath = ui.expandpath(source)
3549 try:
3549 try:
3550 return hg.incoming(ui, repo, source, opts)
3550 return hg.incoming(ui, repo, source, opts)
3551 finally:
3551 finally:
3552 del repo._subtoppath
3552 del repo._subtoppath
3553
3553
3554
3554
3555 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3555 @command('init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3556 helpcategory=command.CATEGORY_REPO_CREATION,
3556 helpcategory=command.CATEGORY_REPO_CREATION,
3557 helpbasic=True, norepo=True)
3557 helpbasic=True, norepo=True)
3558 def init(ui, dest=".", **opts):
3558 def init(ui, dest=".", **opts):
3559 """create a new repository in the given directory
3559 """create a new repository in the given directory
3560
3560
3561 Initialize a new repository in the given directory. If the given
3561 Initialize a new repository in the given directory. If the given
3562 directory does not exist, it will be created.
3562 directory does not exist, it will be created.
3563
3563
3564 If no directory is given, the current directory is used.
3564 If no directory is given, the current directory is used.
3565
3565
3566 It is possible to specify an ``ssh://`` URL as the destination.
3566 It is possible to specify an ``ssh://`` URL as the destination.
3567 See :hg:`help urls` for more information.
3567 See :hg:`help urls` for more information.
3568
3568
3569 Returns 0 on success.
3569 Returns 0 on success.
3570 """
3570 """
3571 opts = pycompat.byteskwargs(opts)
3571 opts = pycompat.byteskwargs(opts)
3572 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3572 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3573
3573
3574 @command('locate',
3574 @command('locate',
3575 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3575 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3576 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3576 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3577 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3577 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3578 ] + walkopts,
3578 ] + walkopts,
3579 _('[OPTION]... [PATTERN]...'),
3579 _('[OPTION]... [PATTERN]...'),
3580 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3580 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
3581 def locate(ui, repo, *pats, **opts):
3581 def locate(ui, repo, *pats, **opts):
3582 """locate files matching specific patterns (DEPRECATED)
3582 """locate files matching specific patterns (DEPRECATED)
3583
3583
3584 Print files under Mercurial control in the working directory whose
3584 Print files under Mercurial control in the working directory whose
3585 names match the given patterns.
3585 names match the given patterns.
3586
3586
3587 By default, this command searches all directories in the working
3587 By default, this command searches all directories in the working
3588 directory. To search just the current directory and its
3588 directory. To search just the current directory and its
3589 subdirectories, use "--include .".
3589 subdirectories, use "--include .".
3590
3590
3591 If no patterns are given to match, this command prints the names
3591 If no patterns are given to match, this command prints the names
3592 of all files under Mercurial control in the working directory.
3592 of all files under Mercurial control in the working directory.
3593
3593
3594 If you want to feed the output of this command into the "xargs"
3594 If you want to feed the output of this command into the "xargs"
3595 command, use the -0 option to both this command and "xargs". This
3595 command, use the -0 option to both this command and "xargs". This
3596 will avoid the problem of "xargs" treating single filenames that
3596 will avoid the problem of "xargs" treating single filenames that
3597 contain whitespace as multiple filenames.
3597 contain whitespace as multiple filenames.
3598
3598
3599 See :hg:`help files` for a more versatile command.
3599 See :hg:`help files` for a more versatile command.
3600
3600
3601 Returns 0 if a match is found, 1 otherwise.
3601 Returns 0 if a match is found, 1 otherwise.
3602 """
3602 """
3603 opts = pycompat.byteskwargs(opts)
3603 opts = pycompat.byteskwargs(opts)
3604 if opts.get('print0'):
3604 if opts.get('print0'):
3605 end = '\0'
3605 end = '\0'
3606 else:
3606 else:
3607 end = '\n'
3607 end = '\n'
3608 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3608 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3609
3609
3610 ret = 1
3610 ret = 1
3611 m = scmutil.match(ctx, pats, opts, default='relglob',
3611 m = scmutil.match(ctx, pats, opts, default='relglob',
3612 badfn=lambda x, y: False)
3612 badfn=lambda x, y: False)
3613
3613
3614 ui.pager('locate')
3614 ui.pager('locate')
3615 if ctx.rev() is None:
3615 if ctx.rev() is None:
3616 # When run on the working copy, "locate" includes removed files, so
3616 # When run on the working copy, "locate" includes removed files, so
3617 # we get the list of files from the dirstate.
3617 # we get the list of files from the dirstate.
3618 filesgen = sorted(repo.dirstate.matches(m))
3618 filesgen = sorted(repo.dirstate.matches(m))
3619 else:
3619 else:
3620 filesgen = ctx.matches(m)
3620 filesgen = ctx.matches(m)
3621 for abs in filesgen:
3621 for abs in filesgen:
3622 if opts.get('fullpath'):
3622 if opts.get('fullpath'):
3623 ui.write(repo.wjoin(abs), end)
3623 ui.write(repo.wjoin(abs), end)
3624 else:
3624 else:
3625 ui.write(((pats and m.rel(abs)) or abs), end)
3625 ui.write(((pats and m.rel(abs)) or abs), end)
3626 ret = 0
3626 ret = 0
3627
3627
3628 return ret
3628 return ret
3629
3629
3630 @command('log|history',
3630 @command('log|history',
3631 [('f', 'follow', None,
3631 [('f', 'follow', None,
3632 _('follow changeset history, or file history across copies and renames')),
3632 _('follow changeset history, or file history across copies and renames')),
3633 ('', 'follow-first', None,
3633 ('', 'follow-first', None,
3634 _('only follow the first parent of merge changesets (DEPRECATED)')),
3634 _('only follow the first parent of merge changesets (DEPRECATED)')),
3635 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3635 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3636 ('C', 'copies', None, _('show copied files')),
3636 ('C', 'copies', None, _('show copied files')),
3637 ('k', 'keyword', [],
3637 ('k', 'keyword', [],
3638 _('do case-insensitive search for a given text'), _('TEXT')),
3638 _('do case-insensitive search for a given text'), _('TEXT')),
3639 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3639 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3640 ('L', 'line-range', [],
3640 ('L', 'line-range', [],
3641 _('follow line range of specified file (EXPERIMENTAL)'),
3641 _('follow line range of specified file (EXPERIMENTAL)'),
3642 _('FILE,RANGE')),
3642 _('FILE,RANGE')),
3643 ('', 'removed', None, _('include revisions where files were removed')),
3643 ('', 'removed', None, _('include revisions where files were removed')),
3644 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3644 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3645 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3645 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3646 ('', 'only-branch', [],
3646 ('', 'only-branch', [],
3647 _('show only changesets within the given named branch (DEPRECATED)'),
3647 _('show only changesets within the given named branch (DEPRECATED)'),
3648 _('BRANCH')),
3648 _('BRANCH')),
3649 ('b', 'branch', [],
3649 ('b', 'branch', [],
3650 _('show changesets within the given named branch'), _('BRANCH')),
3650 _('show changesets within the given named branch'), _('BRANCH')),
3651 ('P', 'prune', [],
3651 ('P', 'prune', [],
3652 _('do not display revision or any of its ancestors'), _('REV')),
3652 _('do not display revision or any of its ancestors'), _('REV')),
3653 ] + logopts + walkopts,
3653 ] + logopts + walkopts,
3654 _('[OPTION]... [FILE]'),
3654 _('[OPTION]... [FILE]'),
3655 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3655 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3656 helpbasic=True, inferrepo=True,
3656 helpbasic=True, inferrepo=True,
3657 intents={INTENT_READONLY})
3657 intents={INTENT_READONLY})
3658 def log(ui, repo, *pats, **opts):
3658 def log(ui, repo, *pats, **opts):
3659 """show revision history of entire repository or files
3659 """show revision history of entire repository or files
3660
3660
3661 Print the revision history of the specified files or the entire
3661 Print the revision history of the specified files or the entire
3662 project.
3662 project.
3663
3663
3664 If no revision range is specified, the default is ``tip:0`` unless
3664 If no revision range is specified, the default is ``tip:0`` unless
3665 --follow is set, in which case the working directory parent is
3665 --follow is set, in which case the working directory parent is
3666 used as the starting revision.
3666 used as the starting revision.
3667
3667
3668 File history is shown without following rename or copy history of
3668 File history is shown without following rename or copy history of
3669 files. Use -f/--follow with a filename to follow history across
3669 files. Use -f/--follow with a filename to follow history across
3670 renames and copies. --follow without a filename will only show
3670 renames and copies. --follow without a filename will only show
3671 ancestors of the starting revision.
3671 ancestors of the starting revision.
3672
3672
3673 By default this command prints revision number and changeset id,
3673 By default this command prints revision number and changeset id,
3674 tags, non-trivial parents, user, date and time, and a summary for
3674 tags, non-trivial parents, user, date and time, and a summary for
3675 each commit. When the -v/--verbose switch is used, the list of
3675 each commit. When the -v/--verbose switch is used, the list of
3676 changed files and full commit message are shown.
3676 changed files and full commit message are shown.
3677
3677
3678 With --graph the revisions are shown as an ASCII art DAG with the most
3678 With --graph the revisions are shown as an ASCII art DAG with the most
3679 recent changeset at the top.
3679 recent changeset at the top.
3680 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3680 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3681 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3681 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3682 changeset from the lines below is a parent of the 'o' merge on the same
3682 changeset from the lines below is a parent of the 'o' merge on the same
3683 line.
3683 line.
3684 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3684 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3685 of a '|' indicates one or more revisions in a path are omitted.
3685 of a '|' indicates one or more revisions in a path are omitted.
3686
3686
3687 .. container:: verbose
3687 .. container:: verbose
3688
3688
3689 Use -L/--line-range FILE,M:N options to follow the history of lines
3689 Use -L/--line-range FILE,M:N options to follow the history of lines
3690 from M to N in FILE. With -p/--patch only diff hunks affecting
3690 from M to N in FILE. With -p/--patch only diff hunks affecting
3691 specified line range will be shown. This option requires --follow;
3691 specified line range will be shown. This option requires --follow;
3692 it can be specified multiple times. Currently, this option is not
3692 it can be specified multiple times. Currently, this option is not
3693 compatible with --graph. This option is experimental.
3693 compatible with --graph. This option is experimental.
3694
3694
3695 .. note::
3695 .. note::
3696
3696
3697 :hg:`log --patch` may generate unexpected diff output for merge
3697 :hg:`log --patch` may generate unexpected diff output for merge
3698 changesets, as it will only compare the merge changeset against
3698 changesets, as it will only compare the merge changeset against
3699 its first parent. Also, only files different from BOTH parents
3699 its first parent. Also, only files different from BOTH parents
3700 will appear in files:.
3700 will appear in files:.
3701
3701
3702 .. note::
3702 .. note::
3703
3703
3704 For performance reasons, :hg:`log FILE` may omit duplicate changes
3704 For performance reasons, :hg:`log FILE` may omit duplicate changes
3705 made on branches and will not show removals or mode changes. To
3705 made on branches and will not show removals or mode changes. To
3706 see all such changes, use the --removed switch.
3706 see all such changes, use the --removed switch.
3707
3707
3708 .. container:: verbose
3708 .. container:: verbose
3709
3709
3710 .. note::
3710 .. note::
3711
3711
3712 The history resulting from -L/--line-range options depends on diff
3712 The history resulting from -L/--line-range options depends on diff
3713 options; for instance if white-spaces are ignored, respective changes
3713 options; for instance if white-spaces are ignored, respective changes
3714 with only white-spaces in specified line range will not be listed.
3714 with only white-spaces in specified line range will not be listed.
3715
3715
3716 .. container:: verbose
3716 .. container:: verbose
3717
3717
3718 Some examples:
3718 Some examples:
3719
3719
3720 - changesets with full descriptions and file lists::
3720 - changesets with full descriptions and file lists::
3721
3721
3722 hg log -v
3722 hg log -v
3723
3723
3724 - changesets ancestral to the working directory::
3724 - changesets ancestral to the working directory::
3725
3725
3726 hg log -f
3726 hg log -f
3727
3727
3728 - last 10 commits on the current branch::
3728 - last 10 commits on the current branch::
3729
3729
3730 hg log -l 10 -b .
3730 hg log -l 10 -b .
3731
3731
3732 - changesets showing all modifications of a file, including removals::
3732 - changesets showing all modifications of a file, including removals::
3733
3733
3734 hg log --removed file.c
3734 hg log --removed file.c
3735
3735
3736 - all changesets that touch a directory, with diffs, excluding merges::
3736 - all changesets that touch a directory, with diffs, excluding merges::
3737
3737
3738 hg log -Mp lib/
3738 hg log -Mp lib/
3739
3739
3740 - all revision numbers that match a keyword::
3740 - all revision numbers that match a keyword::
3741
3741
3742 hg log -k bug --template "{rev}\\n"
3742 hg log -k bug --template "{rev}\\n"
3743
3743
3744 - the full hash identifier of the working directory parent::
3744 - the full hash identifier of the working directory parent::
3745
3745
3746 hg log -r . --template "{node}\\n"
3746 hg log -r . --template "{node}\\n"
3747
3747
3748 - list available log templates::
3748 - list available log templates::
3749
3749
3750 hg log -T list
3750 hg log -T list
3751
3751
3752 - check if a given changeset is included in a tagged release::
3752 - check if a given changeset is included in a tagged release::
3753
3753
3754 hg log -r "a21ccf and ancestor(1.9)"
3754 hg log -r "a21ccf and ancestor(1.9)"
3755
3755
3756 - find all changesets by some user in a date range::
3756 - find all changesets by some user in a date range::
3757
3757
3758 hg log -k alice -d "may 2008 to jul 2008"
3758 hg log -k alice -d "may 2008 to jul 2008"
3759
3759
3760 - summary of all changesets after the last tag::
3760 - summary of all changesets after the last tag::
3761
3761
3762 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3762 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3763
3763
3764 - changesets touching lines 13 to 23 for file.c::
3764 - changesets touching lines 13 to 23 for file.c::
3765
3765
3766 hg log -L file.c,13:23
3766 hg log -L file.c,13:23
3767
3767
3768 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3768 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3769 main.c with patch::
3769 main.c with patch::
3770
3770
3771 hg log -L file.c,13:23 -L main.c,2:6 -p
3771 hg log -L file.c,13:23 -L main.c,2:6 -p
3772
3772
3773 See :hg:`help dates` for a list of formats valid for -d/--date.
3773 See :hg:`help dates` for a list of formats valid for -d/--date.
3774
3774
3775 See :hg:`help revisions` for more about specifying and ordering
3775 See :hg:`help revisions` for more about specifying and ordering
3776 revisions.
3776 revisions.
3777
3777
3778 See :hg:`help templates` for more about pre-packaged styles and
3778 See :hg:`help templates` for more about pre-packaged styles and
3779 specifying custom templates. The default template used by the log
3779 specifying custom templates. The default template used by the log
3780 command can be customized via the ``ui.logtemplate`` configuration
3780 command can be customized via the ``ui.logtemplate`` configuration
3781 setting.
3781 setting.
3782
3782
3783 Returns 0 on success.
3783 Returns 0 on success.
3784
3784
3785 """
3785 """
3786 opts = pycompat.byteskwargs(opts)
3786 opts = pycompat.byteskwargs(opts)
3787 linerange = opts.get('line_range')
3787 linerange = opts.get('line_range')
3788
3788
3789 if linerange and not opts.get('follow'):
3789 if linerange and not opts.get('follow'):
3790 raise error.Abort(_('--line-range requires --follow'))
3790 raise error.Abort(_('--line-range requires --follow'))
3791
3791
3792 if linerange and pats:
3792 if linerange and pats:
3793 # TODO: take pats as patterns with no line-range filter
3793 # TODO: take pats as patterns with no line-range filter
3794 raise error.Abort(
3794 raise error.Abort(
3795 _('FILE arguments are not compatible with --line-range option')
3795 _('FILE arguments are not compatible with --line-range option')
3796 )
3796 )
3797
3797
3798 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3798 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3799 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3799 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3800 if linerange:
3800 if linerange:
3801 # TODO: should follow file history from logcmdutil._initialrevs(),
3801 # TODO: should follow file history from logcmdutil._initialrevs(),
3802 # then filter the result by logcmdutil._makerevset() and --limit
3802 # then filter the result by logcmdutil._makerevset() and --limit
3803 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3803 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3804
3804
3805 getrenamed = None
3805 getrenamed = None
3806 if opts.get('copies'):
3806 if opts.get('copies'):
3807 endrev = None
3807 endrev = None
3808 if revs:
3808 if revs:
3809 endrev = revs.max() + 1
3809 endrev = revs.max() + 1
3810 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3810 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3811
3811
3812 ui.pager('log')
3812 ui.pager('log')
3813 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3813 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3814 buffered=True)
3814 buffered=True)
3815 if opts.get('graph'):
3815 if opts.get('graph'):
3816 displayfn = logcmdutil.displaygraphrevs
3816 displayfn = logcmdutil.displaygraphrevs
3817 else:
3817 else:
3818 displayfn = logcmdutil.displayrevs
3818 displayfn = logcmdutil.displayrevs
3819 displayfn(ui, repo, revs, displayer, getrenamed)
3819 displayfn(ui, repo, revs, displayer, getrenamed)
3820
3820
3821 @command('manifest',
3821 @command('manifest',
3822 [('r', 'rev', '', _('revision to display'), _('REV')),
3822 [('r', 'rev', '', _('revision to display'), _('REV')),
3823 ('', 'all', False, _("list files from all revisions"))]
3823 ('', 'all', False, _("list files from all revisions"))]
3824 + formatteropts,
3824 + formatteropts,
3825 _('[-r REV]'),
3825 _('[-r REV]'),
3826 helpcategory=command.CATEGORY_MAINTENANCE,
3826 helpcategory=command.CATEGORY_MAINTENANCE,
3827 intents={INTENT_READONLY})
3827 intents={INTENT_READONLY})
3828 def manifest(ui, repo, node=None, rev=None, **opts):
3828 def manifest(ui, repo, node=None, rev=None, **opts):
3829 """output the current or given revision of the project manifest
3829 """output the current or given revision of the project manifest
3830
3830
3831 Print a list of version controlled files for the given revision.
3831 Print a list of version controlled files for the given revision.
3832 If no revision is given, the first parent of the working directory
3832 If no revision is given, the first parent of the working directory
3833 is used, or the null revision if no revision is checked out.
3833 is used, or the null revision if no revision is checked out.
3834
3834
3835 With -v, print file permissions, symlink and executable bits.
3835 With -v, print file permissions, symlink and executable bits.
3836 With --debug, print file revision hashes.
3836 With --debug, print file revision hashes.
3837
3837
3838 If option --all is specified, the list of all files from all revisions
3838 If option --all is specified, the list of all files from all revisions
3839 is printed. This includes deleted and renamed files.
3839 is printed. This includes deleted and renamed files.
3840
3840
3841 Returns 0 on success.
3841 Returns 0 on success.
3842 """
3842 """
3843 opts = pycompat.byteskwargs(opts)
3843 opts = pycompat.byteskwargs(opts)
3844 fm = ui.formatter('manifest', opts)
3844 fm = ui.formatter('manifest', opts)
3845
3845
3846 if opts.get('all'):
3846 if opts.get('all'):
3847 if rev or node:
3847 if rev or node:
3848 raise error.Abort(_("can't specify a revision with --all"))
3848 raise error.Abort(_("can't specify a revision with --all"))
3849
3849
3850 res = set()
3850 res = set()
3851 for rev in repo:
3851 for rev in repo:
3852 ctx = repo[rev]
3852 ctx = repo[rev]
3853 res |= set(ctx.files())
3853 res |= set(ctx.files())
3854
3854
3855 ui.pager('manifest')
3855 ui.pager('manifest')
3856 for f in sorted(res):
3856 for f in sorted(res):
3857 fm.startitem()
3857 fm.startitem()
3858 fm.write("path", '%s\n', f)
3858 fm.write("path", '%s\n', f)
3859 fm.end()
3859 fm.end()
3860 return
3860 return
3861
3861
3862 if rev and node:
3862 if rev and node:
3863 raise error.Abort(_("please specify just one revision"))
3863 raise error.Abort(_("please specify just one revision"))
3864
3864
3865 if not node:
3865 if not node:
3866 node = rev
3866 node = rev
3867
3867
3868 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3868 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3869 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3869 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3870 if node:
3870 if node:
3871 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3871 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3872 ctx = scmutil.revsingle(repo, node)
3872 ctx = scmutil.revsingle(repo, node)
3873 mf = ctx.manifest()
3873 mf = ctx.manifest()
3874 ui.pager('manifest')
3874 ui.pager('manifest')
3875 for f in ctx:
3875 for f in ctx:
3876 fm.startitem()
3876 fm.startitem()
3877 fm.context(ctx=ctx)
3877 fm.context(ctx=ctx)
3878 fl = ctx[f].flags()
3878 fl = ctx[f].flags()
3879 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3879 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3880 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3880 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3881 fm.write('path', '%s\n', f)
3881 fm.write('path', '%s\n', f)
3882 fm.end()
3882 fm.end()
3883
3883
3884 @command('merge',
3884 @command('merge',
3885 [('f', 'force', None,
3885 [('f', 'force', None,
3886 _('force a merge including outstanding changes (DEPRECATED)')),
3886 _('force a merge including outstanding changes (DEPRECATED)')),
3887 ('r', 'rev', '', _('revision to merge'), _('REV')),
3887 ('r', 'rev', '', _('revision to merge'), _('REV')),
3888 ('P', 'preview', None,
3888 ('P', 'preview', None,
3889 _('review revisions to merge (no merge is performed)')),
3889 _('review revisions to merge (no merge is performed)')),
3890 ('', 'abort', None, _('abort the ongoing merge')),
3890 ('', 'abort', None, _('abort the ongoing merge')),
3891 ] + mergetoolopts,
3891 ] + mergetoolopts,
3892 _('[-P] [[-r] REV]'),
3892 _('[-P] [[-r] REV]'),
3893 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3893 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, helpbasic=True)
3894 def merge(ui, repo, node=None, **opts):
3894 def merge(ui, repo, node=None, **opts):
3895 """merge another revision into working directory
3895 """merge another revision into working directory
3896
3896
3897 The current working directory is updated with all changes made in
3897 The current working directory is updated with all changes made in
3898 the requested revision since the last common predecessor revision.
3898 the requested revision since the last common predecessor revision.
3899
3899
3900 Files that changed between either parent are marked as changed for
3900 Files that changed between either parent are marked as changed for
3901 the next commit and a commit must be performed before any further
3901 the next commit and a commit must be performed before any further
3902 updates to the repository are allowed. The next commit will have
3902 updates to the repository are allowed. The next commit will have
3903 two parents.
3903 two parents.
3904
3904
3905 ``--tool`` can be used to specify the merge tool used for file
3905 ``--tool`` can be used to specify the merge tool used for file
3906 merges. It overrides the HGMERGE environment variable and your
3906 merges. It overrides the HGMERGE environment variable and your
3907 configuration files. See :hg:`help merge-tools` for options.
3907 configuration files. See :hg:`help merge-tools` for options.
3908
3908
3909 If no revision is specified, the working directory's parent is a
3909 If no revision is specified, the working directory's parent is a
3910 head revision, and the current branch contains exactly one other
3910 head revision, and the current branch contains exactly one other
3911 head, the other head is merged with by default. Otherwise, an
3911 head, the other head is merged with by default. Otherwise, an
3912 explicit revision with which to merge with must be provided.
3912 explicit revision with which to merge with must be provided.
3913
3913
3914 See :hg:`help resolve` for information on handling file conflicts.
3914 See :hg:`help resolve` for information on handling file conflicts.
3915
3915
3916 To undo an uncommitted merge, use :hg:`merge --abort` which
3916 To undo an uncommitted merge, use :hg:`merge --abort` which
3917 will check out a clean copy of the original merge parent, losing
3917 will check out a clean copy of the original merge parent, losing
3918 all changes.
3918 all changes.
3919
3919
3920 Returns 0 on success, 1 if there are unresolved files.
3920 Returns 0 on success, 1 if there are unresolved files.
3921 """
3921 """
3922
3922
3923 opts = pycompat.byteskwargs(opts)
3923 opts = pycompat.byteskwargs(opts)
3924 abort = opts.get('abort')
3924 abort = opts.get('abort')
3925 if abort and repo.dirstate.p2() == nullid:
3925 if abort and repo.dirstate.p2() == nullid:
3926 cmdutil.wrongtooltocontinue(repo, _('merge'))
3926 cmdutil.wrongtooltocontinue(repo, _('merge'))
3927 if abort:
3927 if abort:
3928 if node:
3928 if node:
3929 raise error.Abort(_("cannot specify a node with --abort"))
3929 raise error.Abort(_("cannot specify a node with --abort"))
3930 if opts.get('rev'):
3930 if opts.get('rev'):
3931 raise error.Abort(_("cannot specify both --rev and --abort"))
3931 raise error.Abort(_("cannot specify both --rev and --abort"))
3932 if opts.get('preview'):
3932 if opts.get('preview'):
3933 raise error.Abort(_("cannot specify --preview with --abort"))
3933 raise error.Abort(_("cannot specify --preview with --abort"))
3934 if opts.get('rev') and node:
3934 if opts.get('rev') and node:
3935 raise error.Abort(_("please specify just one revision"))
3935 raise error.Abort(_("please specify just one revision"))
3936 if not node:
3936 if not node:
3937 node = opts.get('rev')
3937 node = opts.get('rev')
3938
3938
3939 if node:
3939 if node:
3940 node = scmutil.revsingle(repo, node).node()
3940 node = scmutil.revsingle(repo, node).node()
3941
3941
3942 if not node and not abort:
3942 if not node and not abort:
3943 node = repo[destutil.destmerge(repo)].node()
3943 node = repo[destutil.destmerge(repo)].node()
3944
3944
3945 if opts.get('preview'):
3945 if opts.get('preview'):
3946 # find nodes that are ancestors of p2 but not of p1
3946 # find nodes that are ancestors of p2 but not of p1
3947 p1 = repo.lookup('.')
3947 p1 = repo.lookup('.')
3948 p2 = node
3948 p2 = node
3949 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3949 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3950
3950
3951 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3951 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3952 for node in nodes:
3952 for node in nodes:
3953 displayer.show(repo[node])
3953 displayer.show(repo[node])
3954 displayer.close()
3954 displayer.close()
3955 return 0
3955 return 0
3956
3956
3957 # ui.forcemerge is an internal variable, do not document
3957 # ui.forcemerge is an internal variable, do not document
3958 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3958 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3959 with ui.configoverride(overrides, 'merge'):
3959 with ui.configoverride(overrides, 'merge'):
3960 force = opts.get('force')
3960 force = opts.get('force')
3961 labels = ['working copy', 'merge rev']
3961 labels = ['working copy', 'merge rev']
3962 return hg.merge(repo, node, force=force, mergeforce=force,
3962 return hg.merge(repo, node, force=force, mergeforce=force,
3963 labels=labels, abort=abort)
3963 labels=labels, abort=abort)
3964
3964
3965 @command('outgoing|out',
3965 @command('outgoing|out',
3966 [('f', 'force', None, _('run even when the destination is unrelated')),
3966 [('f', 'force', None, _('run even when the destination is unrelated')),
3967 ('r', 'rev', [],
3967 ('r', 'rev', [],
3968 _('a changeset intended to be included in the destination'), _('REV')),
3968 _('a changeset intended to be included in the destination'), _('REV')),
3969 ('n', 'newest-first', None, _('show newest record first')),
3969 ('n', 'newest-first', None, _('show newest record first')),
3970 ('B', 'bookmarks', False, _('compare bookmarks')),
3970 ('B', 'bookmarks', False, _('compare bookmarks')),
3971 ('b', 'branch', [], _('a specific branch you would like to push'),
3971 ('b', 'branch', [], _('a specific branch you would like to push'),
3972 _('BRANCH')),
3972 _('BRANCH')),
3973 ] + logopts + remoteopts + subrepoopts,
3973 ] + logopts + remoteopts + subrepoopts,
3974 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
3974 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
3975 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3975 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT)
3976 def outgoing(ui, repo, dest=None, **opts):
3976 def outgoing(ui, repo, dest=None, **opts):
3977 """show changesets not found in the destination
3977 """show changesets not found in the destination
3978
3978
3979 Show changesets not found in the specified destination repository
3979 Show changesets not found in the specified destination repository
3980 or the default push location. These are the changesets that would
3980 or the default push location. These are the changesets that would
3981 be pushed if a push was requested.
3981 be pushed if a push was requested.
3982
3982
3983 See pull for details of valid destination formats.
3983 See pull for details of valid destination formats.
3984
3984
3985 .. container:: verbose
3985 .. container:: verbose
3986
3986
3987 With -B/--bookmarks, the result of bookmark comparison between
3987 With -B/--bookmarks, the result of bookmark comparison between
3988 local and remote repositories is displayed. With -v/--verbose,
3988 local and remote repositories is displayed. With -v/--verbose,
3989 status is also displayed for each bookmark like below::
3989 status is also displayed for each bookmark like below::
3990
3990
3991 BM1 01234567890a added
3991 BM1 01234567890a added
3992 BM2 deleted
3992 BM2 deleted
3993 BM3 234567890abc advanced
3993 BM3 234567890abc advanced
3994 BM4 34567890abcd diverged
3994 BM4 34567890abcd diverged
3995 BM5 4567890abcde changed
3995 BM5 4567890abcde changed
3996
3996
3997 The action taken when pushing depends on the
3997 The action taken when pushing depends on the
3998 status of each bookmark:
3998 status of each bookmark:
3999
3999
4000 :``added``: push with ``-B`` will create it
4000 :``added``: push with ``-B`` will create it
4001 :``deleted``: push with ``-B`` will delete it
4001 :``deleted``: push with ``-B`` will delete it
4002 :``advanced``: push will update it
4002 :``advanced``: push will update it
4003 :``diverged``: push with ``-B`` will update it
4003 :``diverged``: push with ``-B`` will update it
4004 :``changed``: push with ``-B`` will update it
4004 :``changed``: push with ``-B`` will update it
4005
4005
4006 From the point of view of pushing behavior, bookmarks
4006 From the point of view of pushing behavior, bookmarks
4007 existing only in the remote repository are treated as
4007 existing only in the remote repository are treated as
4008 ``deleted``, even if it is in fact added remotely.
4008 ``deleted``, even if it is in fact added remotely.
4009
4009
4010 Returns 0 if there are outgoing changes, 1 otherwise.
4010 Returns 0 if there are outgoing changes, 1 otherwise.
4011 """
4011 """
4012 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4012 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4013 # style URLs, so don't overwrite dest.
4013 # style URLs, so don't overwrite dest.
4014 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4014 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4015 if not path:
4015 if not path:
4016 raise error.Abort(_('default repository not configured!'),
4016 raise error.Abort(_('default repository not configured!'),
4017 hint=_("see 'hg help config.paths'"))
4017 hint=_("see 'hg help config.paths'"))
4018
4018
4019 opts = pycompat.byteskwargs(opts)
4019 opts = pycompat.byteskwargs(opts)
4020 if opts.get('graph'):
4020 if opts.get('graph'):
4021 logcmdutil.checkunsupportedgraphflags([], opts)
4021 logcmdutil.checkunsupportedgraphflags([], opts)
4022 o, other = hg._outgoing(ui, repo, dest, opts)
4022 o, other = hg._outgoing(ui, repo, dest, opts)
4023 if not o:
4023 if not o:
4024 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4024 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4025 return
4025 return
4026
4026
4027 revdag = logcmdutil.graphrevs(repo, o, opts)
4027 revdag = logcmdutil.graphrevs(repo, o, opts)
4028 ui.pager('outgoing')
4028 ui.pager('outgoing')
4029 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4029 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4030 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4030 logcmdutil.displaygraph(ui, repo, revdag, displayer,
4031 graphmod.asciiedges)
4031 graphmod.asciiedges)
4032 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4032 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4033 return 0
4033 return 0
4034
4034
4035 if opts.get('bookmarks'):
4035 if opts.get('bookmarks'):
4036 dest = path.pushloc or path.loc
4036 dest = path.pushloc or path.loc
4037 other = hg.peer(repo, opts, dest)
4037 other = hg.peer(repo, opts, dest)
4038 if 'bookmarks' not in other.listkeys('namespaces'):
4038 if 'bookmarks' not in other.listkeys('namespaces'):
4039 ui.warn(_("remote doesn't support bookmarks\n"))
4039 ui.warn(_("remote doesn't support bookmarks\n"))
4040 return 0
4040 return 0
4041 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4041 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4042 ui.pager('outgoing')
4042 ui.pager('outgoing')
4043 return bookmarks.outgoing(ui, repo, other)
4043 return bookmarks.outgoing(ui, repo, other)
4044
4044
4045 repo._subtoppath = path.pushloc or path.loc
4045 repo._subtoppath = path.pushloc or path.loc
4046 try:
4046 try:
4047 return hg.outgoing(ui, repo, dest, opts)
4047 return hg.outgoing(ui, repo, dest, opts)
4048 finally:
4048 finally:
4049 del repo._subtoppath
4049 del repo._subtoppath
4050
4050
4051 @command('parents',
4051 @command('parents',
4052 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4052 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4053 ] + templateopts,
4053 ] + templateopts,
4054 _('[-r REV] [FILE]'),
4054 _('[-r REV] [FILE]'),
4055 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4055 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4056 inferrepo=True)
4056 inferrepo=True)
4057 def parents(ui, repo, file_=None, **opts):
4057 def parents(ui, repo, file_=None, **opts):
4058 """show the parents of the working directory or revision (DEPRECATED)
4058 """show the parents of the working directory or revision (DEPRECATED)
4059
4059
4060 Print the working directory's parent revisions. If a revision is
4060 Print the working directory's parent revisions. If a revision is
4061 given via -r/--rev, the parent of that revision will be printed.
4061 given via -r/--rev, the parent of that revision will be printed.
4062 If a file argument is given, the revision in which the file was
4062 If a file argument is given, the revision in which the file was
4063 last changed (before the working directory revision or the
4063 last changed (before the working directory revision or the
4064 argument to --rev if given) is printed.
4064 argument to --rev if given) is printed.
4065
4065
4066 This command is equivalent to::
4066 This command is equivalent to::
4067
4067
4068 hg log -r "p1()+p2()" or
4068 hg log -r "p1()+p2()" or
4069 hg log -r "p1(REV)+p2(REV)" or
4069 hg log -r "p1(REV)+p2(REV)" or
4070 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4070 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
4071 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4071 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
4072
4072
4073 See :hg:`summary` and :hg:`help revsets` for related information.
4073 See :hg:`summary` and :hg:`help revsets` for related information.
4074
4074
4075 Returns 0 on success.
4075 Returns 0 on success.
4076 """
4076 """
4077
4077
4078 opts = pycompat.byteskwargs(opts)
4078 opts = pycompat.byteskwargs(opts)
4079 rev = opts.get('rev')
4079 rev = opts.get('rev')
4080 if rev:
4080 if rev:
4081 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4081 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4082 ctx = scmutil.revsingle(repo, rev, None)
4082 ctx = scmutil.revsingle(repo, rev, None)
4083
4083
4084 if file_:
4084 if file_:
4085 m = scmutil.match(ctx, (file_,), opts)
4085 m = scmutil.match(ctx, (file_,), opts)
4086 if m.anypats() or len(m.files()) != 1:
4086 if m.anypats() or len(m.files()) != 1:
4087 raise error.Abort(_('can only specify an explicit filename'))
4087 raise error.Abort(_('can only specify an explicit filename'))
4088 file_ = m.files()[0]
4088 file_ = m.files()[0]
4089 filenodes = []
4089 filenodes = []
4090 for cp in ctx.parents():
4090 for cp in ctx.parents():
4091 if not cp:
4091 if not cp:
4092 continue
4092 continue
4093 try:
4093 try:
4094 filenodes.append(cp.filenode(file_))
4094 filenodes.append(cp.filenode(file_))
4095 except error.LookupError:
4095 except error.LookupError:
4096 pass
4096 pass
4097 if not filenodes:
4097 if not filenodes:
4098 raise error.Abort(_("'%s' not found in manifest!") % file_)
4098 raise error.Abort(_("'%s' not found in manifest!") % file_)
4099 p = []
4099 p = []
4100 for fn in filenodes:
4100 for fn in filenodes:
4101 fctx = repo.filectx(file_, fileid=fn)
4101 fctx = repo.filectx(file_, fileid=fn)
4102 p.append(fctx.node())
4102 p.append(fctx.node())
4103 else:
4103 else:
4104 p = [cp.node() for cp in ctx.parents()]
4104 p = [cp.node() for cp in ctx.parents()]
4105
4105
4106 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4106 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4107 for n in p:
4107 for n in p:
4108 if n != nullid:
4108 if n != nullid:
4109 displayer.show(repo[n])
4109 displayer.show(repo[n])
4110 displayer.close()
4110 displayer.close()
4111
4111
4112 @command('paths', formatteropts, _('[NAME]'),
4112 @command('paths', formatteropts, _('[NAME]'),
4113 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4113 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4114 optionalrepo=True, intents={INTENT_READONLY})
4114 optionalrepo=True, intents={INTENT_READONLY})
4115 def paths(ui, repo, search=None, **opts):
4115 def paths(ui, repo, search=None, **opts):
4116 """show aliases for remote repositories
4116 """show aliases for remote repositories
4117
4117
4118 Show definition of symbolic path name NAME. If no name is given,
4118 Show definition of symbolic path name NAME. If no name is given,
4119 show definition of all available names.
4119 show definition of all available names.
4120
4120
4121 Option -q/--quiet suppresses all output when searching for NAME
4121 Option -q/--quiet suppresses all output when searching for NAME
4122 and shows only the path names when listing all definitions.
4122 and shows only the path names when listing all definitions.
4123
4123
4124 Path names are defined in the [paths] section of your
4124 Path names are defined in the [paths] section of your
4125 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4125 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4126 repository, ``.hg/hgrc`` is used, too.
4126 repository, ``.hg/hgrc`` is used, too.
4127
4127
4128 The path names ``default`` and ``default-push`` have a special
4128 The path names ``default`` and ``default-push`` have a special
4129 meaning. When performing a push or pull operation, they are used
4129 meaning. When performing a push or pull operation, they are used
4130 as fallbacks if no location is specified on the command-line.
4130 as fallbacks if no location is specified on the command-line.
4131 When ``default-push`` is set, it will be used for push and
4131 When ``default-push`` is set, it will be used for push and
4132 ``default`` will be used for pull; otherwise ``default`` is used
4132 ``default`` will be used for pull; otherwise ``default`` is used
4133 as the fallback for both. When cloning a repository, the clone
4133 as the fallback for both. When cloning a repository, the clone
4134 source is written as ``default`` in ``.hg/hgrc``.
4134 source is written as ``default`` in ``.hg/hgrc``.
4135
4135
4136 .. note::
4136 .. note::
4137
4137
4138 ``default`` and ``default-push`` apply to all inbound (e.g.
4138 ``default`` and ``default-push`` apply to all inbound (e.g.
4139 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4139 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
4140 and :hg:`bundle`) operations.
4140 and :hg:`bundle`) operations.
4141
4141
4142 See :hg:`help urls` for more information.
4142 See :hg:`help urls` for more information.
4143
4143
4144 .. container:: verbose
4144 .. container:: verbose
4145
4145
4146 Template:
4146 Template:
4147
4147
4148 The following keywords are supported. See also :hg:`help templates`.
4148 The following keywords are supported. See also :hg:`help templates`.
4149
4149
4150 :name: String. Symbolic name of the path alias.
4150 :name: String. Symbolic name of the path alias.
4151 :pushurl: String. URL for push operations.
4151 :pushurl: String. URL for push operations.
4152 :url: String. URL or directory path for the other operations.
4152 :url: String. URL or directory path for the other operations.
4153
4153
4154 Returns 0 on success.
4154 Returns 0 on success.
4155 """
4155 """
4156
4156
4157 opts = pycompat.byteskwargs(opts)
4157 opts = pycompat.byteskwargs(opts)
4158 ui.pager('paths')
4158 ui.pager('paths')
4159 if search:
4159 if search:
4160 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4160 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4161 if name == search]
4161 if name == search]
4162 else:
4162 else:
4163 pathitems = sorted(ui.paths.iteritems())
4163 pathitems = sorted(ui.paths.iteritems())
4164
4164
4165 fm = ui.formatter('paths', opts)
4165 fm = ui.formatter('paths', opts)
4166 if fm.isplain():
4166 if fm.isplain():
4167 hidepassword = util.hidepassword
4167 hidepassword = util.hidepassword
4168 else:
4168 else:
4169 hidepassword = bytes
4169 hidepassword = bytes
4170 if ui.quiet:
4170 if ui.quiet:
4171 namefmt = '%s\n'
4171 namefmt = '%s\n'
4172 else:
4172 else:
4173 namefmt = '%s = '
4173 namefmt = '%s = '
4174 showsubopts = not search and not ui.quiet
4174 showsubopts = not search and not ui.quiet
4175
4175
4176 for name, path in pathitems:
4176 for name, path in pathitems:
4177 fm.startitem()
4177 fm.startitem()
4178 fm.condwrite(not search, 'name', namefmt, name)
4178 fm.condwrite(not search, 'name', namefmt, name)
4179 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4179 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4180 for subopt, value in sorted(path.suboptions.items()):
4180 for subopt, value in sorted(path.suboptions.items()):
4181 assert subopt not in ('name', 'url')
4181 assert subopt not in ('name', 'url')
4182 if showsubopts:
4182 if showsubopts:
4183 fm.plain('%s:%s = ' % (name, subopt))
4183 fm.plain('%s:%s = ' % (name, subopt))
4184 fm.condwrite(showsubopts, subopt, '%s\n', value)
4184 fm.condwrite(showsubopts, subopt, '%s\n', value)
4185
4185
4186 fm.end()
4186 fm.end()
4187
4187
4188 if search and not pathitems:
4188 if search and not pathitems:
4189 if not ui.quiet:
4189 if not ui.quiet:
4190 ui.warn(_("not found!\n"))
4190 ui.warn(_("not found!\n"))
4191 return 1
4191 return 1
4192 else:
4192 else:
4193 return 0
4193 return 0
4194
4194
4195 @command('phase',
4195 @command('phase',
4196 [('p', 'public', False, _('set changeset phase to public')),
4196 [('p', 'public', False, _('set changeset phase to public')),
4197 ('d', 'draft', False, _('set changeset phase to draft')),
4197 ('d', 'draft', False, _('set changeset phase to draft')),
4198 ('s', 'secret', False, _('set changeset phase to secret')),
4198 ('s', 'secret', False, _('set changeset phase to secret')),
4199 ('f', 'force', False, _('allow to move boundary backward')),
4199 ('f', 'force', False, _('allow to move boundary backward')),
4200 ('r', 'rev', [], _('target revision'), _('REV')),
4200 ('r', 'rev', [], _('target revision'), _('REV')),
4201 ],
4201 ],
4202 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4202 _('[-p|-d|-s] [-f] [-r] [REV...]'),
4203 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4203 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
4204 def phase(ui, repo, *revs, **opts):
4204 def phase(ui, repo, *revs, **opts):
4205 """set or show the current phase name
4205 """set or show the current phase name
4206
4206
4207 With no argument, show the phase name of the current revision(s).
4207 With no argument, show the phase name of the current revision(s).
4208
4208
4209 With one of -p/--public, -d/--draft or -s/--secret, change the
4209 With one of -p/--public, -d/--draft or -s/--secret, change the
4210 phase value of the specified revisions.
4210 phase value of the specified revisions.
4211
4211
4212 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4212 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4213 lower phase to a higher phase. Phases are ordered as follows::
4213 lower phase to a higher phase. Phases are ordered as follows::
4214
4214
4215 public < draft < secret
4215 public < draft < secret
4216
4216
4217 Returns 0 on success, 1 if some phases could not be changed.
4217 Returns 0 on success, 1 if some phases could not be changed.
4218
4218
4219 (For more information about the phases concept, see :hg:`help phases`.)
4219 (For more information about the phases concept, see :hg:`help phases`.)
4220 """
4220 """
4221 opts = pycompat.byteskwargs(opts)
4221 opts = pycompat.byteskwargs(opts)
4222 # search for a unique phase argument
4222 # search for a unique phase argument
4223 targetphase = None
4223 targetphase = None
4224 for idx, name in enumerate(phases.phasenames):
4224 for idx, name in enumerate(phases.phasenames):
4225 if opts.get(name, False):
4225 if opts.get(name, False):
4226 if targetphase is not None:
4226 if targetphase is not None:
4227 raise error.Abort(_('only one phase can be specified'))
4227 raise error.Abort(_('only one phase can be specified'))
4228 targetphase = idx
4228 targetphase = idx
4229
4229
4230 # look for specified revision
4230 # look for specified revision
4231 revs = list(revs)
4231 revs = list(revs)
4232 revs.extend(opts['rev'])
4232 revs.extend(opts['rev'])
4233 if not revs:
4233 if not revs:
4234 # display both parents as the second parent phase can influence
4234 # display both parents as the second parent phase can influence
4235 # the phase of a merge commit
4235 # the phase of a merge commit
4236 revs = [c.rev() for c in repo[None].parents()]
4236 revs = [c.rev() for c in repo[None].parents()]
4237
4237
4238 revs = scmutil.revrange(repo, revs)
4238 revs = scmutil.revrange(repo, revs)
4239
4239
4240 ret = 0
4240 ret = 0
4241 if targetphase is None:
4241 if targetphase is None:
4242 # display
4242 # display
4243 for r in revs:
4243 for r in revs:
4244 ctx = repo[r]
4244 ctx = repo[r]
4245 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4245 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4246 else:
4246 else:
4247 with repo.lock(), repo.transaction("phase") as tr:
4247 with repo.lock(), repo.transaction("phase") as tr:
4248 # set phase
4248 # set phase
4249 if not revs:
4249 if not revs:
4250 raise error.Abort(_('empty revision set'))
4250 raise error.Abort(_('empty revision set'))
4251 nodes = [repo[r].node() for r in revs]
4251 nodes = [repo[r].node() for r in revs]
4252 # moving revision from public to draft may hide them
4252 # moving revision from public to draft may hide them
4253 # We have to check result on an unfiltered repository
4253 # We have to check result on an unfiltered repository
4254 unfi = repo.unfiltered()
4254 unfi = repo.unfiltered()
4255 getphase = unfi._phasecache.phase
4255 getphase = unfi._phasecache.phase
4256 olddata = [getphase(unfi, r) for r in unfi]
4256 olddata = [getphase(unfi, r) for r in unfi]
4257 phases.advanceboundary(repo, tr, targetphase, nodes)
4257 phases.advanceboundary(repo, tr, targetphase, nodes)
4258 if opts['force']:
4258 if opts['force']:
4259 phases.retractboundary(repo, tr, targetphase, nodes)
4259 phases.retractboundary(repo, tr, targetphase, nodes)
4260 getphase = unfi._phasecache.phase
4260 getphase = unfi._phasecache.phase
4261 newdata = [getphase(unfi, r) for r in unfi]
4261 newdata = [getphase(unfi, r) for r in unfi]
4262 changes = sum(newdata[r] != olddata[r] for r in unfi)
4262 changes = sum(newdata[r] != olddata[r] for r in unfi)
4263 cl = unfi.changelog
4263 cl = unfi.changelog
4264 rejected = [n for n in nodes
4264 rejected = [n for n in nodes
4265 if newdata[cl.rev(n)] < targetphase]
4265 if newdata[cl.rev(n)] < targetphase]
4266 if rejected:
4266 if rejected:
4267 ui.warn(_('cannot move %i changesets to a higher '
4267 ui.warn(_('cannot move %i changesets to a higher '
4268 'phase, use --force\n') % len(rejected))
4268 'phase, use --force\n') % len(rejected))
4269 ret = 1
4269 ret = 1
4270 if changes:
4270 if changes:
4271 msg = _('phase changed for %i changesets\n') % changes
4271 msg = _('phase changed for %i changesets\n') % changes
4272 if ret:
4272 if ret:
4273 ui.status(msg)
4273 ui.status(msg)
4274 else:
4274 else:
4275 ui.note(msg)
4275 ui.note(msg)
4276 else:
4276 else:
4277 ui.warn(_('no phases changed\n'))
4277 ui.warn(_('no phases changed\n'))
4278 return ret
4278 return ret
4279
4279
4280 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4280 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4281 """Run after a changegroup has been added via pull/unbundle
4281 """Run after a changegroup has been added via pull/unbundle
4282
4282
4283 This takes arguments below:
4283 This takes arguments below:
4284
4284
4285 :modheads: change of heads by pull/unbundle
4285 :modheads: change of heads by pull/unbundle
4286 :optupdate: updating working directory is needed or not
4286 :optupdate: updating working directory is needed or not
4287 :checkout: update destination revision (or None to default destination)
4287 :checkout: update destination revision (or None to default destination)
4288 :brev: a name, which might be a bookmark to be activated after updating
4288 :brev: a name, which might be a bookmark to be activated after updating
4289 """
4289 """
4290 if modheads == 0:
4290 if modheads == 0:
4291 return
4291 return
4292 if optupdate:
4292 if optupdate:
4293 try:
4293 try:
4294 return hg.updatetotally(ui, repo, checkout, brev)
4294 return hg.updatetotally(ui, repo, checkout, brev)
4295 except error.UpdateAbort as inst:
4295 except error.UpdateAbort as inst:
4296 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4296 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4297 hint = inst.hint
4297 hint = inst.hint
4298 raise error.UpdateAbort(msg, hint=hint)
4298 raise error.UpdateAbort(msg, hint=hint)
4299 if modheads > 1:
4299 if modheads > 1:
4300 currentbranchheads = len(repo.branchheads())
4300 currentbranchheads = len(repo.branchheads())
4301 if currentbranchheads == modheads:
4301 if currentbranchheads == modheads:
4302 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4302 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4303 elif currentbranchheads > 1:
4303 elif currentbranchheads > 1:
4304 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4304 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4305 "merge)\n"))
4305 "merge)\n"))
4306 else:
4306 else:
4307 ui.status(_("(run 'hg heads' to see heads)\n"))
4307 ui.status(_("(run 'hg heads' to see heads)\n"))
4308 elif not ui.configbool('commands', 'update.requiredest'):
4308 elif not ui.configbool('commands', 'update.requiredest'):
4309 ui.status(_("(run 'hg update' to get a working copy)\n"))
4309 ui.status(_("(run 'hg update' to get a working copy)\n"))
4310
4310
4311 @command('pull',
4311 @command('pull',
4312 [('u', 'update', None,
4312 [('u', 'update', None,
4313 _('update to new branch head if new descendants were pulled')),
4313 _('update to new branch head if new descendants were pulled')),
4314 ('f', 'force', None, _('run even when remote repository is unrelated')),
4314 ('f', 'force', None, _('run even when remote repository is unrelated')),
4315 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4315 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4316 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4316 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4317 ('b', 'branch', [], _('a specific branch you would like to pull'),
4317 ('b', 'branch', [], _('a specific branch you would like to pull'),
4318 _('BRANCH')),
4318 _('BRANCH')),
4319 ] + remoteopts,
4319 ] + remoteopts,
4320 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4320 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
4321 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4321 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4322 helpbasic=True)
4322 helpbasic=True)
4323 def pull(ui, repo, source="default", **opts):
4323 def pull(ui, repo, source="default", **opts):
4324 """pull changes from the specified source
4324 """pull changes from the specified source
4325
4325
4326 Pull changes from a remote repository to a local one.
4326 Pull changes from a remote repository to a local one.
4327
4327
4328 This finds all changes from the repository at the specified path
4328 This finds all changes from the repository at the specified path
4329 or URL and adds them to a local repository (the current one unless
4329 or URL and adds them to a local repository (the current one unless
4330 -R is specified). By default, this does not update the copy of the
4330 -R is specified). By default, this does not update the copy of the
4331 project in the working directory.
4331 project in the working directory.
4332
4332
4333 When cloning from servers that support it, Mercurial may fetch
4333 When cloning from servers that support it, Mercurial may fetch
4334 pre-generated data. When this is done, hooks operating on incoming
4334 pre-generated data. When this is done, hooks operating on incoming
4335 changesets and changegroups may fire more than once, once for each
4335 changesets and changegroups may fire more than once, once for each
4336 pre-generated bundle and as well as for any additional remaining
4336 pre-generated bundle and as well as for any additional remaining
4337 data. See :hg:`help -e clonebundles` for more.
4337 data. See :hg:`help -e clonebundles` for more.
4338
4338
4339 Use :hg:`incoming` if you want to see what would have been added
4339 Use :hg:`incoming` if you want to see what would have been added
4340 by a pull at the time you issued this command. If you then decide
4340 by a pull at the time you issued this command. If you then decide
4341 to add those changes to the repository, you should use :hg:`pull
4341 to add those changes to the repository, you should use :hg:`pull
4342 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4342 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4343
4343
4344 If SOURCE is omitted, the 'default' path will be used.
4344 If SOURCE is omitted, the 'default' path will be used.
4345 See :hg:`help urls` for more information.
4345 See :hg:`help urls` for more information.
4346
4346
4347 Specifying bookmark as ``.`` is equivalent to specifying the active
4347 Specifying bookmark as ``.`` is equivalent to specifying the active
4348 bookmark's name.
4348 bookmark's name.
4349
4349
4350 Returns 0 on success, 1 if an update had unresolved files.
4350 Returns 0 on success, 1 if an update had unresolved files.
4351 """
4351 """
4352
4352
4353 opts = pycompat.byteskwargs(opts)
4353 opts = pycompat.byteskwargs(opts)
4354 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4354 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4355 msg = _('update destination required by configuration')
4355 msg = _('update destination required by configuration')
4356 hint = _('use hg pull followed by hg update DEST')
4356 hint = _('use hg pull followed by hg update DEST')
4357 raise error.Abort(msg, hint=hint)
4357 raise error.Abort(msg, hint=hint)
4358
4358
4359 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4359 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4360 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4360 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4361 other = hg.peer(repo, opts, source)
4361 other = hg.peer(repo, opts, source)
4362 try:
4362 try:
4363 revs, checkout = hg.addbranchrevs(repo, other, branches,
4363 revs, checkout = hg.addbranchrevs(repo, other, branches,
4364 opts.get('rev'))
4364 opts.get('rev'))
4365
4365
4366
4366
4367 pullopargs = {}
4367 pullopargs = {}
4368 if opts.get('bookmark'):
4368 if opts.get('bookmark'):
4369 if not revs:
4369 if not revs:
4370 revs = []
4370 revs = []
4371 # The list of bookmark used here is not the one used to actually
4371 # The list of bookmark used here is not the one used to actually
4372 # update the bookmark name. This can result in the revision pulled
4372 # update the bookmark name. This can result in the revision pulled
4373 # not ending up with the name of the bookmark because of a race
4373 # not ending up with the name of the bookmark because of a race
4374 # condition on the server. (See issue 4689 for details)
4374 # condition on the server. (See issue 4689 for details)
4375 remotebookmarks = other.listkeys('bookmarks')
4375 remotebookmarks = other.listkeys('bookmarks')
4376 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4376 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4377 pullopargs['remotebookmarks'] = remotebookmarks
4377 pullopargs['remotebookmarks'] = remotebookmarks
4378 for b in opts['bookmark']:
4378 for b in opts['bookmark']:
4379 b = repo._bookmarks.expandname(b)
4379 b = repo._bookmarks.expandname(b)
4380 if b not in remotebookmarks:
4380 if b not in remotebookmarks:
4381 raise error.Abort(_('remote bookmark %s not found!') % b)
4381 raise error.Abort(_('remote bookmark %s not found!') % b)
4382 revs.append(hex(remotebookmarks[b]))
4382 revs.append(hex(remotebookmarks[b]))
4383
4383
4384 if revs:
4384 if revs:
4385 try:
4385 try:
4386 # When 'rev' is a bookmark name, we cannot guarantee that it
4386 # When 'rev' is a bookmark name, we cannot guarantee that it
4387 # will be updated with that name because of a race condition
4387 # will be updated with that name because of a race condition
4388 # server side. (See issue 4689 for details)
4388 # server side. (See issue 4689 for details)
4389 oldrevs = revs
4389 oldrevs = revs
4390 revs = [] # actually, nodes
4390 revs = [] # actually, nodes
4391 for r in oldrevs:
4391 for r in oldrevs:
4392 with other.commandexecutor() as e:
4392 with other.commandexecutor() as e:
4393 node = e.callcommand('lookup', {'key': r}).result()
4393 node = e.callcommand('lookup', {'key': r}).result()
4394
4394
4395 revs.append(node)
4395 revs.append(node)
4396 if r == checkout:
4396 if r == checkout:
4397 checkout = node
4397 checkout = node
4398 except error.CapabilityError:
4398 except error.CapabilityError:
4399 err = _("other repository doesn't support revision lookup, "
4399 err = _("other repository doesn't support revision lookup, "
4400 "so a rev cannot be specified.")
4400 "so a rev cannot be specified.")
4401 raise error.Abort(err)
4401 raise error.Abort(err)
4402
4402
4403 wlock = util.nullcontextmanager()
4403 wlock = util.nullcontextmanager()
4404 if opts.get('update'):
4404 if opts.get('update'):
4405 wlock = repo.wlock()
4405 wlock = repo.wlock()
4406 with wlock:
4406 with wlock:
4407 pullopargs.update(opts.get('opargs', {}))
4407 pullopargs.update(opts.get('opargs', {}))
4408 modheads = exchange.pull(repo, other, heads=revs,
4408 modheads = exchange.pull(repo, other, heads=revs,
4409 force=opts.get('force'),
4409 force=opts.get('force'),
4410 bookmarks=opts.get('bookmark', ()),
4410 bookmarks=opts.get('bookmark', ()),
4411 opargs=pullopargs).cgresult
4411 opargs=pullopargs).cgresult
4412
4412
4413 # brev is a name, which might be a bookmark to be activated at
4413 # brev is a name, which might be a bookmark to be activated at
4414 # the end of the update. In other words, it is an explicit
4414 # the end of the update. In other words, it is an explicit
4415 # destination of the update
4415 # destination of the update
4416 brev = None
4416 brev = None
4417
4417
4418 if checkout:
4418 if checkout:
4419 checkout = repo.changelog.rev(checkout)
4419 checkout = repo.changelog.rev(checkout)
4420
4420
4421 # order below depends on implementation of
4421 # order below depends on implementation of
4422 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4422 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4423 # because 'checkout' is determined without it.
4423 # because 'checkout' is determined without it.
4424 if opts.get('rev'):
4424 if opts.get('rev'):
4425 brev = opts['rev'][0]
4425 brev = opts['rev'][0]
4426 elif opts.get('branch'):
4426 elif opts.get('branch'):
4427 brev = opts['branch'][0]
4427 brev = opts['branch'][0]
4428 else:
4428 else:
4429 brev = branches[0]
4429 brev = branches[0]
4430 repo._subtoppath = source
4430 repo._subtoppath = source
4431 try:
4431 try:
4432 ret = postincoming(ui, repo, modheads, opts.get('update'),
4432 ret = postincoming(ui, repo, modheads, opts.get('update'),
4433 checkout, brev)
4433 checkout, brev)
4434
4434
4435 finally:
4435 finally:
4436 del repo._subtoppath
4436 del repo._subtoppath
4437
4437
4438 finally:
4438 finally:
4439 other.close()
4439 other.close()
4440 return ret
4440 return ret
4441
4441
4442 @command('push',
4442 @command('push',
4443 [('f', 'force', None, _('force push')),
4443 [('f', 'force', None, _('force push')),
4444 ('r', 'rev', [],
4444 ('r', 'rev', [],
4445 _('a changeset intended to be included in the destination'),
4445 _('a changeset intended to be included in the destination'),
4446 _('REV')),
4446 _('REV')),
4447 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4447 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4448 ('b', 'branch', [],
4448 ('b', 'branch', [],
4449 _('a specific branch you would like to push'), _('BRANCH')),
4449 _('a specific branch you would like to push'), _('BRANCH')),
4450 ('', 'new-branch', False, _('allow pushing a new branch')),
4450 ('', 'new-branch', False, _('allow pushing a new branch')),
4451 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4451 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4452 ] + remoteopts,
4452 ] + remoteopts,
4453 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4453 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
4454 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4454 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4455 helpbasic=True)
4455 helpbasic=True)
4456 def push(ui, repo, dest=None, **opts):
4456 def push(ui, repo, dest=None, **opts):
4457 """push changes to the specified destination
4457 """push changes to the specified destination
4458
4458
4459 Push changesets from the local repository to the specified
4459 Push changesets from the local repository to the specified
4460 destination.
4460 destination.
4461
4461
4462 This operation is symmetrical to pull: it is identical to a pull
4462 This operation is symmetrical to pull: it is identical to a pull
4463 in the destination repository from the current one.
4463 in the destination repository from the current one.
4464
4464
4465 By default, push will not allow creation of new heads at the
4465 By default, push will not allow creation of new heads at the
4466 destination, since multiple heads would make it unclear which head
4466 destination, since multiple heads would make it unclear which head
4467 to use. In this situation, it is recommended to pull and merge
4467 to use. In this situation, it is recommended to pull and merge
4468 before pushing.
4468 before pushing.
4469
4469
4470 Use --new-branch if you want to allow push to create a new named
4470 Use --new-branch if you want to allow push to create a new named
4471 branch that is not present at the destination. This allows you to
4471 branch that is not present at the destination. This allows you to
4472 only create a new branch without forcing other changes.
4472 only create a new branch without forcing other changes.
4473
4473
4474 .. note::
4474 .. note::
4475
4475
4476 Extra care should be taken with the -f/--force option,
4476 Extra care should be taken with the -f/--force option,
4477 which will push all new heads on all branches, an action which will
4477 which will push all new heads on all branches, an action which will
4478 almost always cause confusion for collaborators.
4478 almost always cause confusion for collaborators.
4479
4479
4480 If -r/--rev is used, the specified revision and all its ancestors
4480 If -r/--rev is used, the specified revision and all its ancestors
4481 will be pushed to the remote repository.
4481 will be pushed to the remote repository.
4482
4482
4483 If -B/--bookmark is used, the specified bookmarked revision, its
4483 If -B/--bookmark is used, the specified bookmarked revision, its
4484 ancestors, and the bookmark will be pushed to the remote
4484 ancestors, and the bookmark will be pushed to the remote
4485 repository. Specifying ``.`` is equivalent to specifying the active
4485 repository. Specifying ``.`` is equivalent to specifying the active
4486 bookmark's name.
4486 bookmark's name.
4487
4487
4488 Please see :hg:`help urls` for important details about ``ssh://``
4488 Please see :hg:`help urls` for important details about ``ssh://``
4489 URLs. If DESTINATION is omitted, a default path will be used.
4489 URLs. If DESTINATION is omitted, a default path will be used.
4490
4490
4491 .. container:: verbose
4491 .. container:: verbose
4492
4492
4493 The --pushvars option sends strings to the server that become
4493 The --pushvars option sends strings to the server that become
4494 environment variables prepended with ``HG_USERVAR_``. For example,
4494 environment variables prepended with ``HG_USERVAR_``. For example,
4495 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4495 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4496 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4496 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4497
4497
4498 pushvars can provide for user-overridable hooks as well as set debug
4498 pushvars can provide for user-overridable hooks as well as set debug
4499 levels. One example is having a hook that blocks commits containing
4499 levels. One example is having a hook that blocks commits containing
4500 conflict markers, but enables the user to override the hook if the file
4500 conflict markers, but enables the user to override the hook if the file
4501 is using conflict markers for testing purposes or the file format has
4501 is using conflict markers for testing purposes or the file format has
4502 strings that look like conflict markers.
4502 strings that look like conflict markers.
4503
4503
4504 By default, servers will ignore `--pushvars`. To enable it add the
4504 By default, servers will ignore `--pushvars`. To enable it add the
4505 following to your configuration file::
4505 following to your configuration file::
4506
4506
4507 [push]
4507 [push]
4508 pushvars.server = true
4508 pushvars.server = true
4509
4509
4510 Returns 0 if push was successful, 1 if nothing to push.
4510 Returns 0 if push was successful, 1 if nothing to push.
4511 """
4511 """
4512
4512
4513 opts = pycompat.byteskwargs(opts)
4513 opts = pycompat.byteskwargs(opts)
4514 if opts.get('bookmark'):
4514 if opts.get('bookmark'):
4515 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4515 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4516 for b in opts['bookmark']:
4516 for b in opts['bookmark']:
4517 # translate -B options to -r so changesets get pushed
4517 # translate -B options to -r so changesets get pushed
4518 b = repo._bookmarks.expandname(b)
4518 b = repo._bookmarks.expandname(b)
4519 if b in repo._bookmarks:
4519 if b in repo._bookmarks:
4520 opts.setdefault('rev', []).append(b)
4520 opts.setdefault('rev', []).append(b)
4521 else:
4521 else:
4522 # if we try to push a deleted bookmark, translate it to null
4522 # if we try to push a deleted bookmark, translate it to null
4523 # this lets simultaneous -r, -b options continue working
4523 # this lets simultaneous -r, -b options continue working
4524 opts.setdefault('rev', []).append("null")
4524 opts.setdefault('rev', []).append("null")
4525
4525
4526 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4526 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4527 if not path:
4527 if not path:
4528 raise error.Abort(_('default repository not configured!'),
4528 raise error.Abort(_('default repository not configured!'),
4529 hint=_("see 'hg help config.paths'"))
4529 hint=_("see 'hg help config.paths'"))
4530 dest = path.pushloc or path.loc
4530 dest = path.pushloc or path.loc
4531 branches = (path.branch, opts.get('branch') or [])
4531 branches = (path.branch, opts.get('branch') or [])
4532 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4532 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4533 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4533 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4534 other = hg.peer(repo, opts, dest)
4534 other = hg.peer(repo, opts, dest)
4535
4535
4536 if revs:
4536 if revs:
4537 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4537 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4538 if not revs:
4538 if not revs:
4539 raise error.Abort(_("specified revisions evaluate to an empty set"),
4539 raise error.Abort(_("specified revisions evaluate to an empty set"),
4540 hint=_("use different revision arguments"))
4540 hint=_("use different revision arguments"))
4541 elif path.pushrev:
4541 elif path.pushrev:
4542 # It doesn't make any sense to specify ancestor revisions. So limit
4542 # It doesn't make any sense to specify ancestor revisions. So limit
4543 # to DAG heads to make discovery simpler.
4543 # to DAG heads to make discovery simpler.
4544 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4544 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4545 revs = scmutil.revrange(repo, [expr])
4545 revs = scmutil.revrange(repo, [expr])
4546 revs = [repo[rev].node() for rev in revs]
4546 revs = [repo[rev].node() for rev in revs]
4547 if not revs:
4547 if not revs:
4548 raise error.Abort(_('default push revset for path evaluates to an '
4548 raise error.Abort(_('default push revset for path evaluates to an '
4549 'empty set'))
4549 'empty set'))
4550
4550
4551 repo._subtoppath = dest
4551 repo._subtoppath = dest
4552 try:
4552 try:
4553 # push subrepos depth-first for coherent ordering
4553 # push subrepos depth-first for coherent ordering
4554 c = repo['.']
4554 c = repo['.']
4555 subs = c.substate # only repos that are committed
4555 subs = c.substate # only repos that are committed
4556 for s in sorted(subs):
4556 for s in sorted(subs):
4557 result = c.sub(s).push(opts)
4557 result = c.sub(s).push(opts)
4558 if result == 0:
4558 if result == 0:
4559 return not result
4559 return not result
4560 finally:
4560 finally:
4561 del repo._subtoppath
4561 del repo._subtoppath
4562
4562
4563 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4563 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4564 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4564 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4565
4565
4566 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4566 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4567 newbranch=opts.get('new_branch'),
4567 newbranch=opts.get('new_branch'),
4568 bookmarks=opts.get('bookmark', ()),
4568 bookmarks=opts.get('bookmark', ()),
4569 opargs=opargs)
4569 opargs=opargs)
4570
4570
4571 result = not pushop.cgresult
4571 result = not pushop.cgresult
4572
4572
4573 if pushop.bkresult is not None:
4573 if pushop.bkresult is not None:
4574 if pushop.bkresult == 2:
4574 if pushop.bkresult == 2:
4575 result = 2
4575 result = 2
4576 elif not result and pushop.bkresult:
4576 elif not result and pushop.bkresult:
4577 result = 2
4577 result = 2
4578
4578
4579 return result
4579 return result
4580
4580
4581 @command('recover', [], helpcategory=command.CATEGORY_MAINTENANCE)
4581 @command('recover', [], helpcategory=command.CATEGORY_MAINTENANCE)
4582 def recover(ui, repo):
4582 def recover(ui, repo):
4583 """roll back an interrupted transaction
4583 """roll back an interrupted transaction
4584
4584
4585 Recover from an interrupted commit or pull.
4585 Recover from an interrupted commit or pull.
4586
4586
4587 This command tries to fix the repository status after an
4587 This command tries to fix the repository status after an
4588 interrupted operation. It should only be necessary when Mercurial
4588 interrupted operation. It should only be necessary when Mercurial
4589 suggests it.
4589 suggests it.
4590
4590
4591 Returns 0 if successful, 1 if nothing to recover or verify fails.
4591 Returns 0 if successful, 1 if nothing to recover or verify fails.
4592 """
4592 """
4593 if repo.recover():
4593 if repo.recover():
4594 return hg.verify(repo)
4594 return hg.verify(repo)
4595 return 1
4595 return 1
4596
4596
4597 @command('remove|rm',
4597 @command('remove|rm',
4598 [('A', 'after', None, _('record delete for missing files')),
4598 [('A', 'after', None, _('record delete for missing files')),
4599 ('f', 'force', None,
4599 ('f', 'force', None,
4600 _('forget added files, delete modified files')),
4600 _('forget added files, delete modified files')),
4601 ] + subrepoopts + walkopts + dryrunopts,
4601 ] + subrepoopts + walkopts + dryrunopts,
4602 _('[OPTION]... FILE...'),
4602 _('[OPTION]... FILE...'),
4603 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4603 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4604 helpbasic=True, inferrepo=True)
4604 helpbasic=True, inferrepo=True)
4605 def remove(ui, repo, *pats, **opts):
4605 def remove(ui, repo, *pats, **opts):
4606 """remove the specified files on the next commit
4606 """remove the specified files on the next commit
4607
4607
4608 Schedule the indicated files for removal from the current branch.
4608 Schedule the indicated files for removal from the current branch.
4609
4609
4610 This command schedules the files to be removed at the next commit.
4610 This command schedules the files to be removed at the next commit.
4611 To undo a remove before that, see :hg:`revert`. To undo added
4611 To undo a remove before that, see :hg:`revert`. To undo added
4612 files, see :hg:`forget`.
4612 files, see :hg:`forget`.
4613
4613
4614 .. container:: verbose
4614 .. container:: verbose
4615
4615
4616 -A/--after can be used to remove only files that have already
4616 -A/--after can be used to remove only files that have already
4617 been deleted, -f/--force can be used to force deletion, and -Af
4617 been deleted, -f/--force can be used to force deletion, and -Af
4618 can be used to remove files from the next revision without
4618 can be used to remove files from the next revision without
4619 deleting them from the working directory.
4619 deleting them from the working directory.
4620
4620
4621 The following table details the behavior of remove for different
4621 The following table details the behavior of remove for different
4622 file states (columns) and option combinations (rows). The file
4622 file states (columns) and option combinations (rows). The file
4623 states are Added [A], Clean [C], Modified [M] and Missing [!]
4623 states are Added [A], Clean [C], Modified [M] and Missing [!]
4624 (as reported by :hg:`status`). The actions are Warn, Remove
4624 (as reported by :hg:`status`). The actions are Warn, Remove
4625 (from branch) and Delete (from disk):
4625 (from branch) and Delete (from disk):
4626
4626
4627 ========= == == == ==
4627 ========= == == == ==
4628 opt/state A C M !
4628 opt/state A C M !
4629 ========= == == == ==
4629 ========= == == == ==
4630 none W RD W R
4630 none W RD W R
4631 -f R RD RD R
4631 -f R RD RD R
4632 -A W W W R
4632 -A W W W R
4633 -Af R R R R
4633 -Af R R R R
4634 ========= == == == ==
4634 ========= == == == ==
4635
4635
4636 .. note::
4636 .. note::
4637
4637
4638 :hg:`remove` never deletes files in Added [A] state from the
4638 :hg:`remove` never deletes files in Added [A] state from the
4639 working directory, not even if ``--force`` is specified.
4639 working directory, not even if ``--force`` is specified.
4640
4640
4641 Returns 0 on success, 1 if any warnings encountered.
4641 Returns 0 on success, 1 if any warnings encountered.
4642 """
4642 """
4643
4643
4644 opts = pycompat.byteskwargs(opts)
4644 opts = pycompat.byteskwargs(opts)
4645 after, force = opts.get('after'), opts.get('force')
4645 after, force = opts.get('after'), opts.get('force')
4646 dryrun = opts.get('dry_run')
4646 dryrun = opts.get('dry_run')
4647 if not pats and not after:
4647 if not pats and not after:
4648 raise error.Abort(_('no files specified'))
4648 raise error.Abort(_('no files specified'))
4649
4649
4650 m = scmutil.match(repo[None], pats, opts)
4650 m = scmutil.match(repo[None], pats, opts)
4651 subrepos = opts.get('subrepos')
4651 subrepos = opts.get('subrepos')
4652 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4652 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4653 dryrun=dryrun)
4653 dryrun=dryrun)
4654
4654
4655 @command('rename|move|mv',
4655 @command('rename|move|mv',
4656 [('A', 'after', None, _('record a rename that has already occurred')),
4656 [('A', 'after', None, _('record a rename that has already occurred')),
4657 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4657 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4658 ] + walkopts + dryrunopts,
4658 ] + walkopts + dryrunopts,
4659 _('[OPTION]... SOURCE... DEST'),
4659 _('[OPTION]... SOURCE... DEST'),
4660 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4660 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4661 def rename(ui, repo, *pats, **opts):
4661 def rename(ui, repo, *pats, **opts):
4662 """rename files; equivalent of copy + remove
4662 """rename files; equivalent of copy + remove
4663
4663
4664 Mark dest as copies of sources; mark sources for deletion. If dest
4664 Mark dest as copies of sources; mark sources for deletion. If dest
4665 is a directory, copies are put in that directory. If dest is a
4665 is a directory, copies are put in that directory. If dest is a
4666 file, there can only be one source.
4666 file, there can only be one source.
4667
4667
4668 By default, this command copies the contents of files as they
4668 By default, this command copies the contents of files as they
4669 exist in the working directory. If invoked with -A/--after, the
4669 exist in the working directory. If invoked with -A/--after, the
4670 operation is recorded, but no copying is performed.
4670 operation is recorded, but no copying is performed.
4671
4671
4672 This command takes effect at the next commit. To undo a rename
4672 This command takes effect at the next commit. To undo a rename
4673 before that, see :hg:`revert`.
4673 before that, see :hg:`revert`.
4674
4674
4675 Returns 0 on success, 1 if errors are encountered.
4675 Returns 0 on success, 1 if errors are encountered.
4676 """
4676 """
4677 opts = pycompat.byteskwargs(opts)
4677 opts = pycompat.byteskwargs(opts)
4678 with repo.wlock(False):
4678 with repo.wlock(False):
4679 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4679 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4680
4680
4681 @command('resolve',
4681 @command('resolve',
4682 [('a', 'all', None, _('select all unresolved files')),
4682 [('a', 'all', None, _('select all unresolved files')),
4683 ('l', 'list', None, _('list state of files needing merge')),
4683 ('l', 'list', None, _('list state of files needing merge')),
4684 ('m', 'mark', None, _('mark files as resolved')),
4684 ('m', 'mark', None, _('mark files as resolved')),
4685 ('u', 'unmark', None, _('mark files as unresolved')),
4685 ('u', 'unmark', None, _('mark files as unresolved')),
4686 ('n', 'no-status', None, _('hide status prefix')),
4686 ('n', 'no-status', None, _('hide status prefix')),
4687 ('', 're-merge', None, _('re-merge files'))]
4687 ('', 're-merge', None, _('re-merge files'))]
4688 + mergetoolopts + walkopts + formatteropts,
4688 + mergetoolopts + walkopts + formatteropts,
4689 _('[OPTION]... [FILE]...'),
4689 _('[OPTION]... [FILE]...'),
4690 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4690 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4691 inferrepo=True)
4691 inferrepo=True)
4692 def resolve(ui, repo, *pats, **opts):
4692 def resolve(ui, repo, *pats, **opts):
4693 """redo merges or set/view the merge status of files
4693 """redo merges or set/view the merge status of files
4694
4694
4695 Merges with unresolved conflicts are often the result of
4695 Merges with unresolved conflicts are often the result of
4696 non-interactive merging using the ``internal:merge`` configuration
4696 non-interactive merging using the ``internal:merge`` configuration
4697 setting, or a command-line merge tool like ``diff3``. The resolve
4697 setting, or a command-line merge tool like ``diff3``. The resolve
4698 command is used to manage the files involved in a merge, after
4698 command is used to manage the files involved in a merge, after
4699 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4699 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4700 working directory must have two parents). See :hg:`help
4700 working directory must have two parents). See :hg:`help
4701 merge-tools` for information on configuring merge tools.
4701 merge-tools` for information on configuring merge tools.
4702
4702
4703 The resolve command can be used in the following ways:
4703 The resolve command can be used in the following ways:
4704
4704
4705 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4705 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4706 the specified files, discarding any previous merge attempts. Re-merging
4706 the specified files, discarding any previous merge attempts. Re-merging
4707 is not performed for files already marked as resolved. Use ``--all/-a``
4707 is not performed for files already marked as resolved. Use ``--all/-a``
4708 to select all unresolved files. ``--tool`` can be used to specify
4708 to select all unresolved files. ``--tool`` can be used to specify
4709 the merge tool used for the given files. It overrides the HGMERGE
4709 the merge tool used for the given files. It overrides the HGMERGE
4710 environment variable and your configuration files. Previous file
4710 environment variable and your configuration files. Previous file
4711 contents are saved with a ``.orig`` suffix.
4711 contents are saved with a ``.orig`` suffix.
4712
4712
4713 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4713 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4714 (e.g. after having manually fixed-up the files). The default is
4714 (e.g. after having manually fixed-up the files). The default is
4715 to mark all unresolved files.
4715 to mark all unresolved files.
4716
4716
4717 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4717 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4718 default is to mark all resolved files.
4718 default is to mark all resolved files.
4719
4719
4720 - :hg:`resolve -l`: list files which had or still have conflicts.
4720 - :hg:`resolve -l`: list files which had or still have conflicts.
4721 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4721 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4722 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4722 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4723 the list. See :hg:`help filesets` for details.
4723 the list. See :hg:`help filesets` for details.
4724
4724
4725 .. note::
4725 .. note::
4726
4726
4727 Mercurial will not let you commit files with unresolved merge
4727 Mercurial will not let you commit files with unresolved merge
4728 conflicts. You must use :hg:`resolve -m ...` before you can
4728 conflicts. You must use :hg:`resolve -m ...` before you can
4729 commit after a conflicting merge.
4729 commit after a conflicting merge.
4730
4730
4731 .. container:: verbose
4731 .. container:: verbose
4732
4732
4733 Template:
4733 Template:
4734
4734
4735 The following keywords are supported in addition to the common template
4735 The following keywords are supported in addition to the common template
4736 keywords and functions. See also :hg:`help templates`.
4736 keywords and functions. See also :hg:`help templates`.
4737
4737
4738 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4738 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
4739 :path: String. Repository-absolute path of the file.
4739 :path: String. Repository-absolute path of the file.
4740
4740
4741 Returns 0 on success, 1 if any files fail a resolve attempt.
4741 Returns 0 on success, 1 if any files fail a resolve attempt.
4742 """
4742 """
4743
4743
4744 opts = pycompat.byteskwargs(opts)
4744 opts = pycompat.byteskwargs(opts)
4745 confirm = ui.configbool('commands', 'resolve.confirm')
4745 confirm = ui.configbool('commands', 'resolve.confirm')
4746 flaglist = 'all mark unmark list no_status re_merge'.split()
4746 flaglist = 'all mark unmark list no_status re_merge'.split()
4747 all, mark, unmark, show, nostatus, remerge = \
4747 all, mark, unmark, show, nostatus, remerge = \
4748 [opts.get(o) for o in flaglist]
4748 [opts.get(o) for o in flaglist]
4749
4749
4750 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4750 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4751 if actioncount > 1:
4751 if actioncount > 1:
4752 raise error.Abort(_("too many actions specified"))
4752 raise error.Abort(_("too many actions specified"))
4753 elif (actioncount == 0
4753 elif (actioncount == 0
4754 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4754 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4755 hint = _('use --mark, --unmark, --list or --re-merge')
4755 hint = _('use --mark, --unmark, --list or --re-merge')
4756 raise error.Abort(_('no action specified'), hint=hint)
4756 raise error.Abort(_('no action specified'), hint=hint)
4757 if pats and all:
4757 if pats and all:
4758 raise error.Abort(_("can't specify --all and patterns"))
4758 raise error.Abort(_("can't specify --all and patterns"))
4759 if not (all or pats or show or mark or unmark):
4759 if not (all or pats or show or mark or unmark):
4760 raise error.Abort(_('no files or directories specified'),
4760 raise error.Abort(_('no files or directories specified'),
4761 hint=('use --all to re-merge all unresolved files'))
4761 hint=('use --all to re-merge all unresolved files'))
4762
4762
4763 if confirm:
4763 if confirm:
4764 if all:
4764 if all:
4765 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4765 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4766 b'$$ &Yes $$ &No')):
4766 b'$$ &Yes $$ &No')):
4767 raise error.Abort(_('user quit'))
4767 raise error.Abort(_('user quit'))
4768 if mark and not pats:
4768 if mark and not pats:
4769 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4769 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4770 b'$$ &Yes $$ &No')):
4770 b'$$ &Yes $$ &No')):
4771 raise error.Abort(_('user quit'))
4771 raise error.Abort(_('user quit'))
4772 if unmark and not pats:
4772 if unmark and not pats:
4773 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4773 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4774 b'$$ &Yes $$ &No')):
4774 b'$$ &Yes $$ &No')):
4775 raise error.Abort(_('user quit'))
4775 raise error.Abort(_('user quit'))
4776
4776
4777 if show:
4777 if show:
4778 ui.pager('resolve')
4778 ui.pager('resolve')
4779 fm = ui.formatter('resolve', opts)
4779 fm = ui.formatter('resolve', opts)
4780 ms = mergemod.mergestate.read(repo)
4780 ms = mergemod.mergestate.read(repo)
4781 wctx = repo[None]
4781 wctx = repo[None]
4782 m = scmutil.match(wctx, pats, opts)
4782 m = scmutil.match(wctx, pats, opts)
4783
4783
4784 # Labels and keys based on merge state. Unresolved path conflicts show
4784 # Labels and keys based on merge state. Unresolved path conflicts show
4785 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4785 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4786 # resolved conflicts.
4786 # resolved conflicts.
4787 mergestateinfo = {
4787 mergestateinfo = {
4788 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4788 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4789 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4789 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4790 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4790 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4791 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4791 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4792 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4792 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4793 'D'),
4793 'D'),
4794 }
4794 }
4795
4795
4796 for f in ms:
4796 for f in ms:
4797 if not m(f):
4797 if not m(f):
4798 continue
4798 continue
4799
4799
4800 label, key = mergestateinfo[ms[f]]
4800 label, key = mergestateinfo[ms[f]]
4801 fm.startitem()
4801 fm.startitem()
4802 fm.context(ctx=wctx)
4802 fm.context(ctx=wctx)
4803 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4803 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4804 fm.write('path', '%s\n', f, label=label)
4804 fm.write('path', '%s\n', f, label=label)
4805 fm.end()
4805 fm.end()
4806 return 0
4806 return 0
4807
4807
4808 with repo.wlock():
4808 with repo.wlock():
4809 ms = mergemod.mergestate.read(repo)
4809 ms = mergemod.mergestate.read(repo)
4810
4810
4811 if not (ms.active() or repo.dirstate.p2() != nullid):
4811 if not (ms.active() or repo.dirstate.p2() != nullid):
4812 raise error.Abort(
4812 raise error.Abort(
4813 _('resolve command not applicable when not merging'))
4813 _('resolve command not applicable when not merging'))
4814
4814
4815 wctx = repo[None]
4815 wctx = repo[None]
4816
4816
4817 if (ms.mergedriver
4817 if (ms.mergedriver
4818 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4818 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4819 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4819 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4820 ms.commit()
4820 ms.commit()
4821 # allow mark and unmark to go through
4821 # allow mark and unmark to go through
4822 if not mark and not unmark and not proceed:
4822 if not mark and not unmark and not proceed:
4823 return 1
4823 return 1
4824
4824
4825 m = scmutil.match(wctx, pats, opts)
4825 m = scmutil.match(wctx, pats, opts)
4826 ret = 0
4826 ret = 0
4827 didwork = False
4827 didwork = False
4828 runconclude = False
4828 runconclude = False
4829
4829
4830 tocomplete = []
4830 tocomplete = []
4831 hasconflictmarkers = []
4831 hasconflictmarkers = []
4832 if mark:
4832 if mark:
4833 markcheck = ui.config('commands', 'resolve.mark-check')
4833 markcheck = ui.config('commands', 'resolve.mark-check')
4834 if markcheck not in ['warn', 'abort']:
4834 if markcheck not in ['warn', 'abort']:
4835 # Treat all invalid / unrecognized values as 'none'.
4835 # Treat all invalid / unrecognized values as 'none'.
4836 markcheck = False
4836 markcheck = False
4837 for f in ms:
4837 for f in ms:
4838 if not m(f):
4838 if not m(f):
4839 continue
4839 continue
4840
4840
4841 didwork = True
4841 didwork = True
4842
4842
4843 # don't let driver-resolved files be marked, and run the conclude
4843 # don't let driver-resolved files be marked, and run the conclude
4844 # step if asked to resolve
4844 # step if asked to resolve
4845 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4845 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4846 exact = m.exact(f)
4846 exact = m.exact(f)
4847 if mark:
4847 if mark:
4848 if exact:
4848 if exact:
4849 ui.warn(_('not marking %s as it is driver-resolved\n')
4849 ui.warn(_('not marking %s as it is driver-resolved\n')
4850 % f)
4850 % f)
4851 elif unmark:
4851 elif unmark:
4852 if exact:
4852 if exact:
4853 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4853 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4854 % f)
4854 % f)
4855 else:
4855 else:
4856 runconclude = True
4856 runconclude = True
4857 continue
4857 continue
4858
4858
4859 # path conflicts must be resolved manually
4859 # path conflicts must be resolved manually
4860 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4860 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4861 mergemod.MERGE_RECORD_RESOLVED_PATH):
4861 mergemod.MERGE_RECORD_RESOLVED_PATH):
4862 if mark:
4862 if mark:
4863 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4863 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4864 elif unmark:
4864 elif unmark:
4865 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4865 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4866 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4866 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4867 ui.warn(_('%s: path conflict must be resolved manually\n')
4867 ui.warn(_('%s: path conflict must be resolved manually\n')
4868 % f)
4868 % f)
4869 continue
4869 continue
4870
4870
4871 if mark:
4871 if mark:
4872 if markcheck:
4872 if markcheck:
4873 with repo.wvfs(f) as fobj:
4873 with repo.wvfs(f) as fobj:
4874 fdata = fobj.read()
4874 fdata = fobj.read()
4875 if filemerge.hasconflictmarkers(fdata) and \
4875 if filemerge.hasconflictmarkers(fdata) and \
4876 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4876 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4877 hasconflictmarkers.append(f)
4877 hasconflictmarkers.append(f)
4878 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4878 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4879 elif unmark:
4879 elif unmark:
4880 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4880 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4881 else:
4881 else:
4882 # backup pre-resolve (merge uses .orig for its own purposes)
4882 # backup pre-resolve (merge uses .orig for its own purposes)
4883 a = repo.wjoin(f)
4883 a = repo.wjoin(f)
4884 try:
4884 try:
4885 util.copyfile(a, a + ".resolve")
4885 util.copyfile(a, a + ".resolve")
4886 except (IOError, OSError) as inst:
4886 except (IOError, OSError) as inst:
4887 if inst.errno != errno.ENOENT:
4887 if inst.errno != errno.ENOENT:
4888 raise
4888 raise
4889
4889
4890 try:
4890 try:
4891 # preresolve file
4891 # preresolve file
4892 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4892 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4893 with ui.configoverride(overrides, 'resolve'):
4893 with ui.configoverride(overrides, 'resolve'):
4894 complete, r = ms.preresolve(f, wctx)
4894 complete, r = ms.preresolve(f, wctx)
4895 if not complete:
4895 if not complete:
4896 tocomplete.append(f)
4896 tocomplete.append(f)
4897 elif r:
4897 elif r:
4898 ret = 1
4898 ret = 1
4899 finally:
4899 finally:
4900 ms.commit()
4900 ms.commit()
4901
4901
4902 # replace filemerge's .orig file with our resolve file, but only
4902 # replace filemerge's .orig file with our resolve file, but only
4903 # for merges that are complete
4903 # for merges that are complete
4904 if complete:
4904 if complete:
4905 try:
4905 try:
4906 util.rename(a + ".resolve",
4906 util.rename(a + ".resolve",
4907 scmutil.origpath(ui, repo, a))
4907 scmutil.origpath(ui, repo, a))
4908 except OSError as inst:
4908 except OSError as inst:
4909 if inst.errno != errno.ENOENT:
4909 if inst.errno != errno.ENOENT:
4910 raise
4910 raise
4911
4911
4912 if hasconflictmarkers:
4912 if hasconflictmarkers:
4913 ui.warn(_('warning: the following files still have conflict '
4913 ui.warn(_('warning: the following files still have conflict '
4914 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4914 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4915 if markcheck == 'abort' and not all:
4915 if markcheck == 'abort' and not all and not pats:
4916 raise error.Abort(_('conflict markers detected'),
4916 raise error.Abort(_('conflict markers detected'),
4917 hint=_('use --all to mark anyway'))
4917 hint=_('use --all to mark anyway'))
4918
4918
4919 for f in tocomplete:
4919 for f in tocomplete:
4920 try:
4920 try:
4921 # resolve file
4921 # resolve file
4922 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4922 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4923 with ui.configoverride(overrides, 'resolve'):
4923 with ui.configoverride(overrides, 'resolve'):
4924 r = ms.resolve(f, wctx)
4924 r = ms.resolve(f, wctx)
4925 if r:
4925 if r:
4926 ret = 1
4926 ret = 1
4927 finally:
4927 finally:
4928 ms.commit()
4928 ms.commit()
4929
4929
4930 # replace filemerge's .orig file with our resolve file
4930 # replace filemerge's .orig file with our resolve file
4931 a = repo.wjoin(f)
4931 a = repo.wjoin(f)
4932 try:
4932 try:
4933 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4933 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4934 except OSError as inst:
4934 except OSError as inst:
4935 if inst.errno != errno.ENOENT:
4935 if inst.errno != errno.ENOENT:
4936 raise
4936 raise
4937
4937
4938 ms.commit()
4938 ms.commit()
4939 ms.recordactions()
4939 ms.recordactions()
4940
4940
4941 if not didwork and pats:
4941 if not didwork and pats:
4942 hint = None
4942 hint = None
4943 if not any([p for p in pats if p.find(':') >= 0]):
4943 if not any([p for p in pats if p.find(':') >= 0]):
4944 pats = ['path:%s' % p for p in pats]
4944 pats = ['path:%s' % p for p in pats]
4945 m = scmutil.match(wctx, pats, opts)
4945 m = scmutil.match(wctx, pats, opts)
4946 for f in ms:
4946 for f in ms:
4947 if not m(f):
4947 if not m(f):
4948 continue
4948 continue
4949 def flag(o):
4949 def flag(o):
4950 if o == 're_merge':
4950 if o == 're_merge':
4951 return '--re-merge '
4951 return '--re-merge '
4952 return '-%s ' % o[0:1]
4952 return '-%s ' % o[0:1]
4953 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4953 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4954 hint = _("(try: hg resolve %s%s)\n") % (
4954 hint = _("(try: hg resolve %s%s)\n") % (
4955 flags,
4955 flags,
4956 ' '.join(pats))
4956 ' '.join(pats))
4957 break
4957 break
4958 ui.warn(_("arguments do not match paths that need resolving\n"))
4958 ui.warn(_("arguments do not match paths that need resolving\n"))
4959 if hint:
4959 if hint:
4960 ui.warn(hint)
4960 ui.warn(hint)
4961 elif ms.mergedriver and ms.mdstate() != 's':
4961 elif ms.mergedriver and ms.mdstate() != 's':
4962 # run conclude step when either a driver-resolved file is requested
4962 # run conclude step when either a driver-resolved file is requested
4963 # or there are no driver-resolved files
4963 # or there are no driver-resolved files
4964 # we can't use 'ret' to determine whether any files are unresolved
4964 # we can't use 'ret' to determine whether any files are unresolved
4965 # because we might not have tried to resolve some
4965 # because we might not have tried to resolve some
4966 if ((runconclude or not list(ms.driverresolved()))
4966 if ((runconclude or not list(ms.driverresolved()))
4967 and not list(ms.unresolved())):
4967 and not list(ms.unresolved())):
4968 proceed = mergemod.driverconclude(repo, ms, wctx)
4968 proceed = mergemod.driverconclude(repo, ms, wctx)
4969 ms.commit()
4969 ms.commit()
4970 if not proceed:
4970 if not proceed:
4971 return 1
4971 return 1
4972
4972
4973 # Nudge users into finishing an unfinished operation
4973 # Nudge users into finishing an unfinished operation
4974 unresolvedf = list(ms.unresolved())
4974 unresolvedf = list(ms.unresolved())
4975 driverresolvedf = list(ms.driverresolved())
4975 driverresolvedf = list(ms.driverresolved())
4976 if not unresolvedf and not driverresolvedf:
4976 if not unresolvedf and not driverresolvedf:
4977 ui.status(_('(no more unresolved files)\n'))
4977 ui.status(_('(no more unresolved files)\n'))
4978 cmdutil.checkafterresolved(repo)
4978 cmdutil.checkafterresolved(repo)
4979 elif not unresolvedf:
4979 elif not unresolvedf:
4980 ui.status(_('(no more unresolved files -- '
4980 ui.status(_('(no more unresolved files -- '
4981 'run "hg resolve --all" to conclude)\n'))
4981 'run "hg resolve --all" to conclude)\n'))
4982
4982
4983 return ret
4983 return ret
4984
4984
4985 @command('revert',
4985 @command('revert',
4986 [('a', 'all', None, _('revert all changes when no arguments given')),
4986 [('a', 'all', None, _('revert all changes when no arguments given')),
4987 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4987 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4988 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4988 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4989 ('C', 'no-backup', None, _('do not save backup copies of files')),
4989 ('C', 'no-backup', None, _('do not save backup copies of files')),
4990 ('i', 'interactive', None, _('interactively select the changes')),
4990 ('i', 'interactive', None, _('interactively select the changes')),
4991 ] + walkopts + dryrunopts,
4991 ] + walkopts + dryrunopts,
4992 _('[OPTION]... [-r REV] [NAME]...'),
4992 _('[OPTION]... [-r REV] [NAME]...'),
4993 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4993 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
4994 def revert(ui, repo, *pats, **opts):
4994 def revert(ui, repo, *pats, **opts):
4995 """restore files to their checkout state
4995 """restore files to their checkout state
4996
4996
4997 .. note::
4997 .. note::
4998
4998
4999 To check out earlier revisions, you should use :hg:`update REV`.
4999 To check out earlier revisions, you should use :hg:`update REV`.
5000 To cancel an uncommitted merge (and lose your changes),
5000 To cancel an uncommitted merge (and lose your changes),
5001 use :hg:`merge --abort`.
5001 use :hg:`merge --abort`.
5002
5002
5003 With no revision specified, revert the specified files or directories
5003 With no revision specified, revert the specified files or directories
5004 to the contents they had in the parent of the working directory.
5004 to the contents they had in the parent of the working directory.
5005 This restores the contents of files to an unmodified
5005 This restores the contents of files to an unmodified
5006 state and unschedules adds, removes, copies, and renames. If the
5006 state and unschedules adds, removes, copies, and renames. If the
5007 working directory has two parents, you must explicitly specify a
5007 working directory has two parents, you must explicitly specify a
5008 revision.
5008 revision.
5009
5009
5010 Using the -r/--rev or -d/--date options, revert the given files or
5010 Using the -r/--rev or -d/--date options, revert the given files or
5011 directories to their states as of a specific revision. Because
5011 directories to their states as of a specific revision. Because
5012 revert does not change the working directory parents, this will
5012 revert does not change the working directory parents, this will
5013 cause these files to appear modified. This can be helpful to "back
5013 cause these files to appear modified. This can be helpful to "back
5014 out" some or all of an earlier change. See :hg:`backout` for a
5014 out" some or all of an earlier change. See :hg:`backout` for a
5015 related method.
5015 related method.
5016
5016
5017 Modified files are saved with a .orig suffix before reverting.
5017 Modified files are saved with a .orig suffix before reverting.
5018 To disable these backups, use --no-backup. It is possible to store
5018 To disable these backups, use --no-backup. It is possible to store
5019 the backup files in a custom directory relative to the root of the
5019 the backup files in a custom directory relative to the root of the
5020 repository by setting the ``ui.origbackuppath`` configuration
5020 repository by setting the ``ui.origbackuppath`` configuration
5021 option.
5021 option.
5022
5022
5023 See :hg:`help dates` for a list of formats valid for -d/--date.
5023 See :hg:`help dates` for a list of formats valid for -d/--date.
5024
5024
5025 See :hg:`help backout` for a way to reverse the effect of an
5025 See :hg:`help backout` for a way to reverse the effect of an
5026 earlier changeset.
5026 earlier changeset.
5027
5027
5028 Returns 0 on success.
5028 Returns 0 on success.
5029 """
5029 """
5030
5030
5031 opts = pycompat.byteskwargs(opts)
5031 opts = pycompat.byteskwargs(opts)
5032 if opts.get("date"):
5032 if opts.get("date"):
5033 if opts.get("rev"):
5033 if opts.get("rev"):
5034 raise error.Abort(_("you can't specify a revision and a date"))
5034 raise error.Abort(_("you can't specify a revision and a date"))
5035 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5035 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5036
5036
5037 parent, p2 = repo.dirstate.parents()
5037 parent, p2 = repo.dirstate.parents()
5038 if not opts.get('rev') and p2 != nullid:
5038 if not opts.get('rev') and p2 != nullid:
5039 # revert after merge is a trap for new users (issue2915)
5039 # revert after merge is a trap for new users (issue2915)
5040 raise error.Abort(_('uncommitted merge with no revision specified'),
5040 raise error.Abort(_('uncommitted merge with no revision specified'),
5041 hint=_("use 'hg update' or see 'hg help revert'"))
5041 hint=_("use 'hg update' or see 'hg help revert'"))
5042
5042
5043 rev = opts.get('rev')
5043 rev = opts.get('rev')
5044 if rev:
5044 if rev:
5045 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5045 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5046 ctx = scmutil.revsingle(repo, rev)
5046 ctx = scmutil.revsingle(repo, rev)
5047
5047
5048 if (not (pats or opts.get('include') or opts.get('exclude') or
5048 if (not (pats or opts.get('include') or opts.get('exclude') or
5049 opts.get('all') or opts.get('interactive'))):
5049 opts.get('all') or opts.get('interactive'))):
5050 msg = _("no files or directories specified")
5050 msg = _("no files or directories specified")
5051 if p2 != nullid:
5051 if p2 != nullid:
5052 hint = _("uncommitted merge, use --all to discard all changes,"
5052 hint = _("uncommitted merge, use --all to discard all changes,"
5053 " or 'hg update -C .' to abort the merge")
5053 " or 'hg update -C .' to abort the merge")
5054 raise error.Abort(msg, hint=hint)
5054 raise error.Abort(msg, hint=hint)
5055 dirty = any(repo.status())
5055 dirty = any(repo.status())
5056 node = ctx.node()
5056 node = ctx.node()
5057 if node != parent:
5057 if node != parent:
5058 if dirty:
5058 if dirty:
5059 hint = _("uncommitted changes, use --all to discard all"
5059 hint = _("uncommitted changes, use --all to discard all"
5060 " changes, or 'hg update %d' to update") % ctx.rev()
5060 " changes, or 'hg update %d' to update") % ctx.rev()
5061 else:
5061 else:
5062 hint = _("use --all to revert all files,"
5062 hint = _("use --all to revert all files,"
5063 " or 'hg update %d' to update") % ctx.rev()
5063 " or 'hg update %d' to update") % ctx.rev()
5064 elif dirty:
5064 elif dirty:
5065 hint = _("uncommitted changes, use --all to discard all changes")
5065 hint = _("uncommitted changes, use --all to discard all changes")
5066 else:
5066 else:
5067 hint = _("use --all to revert all files")
5067 hint = _("use --all to revert all files")
5068 raise error.Abort(msg, hint=hint)
5068 raise error.Abort(msg, hint=hint)
5069
5069
5070 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5070 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
5071 **pycompat.strkwargs(opts))
5071 **pycompat.strkwargs(opts))
5072
5072
5073 @command(
5073 @command(
5074 'rollback',
5074 'rollback',
5075 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5075 dryrunopts + [('f', 'force', False, _('ignore safety measures'))],
5076 helpcategory=command.CATEGORY_MAINTENANCE)
5076 helpcategory=command.CATEGORY_MAINTENANCE)
5077 def rollback(ui, repo, **opts):
5077 def rollback(ui, repo, **opts):
5078 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5078 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5079
5079
5080 Please use :hg:`commit --amend` instead of rollback to correct
5080 Please use :hg:`commit --amend` instead of rollback to correct
5081 mistakes in the last commit.
5081 mistakes in the last commit.
5082
5082
5083 This command should be used with care. There is only one level of
5083 This command should be used with care. There is only one level of
5084 rollback, and there is no way to undo a rollback. It will also
5084 rollback, and there is no way to undo a rollback. It will also
5085 restore the dirstate at the time of the last transaction, losing
5085 restore the dirstate at the time of the last transaction, losing
5086 any dirstate changes since that time. This command does not alter
5086 any dirstate changes since that time. This command does not alter
5087 the working directory.
5087 the working directory.
5088
5088
5089 Transactions are used to encapsulate the effects of all commands
5089 Transactions are used to encapsulate the effects of all commands
5090 that create new changesets or propagate existing changesets into a
5090 that create new changesets or propagate existing changesets into a
5091 repository.
5091 repository.
5092
5092
5093 .. container:: verbose
5093 .. container:: verbose
5094
5094
5095 For example, the following commands are transactional, and their
5095 For example, the following commands are transactional, and their
5096 effects can be rolled back:
5096 effects can be rolled back:
5097
5097
5098 - commit
5098 - commit
5099 - import
5099 - import
5100 - pull
5100 - pull
5101 - push (with this repository as the destination)
5101 - push (with this repository as the destination)
5102 - unbundle
5102 - unbundle
5103
5103
5104 To avoid permanent data loss, rollback will refuse to rollback a
5104 To avoid permanent data loss, rollback will refuse to rollback a
5105 commit transaction if it isn't checked out. Use --force to
5105 commit transaction if it isn't checked out. Use --force to
5106 override this protection.
5106 override this protection.
5107
5107
5108 The rollback command can be entirely disabled by setting the
5108 The rollback command can be entirely disabled by setting the
5109 ``ui.rollback`` configuration setting to false. If you're here
5109 ``ui.rollback`` configuration setting to false. If you're here
5110 because you want to use rollback and it's disabled, you can
5110 because you want to use rollback and it's disabled, you can
5111 re-enable the command by setting ``ui.rollback`` to true.
5111 re-enable the command by setting ``ui.rollback`` to true.
5112
5112
5113 This command is not intended for use on public repositories. Once
5113 This command is not intended for use on public repositories. Once
5114 changes are visible for pull by other users, rolling a transaction
5114 changes are visible for pull by other users, rolling a transaction
5115 back locally is ineffective (someone else may already have pulled
5115 back locally is ineffective (someone else may already have pulled
5116 the changes). Furthermore, a race is possible with readers of the
5116 the changes). Furthermore, a race is possible with readers of the
5117 repository; for example an in-progress pull from the repository
5117 repository; for example an in-progress pull from the repository
5118 may fail if a rollback is performed.
5118 may fail if a rollback is performed.
5119
5119
5120 Returns 0 on success, 1 if no rollback data is available.
5120 Returns 0 on success, 1 if no rollback data is available.
5121 """
5121 """
5122 if not ui.configbool('ui', 'rollback'):
5122 if not ui.configbool('ui', 'rollback'):
5123 raise error.Abort(_('rollback is disabled because it is unsafe'),
5123 raise error.Abort(_('rollback is disabled because it is unsafe'),
5124 hint=('see `hg help -v rollback` for information'))
5124 hint=('see `hg help -v rollback` for information'))
5125 return repo.rollback(dryrun=opts.get(r'dry_run'),
5125 return repo.rollback(dryrun=opts.get(r'dry_run'),
5126 force=opts.get(r'force'))
5126 force=opts.get(r'force'))
5127
5127
5128 @command(
5128 @command(
5129 'root', [], intents={INTENT_READONLY},
5129 'root', [], intents={INTENT_READONLY},
5130 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5130 helpcategory=command.CATEGORY_WORKING_DIRECTORY)
5131 def root(ui, repo):
5131 def root(ui, repo):
5132 """print the root (top) of the current working directory
5132 """print the root (top) of the current working directory
5133
5133
5134 Print the root directory of the current repository.
5134 Print the root directory of the current repository.
5135
5135
5136 Returns 0 on success.
5136 Returns 0 on success.
5137 """
5137 """
5138 ui.write(repo.root + "\n")
5138 ui.write(repo.root + "\n")
5139
5139
5140 @command('serve',
5140 @command('serve',
5141 [('A', 'accesslog', '', _('name of access log file to write to'),
5141 [('A', 'accesslog', '', _('name of access log file to write to'),
5142 _('FILE')),
5142 _('FILE')),
5143 ('d', 'daemon', None, _('run server in background')),
5143 ('d', 'daemon', None, _('run server in background')),
5144 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5144 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
5145 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5145 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5146 # use string type, then we can check if something was passed
5146 # use string type, then we can check if something was passed
5147 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5147 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5148 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5148 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5149 _('ADDR')),
5149 _('ADDR')),
5150 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5150 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5151 _('PREFIX')),
5151 _('PREFIX')),
5152 ('n', 'name', '',
5152 ('n', 'name', '',
5153 _('name to show in web pages (default: working directory)'), _('NAME')),
5153 _('name to show in web pages (default: working directory)'), _('NAME')),
5154 ('', 'web-conf', '',
5154 ('', 'web-conf', '',
5155 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5155 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
5156 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5156 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5157 _('FILE')),
5157 _('FILE')),
5158 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5158 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5159 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5159 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
5160 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5160 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
5161 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5161 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5162 ('', 'style', '', _('template style to use'), _('STYLE')),
5162 ('', 'style', '', _('template style to use'), _('STYLE')),
5163 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5163 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5164 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5164 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
5165 ('', 'print-url', None, _('start and print only the URL'))]
5165 ('', 'print-url', None, _('start and print only the URL'))]
5166 + subrepoopts,
5166 + subrepoopts,
5167 _('[OPTION]...'),
5167 _('[OPTION]...'),
5168 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5168 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5169 helpbasic=True, optionalrepo=True)
5169 helpbasic=True, optionalrepo=True)
5170 def serve(ui, repo, **opts):
5170 def serve(ui, repo, **opts):
5171 """start stand-alone webserver
5171 """start stand-alone webserver
5172
5172
5173 Start a local HTTP repository browser and pull server. You can use
5173 Start a local HTTP repository browser and pull server. You can use
5174 this for ad-hoc sharing and browsing of repositories. It is
5174 this for ad-hoc sharing and browsing of repositories. It is
5175 recommended to use a real web server to serve a repository for
5175 recommended to use a real web server to serve a repository for
5176 longer periods of time.
5176 longer periods of time.
5177
5177
5178 Please note that the server does not implement access control.
5178 Please note that the server does not implement access control.
5179 This means that, by default, anybody can read from the server and
5179 This means that, by default, anybody can read from the server and
5180 nobody can write to it by default. Set the ``web.allow-push``
5180 nobody can write to it by default. Set the ``web.allow-push``
5181 option to ``*`` to allow everybody to push to the server. You
5181 option to ``*`` to allow everybody to push to the server. You
5182 should use a real web server if you need to authenticate users.
5182 should use a real web server if you need to authenticate users.
5183
5183
5184 By default, the server logs accesses to stdout and errors to
5184 By default, the server logs accesses to stdout and errors to
5185 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5185 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5186 files.
5186 files.
5187
5187
5188 To have the server choose a free port number to listen on, specify
5188 To have the server choose a free port number to listen on, specify
5189 a port number of 0; in this case, the server will print the port
5189 a port number of 0; in this case, the server will print the port
5190 number it uses.
5190 number it uses.
5191
5191
5192 Returns 0 on success.
5192 Returns 0 on success.
5193 """
5193 """
5194
5194
5195 opts = pycompat.byteskwargs(opts)
5195 opts = pycompat.byteskwargs(opts)
5196 if opts["stdio"] and opts["cmdserver"]:
5196 if opts["stdio"] and opts["cmdserver"]:
5197 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5197 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5198 if opts["print_url"] and ui.verbose:
5198 if opts["print_url"] and ui.verbose:
5199 raise error.Abort(_("cannot use --print-url with --verbose"))
5199 raise error.Abort(_("cannot use --print-url with --verbose"))
5200
5200
5201 if opts["stdio"]:
5201 if opts["stdio"]:
5202 if repo is None:
5202 if repo is None:
5203 raise error.RepoError(_("there is no Mercurial repository here"
5203 raise error.RepoError(_("there is no Mercurial repository here"
5204 " (.hg not found)"))
5204 " (.hg not found)"))
5205 s = wireprotoserver.sshserver(ui, repo)
5205 s = wireprotoserver.sshserver(ui, repo)
5206 s.serve_forever()
5206 s.serve_forever()
5207
5207
5208 service = server.createservice(ui, repo, opts)
5208 service = server.createservice(ui, repo, opts)
5209 return server.runservice(opts, initfn=service.init, runfn=service.run)
5209 return server.runservice(opts, initfn=service.init, runfn=service.run)
5210
5210
5211 _NOTTERSE = 'nothing'
5211 _NOTTERSE = 'nothing'
5212
5212
5213 @command('status|st',
5213 @command('status|st',
5214 [('A', 'all', None, _('show status of all files')),
5214 [('A', 'all', None, _('show status of all files')),
5215 ('m', 'modified', None, _('show only modified files')),
5215 ('m', 'modified', None, _('show only modified files')),
5216 ('a', 'added', None, _('show only added files')),
5216 ('a', 'added', None, _('show only added files')),
5217 ('r', 'removed', None, _('show only removed files')),
5217 ('r', 'removed', None, _('show only removed files')),
5218 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5218 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5219 ('c', 'clean', None, _('show only files without changes')),
5219 ('c', 'clean', None, _('show only files without changes')),
5220 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5220 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5221 ('i', 'ignored', None, _('show only ignored files')),
5221 ('i', 'ignored', None, _('show only ignored files')),
5222 ('n', 'no-status', None, _('hide status prefix')),
5222 ('n', 'no-status', None, _('hide status prefix')),
5223 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5223 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5224 ('C', 'copies', None, _('show source of copied files')),
5224 ('C', 'copies', None, _('show source of copied files')),
5225 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5225 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5226 ('', 'rev', [], _('show difference from revision'), _('REV')),
5226 ('', 'rev', [], _('show difference from revision'), _('REV')),
5227 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5227 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5228 ] + walkopts + subrepoopts + formatteropts,
5228 ] + walkopts + subrepoopts + formatteropts,
5229 _('[OPTION]... [FILE]...'),
5229 _('[OPTION]... [FILE]...'),
5230 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5230 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5231 helpbasic=True, inferrepo=True,
5231 helpbasic=True, inferrepo=True,
5232 intents={INTENT_READONLY})
5232 intents={INTENT_READONLY})
5233 def status(ui, repo, *pats, **opts):
5233 def status(ui, repo, *pats, **opts):
5234 """show changed files in the working directory
5234 """show changed files in the working directory
5235
5235
5236 Show status of files in the repository. If names are given, only
5236 Show status of files in the repository. If names are given, only
5237 files that match are shown. Files that are clean or ignored or
5237 files that match are shown. Files that are clean or ignored or
5238 the source of a copy/move operation, are not listed unless
5238 the source of a copy/move operation, are not listed unless
5239 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5239 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5240 Unless options described with "show only ..." are given, the
5240 Unless options described with "show only ..." are given, the
5241 options -mardu are used.
5241 options -mardu are used.
5242
5242
5243 Option -q/--quiet hides untracked (unknown and ignored) files
5243 Option -q/--quiet hides untracked (unknown and ignored) files
5244 unless explicitly requested with -u/--unknown or -i/--ignored.
5244 unless explicitly requested with -u/--unknown or -i/--ignored.
5245
5245
5246 .. note::
5246 .. note::
5247
5247
5248 :hg:`status` may appear to disagree with diff if permissions have
5248 :hg:`status` may appear to disagree with diff if permissions have
5249 changed or a merge has occurred. The standard diff format does
5249 changed or a merge has occurred. The standard diff format does
5250 not report permission changes and diff only reports changes
5250 not report permission changes and diff only reports changes
5251 relative to one merge parent.
5251 relative to one merge parent.
5252
5252
5253 If one revision is given, it is used as the base revision.
5253 If one revision is given, it is used as the base revision.
5254 If two revisions are given, the differences between them are
5254 If two revisions are given, the differences between them are
5255 shown. The --change option can also be used as a shortcut to list
5255 shown. The --change option can also be used as a shortcut to list
5256 the changed files of a revision from its first parent.
5256 the changed files of a revision from its first parent.
5257
5257
5258 The codes used to show the status of files are::
5258 The codes used to show the status of files are::
5259
5259
5260 M = modified
5260 M = modified
5261 A = added
5261 A = added
5262 R = removed
5262 R = removed
5263 C = clean
5263 C = clean
5264 ! = missing (deleted by non-hg command, but still tracked)
5264 ! = missing (deleted by non-hg command, but still tracked)
5265 ? = not tracked
5265 ? = not tracked
5266 I = ignored
5266 I = ignored
5267 = origin of the previous file (with --copies)
5267 = origin of the previous file (with --copies)
5268
5268
5269 .. container:: verbose
5269 .. container:: verbose
5270
5270
5271 The -t/--terse option abbreviates the output by showing only the directory
5271 The -t/--terse option abbreviates the output by showing only the directory
5272 name if all the files in it share the same status. The option takes an
5272 name if all the files in it share the same status. The option takes an
5273 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5273 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5274 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5274 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5275 for 'ignored' and 'c' for clean.
5275 for 'ignored' and 'c' for clean.
5276
5276
5277 It abbreviates only those statuses which are passed. Note that clean and
5277 It abbreviates only those statuses which are passed. Note that clean and
5278 ignored files are not displayed with '--terse ic' unless the -c/--clean
5278 ignored files are not displayed with '--terse ic' unless the -c/--clean
5279 and -i/--ignored options are also used.
5279 and -i/--ignored options are also used.
5280
5280
5281 The -v/--verbose option shows information when the repository is in an
5281 The -v/--verbose option shows information when the repository is in an
5282 unfinished merge, shelve, rebase state etc. You can have this behavior
5282 unfinished merge, shelve, rebase state etc. You can have this behavior
5283 turned on by default by enabling the ``commands.status.verbose`` option.
5283 turned on by default by enabling the ``commands.status.verbose`` option.
5284
5284
5285 You can skip displaying some of these states by setting
5285 You can skip displaying some of these states by setting
5286 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5286 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5287 'histedit', 'merge', 'rebase', or 'unshelve'.
5287 'histedit', 'merge', 'rebase', or 'unshelve'.
5288
5288
5289 Template:
5289 Template:
5290
5290
5291 The following keywords are supported in addition to the common template
5291 The following keywords are supported in addition to the common template
5292 keywords and functions. See also :hg:`help templates`.
5292 keywords and functions. See also :hg:`help templates`.
5293
5293
5294 :path: String. Repository-absolute path of the file.
5294 :path: String. Repository-absolute path of the file.
5295 :source: String. Repository-absolute path of the file originated from.
5295 :source: String. Repository-absolute path of the file originated from.
5296 Available if ``--copies`` is specified.
5296 Available if ``--copies`` is specified.
5297 :status: String. Character denoting file's status.
5297 :status: String. Character denoting file's status.
5298
5298
5299 Examples:
5299 Examples:
5300
5300
5301 - show changes in the working directory relative to a
5301 - show changes in the working directory relative to a
5302 changeset::
5302 changeset::
5303
5303
5304 hg status --rev 9353
5304 hg status --rev 9353
5305
5305
5306 - show changes in the working directory relative to the
5306 - show changes in the working directory relative to the
5307 current directory (see :hg:`help patterns` for more information)::
5307 current directory (see :hg:`help patterns` for more information)::
5308
5308
5309 hg status re:
5309 hg status re:
5310
5310
5311 - show all changes including copies in an existing changeset::
5311 - show all changes including copies in an existing changeset::
5312
5312
5313 hg status --copies --change 9353
5313 hg status --copies --change 9353
5314
5314
5315 - get a NUL separated list of added files, suitable for xargs::
5315 - get a NUL separated list of added files, suitable for xargs::
5316
5316
5317 hg status -an0
5317 hg status -an0
5318
5318
5319 - show more information about the repository status, abbreviating
5319 - show more information about the repository status, abbreviating
5320 added, removed, modified, deleted, and untracked paths::
5320 added, removed, modified, deleted, and untracked paths::
5321
5321
5322 hg status -v -t mardu
5322 hg status -v -t mardu
5323
5323
5324 Returns 0 on success.
5324 Returns 0 on success.
5325
5325
5326 """
5326 """
5327
5327
5328 opts = pycompat.byteskwargs(opts)
5328 opts = pycompat.byteskwargs(opts)
5329 revs = opts.get('rev')
5329 revs = opts.get('rev')
5330 change = opts.get('change')
5330 change = opts.get('change')
5331 terse = opts.get('terse')
5331 terse = opts.get('terse')
5332 if terse is _NOTTERSE:
5332 if terse is _NOTTERSE:
5333 if revs:
5333 if revs:
5334 terse = ''
5334 terse = ''
5335 else:
5335 else:
5336 terse = ui.config('commands', 'status.terse')
5336 terse = ui.config('commands', 'status.terse')
5337
5337
5338 if revs and change:
5338 if revs and change:
5339 msg = _('cannot specify --rev and --change at the same time')
5339 msg = _('cannot specify --rev and --change at the same time')
5340 raise error.Abort(msg)
5340 raise error.Abort(msg)
5341 elif revs and terse:
5341 elif revs and terse:
5342 msg = _('cannot use --terse with --rev')
5342 msg = _('cannot use --terse with --rev')
5343 raise error.Abort(msg)
5343 raise error.Abort(msg)
5344 elif change:
5344 elif change:
5345 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5345 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5346 ctx2 = scmutil.revsingle(repo, change, None)
5346 ctx2 = scmutil.revsingle(repo, change, None)
5347 ctx1 = ctx2.p1()
5347 ctx1 = ctx2.p1()
5348 else:
5348 else:
5349 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5349 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5350 ctx1, ctx2 = scmutil.revpair(repo, revs)
5350 ctx1, ctx2 = scmutil.revpair(repo, revs)
5351
5351
5352 if pats or ui.configbool('commands', 'status.relative'):
5352 if pats or ui.configbool('commands', 'status.relative'):
5353 cwd = repo.getcwd()
5353 cwd = repo.getcwd()
5354 else:
5354 else:
5355 cwd = ''
5355 cwd = ''
5356
5356
5357 if opts.get('print0'):
5357 if opts.get('print0'):
5358 end = '\0'
5358 end = '\0'
5359 else:
5359 else:
5360 end = '\n'
5360 end = '\n'
5361 copy = {}
5361 copy = {}
5362 states = 'modified added removed deleted unknown ignored clean'.split()
5362 states = 'modified added removed deleted unknown ignored clean'.split()
5363 show = [k for k in states if opts.get(k)]
5363 show = [k for k in states if opts.get(k)]
5364 if opts.get('all'):
5364 if opts.get('all'):
5365 show += ui.quiet and (states[:4] + ['clean']) or states
5365 show += ui.quiet and (states[:4] + ['clean']) or states
5366
5366
5367 if not show:
5367 if not show:
5368 if ui.quiet:
5368 if ui.quiet:
5369 show = states[:4]
5369 show = states[:4]
5370 else:
5370 else:
5371 show = states[:5]
5371 show = states[:5]
5372
5372
5373 m = scmutil.match(ctx2, pats, opts)
5373 m = scmutil.match(ctx2, pats, opts)
5374 if terse:
5374 if terse:
5375 # we need to compute clean and unknown to terse
5375 # we need to compute clean and unknown to terse
5376 stat = repo.status(ctx1.node(), ctx2.node(), m,
5376 stat = repo.status(ctx1.node(), ctx2.node(), m,
5377 'ignored' in show or 'i' in terse,
5377 'ignored' in show or 'i' in terse,
5378 clean=True, unknown=True,
5378 clean=True, unknown=True,
5379 listsubrepos=opts.get('subrepos'))
5379 listsubrepos=opts.get('subrepos'))
5380
5380
5381 stat = cmdutil.tersedir(stat, terse)
5381 stat = cmdutil.tersedir(stat, terse)
5382 else:
5382 else:
5383 stat = repo.status(ctx1.node(), ctx2.node(), m,
5383 stat = repo.status(ctx1.node(), ctx2.node(), m,
5384 'ignored' in show, 'clean' in show,
5384 'ignored' in show, 'clean' in show,
5385 'unknown' in show, opts.get('subrepos'))
5385 'unknown' in show, opts.get('subrepos'))
5386
5386
5387 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5387 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5388
5388
5389 if (opts.get('all') or opts.get('copies')
5389 if (opts.get('all') or opts.get('copies')
5390 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5390 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5391 copy = copies.pathcopies(ctx1, ctx2, m)
5391 copy = copies.pathcopies(ctx1, ctx2, m)
5392
5392
5393 ui.pager('status')
5393 ui.pager('status')
5394 fm = ui.formatter('status', opts)
5394 fm = ui.formatter('status', opts)
5395 fmt = '%s' + end
5395 fmt = '%s' + end
5396 showchar = not opts.get('no_status')
5396 showchar = not opts.get('no_status')
5397
5397
5398 for state, char, files in changestates:
5398 for state, char, files in changestates:
5399 if state in show:
5399 if state in show:
5400 label = 'status.' + state
5400 label = 'status.' + state
5401 for f in files:
5401 for f in files:
5402 fm.startitem()
5402 fm.startitem()
5403 fm.context(ctx=ctx2)
5403 fm.context(ctx=ctx2)
5404 fm.data(path=f)
5404 fm.data(path=f)
5405 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5405 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5406 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5406 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5407 if f in copy:
5407 if f in copy:
5408 fm.data(source=copy[f])
5408 fm.data(source=copy[f])
5409 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5409 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5410 label='status.copied')
5410 label='status.copied')
5411
5411
5412 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5412 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5413 and not ui.plain()):
5413 and not ui.plain()):
5414 cmdutil.morestatus(repo, fm)
5414 cmdutil.morestatus(repo, fm)
5415 fm.end()
5415 fm.end()
5416
5416
5417 @command('summary|sum',
5417 @command('summary|sum',
5418 [('', 'remote', None, _('check for push and pull'))],
5418 [('', 'remote', None, _('check for push and pull'))],
5419 '[--remote]',
5419 '[--remote]',
5420 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5420 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5421 helpbasic=True,
5421 helpbasic=True,
5422 intents={INTENT_READONLY})
5422 intents={INTENT_READONLY})
5423 def summary(ui, repo, **opts):
5423 def summary(ui, repo, **opts):
5424 """summarize working directory state
5424 """summarize working directory state
5425
5425
5426 This generates a brief summary of the working directory state,
5426 This generates a brief summary of the working directory state,
5427 including parents, branch, commit status, phase and available updates.
5427 including parents, branch, commit status, phase and available updates.
5428
5428
5429 With the --remote option, this will check the default paths for
5429 With the --remote option, this will check the default paths for
5430 incoming and outgoing changes. This can be time-consuming.
5430 incoming and outgoing changes. This can be time-consuming.
5431
5431
5432 Returns 0 on success.
5432 Returns 0 on success.
5433 """
5433 """
5434
5434
5435 opts = pycompat.byteskwargs(opts)
5435 opts = pycompat.byteskwargs(opts)
5436 ui.pager('summary')
5436 ui.pager('summary')
5437 ctx = repo[None]
5437 ctx = repo[None]
5438 parents = ctx.parents()
5438 parents = ctx.parents()
5439 pnode = parents[0].node()
5439 pnode = parents[0].node()
5440 marks = []
5440 marks = []
5441
5441
5442 ms = None
5442 ms = None
5443 try:
5443 try:
5444 ms = mergemod.mergestate.read(repo)
5444 ms = mergemod.mergestate.read(repo)
5445 except error.UnsupportedMergeRecords as e:
5445 except error.UnsupportedMergeRecords as e:
5446 s = ' '.join(e.recordtypes)
5446 s = ' '.join(e.recordtypes)
5447 ui.warn(
5447 ui.warn(
5448 _('warning: merge state has unsupported record types: %s\n') % s)
5448 _('warning: merge state has unsupported record types: %s\n') % s)
5449 unresolved = []
5449 unresolved = []
5450 else:
5450 else:
5451 unresolved = list(ms.unresolved())
5451 unresolved = list(ms.unresolved())
5452
5452
5453 for p in parents:
5453 for p in parents:
5454 # label with log.changeset (instead of log.parent) since this
5454 # label with log.changeset (instead of log.parent) since this
5455 # shows a working directory parent *changeset*:
5455 # shows a working directory parent *changeset*:
5456 # i18n: column positioning for "hg summary"
5456 # i18n: column positioning for "hg summary"
5457 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5457 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5458 label=logcmdutil.changesetlabels(p))
5458 label=logcmdutil.changesetlabels(p))
5459 ui.write(' '.join(p.tags()), label='log.tag')
5459 ui.write(' '.join(p.tags()), label='log.tag')
5460 if p.bookmarks():
5460 if p.bookmarks():
5461 marks.extend(p.bookmarks())
5461 marks.extend(p.bookmarks())
5462 if p.rev() == -1:
5462 if p.rev() == -1:
5463 if not len(repo):
5463 if not len(repo):
5464 ui.write(_(' (empty repository)'))
5464 ui.write(_(' (empty repository)'))
5465 else:
5465 else:
5466 ui.write(_(' (no revision checked out)'))
5466 ui.write(_(' (no revision checked out)'))
5467 if p.obsolete():
5467 if p.obsolete():
5468 ui.write(_(' (obsolete)'))
5468 ui.write(_(' (obsolete)'))
5469 if p.isunstable():
5469 if p.isunstable():
5470 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5470 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5471 for instability in p.instabilities())
5471 for instability in p.instabilities())
5472 ui.write(' ('
5472 ui.write(' ('
5473 + ', '.join(instabilities)
5473 + ', '.join(instabilities)
5474 + ')')
5474 + ')')
5475 ui.write('\n')
5475 ui.write('\n')
5476 if p.description():
5476 if p.description():
5477 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5477 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5478 label='log.summary')
5478 label='log.summary')
5479
5479
5480 branch = ctx.branch()
5480 branch = ctx.branch()
5481 bheads = repo.branchheads(branch)
5481 bheads = repo.branchheads(branch)
5482 # i18n: column positioning for "hg summary"
5482 # i18n: column positioning for "hg summary"
5483 m = _('branch: %s\n') % branch
5483 m = _('branch: %s\n') % branch
5484 if branch != 'default':
5484 if branch != 'default':
5485 ui.write(m, label='log.branch')
5485 ui.write(m, label='log.branch')
5486 else:
5486 else:
5487 ui.status(m, label='log.branch')
5487 ui.status(m, label='log.branch')
5488
5488
5489 if marks:
5489 if marks:
5490 active = repo._activebookmark
5490 active = repo._activebookmark
5491 # i18n: column positioning for "hg summary"
5491 # i18n: column positioning for "hg summary"
5492 ui.write(_('bookmarks:'), label='log.bookmark')
5492 ui.write(_('bookmarks:'), label='log.bookmark')
5493 if active is not None:
5493 if active is not None:
5494 if active in marks:
5494 if active in marks:
5495 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5495 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5496 marks.remove(active)
5496 marks.remove(active)
5497 else:
5497 else:
5498 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5498 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5499 for m in marks:
5499 for m in marks:
5500 ui.write(' ' + m, label='log.bookmark')
5500 ui.write(' ' + m, label='log.bookmark')
5501 ui.write('\n', label='log.bookmark')
5501 ui.write('\n', label='log.bookmark')
5502
5502
5503 status = repo.status(unknown=True)
5503 status = repo.status(unknown=True)
5504
5504
5505 c = repo.dirstate.copies()
5505 c = repo.dirstate.copies()
5506 copied, renamed = [], []
5506 copied, renamed = [], []
5507 for d, s in c.iteritems():
5507 for d, s in c.iteritems():
5508 if s in status.removed:
5508 if s in status.removed:
5509 status.removed.remove(s)
5509 status.removed.remove(s)
5510 renamed.append(d)
5510 renamed.append(d)
5511 else:
5511 else:
5512 copied.append(d)
5512 copied.append(d)
5513 if d in status.added:
5513 if d in status.added:
5514 status.added.remove(d)
5514 status.added.remove(d)
5515
5515
5516 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5516 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5517
5517
5518 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5518 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5519 (ui.label(_('%d added'), 'status.added'), status.added),
5519 (ui.label(_('%d added'), 'status.added'), status.added),
5520 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5520 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5521 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5521 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5522 (ui.label(_('%d copied'), 'status.copied'), copied),
5522 (ui.label(_('%d copied'), 'status.copied'), copied),
5523 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5523 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5524 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5524 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5525 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5525 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5526 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5526 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5527 t = []
5527 t = []
5528 for l, s in labels:
5528 for l, s in labels:
5529 if s:
5529 if s:
5530 t.append(l % len(s))
5530 t.append(l % len(s))
5531
5531
5532 t = ', '.join(t)
5532 t = ', '.join(t)
5533 cleanworkdir = False
5533 cleanworkdir = False
5534
5534
5535 if repo.vfs.exists('graftstate'):
5535 if repo.vfs.exists('graftstate'):
5536 t += _(' (graft in progress)')
5536 t += _(' (graft in progress)')
5537 if repo.vfs.exists('updatestate'):
5537 if repo.vfs.exists('updatestate'):
5538 t += _(' (interrupted update)')
5538 t += _(' (interrupted update)')
5539 elif len(parents) > 1:
5539 elif len(parents) > 1:
5540 t += _(' (merge)')
5540 t += _(' (merge)')
5541 elif branch != parents[0].branch():
5541 elif branch != parents[0].branch():
5542 t += _(' (new branch)')
5542 t += _(' (new branch)')
5543 elif (parents[0].closesbranch() and
5543 elif (parents[0].closesbranch() and
5544 pnode in repo.branchheads(branch, closed=True)):
5544 pnode in repo.branchheads(branch, closed=True)):
5545 t += _(' (head closed)')
5545 t += _(' (head closed)')
5546 elif not (status.modified or status.added or status.removed or renamed or
5546 elif not (status.modified or status.added or status.removed or renamed or
5547 copied or subs):
5547 copied or subs):
5548 t += _(' (clean)')
5548 t += _(' (clean)')
5549 cleanworkdir = True
5549 cleanworkdir = True
5550 elif pnode not in bheads:
5550 elif pnode not in bheads:
5551 t += _(' (new branch head)')
5551 t += _(' (new branch head)')
5552
5552
5553 if parents:
5553 if parents:
5554 pendingphase = max(p.phase() for p in parents)
5554 pendingphase = max(p.phase() for p in parents)
5555 else:
5555 else:
5556 pendingphase = phases.public
5556 pendingphase = phases.public
5557
5557
5558 if pendingphase > phases.newcommitphase(ui):
5558 if pendingphase > phases.newcommitphase(ui):
5559 t += ' (%s)' % phases.phasenames[pendingphase]
5559 t += ' (%s)' % phases.phasenames[pendingphase]
5560
5560
5561 if cleanworkdir:
5561 if cleanworkdir:
5562 # i18n: column positioning for "hg summary"
5562 # i18n: column positioning for "hg summary"
5563 ui.status(_('commit: %s\n') % t.strip())
5563 ui.status(_('commit: %s\n') % t.strip())
5564 else:
5564 else:
5565 # i18n: column positioning for "hg summary"
5565 # i18n: column positioning for "hg summary"
5566 ui.write(_('commit: %s\n') % t.strip())
5566 ui.write(_('commit: %s\n') % t.strip())
5567
5567
5568 # all ancestors of branch heads - all ancestors of parent = new csets
5568 # all ancestors of branch heads - all ancestors of parent = new csets
5569 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5569 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5570 bheads))
5570 bheads))
5571
5571
5572 if new == 0:
5572 if new == 0:
5573 # i18n: column positioning for "hg summary"
5573 # i18n: column positioning for "hg summary"
5574 ui.status(_('update: (current)\n'))
5574 ui.status(_('update: (current)\n'))
5575 elif pnode not in bheads:
5575 elif pnode not in bheads:
5576 # i18n: column positioning for "hg summary"
5576 # i18n: column positioning for "hg summary"
5577 ui.write(_('update: %d new changesets (update)\n') % new)
5577 ui.write(_('update: %d new changesets (update)\n') % new)
5578 else:
5578 else:
5579 # i18n: column positioning for "hg summary"
5579 # i18n: column positioning for "hg summary"
5580 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5580 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5581 (new, len(bheads)))
5581 (new, len(bheads)))
5582
5582
5583 t = []
5583 t = []
5584 draft = len(repo.revs('draft()'))
5584 draft = len(repo.revs('draft()'))
5585 if draft:
5585 if draft:
5586 t.append(_('%d draft') % draft)
5586 t.append(_('%d draft') % draft)
5587 secret = len(repo.revs('secret()'))
5587 secret = len(repo.revs('secret()'))
5588 if secret:
5588 if secret:
5589 t.append(_('%d secret') % secret)
5589 t.append(_('%d secret') % secret)
5590
5590
5591 if draft or secret:
5591 if draft or secret:
5592 ui.status(_('phases: %s\n') % ', '.join(t))
5592 ui.status(_('phases: %s\n') % ', '.join(t))
5593
5593
5594 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5594 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5595 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5595 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5596 numtrouble = len(repo.revs(trouble + "()"))
5596 numtrouble = len(repo.revs(trouble + "()"))
5597 # We write all the possibilities to ease translation
5597 # We write all the possibilities to ease translation
5598 troublemsg = {
5598 troublemsg = {
5599 "orphan": _("orphan: %d changesets"),
5599 "orphan": _("orphan: %d changesets"),
5600 "contentdivergent": _("content-divergent: %d changesets"),
5600 "contentdivergent": _("content-divergent: %d changesets"),
5601 "phasedivergent": _("phase-divergent: %d changesets"),
5601 "phasedivergent": _("phase-divergent: %d changesets"),
5602 }
5602 }
5603 if numtrouble > 0:
5603 if numtrouble > 0:
5604 ui.status(troublemsg[trouble] % numtrouble + "\n")
5604 ui.status(troublemsg[trouble] % numtrouble + "\n")
5605
5605
5606 cmdutil.summaryhooks(ui, repo)
5606 cmdutil.summaryhooks(ui, repo)
5607
5607
5608 if opts.get('remote'):
5608 if opts.get('remote'):
5609 needsincoming, needsoutgoing = True, True
5609 needsincoming, needsoutgoing = True, True
5610 else:
5610 else:
5611 needsincoming, needsoutgoing = False, False
5611 needsincoming, needsoutgoing = False, False
5612 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5612 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5613 if i:
5613 if i:
5614 needsincoming = True
5614 needsincoming = True
5615 if o:
5615 if o:
5616 needsoutgoing = True
5616 needsoutgoing = True
5617 if not needsincoming and not needsoutgoing:
5617 if not needsincoming and not needsoutgoing:
5618 return
5618 return
5619
5619
5620 def getincoming():
5620 def getincoming():
5621 source, branches = hg.parseurl(ui.expandpath('default'))
5621 source, branches = hg.parseurl(ui.expandpath('default'))
5622 sbranch = branches[0]
5622 sbranch = branches[0]
5623 try:
5623 try:
5624 other = hg.peer(repo, {}, source)
5624 other = hg.peer(repo, {}, source)
5625 except error.RepoError:
5625 except error.RepoError:
5626 if opts.get('remote'):
5626 if opts.get('remote'):
5627 raise
5627 raise
5628 return source, sbranch, None, None, None
5628 return source, sbranch, None, None, None
5629 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5629 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5630 if revs:
5630 if revs:
5631 revs = [other.lookup(rev) for rev in revs]
5631 revs = [other.lookup(rev) for rev in revs]
5632 ui.debug('comparing with %s\n' % util.hidepassword(source))
5632 ui.debug('comparing with %s\n' % util.hidepassword(source))
5633 repo.ui.pushbuffer()
5633 repo.ui.pushbuffer()
5634 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5634 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5635 repo.ui.popbuffer()
5635 repo.ui.popbuffer()
5636 return source, sbranch, other, commoninc, commoninc[1]
5636 return source, sbranch, other, commoninc, commoninc[1]
5637
5637
5638 if needsincoming:
5638 if needsincoming:
5639 source, sbranch, sother, commoninc, incoming = getincoming()
5639 source, sbranch, sother, commoninc, incoming = getincoming()
5640 else:
5640 else:
5641 source = sbranch = sother = commoninc = incoming = None
5641 source = sbranch = sother = commoninc = incoming = None
5642
5642
5643 def getoutgoing():
5643 def getoutgoing():
5644 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5644 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5645 dbranch = branches[0]
5645 dbranch = branches[0]
5646 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5646 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5647 if source != dest:
5647 if source != dest:
5648 try:
5648 try:
5649 dother = hg.peer(repo, {}, dest)
5649 dother = hg.peer(repo, {}, dest)
5650 except error.RepoError:
5650 except error.RepoError:
5651 if opts.get('remote'):
5651 if opts.get('remote'):
5652 raise
5652 raise
5653 return dest, dbranch, None, None
5653 return dest, dbranch, None, None
5654 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5654 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5655 elif sother is None:
5655 elif sother is None:
5656 # there is no explicit destination peer, but source one is invalid
5656 # there is no explicit destination peer, but source one is invalid
5657 return dest, dbranch, None, None
5657 return dest, dbranch, None, None
5658 else:
5658 else:
5659 dother = sother
5659 dother = sother
5660 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5660 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5661 common = None
5661 common = None
5662 else:
5662 else:
5663 common = commoninc
5663 common = commoninc
5664 if revs:
5664 if revs:
5665 revs = [repo.lookup(rev) for rev in revs]
5665 revs = [repo.lookup(rev) for rev in revs]
5666 repo.ui.pushbuffer()
5666 repo.ui.pushbuffer()
5667 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5667 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5668 commoninc=common)
5668 commoninc=common)
5669 repo.ui.popbuffer()
5669 repo.ui.popbuffer()
5670 return dest, dbranch, dother, outgoing
5670 return dest, dbranch, dother, outgoing
5671
5671
5672 if needsoutgoing:
5672 if needsoutgoing:
5673 dest, dbranch, dother, outgoing = getoutgoing()
5673 dest, dbranch, dother, outgoing = getoutgoing()
5674 else:
5674 else:
5675 dest = dbranch = dother = outgoing = None
5675 dest = dbranch = dother = outgoing = None
5676
5676
5677 if opts.get('remote'):
5677 if opts.get('remote'):
5678 t = []
5678 t = []
5679 if incoming:
5679 if incoming:
5680 t.append(_('1 or more incoming'))
5680 t.append(_('1 or more incoming'))
5681 o = outgoing.missing
5681 o = outgoing.missing
5682 if o:
5682 if o:
5683 t.append(_('%d outgoing') % len(o))
5683 t.append(_('%d outgoing') % len(o))
5684 other = dother or sother
5684 other = dother or sother
5685 if 'bookmarks' in other.listkeys('namespaces'):
5685 if 'bookmarks' in other.listkeys('namespaces'):
5686 counts = bookmarks.summary(repo, other)
5686 counts = bookmarks.summary(repo, other)
5687 if counts[0] > 0:
5687 if counts[0] > 0:
5688 t.append(_('%d incoming bookmarks') % counts[0])
5688 t.append(_('%d incoming bookmarks') % counts[0])
5689 if counts[1] > 0:
5689 if counts[1] > 0:
5690 t.append(_('%d outgoing bookmarks') % counts[1])
5690 t.append(_('%d outgoing bookmarks') % counts[1])
5691
5691
5692 if t:
5692 if t:
5693 # i18n: column positioning for "hg summary"
5693 # i18n: column positioning for "hg summary"
5694 ui.write(_('remote: %s\n') % (', '.join(t)))
5694 ui.write(_('remote: %s\n') % (', '.join(t)))
5695 else:
5695 else:
5696 # i18n: column positioning for "hg summary"
5696 # i18n: column positioning for "hg summary"
5697 ui.status(_('remote: (synced)\n'))
5697 ui.status(_('remote: (synced)\n'))
5698
5698
5699 cmdutil.summaryremotehooks(ui, repo, opts,
5699 cmdutil.summaryremotehooks(ui, repo, opts,
5700 ((source, sbranch, sother, commoninc),
5700 ((source, sbranch, sother, commoninc),
5701 (dest, dbranch, dother, outgoing)))
5701 (dest, dbranch, dother, outgoing)))
5702
5702
5703 @command('tag',
5703 @command('tag',
5704 [('f', 'force', None, _('force tag')),
5704 [('f', 'force', None, _('force tag')),
5705 ('l', 'local', None, _('make the tag local')),
5705 ('l', 'local', None, _('make the tag local')),
5706 ('r', 'rev', '', _('revision to tag'), _('REV')),
5706 ('r', 'rev', '', _('revision to tag'), _('REV')),
5707 ('', 'remove', None, _('remove a tag')),
5707 ('', 'remove', None, _('remove a tag')),
5708 # -l/--local is already there, commitopts cannot be used
5708 # -l/--local is already there, commitopts cannot be used
5709 ('e', 'edit', None, _('invoke editor on commit messages')),
5709 ('e', 'edit', None, _('invoke editor on commit messages')),
5710 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5710 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5711 ] + commitopts2,
5711 ] + commitopts2,
5712 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5712 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
5713 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5713 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
5714 def tag(ui, repo, name1, *names, **opts):
5714 def tag(ui, repo, name1, *names, **opts):
5715 """add one or more tags for the current or given revision
5715 """add one or more tags for the current or given revision
5716
5716
5717 Name a particular revision using <name>.
5717 Name a particular revision using <name>.
5718
5718
5719 Tags are used to name particular revisions of the repository and are
5719 Tags are used to name particular revisions of the repository and are
5720 very useful to compare different revisions, to go back to significant
5720 very useful to compare different revisions, to go back to significant
5721 earlier versions or to mark branch points as releases, etc. Changing
5721 earlier versions or to mark branch points as releases, etc. Changing
5722 an existing tag is normally disallowed; use -f/--force to override.
5722 an existing tag is normally disallowed; use -f/--force to override.
5723
5723
5724 If no revision is given, the parent of the working directory is
5724 If no revision is given, the parent of the working directory is
5725 used.
5725 used.
5726
5726
5727 To facilitate version control, distribution, and merging of tags,
5727 To facilitate version control, distribution, and merging of tags,
5728 they are stored as a file named ".hgtags" which is managed similarly
5728 they are stored as a file named ".hgtags" which is managed similarly
5729 to other project files and can be hand-edited if necessary. This
5729 to other project files and can be hand-edited if necessary. This
5730 also means that tagging creates a new commit. The file
5730 also means that tagging creates a new commit. The file
5731 ".hg/localtags" is used for local tags (not shared among
5731 ".hg/localtags" is used for local tags (not shared among
5732 repositories).
5732 repositories).
5733
5733
5734 Tag commits are usually made at the head of a branch. If the parent
5734 Tag commits are usually made at the head of a branch. If the parent
5735 of the working directory is not a branch head, :hg:`tag` aborts; use
5735 of the working directory is not a branch head, :hg:`tag` aborts; use
5736 -f/--force to force the tag commit to be based on a non-head
5736 -f/--force to force the tag commit to be based on a non-head
5737 changeset.
5737 changeset.
5738
5738
5739 See :hg:`help dates` for a list of formats valid for -d/--date.
5739 See :hg:`help dates` for a list of formats valid for -d/--date.
5740
5740
5741 Since tag names have priority over branch names during revision
5741 Since tag names have priority over branch names during revision
5742 lookup, using an existing branch name as a tag name is discouraged.
5742 lookup, using an existing branch name as a tag name is discouraged.
5743
5743
5744 Returns 0 on success.
5744 Returns 0 on success.
5745 """
5745 """
5746 opts = pycompat.byteskwargs(opts)
5746 opts = pycompat.byteskwargs(opts)
5747 with repo.wlock(), repo.lock():
5747 with repo.wlock(), repo.lock():
5748 rev_ = "."
5748 rev_ = "."
5749 names = [t.strip() for t in (name1,) + names]
5749 names = [t.strip() for t in (name1,) + names]
5750 if len(names) != len(set(names)):
5750 if len(names) != len(set(names)):
5751 raise error.Abort(_('tag names must be unique'))
5751 raise error.Abort(_('tag names must be unique'))
5752 for n in names:
5752 for n in names:
5753 scmutil.checknewlabel(repo, n, 'tag')
5753 scmutil.checknewlabel(repo, n, 'tag')
5754 if not n:
5754 if not n:
5755 raise error.Abort(_('tag names cannot consist entirely of '
5755 raise error.Abort(_('tag names cannot consist entirely of '
5756 'whitespace'))
5756 'whitespace'))
5757 if opts.get('rev') and opts.get('remove'):
5757 if opts.get('rev') and opts.get('remove'):
5758 raise error.Abort(_("--rev and --remove are incompatible"))
5758 raise error.Abort(_("--rev and --remove are incompatible"))
5759 if opts.get('rev'):
5759 if opts.get('rev'):
5760 rev_ = opts['rev']
5760 rev_ = opts['rev']
5761 message = opts.get('message')
5761 message = opts.get('message')
5762 if opts.get('remove'):
5762 if opts.get('remove'):
5763 if opts.get('local'):
5763 if opts.get('local'):
5764 expectedtype = 'local'
5764 expectedtype = 'local'
5765 else:
5765 else:
5766 expectedtype = 'global'
5766 expectedtype = 'global'
5767
5767
5768 for n in names:
5768 for n in names:
5769 if not repo.tagtype(n):
5769 if not repo.tagtype(n):
5770 raise error.Abort(_("tag '%s' does not exist") % n)
5770 raise error.Abort(_("tag '%s' does not exist") % n)
5771 if repo.tagtype(n) != expectedtype:
5771 if repo.tagtype(n) != expectedtype:
5772 if expectedtype == 'global':
5772 if expectedtype == 'global':
5773 raise error.Abort(_("tag '%s' is not a global tag") % n)
5773 raise error.Abort(_("tag '%s' is not a global tag") % n)
5774 else:
5774 else:
5775 raise error.Abort(_("tag '%s' is not a local tag") % n)
5775 raise error.Abort(_("tag '%s' is not a local tag") % n)
5776 rev_ = 'null'
5776 rev_ = 'null'
5777 if not message:
5777 if not message:
5778 # we don't translate commit messages
5778 # we don't translate commit messages
5779 message = 'Removed tag %s' % ', '.join(names)
5779 message = 'Removed tag %s' % ', '.join(names)
5780 elif not opts.get('force'):
5780 elif not opts.get('force'):
5781 for n in names:
5781 for n in names:
5782 if n in repo.tags():
5782 if n in repo.tags():
5783 raise error.Abort(_("tag '%s' already exists "
5783 raise error.Abort(_("tag '%s' already exists "
5784 "(use -f to force)") % n)
5784 "(use -f to force)") % n)
5785 if not opts.get('local'):
5785 if not opts.get('local'):
5786 p1, p2 = repo.dirstate.parents()
5786 p1, p2 = repo.dirstate.parents()
5787 if p2 != nullid:
5787 if p2 != nullid:
5788 raise error.Abort(_('uncommitted merge'))
5788 raise error.Abort(_('uncommitted merge'))
5789 bheads = repo.branchheads()
5789 bheads = repo.branchheads()
5790 if not opts.get('force') and bheads and p1 not in bheads:
5790 if not opts.get('force') and bheads and p1 not in bheads:
5791 raise error.Abort(_('working directory is not at a branch head '
5791 raise error.Abort(_('working directory is not at a branch head '
5792 '(use -f to force)'))
5792 '(use -f to force)'))
5793 node = scmutil.revsingle(repo, rev_).node()
5793 node = scmutil.revsingle(repo, rev_).node()
5794
5794
5795 if not message:
5795 if not message:
5796 # we don't translate commit messages
5796 # we don't translate commit messages
5797 message = ('Added tag %s for changeset %s' %
5797 message = ('Added tag %s for changeset %s' %
5798 (', '.join(names), short(node)))
5798 (', '.join(names), short(node)))
5799
5799
5800 date = opts.get('date')
5800 date = opts.get('date')
5801 if date:
5801 if date:
5802 date = dateutil.parsedate(date)
5802 date = dateutil.parsedate(date)
5803
5803
5804 if opts.get('remove'):
5804 if opts.get('remove'):
5805 editform = 'tag.remove'
5805 editform = 'tag.remove'
5806 else:
5806 else:
5807 editform = 'tag.add'
5807 editform = 'tag.add'
5808 editor = cmdutil.getcommiteditor(editform=editform,
5808 editor = cmdutil.getcommiteditor(editform=editform,
5809 **pycompat.strkwargs(opts))
5809 **pycompat.strkwargs(opts))
5810
5810
5811 # don't allow tagging the null rev
5811 # don't allow tagging the null rev
5812 if (not opts.get('remove') and
5812 if (not opts.get('remove') and
5813 scmutil.revsingle(repo, rev_).rev() == nullrev):
5813 scmutil.revsingle(repo, rev_).rev() == nullrev):
5814 raise error.Abort(_("cannot tag null revision"))
5814 raise error.Abort(_("cannot tag null revision"))
5815
5815
5816 tagsmod.tag(repo, names, node, message, opts.get('local'),
5816 tagsmod.tag(repo, names, node, message, opts.get('local'),
5817 opts.get('user'), date, editor=editor)
5817 opts.get('user'), date, editor=editor)
5818
5818
5819 @command(
5819 @command(
5820 'tags', formatteropts, '',
5820 'tags', formatteropts, '',
5821 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5821 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5822 intents={INTENT_READONLY})
5822 intents={INTENT_READONLY})
5823 def tags(ui, repo, **opts):
5823 def tags(ui, repo, **opts):
5824 """list repository tags
5824 """list repository tags
5825
5825
5826 This lists both regular and local tags. When the -v/--verbose
5826 This lists both regular and local tags. When the -v/--verbose
5827 switch is used, a third column "local" is printed for local tags.
5827 switch is used, a third column "local" is printed for local tags.
5828 When the -q/--quiet switch is used, only the tag name is printed.
5828 When the -q/--quiet switch is used, only the tag name is printed.
5829
5829
5830 .. container:: verbose
5830 .. container:: verbose
5831
5831
5832 Template:
5832 Template:
5833
5833
5834 The following keywords are supported in addition to the common template
5834 The following keywords are supported in addition to the common template
5835 keywords and functions such as ``{tag}``. See also
5835 keywords and functions such as ``{tag}``. See also
5836 :hg:`help templates`.
5836 :hg:`help templates`.
5837
5837
5838 :type: String. ``local`` for local tags.
5838 :type: String. ``local`` for local tags.
5839
5839
5840 Returns 0 on success.
5840 Returns 0 on success.
5841 """
5841 """
5842
5842
5843 opts = pycompat.byteskwargs(opts)
5843 opts = pycompat.byteskwargs(opts)
5844 ui.pager('tags')
5844 ui.pager('tags')
5845 fm = ui.formatter('tags', opts)
5845 fm = ui.formatter('tags', opts)
5846 hexfunc = fm.hexfunc
5846 hexfunc = fm.hexfunc
5847 tagtype = ""
5847 tagtype = ""
5848
5848
5849 for t, n in reversed(repo.tagslist()):
5849 for t, n in reversed(repo.tagslist()):
5850 hn = hexfunc(n)
5850 hn = hexfunc(n)
5851 label = 'tags.normal'
5851 label = 'tags.normal'
5852 tagtype = ''
5852 tagtype = ''
5853 if repo.tagtype(t) == 'local':
5853 if repo.tagtype(t) == 'local':
5854 label = 'tags.local'
5854 label = 'tags.local'
5855 tagtype = 'local'
5855 tagtype = 'local'
5856
5856
5857 fm.startitem()
5857 fm.startitem()
5858 fm.context(repo=repo)
5858 fm.context(repo=repo)
5859 fm.write('tag', '%s', t, label=label)
5859 fm.write('tag', '%s', t, label=label)
5860 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5860 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5861 fm.condwrite(not ui.quiet, 'rev node', fmt,
5861 fm.condwrite(not ui.quiet, 'rev node', fmt,
5862 repo.changelog.rev(n), hn, label=label)
5862 repo.changelog.rev(n), hn, label=label)
5863 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5863 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5864 tagtype, label=label)
5864 tagtype, label=label)
5865 fm.plain('\n')
5865 fm.plain('\n')
5866 fm.end()
5866 fm.end()
5867
5867
5868 @command('tip',
5868 @command('tip',
5869 [('p', 'patch', None, _('show patch')),
5869 [('p', 'patch', None, _('show patch')),
5870 ('g', 'git', None, _('use git extended diff format')),
5870 ('g', 'git', None, _('use git extended diff format')),
5871 ] + templateopts,
5871 ] + templateopts,
5872 _('[-p] [-g]'),
5872 _('[-p] [-g]'),
5873 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
5873 helpcategory=command.CATEGORY_CHANGE_NAVIGATION)
5874 def tip(ui, repo, **opts):
5874 def tip(ui, repo, **opts):
5875 """show the tip revision (DEPRECATED)
5875 """show the tip revision (DEPRECATED)
5876
5876
5877 The tip revision (usually just called the tip) is the changeset
5877 The tip revision (usually just called the tip) is the changeset
5878 most recently added to the repository (and therefore the most
5878 most recently added to the repository (and therefore the most
5879 recently changed head).
5879 recently changed head).
5880
5880
5881 If you have just made a commit, that commit will be the tip. If
5881 If you have just made a commit, that commit will be the tip. If
5882 you have just pulled changes from another repository, the tip of
5882 you have just pulled changes from another repository, the tip of
5883 that repository becomes the current tip. The "tip" tag is special
5883 that repository becomes the current tip. The "tip" tag is special
5884 and cannot be renamed or assigned to a different changeset.
5884 and cannot be renamed or assigned to a different changeset.
5885
5885
5886 This command is deprecated, please use :hg:`heads` instead.
5886 This command is deprecated, please use :hg:`heads` instead.
5887
5887
5888 Returns 0 on success.
5888 Returns 0 on success.
5889 """
5889 """
5890 opts = pycompat.byteskwargs(opts)
5890 opts = pycompat.byteskwargs(opts)
5891 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5891 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5892 displayer.show(repo['tip'])
5892 displayer.show(repo['tip'])
5893 displayer.close()
5893 displayer.close()
5894
5894
5895 @command('unbundle',
5895 @command('unbundle',
5896 [('u', 'update', None,
5896 [('u', 'update', None,
5897 _('update to new branch head if changesets were unbundled'))],
5897 _('update to new branch head if changesets were unbundled'))],
5898 _('[-u] FILE...'),
5898 _('[-u] FILE...'),
5899 helpcategory=command.CATEGORY_IMPORT_EXPORT)
5899 helpcategory=command.CATEGORY_IMPORT_EXPORT)
5900 def unbundle(ui, repo, fname1, *fnames, **opts):
5900 def unbundle(ui, repo, fname1, *fnames, **opts):
5901 """apply one or more bundle files
5901 """apply one or more bundle files
5902
5902
5903 Apply one or more bundle files generated by :hg:`bundle`.
5903 Apply one or more bundle files generated by :hg:`bundle`.
5904
5904
5905 Returns 0 on success, 1 if an update has unresolved files.
5905 Returns 0 on success, 1 if an update has unresolved files.
5906 """
5906 """
5907 fnames = (fname1,) + fnames
5907 fnames = (fname1,) + fnames
5908
5908
5909 with repo.lock():
5909 with repo.lock():
5910 for fname in fnames:
5910 for fname in fnames:
5911 f = hg.openpath(ui, fname)
5911 f = hg.openpath(ui, fname)
5912 gen = exchange.readbundle(ui, f, fname)
5912 gen = exchange.readbundle(ui, f, fname)
5913 if isinstance(gen, streamclone.streamcloneapplier):
5913 if isinstance(gen, streamclone.streamcloneapplier):
5914 raise error.Abort(
5914 raise error.Abort(
5915 _('packed bundles cannot be applied with '
5915 _('packed bundles cannot be applied with '
5916 '"hg unbundle"'),
5916 '"hg unbundle"'),
5917 hint=_('use "hg debugapplystreamclonebundle"'))
5917 hint=_('use "hg debugapplystreamclonebundle"'))
5918 url = 'bundle:' + fname
5918 url = 'bundle:' + fname
5919 try:
5919 try:
5920 txnname = 'unbundle'
5920 txnname = 'unbundle'
5921 if not isinstance(gen, bundle2.unbundle20):
5921 if not isinstance(gen, bundle2.unbundle20):
5922 txnname = 'unbundle\n%s' % util.hidepassword(url)
5922 txnname = 'unbundle\n%s' % util.hidepassword(url)
5923 with repo.transaction(txnname) as tr:
5923 with repo.transaction(txnname) as tr:
5924 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5924 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5925 url=url)
5925 url=url)
5926 except error.BundleUnknownFeatureError as exc:
5926 except error.BundleUnknownFeatureError as exc:
5927 raise error.Abort(
5927 raise error.Abort(
5928 _('%s: unknown bundle feature, %s') % (fname, exc),
5928 _('%s: unknown bundle feature, %s') % (fname, exc),
5929 hint=_("see https://mercurial-scm.org/"
5929 hint=_("see https://mercurial-scm.org/"
5930 "wiki/BundleFeature for more "
5930 "wiki/BundleFeature for more "
5931 "information"))
5931 "information"))
5932 modheads = bundle2.combinechangegroupresults(op)
5932 modheads = bundle2.combinechangegroupresults(op)
5933
5933
5934 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5934 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5935
5935
5936 @command('update|up|checkout|co',
5936 @command('update|up|checkout|co',
5937 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5937 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5938 ('c', 'check', None, _('require clean working directory')),
5938 ('c', 'check', None, _('require clean working directory')),
5939 ('m', 'merge', None, _('merge uncommitted changes')),
5939 ('m', 'merge', None, _('merge uncommitted changes')),
5940 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5940 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5941 ('r', 'rev', '', _('revision'), _('REV'))
5941 ('r', 'rev', '', _('revision'), _('REV'))
5942 ] + mergetoolopts,
5942 ] + mergetoolopts,
5943 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
5943 _('[-C|-c|-m] [-d DATE] [[-r] REV]'),
5944 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5944 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5945 helpbasic=True)
5945 helpbasic=True)
5946 def update(ui, repo, node=None, **opts):
5946 def update(ui, repo, node=None, **opts):
5947 """update working directory (or switch revisions)
5947 """update working directory (or switch revisions)
5948
5948
5949 Update the repository's working directory to the specified
5949 Update the repository's working directory to the specified
5950 changeset. If no changeset is specified, update to the tip of the
5950 changeset. If no changeset is specified, update to the tip of the
5951 current named branch and move the active bookmark (see :hg:`help
5951 current named branch and move the active bookmark (see :hg:`help
5952 bookmarks`).
5952 bookmarks`).
5953
5953
5954 Update sets the working directory's parent revision to the specified
5954 Update sets the working directory's parent revision to the specified
5955 changeset (see :hg:`help parents`).
5955 changeset (see :hg:`help parents`).
5956
5956
5957 If the changeset is not a descendant or ancestor of the working
5957 If the changeset is not a descendant or ancestor of the working
5958 directory's parent and there are uncommitted changes, the update is
5958 directory's parent and there are uncommitted changes, the update is
5959 aborted. With the -c/--check option, the working directory is checked
5959 aborted. With the -c/--check option, the working directory is checked
5960 for uncommitted changes; if none are found, the working directory is
5960 for uncommitted changes; if none are found, the working directory is
5961 updated to the specified changeset.
5961 updated to the specified changeset.
5962
5962
5963 .. container:: verbose
5963 .. container:: verbose
5964
5964
5965 The -C/--clean, -c/--check, and -m/--merge options control what
5965 The -C/--clean, -c/--check, and -m/--merge options control what
5966 happens if the working directory contains uncommitted changes.
5966 happens if the working directory contains uncommitted changes.
5967 At most of one of them can be specified.
5967 At most of one of them can be specified.
5968
5968
5969 1. If no option is specified, and if
5969 1. If no option is specified, and if
5970 the requested changeset is an ancestor or descendant of
5970 the requested changeset is an ancestor or descendant of
5971 the working directory's parent, the uncommitted changes
5971 the working directory's parent, the uncommitted changes
5972 are merged into the requested changeset and the merged
5972 are merged into the requested changeset and the merged
5973 result is left uncommitted. If the requested changeset is
5973 result is left uncommitted. If the requested changeset is
5974 not an ancestor or descendant (that is, it is on another
5974 not an ancestor or descendant (that is, it is on another
5975 branch), the update is aborted and the uncommitted changes
5975 branch), the update is aborted and the uncommitted changes
5976 are preserved.
5976 are preserved.
5977
5977
5978 2. With the -m/--merge option, the update is allowed even if the
5978 2. With the -m/--merge option, the update is allowed even if the
5979 requested changeset is not an ancestor or descendant of
5979 requested changeset is not an ancestor or descendant of
5980 the working directory's parent.
5980 the working directory's parent.
5981
5981
5982 3. With the -c/--check option, the update is aborted and the
5982 3. With the -c/--check option, the update is aborted and the
5983 uncommitted changes are preserved.
5983 uncommitted changes are preserved.
5984
5984
5985 4. With the -C/--clean option, uncommitted changes are discarded and
5985 4. With the -C/--clean option, uncommitted changes are discarded and
5986 the working directory is updated to the requested changeset.
5986 the working directory is updated to the requested changeset.
5987
5987
5988 To cancel an uncommitted merge (and lose your changes), use
5988 To cancel an uncommitted merge (and lose your changes), use
5989 :hg:`merge --abort`.
5989 :hg:`merge --abort`.
5990
5990
5991 Use null as the changeset to remove the working directory (like
5991 Use null as the changeset to remove the working directory (like
5992 :hg:`clone -U`).
5992 :hg:`clone -U`).
5993
5993
5994 If you want to revert just one file to an older revision, use
5994 If you want to revert just one file to an older revision, use
5995 :hg:`revert [-r REV] NAME`.
5995 :hg:`revert [-r REV] NAME`.
5996
5996
5997 See :hg:`help dates` for a list of formats valid for -d/--date.
5997 See :hg:`help dates` for a list of formats valid for -d/--date.
5998
5998
5999 Returns 0 on success, 1 if there are unresolved files.
5999 Returns 0 on success, 1 if there are unresolved files.
6000 """
6000 """
6001 rev = opts.get(r'rev')
6001 rev = opts.get(r'rev')
6002 date = opts.get(r'date')
6002 date = opts.get(r'date')
6003 clean = opts.get(r'clean')
6003 clean = opts.get(r'clean')
6004 check = opts.get(r'check')
6004 check = opts.get(r'check')
6005 merge = opts.get(r'merge')
6005 merge = opts.get(r'merge')
6006 if rev and node:
6006 if rev and node:
6007 raise error.Abort(_("please specify just one revision"))
6007 raise error.Abort(_("please specify just one revision"))
6008
6008
6009 if ui.configbool('commands', 'update.requiredest'):
6009 if ui.configbool('commands', 'update.requiredest'):
6010 if not node and not rev and not date:
6010 if not node and not rev and not date:
6011 raise error.Abort(_('you must specify a destination'),
6011 raise error.Abort(_('you must specify a destination'),
6012 hint=_('for example: hg update ".::"'))
6012 hint=_('for example: hg update ".::"'))
6013
6013
6014 if rev is None or rev == '':
6014 if rev is None or rev == '':
6015 rev = node
6015 rev = node
6016
6016
6017 if date and rev is not None:
6017 if date and rev is not None:
6018 raise error.Abort(_("you can't specify a revision and a date"))
6018 raise error.Abort(_("you can't specify a revision and a date"))
6019
6019
6020 if len([x for x in (clean, check, merge) if x]) > 1:
6020 if len([x for x in (clean, check, merge) if x]) > 1:
6021 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6021 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
6022 "or -m/--merge"))
6022 "or -m/--merge"))
6023
6023
6024 updatecheck = None
6024 updatecheck = None
6025 if check:
6025 if check:
6026 updatecheck = 'abort'
6026 updatecheck = 'abort'
6027 elif merge:
6027 elif merge:
6028 updatecheck = 'none'
6028 updatecheck = 'none'
6029
6029
6030 with repo.wlock():
6030 with repo.wlock():
6031 cmdutil.clearunfinished(repo)
6031 cmdutil.clearunfinished(repo)
6032
6032
6033 if date:
6033 if date:
6034 rev = cmdutil.finddate(ui, repo, date)
6034 rev = cmdutil.finddate(ui, repo, date)
6035
6035
6036 # if we defined a bookmark, we have to remember the original name
6036 # if we defined a bookmark, we have to remember the original name
6037 brev = rev
6037 brev = rev
6038 if rev:
6038 if rev:
6039 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6039 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
6040 ctx = scmutil.revsingle(repo, rev, rev)
6040 ctx = scmutil.revsingle(repo, rev, rev)
6041 rev = ctx.rev()
6041 rev = ctx.rev()
6042 hidden = ctx.hidden()
6042 hidden = ctx.hidden()
6043 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6043 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
6044 with ui.configoverride(overrides, 'update'):
6044 with ui.configoverride(overrides, 'update'):
6045 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6045 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
6046 updatecheck=updatecheck)
6046 updatecheck=updatecheck)
6047 if hidden:
6047 if hidden:
6048 ctxstr = ctx.hex()[:12]
6048 ctxstr = ctx.hex()[:12]
6049 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6049 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
6050
6050
6051 if ctx.obsolete():
6051 if ctx.obsolete():
6052 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6052 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
6053 ui.warn("(%s)\n" % obsfatemsg)
6053 ui.warn("(%s)\n" % obsfatemsg)
6054 return ret
6054 return ret
6055
6055
6056 @command('verify', [], helpcategory=command.CATEGORY_MAINTENANCE)
6056 @command('verify', [], helpcategory=command.CATEGORY_MAINTENANCE)
6057 def verify(ui, repo):
6057 def verify(ui, repo):
6058 """verify the integrity of the repository
6058 """verify the integrity of the repository
6059
6059
6060 Verify the integrity of the current repository.
6060 Verify the integrity of the current repository.
6061
6061
6062 This will perform an extensive check of the repository's
6062 This will perform an extensive check of the repository's
6063 integrity, validating the hashes and checksums of each entry in
6063 integrity, validating the hashes and checksums of each entry in
6064 the changelog, manifest, and tracked files, as well as the
6064 the changelog, manifest, and tracked files, as well as the
6065 integrity of their crosslinks and indices.
6065 integrity of their crosslinks and indices.
6066
6066
6067 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6067 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6068 for more information about recovery from corruption of the
6068 for more information about recovery from corruption of the
6069 repository.
6069 repository.
6070
6070
6071 Returns 0 on success, 1 if errors are encountered.
6071 Returns 0 on success, 1 if errors are encountered.
6072 """
6072 """
6073 return hg.verify(repo)
6073 return hg.verify(repo)
6074
6074
6075 @command(
6075 @command(
6076 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6076 'version', [] + formatteropts, helpcategory=command.CATEGORY_HELP,
6077 norepo=True, intents={INTENT_READONLY})
6077 norepo=True, intents={INTENT_READONLY})
6078 def version_(ui, **opts):
6078 def version_(ui, **opts):
6079 """output version and copyright information
6079 """output version and copyright information
6080
6080
6081 .. container:: verbose
6081 .. container:: verbose
6082
6082
6083 Template:
6083 Template:
6084
6084
6085 The following keywords are supported. See also :hg:`help templates`.
6085 The following keywords are supported. See also :hg:`help templates`.
6086
6086
6087 :extensions: List of extensions.
6087 :extensions: List of extensions.
6088 :ver: String. Version number.
6088 :ver: String. Version number.
6089
6089
6090 And each entry of ``{extensions}`` provides the following sub-keywords
6090 And each entry of ``{extensions}`` provides the following sub-keywords
6091 in addition to ``{ver}``.
6091 in addition to ``{ver}``.
6092
6092
6093 :bundled: Boolean. True if included in the release.
6093 :bundled: Boolean. True if included in the release.
6094 :name: String. Extension name.
6094 :name: String. Extension name.
6095 """
6095 """
6096 opts = pycompat.byteskwargs(opts)
6096 opts = pycompat.byteskwargs(opts)
6097 if ui.verbose:
6097 if ui.verbose:
6098 ui.pager('version')
6098 ui.pager('version')
6099 fm = ui.formatter("version", opts)
6099 fm = ui.formatter("version", opts)
6100 fm.startitem()
6100 fm.startitem()
6101 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6101 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
6102 util.version())
6102 util.version())
6103 license = _(
6103 license = _(
6104 "(see https://mercurial-scm.org for more information)\n"
6104 "(see https://mercurial-scm.org for more information)\n"
6105 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
6105 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
6106 "This is free software; see the source for copying conditions. "
6106 "This is free software; see the source for copying conditions. "
6107 "There is NO\nwarranty; "
6107 "There is NO\nwarranty; "
6108 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6108 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6109 )
6109 )
6110 if not ui.quiet:
6110 if not ui.quiet:
6111 fm.plain(license)
6111 fm.plain(license)
6112
6112
6113 if ui.verbose:
6113 if ui.verbose:
6114 fm.plain(_("\nEnabled extensions:\n\n"))
6114 fm.plain(_("\nEnabled extensions:\n\n"))
6115 # format names and versions into columns
6115 # format names and versions into columns
6116 names = []
6116 names = []
6117 vers = []
6117 vers = []
6118 isinternals = []
6118 isinternals = []
6119 for name, module in extensions.extensions():
6119 for name, module in extensions.extensions():
6120 names.append(name)
6120 names.append(name)
6121 vers.append(extensions.moduleversion(module) or None)
6121 vers.append(extensions.moduleversion(module) or None)
6122 isinternals.append(extensions.ismoduleinternal(module))
6122 isinternals.append(extensions.ismoduleinternal(module))
6123 fn = fm.nested("extensions", tmpl='{name}\n')
6123 fn = fm.nested("extensions", tmpl='{name}\n')
6124 if names:
6124 if names:
6125 namefmt = " %%-%ds " % max(len(n) for n in names)
6125 namefmt = " %%-%ds " % max(len(n) for n in names)
6126 places = [_("external"), _("internal")]
6126 places = [_("external"), _("internal")]
6127 for n, v, p in zip(names, vers, isinternals):
6127 for n, v, p in zip(names, vers, isinternals):
6128 fn.startitem()
6128 fn.startitem()
6129 fn.condwrite(ui.verbose, "name", namefmt, n)
6129 fn.condwrite(ui.verbose, "name", namefmt, n)
6130 if ui.verbose:
6130 if ui.verbose:
6131 fn.plain("%s " % places[p])
6131 fn.plain("%s " % places[p])
6132 fn.data(bundled=p)
6132 fn.data(bundled=p)
6133 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6133 fn.condwrite(ui.verbose and v, "ver", "%s", v)
6134 if ui.verbose:
6134 if ui.verbose:
6135 fn.plain("\n")
6135 fn.plain("\n")
6136 fn.end()
6136 fn.end()
6137 fm.end()
6137 fm.end()
6138
6138
6139 def loadcmdtable(ui, name, cmdtable):
6139 def loadcmdtable(ui, name, cmdtable):
6140 """Load command functions from specified cmdtable
6140 """Load command functions from specified cmdtable
6141 """
6141 """
6142 cmdtable = cmdtable.copy()
6142 cmdtable = cmdtable.copy()
6143 for cmd in list(cmdtable):
6143 for cmd in list(cmdtable):
6144 if not cmd.startswith('^'):
6144 if not cmd.startswith('^'):
6145 continue
6145 continue
6146 ui.deprecwarn("old-style command registration '%s' in extension '%s'"
6146 ui.deprecwarn("old-style command registration '%s' in extension '%s'"
6147 % (cmd, name), '4.8')
6147 % (cmd, name), '4.8')
6148 entry = cmdtable.pop(cmd)
6148 entry = cmdtable.pop(cmd)
6149 entry[0].helpbasic = True
6149 entry[0].helpbasic = True
6150 cmdtable[cmd[1:]] = entry
6150 cmdtable[cmd[1:]] = entry
6151
6151
6152 overrides = [cmd for cmd in cmdtable if cmd in table]
6152 overrides = [cmd for cmd in cmdtable if cmd in table]
6153 if overrides:
6153 if overrides:
6154 ui.warn(_("extension '%s' overrides commands: %s\n")
6154 ui.warn(_("extension '%s' overrides commands: %s\n")
6155 % (name, " ".join(overrides)))
6155 % (name, " ".join(overrides)))
6156 table.update(cmdtable)
6156 table.update(cmdtable)
@@ -1,616 +1,629 b''
1 test that a commit clears the merge state.
1 test that a commit clears the merge state.
2
2
3 $ hg init repo
3 $ hg init repo
4 $ cd repo
4 $ cd repo
5
5
6 $ echo foo > file1
6 $ echo foo > file1
7 $ echo foo > file2
7 $ echo foo > file2
8 $ hg commit -Am 'add files'
8 $ hg commit -Am 'add files'
9 adding file1
9 adding file1
10 adding file2
10 adding file2
11
11
12 $ echo bar >> file1
12 $ echo bar >> file1
13 $ echo bar >> file2
13 $ echo bar >> file2
14 $ hg commit -Am 'append bar to files'
14 $ hg commit -Am 'append bar to files'
15
15
16 create a second head with conflicting edits
16 create a second head with conflicting edits
17
17
18 $ hg up -C 0
18 $ hg up -C 0
19 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
19 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 $ echo baz >> file1
20 $ echo baz >> file1
21 $ echo baz >> file2
21 $ echo baz >> file2
22 $ hg commit -Am 'append baz to files'
22 $ hg commit -Am 'append baz to files'
23 created new head
23 created new head
24
24
25 create a third head with no conflicting edits
25 create a third head with no conflicting edits
26 $ hg up -qC 0
26 $ hg up -qC 0
27 $ echo foo > file3
27 $ echo foo > file3
28 $ hg commit -Am 'add non-conflicting file'
28 $ hg commit -Am 'add non-conflicting file'
29 adding file3
29 adding file3
30 created new head
30 created new head
31
31
32 failing merge
32 failing merge
33
33
34 $ hg up -qC 2
34 $ hg up -qC 2
35 $ hg merge --tool=internal:fail 1
35 $ hg merge --tool=internal:fail 1
36 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
36 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
37 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
37 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
38 [1]
38 [1]
39
39
40 resolve -l should contain unresolved entries
40 resolve -l should contain unresolved entries
41
41
42 $ hg resolve -l
42 $ hg resolve -l
43 U file1
43 U file1
44 U file2
44 U file2
45
45
46 $ hg resolve -l --no-status
46 $ hg resolve -l --no-status
47 file1
47 file1
48 file2
48 file2
49
49
50 resolving an unknown path should emit a warning, but not for -l
50 resolving an unknown path should emit a warning, but not for -l
51
51
52 $ hg resolve -m does-not-exist
52 $ hg resolve -m does-not-exist
53 arguments do not match paths that need resolving
53 arguments do not match paths that need resolving
54 $ hg resolve -l does-not-exist
54 $ hg resolve -l does-not-exist
55
55
56 tell users how they could have used resolve
56 tell users how they could have used resolve
57
57
58 $ mkdir nested
58 $ mkdir nested
59 $ cd nested
59 $ cd nested
60 $ hg resolve -m file1
60 $ hg resolve -m file1
61 arguments do not match paths that need resolving
61 arguments do not match paths that need resolving
62 (try: hg resolve -m path:file1)
62 (try: hg resolve -m path:file1)
63 $ hg resolve -m file1 filez
63 $ hg resolve -m file1 filez
64 arguments do not match paths that need resolving
64 arguments do not match paths that need resolving
65 (try: hg resolve -m path:file1 path:filez)
65 (try: hg resolve -m path:file1 path:filez)
66 $ hg resolve -m path:file1 path:filez
66 $ hg resolve -m path:file1 path:filez
67 $ hg resolve -l
67 $ hg resolve -l
68 R file1
68 R file1
69 U file2
69 U file2
70 $ hg resolve --re-merge filez file2
70 $ hg resolve --re-merge filez file2
71 arguments do not match paths that need resolving
71 arguments do not match paths that need resolving
72 (try: hg resolve --re-merge path:filez path:file2)
72 (try: hg resolve --re-merge path:filez path:file2)
73 $ hg resolve -m filez file2
73 $ hg resolve -m filez file2
74 arguments do not match paths that need resolving
74 arguments do not match paths that need resolving
75 (try: hg resolve -m path:filez path:file2)
75 (try: hg resolve -m path:filez path:file2)
76 $ hg resolve -m path:filez path:file2
76 $ hg resolve -m path:filez path:file2
77 (no more unresolved files)
77 (no more unresolved files)
78 $ hg resolve -l
78 $ hg resolve -l
79 R file1
79 R file1
80 R file2
80 R file2
81
81
82 cleanup
82 cleanup
83 $ hg resolve -u
83 $ hg resolve -u
84 $ cd ..
84 $ cd ..
85 $ rmdir nested
85 $ rmdir nested
86
86
87 don't allow marking or unmarking driver-resolved files
87 don't allow marking or unmarking driver-resolved files
88
88
89 $ cat > $TESTTMP/markdriver.py << EOF
89 $ cat > $TESTTMP/markdriver.py << EOF
90 > '''mark and unmark files as driver-resolved'''
90 > '''mark and unmark files as driver-resolved'''
91 > from mercurial import (
91 > from mercurial import (
92 > merge,
92 > merge,
93 > pycompat,
93 > pycompat,
94 > registrar,
94 > registrar,
95 > scmutil,
95 > scmutil,
96 > )
96 > )
97 > cmdtable = {}
97 > cmdtable = {}
98 > command = registrar.command(cmdtable)
98 > command = registrar.command(cmdtable)
99 > @command(b'markdriver',
99 > @command(b'markdriver',
100 > [(b'u', b'unmark', None, b'')],
100 > [(b'u', b'unmark', None, b'')],
101 > b'FILE...')
101 > b'FILE...')
102 > def markdriver(ui, repo, *pats, **opts):
102 > def markdriver(ui, repo, *pats, **opts):
103 > wlock = repo.wlock()
103 > wlock = repo.wlock()
104 > opts = pycompat.byteskwargs(opts)
104 > opts = pycompat.byteskwargs(opts)
105 > try:
105 > try:
106 > ms = merge.mergestate.read(repo)
106 > ms = merge.mergestate.read(repo)
107 > m = scmutil.match(repo[None], pats, opts)
107 > m = scmutil.match(repo[None], pats, opts)
108 > for f in ms:
108 > for f in ms:
109 > if not m(f):
109 > if not m(f):
110 > continue
110 > continue
111 > if not opts[b'unmark']:
111 > if not opts[b'unmark']:
112 > ms.mark(f, b'd')
112 > ms.mark(f, b'd')
113 > else:
113 > else:
114 > ms.mark(f, b'u')
114 > ms.mark(f, b'u')
115 > ms.commit()
115 > ms.commit()
116 > finally:
116 > finally:
117 > wlock.release()
117 > wlock.release()
118 > EOF
118 > EOF
119 $ hg --config extensions.markdriver=$TESTTMP/markdriver.py markdriver file1
119 $ hg --config extensions.markdriver=$TESTTMP/markdriver.py markdriver file1
120 $ hg resolve --list
120 $ hg resolve --list
121 D file1
121 D file1
122 U file2
122 U file2
123 $ hg resolve --mark file1
123 $ hg resolve --mark file1
124 not marking file1 as it is driver-resolved
124 not marking file1 as it is driver-resolved
125 this should not print out file1
125 this should not print out file1
126 $ hg resolve --mark --all
126 $ hg resolve --mark --all
127 (no more unresolved files -- run "hg resolve --all" to conclude)
127 (no more unresolved files -- run "hg resolve --all" to conclude)
128 $ hg resolve --mark 'glob:file*'
128 $ hg resolve --mark 'glob:file*'
129 (no more unresolved files -- run "hg resolve --all" to conclude)
129 (no more unresolved files -- run "hg resolve --all" to conclude)
130 $ hg resolve --list
130 $ hg resolve --list
131 D file1
131 D file1
132 R file2
132 R file2
133 $ hg resolve --unmark file1
133 $ hg resolve --unmark file1
134 not unmarking file1 as it is driver-resolved
134 not unmarking file1 as it is driver-resolved
135 (no more unresolved files -- run "hg resolve --all" to conclude)
135 (no more unresolved files -- run "hg resolve --all" to conclude)
136 $ hg resolve --unmark --all
136 $ hg resolve --unmark --all
137 $ hg resolve --list
137 $ hg resolve --list
138 D file1
138 D file1
139 U file2
139 U file2
140 $ hg --config extensions.markdriver=$TESTTMP/markdriver.py markdriver --unmark file1
140 $ hg --config extensions.markdriver=$TESTTMP/markdriver.py markdriver --unmark file1
141 $ hg resolve --list
141 $ hg resolve --list
142 U file1
142 U file1
143 U file2
143 U file2
144
144
145 resolve the failure
145 resolve the failure
146
146
147 $ echo resolved > file1
147 $ echo resolved > file1
148 $ hg resolve -m file1
148 $ hg resolve -m file1
149
149
150 resolve -l should show resolved file as resolved
150 resolve -l should show resolved file as resolved
151
151
152 $ hg resolve -l
152 $ hg resolve -l
153 R file1
153 R file1
154 U file2
154 U file2
155
155
156 $ hg resolve -l -Tjson
156 $ hg resolve -l -Tjson
157 [
157 [
158 {
158 {
159 "mergestatus": "R",
159 "mergestatus": "R",
160 "path": "file1"
160 "path": "file1"
161 },
161 },
162 {
162 {
163 "mergestatus": "U",
163 "mergestatus": "U",
164 "path": "file2"
164 "path": "file2"
165 }
165 }
166 ]
166 ]
167
167
168 $ hg resolve -l -T '{path} {mergestatus} {status} {p1rev} {p2rev}\n'
168 $ hg resolve -l -T '{path} {mergestatus} {status} {p1rev} {p2rev}\n'
169 file1 R M 2 1
169 file1 R M 2 1
170 file2 U M 2 1
170 file2 U M 2 1
171
171
172 resolve -m without paths should mark all resolved
172 resolve -m without paths should mark all resolved
173
173
174 $ hg resolve -m
174 $ hg resolve -m
175 (no more unresolved files)
175 (no more unresolved files)
176 $ hg commit -m 'resolved'
176 $ hg commit -m 'resolved'
177
177
178 resolve -l should be empty after commit
178 resolve -l should be empty after commit
179
179
180 $ hg resolve -l
180 $ hg resolve -l
181
181
182 $ hg resolve -l -Tjson
182 $ hg resolve -l -Tjson
183 [
183 [
184 ]
184 ]
185
185
186 resolve --all should abort when no merge in progress
186 resolve --all should abort when no merge in progress
187
187
188 $ hg resolve --all
188 $ hg resolve --all
189 abort: resolve command not applicable when not merging
189 abort: resolve command not applicable when not merging
190 [255]
190 [255]
191
191
192 resolve -m should abort when no merge in progress
192 resolve -m should abort when no merge in progress
193
193
194 $ hg resolve -m
194 $ hg resolve -m
195 abort: resolve command not applicable when not merging
195 abort: resolve command not applicable when not merging
196 [255]
196 [255]
197
197
198 can not update or merge when there are unresolved conflicts
198 can not update or merge when there are unresolved conflicts
199
199
200 $ hg up -qC 0
200 $ hg up -qC 0
201 $ echo quux >> file1
201 $ echo quux >> file1
202 $ hg up 1
202 $ hg up 1
203 merging file1
203 merging file1
204 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
204 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
205 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
205 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
206 use 'hg resolve' to retry unresolved file merges
206 use 'hg resolve' to retry unresolved file merges
207 [1]
207 [1]
208 $ hg up 0
208 $ hg up 0
209 abort: outstanding merge conflicts
209 abort: outstanding merge conflicts
210 [255]
210 [255]
211 $ hg merge 2
211 $ hg merge 2
212 abort: outstanding merge conflicts
212 abort: outstanding merge conflicts
213 [255]
213 [255]
214 $ hg merge --force 2
214 $ hg merge --force 2
215 abort: outstanding merge conflicts
215 abort: outstanding merge conflicts
216 [255]
216 [255]
217
217
218 set up conflict-free merge
218 set up conflict-free merge
219
219
220 $ hg up -qC 3
220 $ hg up -qC 3
221 $ hg merge 1
221 $ hg merge 1
222 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
222 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
223 (branch merge, don't forget to commit)
223 (branch merge, don't forget to commit)
224
224
225 resolve --all should do nothing in merge without conflicts
225 resolve --all should do nothing in merge without conflicts
226 $ hg resolve --all
226 $ hg resolve --all
227 (no more unresolved files)
227 (no more unresolved files)
228
228
229 resolve -m should do nothing in merge without conflicts
229 resolve -m should do nothing in merge without conflicts
230
230
231 $ hg resolve -m
231 $ hg resolve -m
232 (no more unresolved files)
232 (no more unresolved files)
233
233
234 get back to conflicting state
234 get back to conflicting state
235
235
236 $ hg up -qC 2
236 $ hg up -qC 2
237 $ hg merge --tool=internal:fail 1
237 $ hg merge --tool=internal:fail 1
238 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
238 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
239 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
239 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
240 [1]
240 [1]
241
241
242 resolve without arguments should suggest --all
242 resolve without arguments should suggest --all
243 $ hg resolve
243 $ hg resolve
244 abort: no files or directories specified
244 abort: no files or directories specified
245 (use --all to re-merge all unresolved files)
245 (use --all to re-merge all unresolved files)
246 [255]
246 [255]
247
247
248 resolve --all should re-merge all unresolved files
248 resolve --all should re-merge all unresolved files
249 $ hg resolve --all
249 $ hg resolve --all
250 merging file1
250 merging file1
251 merging file2
251 merging file2
252 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
252 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
253 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
253 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
254 [1]
254 [1]
255 $ cat file1.orig
255 $ cat file1.orig
256 foo
256 foo
257 baz
257 baz
258 $ cat file2.orig
258 $ cat file2.orig
259 foo
259 foo
260 baz
260 baz
261
261
262 .orig files should exists where specified
262 .orig files should exists where specified
263 $ hg resolve --all --verbose --config 'ui.origbackuppath=.hg/origbackups'
263 $ hg resolve --all --verbose --config 'ui.origbackuppath=.hg/origbackups'
264 merging file1
264 merging file1
265 creating directory: $TESTTMP/repo/.hg/origbackups
265 creating directory: $TESTTMP/repo/.hg/origbackups
266 merging file2
266 merging file2
267 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
267 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
268 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
268 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
269 [1]
269 [1]
270 $ ls .hg/origbackups
270 $ ls .hg/origbackups
271 file1
271 file1
272 file2
272 file2
273 $ grep '<<<' file1 > /dev/null
273 $ grep '<<<' file1 > /dev/null
274 $ grep '<<<' file2 > /dev/null
274 $ grep '<<<' file2 > /dev/null
275
275
276 resolve <file> should re-merge file
276 resolve <file> should re-merge file
277 $ echo resolved > file1
277 $ echo resolved > file1
278 $ hg resolve -q file1
278 $ hg resolve -q file1
279 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
279 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
280 [1]
280 [1]
281 $ grep '<<<' file1 > /dev/null
281 $ grep '<<<' file1 > /dev/null
282
282
283 test .orig behavior with resolve
283 test .orig behavior with resolve
284
284
285 $ hg resolve -q file1 --tool "sh -c 'f --dump \"$TESTTMP/repo/file1.orig\"'"
285 $ hg resolve -q file1 --tool "sh -c 'f --dump \"$TESTTMP/repo/file1.orig\"'"
286 $TESTTMP/repo/file1.orig:
286 $TESTTMP/repo/file1.orig:
287 >>>
287 >>>
288 foo
288 foo
289 baz
289 baz
290 <<<
290 <<<
291
291
292 resolve <file> should do nothing if 'file' was marked resolved
292 resolve <file> should do nothing if 'file' was marked resolved
293 $ echo resolved > file1
293 $ echo resolved > file1
294 $ hg resolve -m file1
294 $ hg resolve -m file1
295 $ hg resolve -q file1
295 $ hg resolve -q file1
296 $ cat file1
296 $ cat file1
297 resolved
297 resolved
298
298
299 insert unsupported advisory merge record
299 insert unsupported advisory merge record
300
300
301 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
301 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
302 $ hg debugmergestate
302 $ hg debugmergestate
303 * version 2 records
303 * version 2 records
304 local: 57653b9f834a4493f7240b0681efcb9ae7cab745
304 local: 57653b9f834a4493f7240b0681efcb9ae7cab745
305 other: dc77451844e37f03f5c559e3b8529b2b48d381d1
305 other: dc77451844e37f03f5c559e3b8529b2b48d381d1
306 labels:
306 labels:
307 local: working copy
307 local: working copy
308 other: merge rev
308 other: merge rev
309 unrecognized entry: x advisory record
309 unrecognized entry: x advisory record
310 file extras: file1 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
310 file extras: file1 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
311 file: file1 (record type "F", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
311 file: file1 (record type "F", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
312 local path: file1 (flags "")
312 local path: file1 (flags "")
313 ancestor path: file1 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
313 ancestor path: file1 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
314 other path: file1 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
314 other path: file1 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
315 file extras: file2 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
315 file extras: file2 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
316 file: file2 (record type "F", state "u", hash cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523)
316 file: file2 (record type "F", state "u", hash cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523)
317 local path: file2 (flags "")
317 local path: file2 (flags "")
318 ancestor path: file2 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
318 ancestor path: file2 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
319 other path: file2 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
319 other path: file2 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
320 $ hg resolve -l
320 $ hg resolve -l
321 R file1
321 R file1
322 U file2
322 U file2
323
323
324 insert unsupported mandatory merge record
324 insert unsupported mandatory merge record
325
325
326 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
326 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
327 $ hg debugmergestate
327 $ hg debugmergestate
328 * version 2 records
328 * version 2 records
329 local: 57653b9f834a4493f7240b0681efcb9ae7cab745
329 local: 57653b9f834a4493f7240b0681efcb9ae7cab745
330 other: dc77451844e37f03f5c559e3b8529b2b48d381d1
330 other: dc77451844e37f03f5c559e3b8529b2b48d381d1
331 labels:
331 labels:
332 local: working copy
332 local: working copy
333 other: merge rev
333 other: merge rev
334 file extras: file1 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
334 file extras: file1 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
335 file: file1 (record type "F", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
335 file: file1 (record type "F", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
336 local path: file1 (flags "")
336 local path: file1 (flags "")
337 ancestor path: file1 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
337 ancestor path: file1 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
338 other path: file1 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
338 other path: file1 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
339 file extras: file2 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
339 file extras: file2 (ancestorlinknode = 99726c03216e233810a2564cbc0adfe395007eac)
340 file: file2 (record type "F", state "u", hash cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523)
340 file: file2 (record type "F", state "u", hash cb99b709a1978bd205ab9dfd4c5aaa1fc91c7523)
341 local path: file2 (flags "")
341 local path: file2 (flags "")
342 ancestor path: file2 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
342 ancestor path: file2 (node 2ed2a3912a0b24502043eae84ee4b279c18b90dd)
343 other path: file2 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
343 other path: file2 (node 6f4310b00b9a147241b071a60c28a650827fb03d)
344 unrecognized entry: X mandatory record
344 unrecognized entry: X mandatory record
345 $ hg resolve -l
345 $ hg resolve -l
346 abort: unsupported merge state records: X
346 abort: unsupported merge state records: X
347 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
347 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
348 [255]
348 [255]
349 $ hg resolve -ma
349 $ hg resolve -ma
350 abort: unsupported merge state records: X
350 abort: unsupported merge state records: X
351 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
351 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
352 [255]
352 [255]
353 $ hg summary
353 $ hg summary
354 warning: merge state has unsupported record types: X
354 warning: merge state has unsupported record types: X
355 parent: 2:57653b9f834a
355 parent: 2:57653b9f834a
356 append baz to files
356 append baz to files
357 parent: 1:dc77451844e3
357 parent: 1:dc77451844e3
358 append bar to files
358 append bar to files
359 branch: default
359 branch: default
360 commit: 2 modified, 2 unknown (merge)
360 commit: 2 modified, 2 unknown (merge)
361 update: 2 new changesets (update)
361 update: 2 new changesets (update)
362 phases: 5 draft
362 phases: 5 draft
363
363
364 update --clean shouldn't abort on unsupported records
364 update --clean shouldn't abort on unsupported records
365
365
366 $ hg up -qC 1
366 $ hg up -qC 1
367 $ hg debugmergestate
367 $ hg debugmergestate
368 no merge state found
368 no merge state found
369
369
370 test crashed merge with empty mergestate
370 test crashed merge with empty mergestate
371
371
372 $ mkdir .hg/merge
372 $ mkdir .hg/merge
373 $ touch .hg/merge/state
373 $ touch .hg/merge/state
374
374
375 resolve -l should be empty
375 resolve -l should be empty
376
376
377 $ hg resolve -l
377 $ hg resolve -l
378
378
379 resolve -m can be configured to look for remaining conflict markers
379 resolve -m can be configured to look for remaining conflict markers
380 $ hg up -qC 2
380 $ hg up -qC 2
381 $ hg merge -q --tool=internal:merge 1
381 $ hg merge -q --tool=internal:merge 1
382 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
382 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
383 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
383 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
384 [1]
384 [1]
385 $ hg resolve -l
385 $ hg resolve -l
386 U file1
386 U file1
387 U file2
387 U file2
388 $ echo 'remove markers' > file1
388 $ echo 'remove markers' > file1
389 $ hg --config commands.resolve.mark-check=abort resolve -m
389 $ hg --config commands.resolve.mark-check=abort resolve -m
390 warning: the following files still have conflict markers:
390 warning: the following files still have conflict markers:
391 file2
391 file2
392 abort: conflict markers detected
392 abort: conflict markers detected
393 (use --all to mark anyway)
393 (use --all to mark anyway)
394 [255]
394 [255]
395 $ hg resolve -l
395 $ hg resolve -l
396 U file1
396 U file1
397 U file2
397 U file2
398 Try with --all from the hint
398 Try with --all from the hint
399 $ hg --config commands.resolve.mark-check=abort resolve -m --all
399 $ hg --config commands.resolve.mark-check=abort resolve -m --all
400 warning: the following files still have conflict markers:
400 warning: the following files still have conflict markers:
401 file2
401 file2
402 (no more unresolved files)
402 (no more unresolved files)
403 $ hg resolve -l
403 $ hg resolve -l
404 R file1
404 R file1
405 R file2
405 R file2
406 Test option value 'warn'
406 Test option value 'warn'
407 $ hg resolve --unmark
407 $ hg resolve --unmark
408 $ hg resolve -l
408 $ hg resolve -l
409 U file1
409 U file1
410 U file2
410 U file2
411 $ hg --config commands.resolve.mark-check=warn resolve -m
411 $ hg --config commands.resolve.mark-check=warn resolve -m
412 warning: the following files still have conflict markers:
412 warning: the following files still have conflict markers:
413 file2
413 file2
414 (no more unresolved files)
414 (no more unresolved files)
415 $ hg resolve -l
415 $ hg resolve -l
416 R file1
416 R file1
417 R file2
417 R file2
418 If the file is already marked as resolved, we don't warn about it
418 If the file is already marked as resolved, we don't warn about it
419 $ hg resolve --unmark file1
419 $ hg resolve --unmark file1
420 $ hg resolve -l
420 $ hg resolve -l
421 U file1
421 U file1
422 R file2
422 R file2
423 $ hg --config commands.resolve.mark-check=warn resolve -m
423 $ hg --config commands.resolve.mark-check=warn resolve -m
424 (no more unresolved files)
424 (no more unresolved files)
425 $ hg resolve -l
425 $ hg resolve -l
426 R file1
426 R file1
427 R file2
427 R file2
428 If the user passes an invalid value, we treat it as 'none'.
428 If the user passes an invalid value, we treat it as 'none'.
429 $ hg resolve --unmark
429 $ hg resolve --unmark
430 $ hg resolve -l
430 $ hg resolve -l
431 U file1
431 U file1
432 U file2
432 U file2
433 $ hg --config commands.resolve.mark-check=nope resolve -m
433 $ hg --config commands.resolve.mark-check=nope resolve -m
434 (no more unresolved files)
434 (no more unresolved files)
435 $ hg resolve -l
435 $ hg resolve -l
436 R file1
436 R file1
437 R file2
437 R file2
438 Test explicitly setting the otion to 'none'
438 Test explicitly setting the otion to 'none'
439 $ hg resolve --unmark
439 $ hg resolve --unmark
440 $ hg resolve -l
440 $ hg resolve -l
441 U file1
441 U file1
442 U file2
442 U file2
443 $ hg --config commands.resolve.mark-check=none resolve -m
443 $ hg --config commands.resolve.mark-check=none resolve -m
444 (no more unresolved files)
444 (no more unresolved files)
445 $ hg resolve -l
445 $ hg resolve -l
446 R file1
446 R file1
447 R file2
447 R file2
448 Test with marking an explicit file as resolved, this should not abort (since
449 there's no --force flag, we have no way of combining --all with a filename)
450 $ hg resolve --unmark
451 $ hg resolve -l
452 U file1
453 U file2
454 (This downgrades to a warning since an explicit file was specified).
455 $ hg --config commands.resolve.mark-check=abort resolve -m file2
456 warning: the following files still have conflict markers:
457 file2
458 $ hg resolve -l
459 U file1
460 R file2
448 Testing the --re-merge flag
461 Testing the --re-merge flag
449 $ hg resolve --unmark file1
462 $ hg resolve --unmark file1
450 $ hg resolve -l
463 $ hg resolve -l
451 U file1
464 U file1
452 R file2
465 R file2
453 $ hg resolve --mark --re-merge
466 $ hg resolve --mark --re-merge
454 abort: too many actions specified
467 abort: too many actions specified
455 [255]
468 [255]
456 $ hg resolve --re-merge --all
469 $ hg resolve --re-merge --all
457 merging file1
470 merging file1
458 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
471 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
459 [1]
472 [1]
460 Explicit re-merge
473 Explicit re-merge
461 $ hg resolve --unmark file1
474 $ hg resolve --unmark file1
462 $ hg resolve --config commands.resolve.explicit-re-merge=1 --all
475 $ hg resolve --config commands.resolve.explicit-re-merge=1 --all
463 abort: no action specified
476 abort: no action specified
464 (use --mark, --unmark, --list or --re-merge)
477 (use --mark, --unmark, --list or --re-merge)
465 [255]
478 [255]
466 $ hg resolve --config commands.resolve.explicit-re-merge=1 --re-merge --all
479 $ hg resolve --config commands.resolve.explicit-re-merge=1 --re-merge --all
467 merging file1
480 merging file1
468 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
481 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
469 [1]
482 [1]
470
483
471 $ cd ..
484 $ cd ..
472
485
473 ======================================================
486 ======================================================
474 Test 'hg resolve' confirm config option functionality |
487 Test 'hg resolve' confirm config option functionality |
475 ======================================================
488 ======================================================
476 $ cat >> $HGRCPATH << EOF
489 $ cat >> $HGRCPATH << EOF
477 > [extensions]
490 > [extensions]
478 > rebase=
491 > rebase=
479 > EOF
492 > EOF
480
493
481 $ hg init repo2
494 $ hg init repo2
482 $ cd repo2
495 $ cd repo2
483
496
484 $ echo boss > boss
497 $ echo boss > boss
485 $ hg ci -Am "add boss"
498 $ hg ci -Am "add boss"
486 adding boss
499 adding boss
487
500
488 $ for emp in emp1 emp2 emp3; do echo work > $emp; done;
501 $ for emp in emp1 emp2 emp3; do echo work > $emp; done;
489 $ hg ci -Aqm "added emp1 emp2 emp3"
502 $ hg ci -Aqm "added emp1 emp2 emp3"
490
503
491 $ hg up 0
504 $ hg up 0
492 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
505 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
493
506
494 $ for emp in emp1 emp2 emp3; do echo nowork > $emp; done;
507 $ for emp in emp1 emp2 emp3; do echo nowork > $emp; done;
495 $ hg ci -Aqm "added lazy emp1 emp2 emp3"
508 $ hg ci -Aqm "added lazy emp1 emp2 emp3"
496
509
497 $ hg log -GT "{rev} {node|short} {firstline(desc)}\n"
510 $ hg log -GT "{rev} {node|short} {firstline(desc)}\n"
498 @ 2 0acfd4a49af0 added lazy emp1 emp2 emp3
511 @ 2 0acfd4a49af0 added lazy emp1 emp2 emp3
499 |
512 |
500 | o 1 f30f98a8181f added emp1 emp2 emp3
513 | o 1 f30f98a8181f added emp1 emp2 emp3
501 |/
514 |/
502 o 0 88660038d466 add boss
515 o 0 88660038d466 add boss
503
516
504 $ hg rebase -s 1 -d 2
517 $ hg rebase -s 1 -d 2
505 rebasing 1:f30f98a8181f "added emp1 emp2 emp3"
518 rebasing 1:f30f98a8181f "added emp1 emp2 emp3"
506 merging emp1
519 merging emp1
507 merging emp2
520 merging emp2
508 merging emp3
521 merging emp3
509 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
522 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
510 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
523 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
511 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
524 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
512 unresolved conflicts (see hg resolve, then hg rebase --continue)
525 unresolved conflicts (see hg resolve, then hg rebase --continue)
513 [1]
526 [1]
514
527
515 Test when commands.resolve.confirm config option is not set:
528 Test when commands.resolve.confirm config option is not set:
516 ===========================================================
529 ===========================================================
517 $ hg resolve --all
530 $ hg resolve --all
518 merging emp1
531 merging emp1
519 merging emp2
532 merging emp2
520 merging emp3
533 merging emp3
521 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
534 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
522 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
535 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
523 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
536 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
524 [1]
537 [1]
525
538
526 Test when config option is set:
539 Test when config option is set:
527 ==============================
540 ==============================
528 $ cat >> $HGRCPATH << EOF
541 $ cat >> $HGRCPATH << EOF
529 > [ui]
542 > [ui]
530 > interactive = True
543 > interactive = True
531 > [commands]
544 > [commands]
532 > resolve.confirm = True
545 > resolve.confirm = True
533 > EOF
546 > EOF
534
547
535 $ hg resolve
548 $ hg resolve
536 abort: no files or directories specified
549 abort: no files or directories specified
537 (use --all to re-merge all unresolved files)
550 (use --all to re-merge all unresolved files)
538 [255]
551 [255]
539 $ hg resolve --all << EOF
552 $ hg resolve --all << EOF
540 > n
553 > n
541 > EOF
554 > EOF
542 re-merge all unresolved files (yn)? n
555 re-merge all unresolved files (yn)? n
543 abort: user quit
556 abort: user quit
544 [255]
557 [255]
545
558
546 $ hg resolve --all << EOF
559 $ hg resolve --all << EOF
547 > y
560 > y
548 > EOF
561 > EOF
549 re-merge all unresolved files (yn)? y
562 re-merge all unresolved files (yn)? y
550 merging emp1
563 merging emp1
551 merging emp2
564 merging emp2
552 merging emp3
565 merging emp3
553 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
566 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
554 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
567 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
555 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
568 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
556 [1]
569 [1]
557
570
558 Test that commands.resolve.confirm respect --mark option (only when no patterns args are given):
571 Test that commands.resolve.confirm respect --mark option (only when no patterns args are given):
559 ===============================================================================================
572 ===============================================================================================
560
573
561 $ hg resolve -m emp1
574 $ hg resolve -m emp1
562 $ hg resolve -l
575 $ hg resolve -l
563 R emp1
576 R emp1
564 U emp2
577 U emp2
565 U emp3
578 U emp3
566
579
567 $ hg resolve -m << EOF
580 $ hg resolve -m << EOF
568 > n
581 > n
569 > EOF
582 > EOF
570 mark all unresolved files as resolved (yn)? n
583 mark all unresolved files as resolved (yn)? n
571 abort: user quit
584 abort: user quit
572 [255]
585 [255]
573
586
574 $ hg resolve -m << EOF
587 $ hg resolve -m << EOF
575 > y
588 > y
576 > EOF
589 > EOF
577 mark all unresolved files as resolved (yn)? y
590 mark all unresolved files as resolved (yn)? y
578 (no more unresolved files)
591 (no more unresolved files)
579 continue: hg rebase --continue
592 continue: hg rebase --continue
580 $ hg resolve -l
593 $ hg resolve -l
581 R emp1
594 R emp1
582 R emp2
595 R emp2
583 R emp3
596 R emp3
584
597
585 Test that commands.resolve.confirm respect --unmark option (only when no patterns args are given):
598 Test that commands.resolve.confirm respect --unmark option (only when no patterns args are given):
586 ===============================================================================================
599 ===============================================================================================
587
600
588 $ hg resolve -u emp1
601 $ hg resolve -u emp1
589
602
590 $ hg resolve -l
603 $ hg resolve -l
591 U emp1
604 U emp1
592 R emp2
605 R emp2
593 R emp3
606 R emp3
594
607
595 $ hg resolve -u << EOF
608 $ hg resolve -u << EOF
596 > n
609 > n
597 > EOF
610 > EOF
598 mark all resolved files as unresolved (yn)? n
611 mark all resolved files as unresolved (yn)? n
599 abort: user quit
612 abort: user quit
600 [255]
613 [255]
601
614
602 $ hg resolve -m << EOF
615 $ hg resolve -m << EOF
603 > y
616 > y
604 > EOF
617 > EOF
605 mark all unresolved files as resolved (yn)? y
618 mark all unresolved files as resolved (yn)? y
606 (no more unresolved files)
619 (no more unresolved files)
607 continue: hg rebase --continue
620 continue: hg rebase --continue
608
621
609 $ hg resolve -l
622 $ hg resolve -l
610 R emp1
623 R emp1
611 R emp2
624 R emp2
612 R emp3
625 R emp3
613
626
614 $ hg rebase --abort
627 $ hg rebase --abort
615 rebase aborted
628 rebase aborted
616 $ cd ..
629 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now