##// END OF EJS Templates
resolve: rename {status} to {mergestatus} to not shadow change status (BC)...
Yuya Nishihara -
r39964:f07ab9dd default
parent child Browse files
Show More
@@ -1,5914 +1,5914 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 match as matchmod,
47 match as matchmod,
48 merge as mergemod,
48 merge as mergemod,
49 narrowspec,
49 narrowspec,
50 obsolete,
50 obsolete,
51 obsutil,
51 obsutil,
52 patch,
52 patch,
53 phases,
53 phases,
54 pycompat,
54 pycompat,
55 rcutil,
55 rcutil,
56 registrar,
56 registrar,
57 repair,
57 repair,
58 revsetlang,
58 revsetlang,
59 rewriteutil,
59 rewriteutil,
60 scmutil,
60 scmutil,
61 server,
61 server,
62 state as statemod,
62 state as statemod,
63 streamclone,
63 streamclone,
64 tags as tagsmod,
64 tags as tagsmod,
65 templatekw,
65 templatekw,
66 ui as uimod,
66 ui as uimod,
67 util,
67 util,
68 wireprotoserver,
68 wireprotoserver,
69 )
69 )
70 from .utils import (
70 from .utils import (
71 dateutil,
71 dateutil,
72 stringutil,
72 stringutil,
73 )
73 )
74
74
75 table = {}
75 table = {}
76 table.update(debugcommandsmod.command._table)
76 table.update(debugcommandsmod.command._table)
77
77
78 command = registrar.command(table)
78 command = registrar.command(table)
79 INTENT_READONLY = registrar.INTENT_READONLY
79 INTENT_READONLY = registrar.INTENT_READONLY
80
80
81 # common command options
81 # common command options
82
82
83 globalopts = [
83 globalopts = [
84 ('R', 'repository', '',
84 ('R', 'repository', '',
85 _('repository root directory or name of overlay bundle file'),
85 _('repository root directory or name of overlay bundle file'),
86 _('REPO')),
86 _('REPO')),
87 ('', 'cwd', '',
87 ('', 'cwd', '',
88 _('change working directory'), _('DIR')),
88 _('change working directory'), _('DIR')),
89 ('y', 'noninteractive', None,
89 ('y', 'noninteractive', None,
90 _('do not prompt, automatically pick the first choice for all prompts')),
90 _('do not prompt, automatically pick the first choice for all prompts')),
91 ('q', 'quiet', None, _('suppress output')),
91 ('q', 'quiet', None, _('suppress output')),
92 ('v', 'verbose', None, _('enable additional output')),
92 ('v', 'verbose', None, _('enable additional output')),
93 ('', 'color', '',
93 ('', 'color', '',
94 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
94 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
95 # and should not be translated
95 # and should not be translated
96 _("when to colorize (boolean, always, auto, never, or debug)"),
96 _("when to colorize (boolean, always, auto, never, or debug)"),
97 _('TYPE')),
97 _('TYPE')),
98 ('', 'config', [],
98 ('', 'config', [],
99 _('set/override config option (use \'section.name=value\')'),
99 _('set/override config option (use \'section.name=value\')'),
100 _('CONFIG')),
100 _('CONFIG')),
101 ('', 'debug', None, _('enable debugging output')),
101 ('', 'debug', None, _('enable debugging output')),
102 ('', 'debugger', None, _('start debugger')),
102 ('', 'debugger', None, _('start debugger')),
103 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
103 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
104 _('ENCODE')),
104 _('ENCODE')),
105 ('', 'encodingmode', encoding.encodingmode,
105 ('', 'encodingmode', encoding.encodingmode,
106 _('set the charset encoding mode'), _('MODE')),
106 _('set the charset encoding mode'), _('MODE')),
107 ('', 'traceback', None, _('always print a traceback on exception')),
107 ('', 'traceback', None, _('always print a traceback on exception')),
108 ('', 'time', None, _('time how long the command takes')),
108 ('', 'time', None, _('time how long the command takes')),
109 ('', 'profile', None, _('print command execution profile')),
109 ('', 'profile', None, _('print command execution profile')),
110 ('', 'version', None, _('output version information and exit')),
110 ('', 'version', None, _('output version information and exit')),
111 ('h', 'help', None, _('display help and exit')),
111 ('h', 'help', None, _('display help and exit')),
112 ('', 'hidden', False, _('consider hidden changesets')),
112 ('', 'hidden', False, _('consider hidden changesets')),
113 ('', 'pager', 'auto',
113 ('', 'pager', 'auto',
114 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
114 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
115 ]
115 ]
116
116
117 dryrunopts = cmdutil.dryrunopts
117 dryrunopts = cmdutil.dryrunopts
118 remoteopts = cmdutil.remoteopts
118 remoteopts = cmdutil.remoteopts
119 walkopts = cmdutil.walkopts
119 walkopts = cmdutil.walkopts
120 commitopts = cmdutil.commitopts
120 commitopts = cmdutil.commitopts
121 commitopts2 = cmdutil.commitopts2
121 commitopts2 = cmdutil.commitopts2
122 formatteropts = cmdutil.formatteropts
122 formatteropts = cmdutil.formatteropts
123 templateopts = cmdutil.templateopts
123 templateopts = cmdutil.templateopts
124 logopts = cmdutil.logopts
124 logopts = cmdutil.logopts
125 diffopts = cmdutil.diffopts
125 diffopts = cmdutil.diffopts
126 diffwsopts = cmdutil.diffwsopts
126 diffwsopts = cmdutil.diffwsopts
127 diffopts2 = cmdutil.diffopts2
127 diffopts2 = cmdutil.diffopts2
128 mergetoolopts = cmdutil.mergetoolopts
128 mergetoolopts = cmdutil.mergetoolopts
129 similarityopts = cmdutil.similarityopts
129 similarityopts = cmdutil.similarityopts
130 subrepoopts = cmdutil.subrepoopts
130 subrepoopts = cmdutil.subrepoopts
131 debugrevlogopts = cmdutil.debugrevlogopts
131 debugrevlogopts = cmdutil.debugrevlogopts
132
132
133 # Commands start here, listed alphabetically
133 # Commands start here, listed alphabetically
134
134
135 @command('^add',
135 @command('^add',
136 walkopts + subrepoopts + dryrunopts,
136 walkopts + subrepoopts + dryrunopts,
137 _('[OPTION]... [FILE]...'),
137 _('[OPTION]... [FILE]...'),
138 inferrepo=True)
138 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 inferrepo=True)
189 inferrepo=True)
190 def addremove(ui, repo, *pats, **opts):
190 def addremove(ui, repo, *pats, **opts):
191 """add all new files, delete all missing files
191 """add all new files, delete all missing files
192
192
193 Add all new files and remove all missing files from the
193 Add all new files and remove all missing files from the
194 repository.
194 repository.
195
195
196 Unless names are given, new files are ignored if they match any of
196 Unless names are given, new files are ignored if they match any of
197 the patterns in ``.hgignore``. As with add, these changes take
197 the patterns in ``.hgignore``. As with add, these changes take
198 effect at the next commit.
198 effect at the next commit.
199
199
200 Use the -s/--similarity option to detect renamed files. This
200 Use the -s/--similarity option to detect renamed files. This
201 option takes a percentage between 0 (disabled) and 100 (files must
201 option takes a percentage between 0 (disabled) and 100 (files must
202 be identical) as its parameter. With a parameter greater than 0,
202 be identical) as its parameter. With a parameter greater than 0,
203 this compares every removed file with every added file and records
203 this compares every removed file with every added file and records
204 those similar enough as renames. Detecting renamed files this way
204 those similar enough as renames. Detecting renamed files this way
205 can be expensive. After using this option, :hg:`status -C` can be
205 can be expensive. After using this option, :hg:`status -C` can be
206 used to check which files were identified as moved or renamed. If
206 used to check which files were identified as moved or renamed. If
207 not specified, -s/--similarity defaults to 100 and only renames of
207 not specified, -s/--similarity defaults to 100 and only renames of
208 identical files are detected.
208 identical files are detected.
209
209
210 .. container:: verbose
210 .. container:: verbose
211
211
212 Examples:
212 Examples:
213
213
214 - A number of files (bar.c and foo.c) are new,
214 - A number of files (bar.c and foo.c) are new,
215 while foobar.c has been removed (without using :hg:`remove`)
215 while foobar.c has been removed (without using :hg:`remove`)
216 from the repository::
216 from the repository::
217
217
218 $ ls
218 $ ls
219 bar.c foo.c
219 bar.c foo.c
220 $ hg status
220 $ hg status
221 ! foobar.c
221 ! foobar.c
222 ? bar.c
222 ? bar.c
223 ? foo.c
223 ? foo.c
224 $ hg addremove
224 $ hg addremove
225 adding bar.c
225 adding bar.c
226 adding foo.c
226 adding foo.c
227 removing foobar.c
227 removing foobar.c
228 $ hg status
228 $ hg status
229 A bar.c
229 A bar.c
230 A foo.c
230 A foo.c
231 R foobar.c
231 R foobar.c
232
232
233 - A file foobar.c was moved to foo.c without using :hg:`rename`.
233 - A file foobar.c was moved to foo.c without using :hg:`rename`.
234 Afterwards, it was edited slightly::
234 Afterwards, it was edited slightly::
235
235
236 $ ls
236 $ ls
237 foo.c
237 foo.c
238 $ hg status
238 $ hg status
239 ! foobar.c
239 ! foobar.c
240 ? foo.c
240 ? foo.c
241 $ hg addremove --similarity 90
241 $ hg addremove --similarity 90
242 removing foobar.c
242 removing foobar.c
243 adding foo.c
243 adding foo.c
244 recording removal of foobar.c as rename to foo.c (94% similar)
244 recording removal of foobar.c as rename to foo.c (94% similar)
245 $ hg status -C
245 $ hg status -C
246 A foo.c
246 A foo.c
247 foobar.c
247 foobar.c
248 R foobar.c
248 R foobar.c
249
249
250 Returns 0 if all files are successfully added.
250 Returns 0 if all files are successfully added.
251 """
251 """
252 opts = pycompat.byteskwargs(opts)
252 opts = pycompat.byteskwargs(opts)
253 if not opts.get('similarity'):
253 if not opts.get('similarity'):
254 opts['similarity'] = '100'
254 opts['similarity'] = '100'
255 matcher = scmutil.match(repo[None], pats, opts)
255 matcher = scmutil.match(repo[None], pats, opts)
256 return scmutil.addremove(repo, matcher, "", opts)
256 return scmutil.addremove(repo, matcher, "", opts)
257
257
258 @command('^annotate|blame',
258 @command('^annotate|blame',
259 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
259 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
260 ('', 'follow', None,
260 ('', 'follow', None,
261 _('follow copies/renames and list the filename (DEPRECATED)')),
261 _('follow copies/renames and list the filename (DEPRECATED)')),
262 ('', 'no-follow', None, _("don't follow copies and renames")),
262 ('', 'no-follow', None, _("don't follow copies and renames")),
263 ('a', 'text', None, _('treat all files as text')),
263 ('a', 'text', None, _('treat all files as text')),
264 ('u', 'user', None, _('list the author (long with -v)')),
264 ('u', 'user', None, _('list the author (long with -v)')),
265 ('f', 'file', None, _('list the filename')),
265 ('f', 'file', None, _('list the filename')),
266 ('d', 'date', None, _('list the date (short with -q)')),
266 ('d', 'date', None, _('list the date (short with -q)')),
267 ('n', 'number', None, _('list the revision number (default)')),
267 ('n', 'number', None, _('list the revision number (default)')),
268 ('c', 'changeset', None, _('list the changeset')),
268 ('c', 'changeset', None, _('list the changeset')),
269 ('l', 'line-number', None, _('show line number at the first appearance')),
269 ('l', 'line-number', None, _('show line number at the first appearance')),
270 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
270 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
271 ] + diffwsopts + walkopts + formatteropts,
271 ] + diffwsopts + walkopts + formatteropts,
272 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
272 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
273 inferrepo=True)
273 inferrepo=True)
274 def annotate(ui, repo, *pats, **opts):
274 def annotate(ui, repo, *pats, **opts):
275 """show changeset information by line for each file
275 """show changeset information by line for each file
276
276
277 List changes in files, showing the revision id responsible for
277 List changes in files, showing the revision id responsible for
278 each line.
278 each line.
279
279
280 This command is useful for discovering when a change was made and
280 This command is useful for discovering when a change was made and
281 by whom.
281 by whom.
282
282
283 If you include --file, --user, or --date, the revision number is
283 If you include --file, --user, or --date, the revision number is
284 suppressed unless you also include --number.
284 suppressed unless you also include --number.
285
285
286 Without the -a/--text option, annotate will avoid processing files
286 Without the -a/--text option, annotate will avoid processing files
287 it detects as binary. With -a, annotate will annotate the file
287 it detects as binary. With -a, annotate will annotate the file
288 anyway, although the results will probably be neither useful
288 anyway, although the results will probably be neither useful
289 nor desirable.
289 nor desirable.
290
290
291 Returns 0 on success.
291 Returns 0 on success.
292 """
292 """
293 opts = pycompat.byteskwargs(opts)
293 opts = pycompat.byteskwargs(opts)
294 if not pats:
294 if not pats:
295 raise error.Abort(_('at least one filename or pattern is required'))
295 raise error.Abort(_('at least one filename or pattern is required'))
296
296
297 if opts.get('follow'):
297 if opts.get('follow'):
298 # --follow is deprecated and now just an alias for -f/--file
298 # --follow is deprecated and now just an alias for -f/--file
299 # to mimic the behavior of Mercurial before version 1.5
299 # to mimic the behavior of Mercurial before version 1.5
300 opts['file'] = True
300 opts['file'] = True
301
301
302 rev = opts.get('rev')
302 rev = opts.get('rev')
303 if rev:
303 if rev:
304 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
304 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
305 ctx = scmutil.revsingle(repo, rev)
305 ctx = scmutil.revsingle(repo, rev)
306
306
307 rootfm = ui.formatter('annotate', opts)
307 rootfm = ui.formatter('annotate', opts)
308 if ui.debugflag:
308 if ui.debugflag:
309 shorthex = pycompat.identity
309 shorthex = pycompat.identity
310 else:
310 else:
311 def shorthex(h):
311 def shorthex(h):
312 return h[:12]
312 return h[:12]
313 if ui.quiet:
313 if ui.quiet:
314 datefunc = dateutil.shortdate
314 datefunc = dateutil.shortdate
315 else:
315 else:
316 datefunc = dateutil.datestr
316 datefunc = dateutil.datestr
317 if ctx.rev() is None:
317 if ctx.rev() is None:
318 if opts.get('changeset'):
318 if opts.get('changeset'):
319 # omit "+" suffix which is appended to node hex
319 # omit "+" suffix which is appended to node hex
320 def formatrev(rev):
320 def formatrev(rev):
321 if rev == wdirrev:
321 if rev == wdirrev:
322 return '%d' % ctx.p1().rev()
322 return '%d' % ctx.p1().rev()
323 else:
323 else:
324 return '%d' % rev
324 return '%d' % rev
325 else:
325 else:
326 def formatrev(rev):
326 def formatrev(rev):
327 if rev == wdirrev:
327 if rev == wdirrev:
328 return '%d+' % ctx.p1().rev()
328 return '%d+' % ctx.p1().rev()
329 else:
329 else:
330 return '%d ' % rev
330 return '%d ' % rev
331 def formathex(h):
331 def formathex(h):
332 if h == wdirhex:
332 if h == wdirhex:
333 return '%s+' % shorthex(hex(ctx.p1().node()))
333 return '%s+' % shorthex(hex(ctx.p1().node()))
334 else:
334 else:
335 return '%s ' % shorthex(h)
335 return '%s ' % shorthex(h)
336 else:
336 else:
337 formatrev = b'%d'.__mod__
337 formatrev = b'%d'.__mod__
338 formathex = shorthex
338 formathex = shorthex
339
339
340 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
340 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
341 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
341 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
342 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
342 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
343 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
343 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
344 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
344 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
345 ('line_number', ':', lambda x: x.lineno, pycompat.bytestr),
345 ('line_number', ':', lambda x: x.lineno, pycompat.bytestr),
346 ]
346 ]
347 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file'}
347 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file'}
348
348
349 if (not opts.get('user') and not opts.get('changeset')
349 if (not opts.get('user') and not opts.get('changeset')
350 and not opts.get('date') and not opts.get('file')):
350 and not opts.get('date') and not opts.get('file')):
351 opts['number'] = True
351 opts['number'] = True
352
352
353 linenumber = opts.get('line_number') is not None
353 linenumber = opts.get('line_number') is not None
354 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
354 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
355 raise error.Abort(_('at least one of -n/-c is required for -l'))
355 raise error.Abort(_('at least one of -n/-c is required for -l'))
356
356
357 ui.pager('annotate')
357 ui.pager('annotate')
358
358
359 if rootfm.isplain():
359 if rootfm.isplain():
360 def makefunc(get, fmt):
360 def makefunc(get, fmt):
361 return lambda x: fmt(get(x))
361 return lambda x: fmt(get(x))
362 else:
362 else:
363 def makefunc(get, fmt):
363 def makefunc(get, fmt):
364 return get
364 return get
365 datahint = rootfm.datahint()
365 datahint = rootfm.datahint()
366 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
366 funcmap = [(makefunc(get, fmt), sep) for fn, sep, get, fmt in opmap
367 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
367 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
368 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
368 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
369 fields = ' '.join(fn for fn, sep, get, fmt in opmap
369 fields = ' '.join(fn for fn, sep, get, fmt in opmap
370 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
370 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
371
371
372 def bad(x, y):
372 def bad(x, y):
373 raise error.Abort("%s: %s" % (x, y))
373 raise error.Abort("%s: %s" % (x, y))
374
374
375 m = scmutil.match(ctx, pats, opts, badfn=bad)
375 m = scmutil.match(ctx, pats, opts, badfn=bad)
376
376
377 follow = not opts.get('no_follow')
377 follow = not opts.get('no_follow')
378 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
378 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
379 whitespace=True)
379 whitespace=True)
380 skiprevs = opts.get('skip')
380 skiprevs = opts.get('skip')
381 if skiprevs:
381 if skiprevs:
382 skiprevs = scmutil.revrange(repo, skiprevs)
382 skiprevs = scmutil.revrange(repo, skiprevs)
383
383
384 for abs in ctx.walk(m):
384 for abs in ctx.walk(m):
385 fctx = ctx[abs]
385 fctx = ctx[abs]
386 rootfm.startitem()
386 rootfm.startitem()
387 rootfm.data(path=abs)
387 rootfm.data(path=abs)
388 if not opts.get('text') and fctx.isbinary():
388 if not opts.get('text') and fctx.isbinary():
389 rootfm.plain(_("%s: binary file\n")
389 rootfm.plain(_("%s: binary file\n")
390 % ((pats and m.rel(abs)) or abs))
390 % ((pats and m.rel(abs)) or abs))
391 continue
391 continue
392
392
393 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
393 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
394 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
394 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
395 diffopts=diffopts)
395 diffopts=diffopts)
396 if not lines:
396 if not lines:
397 fm.end()
397 fm.end()
398 continue
398 continue
399 formats = []
399 formats = []
400 pieces = []
400 pieces = []
401
401
402 for f, sep in funcmap:
402 for f, sep in funcmap:
403 l = [f(n) for n in lines]
403 l = [f(n) for n in lines]
404 if fm.isplain():
404 if fm.isplain():
405 sizes = [encoding.colwidth(x) for x in l]
405 sizes = [encoding.colwidth(x) for x in l]
406 ml = max(sizes)
406 ml = max(sizes)
407 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
407 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
408 else:
408 else:
409 formats.append(['%s' for x in l])
409 formats.append(['%s' for x in l])
410 pieces.append(l)
410 pieces.append(l)
411
411
412 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
412 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
413 fm.startitem()
413 fm.startitem()
414 fm.context(fctx=n.fctx)
414 fm.context(fctx=n.fctx)
415 fm.write(fields, "".join(f), *p)
415 fm.write(fields, "".join(f), *p)
416 if n.skip:
416 if n.skip:
417 fmt = "* %s"
417 fmt = "* %s"
418 else:
418 else:
419 fmt = ": %s"
419 fmt = ": %s"
420 fm.write('line', fmt, n.text)
420 fm.write('line', fmt, n.text)
421
421
422 if not lines[-1].text.endswith('\n'):
422 if not lines[-1].text.endswith('\n'):
423 fm.plain('\n')
423 fm.plain('\n')
424 fm.end()
424 fm.end()
425
425
426 rootfm.end()
426 rootfm.end()
427
427
428 @command('archive',
428 @command('archive',
429 [('', 'no-decode', None, _('do not pass files through decoders')),
429 [('', 'no-decode', None, _('do not pass files through decoders')),
430 ('p', 'prefix', '', _('directory prefix for files in archive'),
430 ('p', 'prefix', '', _('directory prefix for files in archive'),
431 _('PREFIX')),
431 _('PREFIX')),
432 ('r', 'rev', '', _('revision to distribute'), _('REV')),
432 ('r', 'rev', '', _('revision to distribute'), _('REV')),
433 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
433 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
434 ] + subrepoopts + walkopts,
434 ] + subrepoopts + walkopts,
435 _('[OPTION]... DEST'))
435 _('[OPTION]... DEST'))
436 def archive(ui, repo, dest, **opts):
436 def archive(ui, repo, dest, **opts):
437 '''create an unversioned archive of a repository revision
437 '''create an unversioned archive of a repository revision
438
438
439 By default, the revision used is the parent of the working
439 By default, the revision used is the parent of the working
440 directory; use -r/--rev to specify a different revision.
440 directory; use -r/--rev to specify a different revision.
441
441
442 The archive type is automatically detected based on file
442 The archive type is automatically detected based on file
443 extension (to override, use -t/--type).
443 extension (to override, use -t/--type).
444
444
445 .. container:: verbose
445 .. container:: verbose
446
446
447 Examples:
447 Examples:
448
448
449 - create a zip file containing the 1.0 release::
449 - create a zip file containing the 1.0 release::
450
450
451 hg archive -r 1.0 project-1.0.zip
451 hg archive -r 1.0 project-1.0.zip
452
452
453 - create a tarball excluding .hg files::
453 - create a tarball excluding .hg files::
454
454
455 hg archive project.tar.gz -X ".hg*"
455 hg archive project.tar.gz -X ".hg*"
456
456
457 Valid types are:
457 Valid types are:
458
458
459 :``files``: a directory full of files (default)
459 :``files``: a directory full of files (default)
460 :``tar``: tar archive, uncompressed
460 :``tar``: tar archive, uncompressed
461 :``tbz2``: tar archive, compressed using bzip2
461 :``tbz2``: tar archive, compressed using bzip2
462 :``tgz``: tar archive, compressed using gzip
462 :``tgz``: tar archive, compressed using gzip
463 :``uzip``: zip archive, uncompressed
463 :``uzip``: zip archive, uncompressed
464 :``zip``: zip archive, compressed using deflate
464 :``zip``: zip archive, compressed using deflate
465
465
466 The exact name of the destination archive or directory is given
466 The exact name of the destination archive or directory is given
467 using a format string; see :hg:`help export` for details.
467 using a format string; see :hg:`help export` for details.
468
468
469 Each member added to an archive file has a directory prefix
469 Each member added to an archive file has a directory prefix
470 prepended. Use -p/--prefix to specify a format string for the
470 prepended. Use -p/--prefix to specify a format string for the
471 prefix. The default is the basename of the archive, with suffixes
471 prefix. The default is the basename of the archive, with suffixes
472 removed.
472 removed.
473
473
474 Returns 0 on success.
474 Returns 0 on success.
475 '''
475 '''
476
476
477 opts = pycompat.byteskwargs(opts)
477 opts = pycompat.byteskwargs(opts)
478 rev = opts.get('rev')
478 rev = opts.get('rev')
479 if rev:
479 if rev:
480 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
480 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
481 ctx = scmutil.revsingle(repo, rev)
481 ctx = scmutil.revsingle(repo, rev)
482 if not ctx:
482 if not ctx:
483 raise error.Abort(_('no working directory: please specify a revision'))
483 raise error.Abort(_('no working directory: please specify a revision'))
484 node = ctx.node()
484 node = ctx.node()
485 dest = cmdutil.makefilename(ctx, dest)
485 dest = cmdutil.makefilename(ctx, dest)
486 if os.path.realpath(dest) == repo.root:
486 if os.path.realpath(dest) == repo.root:
487 raise error.Abort(_('repository root cannot be destination'))
487 raise error.Abort(_('repository root cannot be destination'))
488
488
489 kind = opts.get('type') or archival.guesskind(dest) or 'files'
489 kind = opts.get('type') or archival.guesskind(dest) or 'files'
490 prefix = opts.get('prefix')
490 prefix = opts.get('prefix')
491
491
492 if dest == '-':
492 if dest == '-':
493 if kind == 'files':
493 if kind == 'files':
494 raise error.Abort(_('cannot archive plain files to stdout'))
494 raise error.Abort(_('cannot archive plain files to stdout'))
495 dest = cmdutil.makefileobj(ctx, dest)
495 dest = cmdutil.makefileobj(ctx, dest)
496 if not prefix:
496 if not prefix:
497 prefix = os.path.basename(repo.root) + '-%h'
497 prefix = os.path.basename(repo.root) + '-%h'
498
498
499 prefix = cmdutil.makefilename(ctx, prefix)
499 prefix = cmdutil.makefilename(ctx, prefix)
500 match = scmutil.match(ctx, [], opts)
500 match = scmutil.match(ctx, [], opts)
501 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
501 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
502 match, prefix, subrepos=opts.get('subrepos'))
502 match, prefix, subrepos=opts.get('subrepos'))
503
503
504 @command('backout',
504 @command('backout',
505 [('', 'merge', None, _('merge with old dirstate parent after backout')),
505 [('', 'merge', None, _('merge with old dirstate parent after backout')),
506 ('', 'commit', None,
506 ('', 'commit', None,
507 _('commit if no conflicts were encountered (DEPRECATED)')),
507 _('commit if no conflicts were encountered (DEPRECATED)')),
508 ('', 'no-commit', None, _('do not commit')),
508 ('', 'no-commit', None, _('do not commit')),
509 ('', 'parent', '',
509 ('', 'parent', '',
510 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
510 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
511 ('r', 'rev', '', _('revision to backout'), _('REV')),
511 ('r', 'rev', '', _('revision to backout'), _('REV')),
512 ('e', 'edit', False, _('invoke editor on commit messages')),
512 ('e', 'edit', False, _('invoke editor on commit messages')),
513 ] + mergetoolopts + walkopts + commitopts + commitopts2,
513 ] + mergetoolopts + walkopts + commitopts + commitopts2,
514 _('[OPTION]... [-r] REV'))
514 _('[OPTION]... [-r] REV'))
515 def backout(ui, repo, node=None, rev=None, **opts):
515 def backout(ui, repo, node=None, rev=None, **opts):
516 '''reverse effect of earlier changeset
516 '''reverse effect of earlier changeset
517
517
518 Prepare a new changeset with the effect of REV undone in the
518 Prepare a new changeset with the effect of REV undone in the
519 current working directory. If no conflicts were encountered,
519 current working directory. If no conflicts were encountered,
520 it will be committed immediately.
520 it will be committed immediately.
521
521
522 If REV is the parent of the working directory, then this new changeset
522 If REV is the parent of the working directory, then this new changeset
523 is committed automatically (unless --no-commit is specified).
523 is committed automatically (unless --no-commit is specified).
524
524
525 .. note::
525 .. note::
526
526
527 :hg:`backout` cannot be used to fix either an unwanted or
527 :hg:`backout` cannot be used to fix either an unwanted or
528 incorrect merge.
528 incorrect merge.
529
529
530 .. container:: verbose
530 .. container:: verbose
531
531
532 Examples:
532 Examples:
533
533
534 - Reverse the effect of the parent of the working directory.
534 - Reverse the effect of the parent of the working directory.
535 This backout will be committed immediately::
535 This backout will be committed immediately::
536
536
537 hg backout -r .
537 hg backout -r .
538
538
539 - Reverse the effect of previous bad revision 23::
539 - Reverse the effect of previous bad revision 23::
540
540
541 hg backout -r 23
541 hg backout -r 23
542
542
543 - Reverse the effect of previous bad revision 23 and
543 - Reverse the effect of previous bad revision 23 and
544 leave changes uncommitted::
544 leave changes uncommitted::
545
545
546 hg backout -r 23 --no-commit
546 hg backout -r 23 --no-commit
547 hg commit -m "Backout revision 23"
547 hg commit -m "Backout revision 23"
548
548
549 By default, the pending changeset will have one parent,
549 By default, the pending changeset will have one parent,
550 maintaining a linear history. With --merge, the pending
550 maintaining a linear history. With --merge, the pending
551 changeset will instead have two parents: the old parent of the
551 changeset will instead have two parents: the old parent of the
552 working directory and a new child of REV that simply undoes REV.
552 working directory and a new child of REV that simply undoes REV.
553
553
554 Before version 1.7, the behavior without --merge was equivalent
554 Before version 1.7, the behavior without --merge was equivalent
555 to specifying --merge followed by :hg:`update --clean .` to
555 to specifying --merge followed by :hg:`update --clean .` to
556 cancel the merge and leave the child of REV as a head to be
556 cancel the merge and leave the child of REV as a head to be
557 merged separately.
557 merged separately.
558
558
559 See :hg:`help dates` for a list of formats valid for -d/--date.
559 See :hg:`help dates` for a list of formats valid for -d/--date.
560
560
561 See :hg:`help revert` for a way to restore files to the state
561 See :hg:`help revert` for a way to restore files to the state
562 of another revision.
562 of another revision.
563
563
564 Returns 0 on success, 1 if nothing to backout or there are unresolved
564 Returns 0 on success, 1 if nothing to backout or there are unresolved
565 files.
565 files.
566 '''
566 '''
567 with repo.wlock(), repo.lock():
567 with repo.wlock(), repo.lock():
568 return _dobackout(ui, repo, node, rev, **opts)
568 return _dobackout(ui, repo, node, rev, **opts)
569
569
570 def _dobackout(ui, repo, node=None, rev=None, **opts):
570 def _dobackout(ui, repo, node=None, rev=None, **opts):
571 opts = pycompat.byteskwargs(opts)
571 opts = pycompat.byteskwargs(opts)
572 if opts.get('commit') and opts.get('no_commit'):
572 if opts.get('commit') and opts.get('no_commit'):
573 raise error.Abort(_("cannot use --commit with --no-commit"))
573 raise error.Abort(_("cannot use --commit with --no-commit"))
574 if opts.get('merge') and opts.get('no_commit'):
574 if opts.get('merge') and opts.get('no_commit'):
575 raise error.Abort(_("cannot use --merge with --no-commit"))
575 raise error.Abort(_("cannot use --merge with --no-commit"))
576
576
577 if rev and node:
577 if rev and node:
578 raise error.Abort(_("please specify just one revision"))
578 raise error.Abort(_("please specify just one revision"))
579
579
580 if not rev:
580 if not rev:
581 rev = node
581 rev = node
582
582
583 if not rev:
583 if not rev:
584 raise error.Abort(_("please specify a revision to backout"))
584 raise error.Abort(_("please specify a revision to backout"))
585
585
586 date = opts.get('date')
586 date = opts.get('date')
587 if date:
587 if date:
588 opts['date'] = dateutil.parsedate(date)
588 opts['date'] = dateutil.parsedate(date)
589
589
590 cmdutil.checkunfinished(repo)
590 cmdutil.checkunfinished(repo)
591 cmdutil.bailifchanged(repo)
591 cmdutil.bailifchanged(repo)
592 node = scmutil.revsingle(repo, rev).node()
592 node = scmutil.revsingle(repo, rev).node()
593
593
594 op1, op2 = repo.dirstate.parents()
594 op1, op2 = repo.dirstate.parents()
595 if not repo.changelog.isancestor(node, op1):
595 if not repo.changelog.isancestor(node, op1):
596 raise error.Abort(_('cannot backout change that is not an ancestor'))
596 raise error.Abort(_('cannot backout change that is not an ancestor'))
597
597
598 p1, p2 = repo.changelog.parents(node)
598 p1, p2 = repo.changelog.parents(node)
599 if p1 == nullid:
599 if p1 == nullid:
600 raise error.Abort(_('cannot backout a change with no parents'))
600 raise error.Abort(_('cannot backout a change with no parents'))
601 if p2 != nullid:
601 if p2 != nullid:
602 if not opts.get('parent'):
602 if not opts.get('parent'):
603 raise error.Abort(_('cannot backout a merge changeset'))
603 raise error.Abort(_('cannot backout a merge changeset'))
604 p = repo.lookup(opts['parent'])
604 p = repo.lookup(opts['parent'])
605 if p not in (p1, p2):
605 if p not in (p1, p2):
606 raise error.Abort(_('%s is not a parent of %s') %
606 raise error.Abort(_('%s is not a parent of %s') %
607 (short(p), short(node)))
607 (short(p), short(node)))
608 parent = p
608 parent = p
609 else:
609 else:
610 if opts.get('parent'):
610 if opts.get('parent'):
611 raise error.Abort(_('cannot use --parent on non-merge changeset'))
611 raise error.Abort(_('cannot use --parent on non-merge changeset'))
612 parent = p1
612 parent = p1
613
613
614 # the backout should appear on the same branch
614 # the backout should appear on the same branch
615 branch = repo.dirstate.branch()
615 branch = repo.dirstate.branch()
616 bheads = repo.branchheads(branch)
616 bheads = repo.branchheads(branch)
617 rctx = scmutil.revsingle(repo, hex(parent))
617 rctx = scmutil.revsingle(repo, hex(parent))
618 if not opts.get('merge') and op1 != node:
618 if not opts.get('merge') and op1 != node:
619 with dirstateguard.dirstateguard(repo, 'backout'):
619 with dirstateguard.dirstateguard(repo, 'backout'):
620 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
620 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
621 with ui.configoverride(overrides, 'backout'):
621 with ui.configoverride(overrides, 'backout'):
622 stats = mergemod.update(repo, parent, True, True, node, False)
622 stats = mergemod.update(repo, parent, True, True, node, False)
623 repo.setparents(op1, op2)
623 repo.setparents(op1, op2)
624 hg._showstats(repo, stats)
624 hg._showstats(repo, stats)
625 if stats.unresolvedcount:
625 if stats.unresolvedcount:
626 repo.ui.status(_("use 'hg resolve' to retry unresolved "
626 repo.ui.status(_("use 'hg resolve' to retry unresolved "
627 "file merges\n"))
627 "file merges\n"))
628 return 1
628 return 1
629 else:
629 else:
630 hg.clean(repo, node, show_stats=False)
630 hg.clean(repo, node, show_stats=False)
631 repo.dirstate.setbranch(branch)
631 repo.dirstate.setbranch(branch)
632 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
632 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
633
633
634 if opts.get('no_commit'):
634 if opts.get('no_commit'):
635 msg = _("changeset %s backed out, "
635 msg = _("changeset %s backed out, "
636 "don't forget to commit.\n")
636 "don't forget to commit.\n")
637 ui.status(msg % short(node))
637 ui.status(msg % short(node))
638 return 0
638 return 0
639
639
640 def commitfunc(ui, repo, message, match, opts):
640 def commitfunc(ui, repo, message, match, opts):
641 editform = 'backout'
641 editform = 'backout'
642 e = cmdutil.getcommiteditor(editform=editform,
642 e = cmdutil.getcommiteditor(editform=editform,
643 **pycompat.strkwargs(opts))
643 **pycompat.strkwargs(opts))
644 if not message:
644 if not message:
645 # we don't translate commit messages
645 # we don't translate commit messages
646 message = "Backed out changeset %s" % short(node)
646 message = "Backed out changeset %s" % short(node)
647 e = cmdutil.getcommiteditor(edit=True, editform=editform)
647 e = cmdutil.getcommiteditor(edit=True, editform=editform)
648 return repo.commit(message, opts.get('user'), opts.get('date'),
648 return repo.commit(message, opts.get('user'), opts.get('date'),
649 match, editor=e)
649 match, editor=e)
650 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
650 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
651 if not newnode:
651 if not newnode:
652 ui.status(_("nothing changed\n"))
652 ui.status(_("nothing changed\n"))
653 return 1
653 return 1
654 cmdutil.commitstatus(repo, newnode, branch, bheads)
654 cmdutil.commitstatus(repo, newnode, branch, bheads)
655
655
656 def nice(node):
656 def nice(node):
657 return '%d:%s' % (repo.changelog.rev(node), short(node))
657 return '%d:%s' % (repo.changelog.rev(node), short(node))
658 ui.status(_('changeset %s backs out changeset %s\n') %
658 ui.status(_('changeset %s backs out changeset %s\n') %
659 (nice(repo.changelog.tip()), nice(node)))
659 (nice(repo.changelog.tip()), nice(node)))
660 if opts.get('merge') and op1 != node:
660 if opts.get('merge') and op1 != node:
661 hg.clean(repo, op1, show_stats=False)
661 hg.clean(repo, op1, show_stats=False)
662 ui.status(_('merging with changeset %s\n')
662 ui.status(_('merging with changeset %s\n')
663 % nice(repo.changelog.tip()))
663 % nice(repo.changelog.tip()))
664 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
664 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
665 with ui.configoverride(overrides, 'backout'):
665 with ui.configoverride(overrides, 'backout'):
666 return hg.merge(repo, hex(repo.changelog.tip()))
666 return hg.merge(repo, hex(repo.changelog.tip()))
667 return 0
667 return 0
668
668
669 @command('bisect',
669 @command('bisect',
670 [('r', 'reset', False, _('reset bisect state')),
670 [('r', 'reset', False, _('reset bisect state')),
671 ('g', 'good', False, _('mark changeset good')),
671 ('g', 'good', False, _('mark changeset good')),
672 ('b', 'bad', False, _('mark changeset bad')),
672 ('b', 'bad', False, _('mark changeset bad')),
673 ('s', 'skip', False, _('skip testing changeset')),
673 ('s', 'skip', False, _('skip testing changeset')),
674 ('e', 'extend', False, _('extend the bisect range')),
674 ('e', 'extend', False, _('extend the bisect range')),
675 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
675 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
676 ('U', 'noupdate', False, _('do not update to target'))],
676 ('U', 'noupdate', False, _('do not update to target'))],
677 _("[-gbsr] [-U] [-c CMD] [REV]"))
677 _("[-gbsr] [-U] [-c CMD] [REV]"))
678 def bisect(ui, repo, rev=None, extra=None, command=None,
678 def bisect(ui, repo, rev=None, extra=None, command=None,
679 reset=None, good=None, bad=None, skip=None, extend=None,
679 reset=None, good=None, bad=None, skip=None, extend=None,
680 noupdate=None):
680 noupdate=None):
681 """subdivision search of changesets
681 """subdivision search of changesets
682
682
683 This command helps to find changesets which introduce problems. To
683 This command helps to find changesets which introduce problems. To
684 use, mark the earliest changeset you know exhibits the problem as
684 use, mark the earliest changeset you know exhibits the problem as
685 bad, then mark the latest changeset which is free from the problem
685 bad, then mark the latest changeset which is free from the problem
686 as good. Bisect will update your working directory to a revision
686 as good. Bisect will update your working directory to a revision
687 for testing (unless the -U/--noupdate option is specified). Once
687 for testing (unless the -U/--noupdate option is specified). Once
688 you have performed tests, mark the working directory as good or
688 you have performed tests, mark the working directory as good or
689 bad, and bisect will either update to another candidate changeset
689 bad, and bisect will either update to another candidate changeset
690 or announce that it has found the bad revision.
690 or announce that it has found the bad revision.
691
691
692 As a shortcut, you can also use the revision argument to mark a
692 As a shortcut, you can also use the revision argument to mark a
693 revision as good or bad without checking it out first.
693 revision as good or bad without checking it out first.
694
694
695 If you supply a command, it will be used for automatic bisection.
695 If you supply a command, it will be used for automatic bisection.
696 The environment variable HG_NODE will contain the ID of the
696 The environment variable HG_NODE will contain the ID of the
697 changeset being tested. The exit status of the command will be
697 changeset being tested. The exit status of the command will be
698 used to mark revisions as good or bad: status 0 means good, 125
698 used to mark revisions as good or bad: status 0 means good, 125
699 means to skip the revision, 127 (command not found) will abort the
699 means to skip the revision, 127 (command not found) will abort the
700 bisection, and any other non-zero exit status means the revision
700 bisection, and any other non-zero exit status means the revision
701 is bad.
701 is bad.
702
702
703 .. container:: verbose
703 .. container:: verbose
704
704
705 Some examples:
705 Some examples:
706
706
707 - start a bisection with known bad revision 34, and good revision 12::
707 - start a bisection with known bad revision 34, and good revision 12::
708
708
709 hg bisect --bad 34
709 hg bisect --bad 34
710 hg bisect --good 12
710 hg bisect --good 12
711
711
712 - advance the current bisection by marking current revision as good or
712 - advance the current bisection by marking current revision as good or
713 bad::
713 bad::
714
714
715 hg bisect --good
715 hg bisect --good
716 hg bisect --bad
716 hg bisect --bad
717
717
718 - mark the current revision, or a known revision, to be skipped (e.g. if
718 - mark the current revision, or a known revision, to be skipped (e.g. if
719 that revision is not usable because of another issue)::
719 that revision is not usable because of another issue)::
720
720
721 hg bisect --skip
721 hg bisect --skip
722 hg bisect --skip 23
722 hg bisect --skip 23
723
723
724 - skip all revisions that do not touch directories ``foo`` or ``bar``::
724 - skip all revisions that do not touch directories ``foo`` or ``bar``::
725
725
726 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
726 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
727
727
728 - forget the current bisection::
728 - forget the current bisection::
729
729
730 hg bisect --reset
730 hg bisect --reset
731
731
732 - use 'make && make tests' to automatically find the first broken
732 - use 'make && make tests' to automatically find the first broken
733 revision::
733 revision::
734
734
735 hg bisect --reset
735 hg bisect --reset
736 hg bisect --bad 34
736 hg bisect --bad 34
737 hg bisect --good 12
737 hg bisect --good 12
738 hg bisect --command "make && make tests"
738 hg bisect --command "make && make tests"
739
739
740 - see all changesets whose states are already known in the current
740 - see all changesets whose states are already known in the current
741 bisection::
741 bisection::
742
742
743 hg log -r "bisect(pruned)"
743 hg log -r "bisect(pruned)"
744
744
745 - see the changeset currently being bisected (especially useful
745 - see the changeset currently being bisected (especially useful
746 if running with -U/--noupdate)::
746 if running with -U/--noupdate)::
747
747
748 hg log -r "bisect(current)"
748 hg log -r "bisect(current)"
749
749
750 - see all changesets that took part in the current bisection::
750 - see all changesets that took part in the current bisection::
751
751
752 hg log -r "bisect(range)"
752 hg log -r "bisect(range)"
753
753
754 - you can even get a nice graph::
754 - you can even get a nice graph::
755
755
756 hg log --graph -r "bisect(range)"
756 hg log --graph -r "bisect(range)"
757
757
758 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
758 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
759
759
760 Returns 0 on success.
760 Returns 0 on success.
761 """
761 """
762 # backward compatibility
762 # backward compatibility
763 if rev in "good bad reset init".split():
763 if rev in "good bad reset init".split():
764 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
764 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
765 cmd, rev, extra = rev, extra, None
765 cmd, rev, extra = rev, extra, None
766 if cmd == "good":
766 if cmd == "good":
767 good = True
767 good = True
768 elif cmd == "bad":
768 elif cmd == "bad":
769 bad = True
769 bad = True
770 else:
770 else:
771 reset = True
771 reset = True
772 elif extra:
772 elif extra:
773 raise error.Abort(_('incompatible arguments'))
773 raise error.Abort(_('incompatible arguments'))
774
774
775 incompatibles = {
775 incompatibles = {
776 '--bad': bad,
776 '--bad': bad,
777 '--command': bool(command),
777 '--command': bool(command),
778 '--extend': extend,
778 '--extend': extend,
779 '--good': good,
779 '--good': good,
780 '--reset': reset,
780 '--reset': reset,
781 '--skip': skip,
781 '--skip': skip,
782 }
782 }
783
783
784 enabled = [x for x in incompatibles if incompatibles[x]]
784 enabled = [x for x in incompatibles if incompatibles[x]]
785
785
786 if len(enabled) > 1:
786 if len(enabled) > 1:
787 raise error.Abort(_('%s and %s are incompatible') %
787 raise error.Abort(_('%s and %s are incompatible') %
788 tuple(sorted(enabled)[0:2]))
788 tuple(sorted(enabled)[0:2]))
789
789
790 if reset:
790 if reset:
791 hbisect.resetstate(repo)
791 hbisect.resetstate(repo)
792 return
792 return
793
793
794 state = hbisect.load_state(repo)
794 state = hbisect.load_state(repo)
795
795
796 # update state
796 # update state
797 if good or bad or skip:
797 if good or bad or skip:
798 if rev:
798 if rev:
799 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
799 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
800 else:
800 else:
801 nodes = [repo.lookup('.')]
801 nodes = [repo.lookup('.')]
802 if good:
802 if good:
803 state['good'] += nodes
803 state['good'] += nodes
804 elif bad:
804 elif bad:
805 state['bad'] += nodes
805 state['bad'] += nodes
806 elif skip:
806 elif skip:
807 state['skip'] += nodes
807 state['skip'] += nodes
808 hbisect.save_state(repo, state)
808 hbisect.save_state(repo, state)
809 if not (state['good'] and state['bad']):
809 if not (state['good'] and state['bad']):
810 return
810 return
811
811
812 def mayupdate(repo, node, show_stats=True):
812 def mayupdate(repo, node, show_stats=True):
813 """common used update sequence"""
813 """common used update sequence"""
814 if noupdate:
814 if noupdate:
815 return
815 return
816 cmdutil.checkunfinished(repo)
816 cmdutil.checkunfinished(repo)
817 cmdutil.bailifchanged(repo)
817 cmdutil.bailifchanged(repo)
818 return hg.clean(repo, node, show_stats=show_stats)
818 return hg.clean(repo, node, show_stats=show_stats)
819
819
820 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
820 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
821
821
822 if command:
822 if command:
823 changesets = 1
823 changesets = 1
824 if noupdate:
824 if noupdate:
825 try:
825 try:
826 node = state['current'][0]
826 node = state['current'][0]
827 except LookupError:
827 except LookupError:
828 raise error.Abort(_('current bisect revision is unknown - '
828 raise error.Abort(_('current bisect revision is unknown - '
829 'start a new bisect to fix'))
829 'start a new bisect to fix'))
830 else:
830 else:
831 node, p2 = repo.dirstate.parents()
831 node, p2 = repo.dirstate.parents()
832 if p2 != nullid:
832 if p2 != nullid:
833 raise error.Abort(_('current bisect revision is a merge'))
833 raise error.Abort(_('current bisect revision is a merge'))
834 if rev:
834 if rev:
835 node = repo[scmutil.revsingle(repo, rev, node)].node()
835 node = repo[scmutil.revsingle(repo, rev, node)].node()
836 try:
836 try:
837 while changesets:
837 while changesets:
838 # update state
838 # update state
839 state['current'] = [node]
839 state['current'] = [node]
840 hbisect.save_state(repo, state)
840 hbisect.save_state(repo, state)
841 status = ui.system(command, environ={'HG_NODE': hex(node)},
841 status = ui.system(command, environ={'HG_NODE': hex(node)},
842 blockedtag='bisect_check')
842 blockedtag='bisect_check')
843 if status == 125:
843 if status == 125:
844 transition = "skip"
844 transition = "skip"
845 elif status == 0:
845 elif status == 0:
846 transition = "good"
846 transition = "good"
847 # status < 0 means process was killed
847 # status < 0 means process was killed
848 elif status == 127:
848 elif status == 127:
849 raise error.Abort(_("failed to execute %s") % command)
849 raise error.Abort(_("failed to execute %s") % command)
850 elif status < 0:
850 elif status < 0:
851 raise error.Abort(_("%s killed") % command)
851 raise error.Abort(_("%s killed") % command)
852 else:
852 else:
853 transition = "bad"
853 transition = "bad"
854 state[transition].append(node)
854 state[transition].append(node)
855 ctx = repo[node]
855 ctx = repo[node]
856 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
856 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
857 transition))
857 transition))
858 hbisect.checkstate(state)
858 hbisect.checkstate(state)
859 # bisect
859 # bisect
860 nodes, changesets, bgood = hbisect.bisect(repo, state)
860 nodes, changesets, bgood = hbisect.bisect(repo, state)
861 # update to next check
861 # update to next check
862 node = nodes[0]
862 node = nodes[0]
863 mayupdate(repo, node, show_stats=False)
863 mayupdate(repo, node, show_stats=False)
864 finally:
864 finally:
865 state['current'] = [node]
865 state['current'] = [node]
866 hbisect.save_state(repo, state)
866 hbisect.save_state(repo, state)
867 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
867 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
868 return
868 return
869
869
870 hbisect.checkstate(state)
870 hbisect.checkstate(state)
871
871
872 # actually bisect
872 # actually bisect
873 nodes, changesets, good = hbisect.bisect(repo, state)
873 nodes, changesets, good = hbisect.bisect(repo, state)
874 if extend:
874 if extend:
875 if not changesets:
875 if not changesets:
876 extendnode = hbisect.extendrange(repo, state, nodes, good)
876 extendnode = hbisect.extendrange(repo, state, nodes, good)
877 if extendnode is not None:
877 if extendnode is not None:
878 ui.write(_("Extending search to changeset %d:%s\n")
878 ui.write(_("Extending search to changeset %d:%s\n")
879 % (extendnode.rev(), extendnode))
879 % (extendnode.rev(), extendnode))
880 state['current'] = [extendnode.node()]
880 state['current'] = [extendnode.node()]
881 hbisect.save_state(repo, state)
881 hbisect.save_state(repo, state)
882 return mayupdate(repo, extendnode.node())
882 return mayupdate(repo, extendnode.node())
883 raise error.Abort(_("nothing to extend"))
883 raise error.Abort(_("nothing to extend"))
884
884
885 if changesets == 0:
885 if changesets == 0:
886 hbisect.printresult(ui, repo, state, displayer, nodes, good)
886 hbisect.printresult(ui, repo, state, displayer, nodes, good)
887 else:
887 else:
888 assert len(nodes) == 1 # only a single node can be tested next
888 assert len(nodes) == 1 # only a single node can be tested next
889 node = nodes[0]
889 node = nodes[0]
890 # compute the approximate number of remaining tests
890 # compute the approximate number of remaining tests
891 tests, size = 0, 2
891 tests, size = 0, 2
892 while size <= changesets:
892 while size <= changesets:
893 tests, size = tests + 1, size * 2
893 tests, size = tests + 1, size * 2
894 rev = repo.changelog.rev(node)
894 rev = repo.changelog.rev(node)
895 ui.write(_("Testing changeset %d:%s "
895 ui.write(_("Testing changeset %d:%s "
896 "(%d changesets remaining, ~%d tests)\n")
896 "(%d changesets remaining, ~%d tests)\n")
897 % (rev, short(node), changesets, tests))
897 % (rev, short(node), changesets, tests))
898 state['current'] = [node]
898 state['current'] = [node]
899 hbisect.save_state(repo, state)
899 hbisect.save_state(repo, state)
900 return mayupdate(repo, node)
900 return mayupdate(repo, node)
901
901
902 @command('bookmarks|bookmark',
902 @command('bookmarks|bookmark',
903 [('f', 'force', False, _('force')),
903 [('f', 'force', False, _('force')),
904 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
904 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
905 ('d', 'delete', False, _('delete a given bookmark')),
905 ('d', 'delete', False, _('delete a given bookmark')),
906 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
906 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
907 ('i', 'inactive', False, _('mark a bookmark inactive')),
907 ('i', 'inactive', False, _('mark a bookmark inactive')),
908 ('l', 'list', False, _('list existing bookmarks')),
908 ('l', 'list', False, _('list existing bookmarks')),
909 ] + formatteropts,
909 ] + formatteropts,
910 _('hg bookmarks [OPTIONS]... [NAME]...'))
910 _('hg bookmarks [OPTIONS]... [NAME]...'))
911 def bookmark(ui, repo, *names, **opts):
911 def bookmark(ui, repo, *names, **opts):
912 '''create a new bookmark or list existing bookmarks
912 '''create a new bookmark or list existing bookmarks
913
913
914 Bookmarks are labels on changesets to help track lines of development.
914 Bookmarks are labels on changesets to help track lines of development.
915 Bookmarks are unversioned and can be moved, renamed and deleted.
915 Bookmarks are unversioned and can be moved, renamed and deleted.
916 Deleting or moving a bookmark has no effect on the associated changesets.
916 Deleting or moving a bookmark has no effect on the associated changesets.
917
917
918 Creating or updating to a bookmark causes it to be marked as 'active'.
918 Creating or updating to a bookmark causes it to be marked as 'active'.
919 The active bookmark is indicated with a '*'.
919 The active bookmark is indicated with a '*'.
920 When a commit is made, the active bookmark will advance to the new commit.
920 When a commit is made, the active bookmark will advance to the new commit.
921 A plain :hg:`update` will also advance an active bookmark, if possible.
921 A plain :hg:`update` will also advance an active bookmark, if possible.
922 Updating away from a bookmark will cause it to be deactivated.
922 Updating away from a bookmark will cause it to be deactivated.
923
923
924 Bookmarks can be pushed and pulled between repositories (see
924 Bookmarks can be pushed and pulled between repositories (see
925 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
925 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
926 diverged, a new 'divergent bookmark' of the form 'name@path' will
926 diverged, a new 'divergent bookmark' of the form 'name@path' will
927 be created. Using :hg:`merge` will resolve the divergence.
927 be created. Using :hg:`merge` will resolve the divergence.
928
928
929 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
929 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
930 the active bookmark's name.
930 the active bookmark's name.
931
931
932 A bookmark named '@' has the special property that :hg:`clone` will
932 A bookmark named '@' has the special property that :hg:`clone` will
933 check it out by default if it exists.
933 check it out by default if it exists.
934
934
935 .. container:: verbose
935 .. container:: verbose
936
936
937 Examples:
937 Examples:
938
938
939 - create an active bookmark for a new line of development::
939 - create an active bookmark for a new line of development::
940
940
941 hg book new-feature
941 hg book new-feature
942
942
943 - create an inactive bookmark as a place marker::
943 - create an inactive bookmark as a place marker::
944
944
945 hg book -i reviewed
945 hg book -i reviewed
946
946
947 - create an inactive bookmark on another changeset::
947 - create an inactive bookmark on another changeset::
948
948
949 hg book -r .^ tested
949 hg book -r .^ tested
950
950
951 - rename bookmark turkey to dinner::
951 - rename bookmark turkey to dinner::
952
952
953 hg book -m turkey dinner
953 hg book -m turkey dinner
954
954
955 - move the '@' bookmark from another branch::
955 - move the '@' bookmark from another branch::
956
956
957 hg book -f @
957 hg book -f @
958
958
959 - print only the active bookmark name::
959 - print only the active bookmark name::
960
960
961 hg book -ql .
961 hg book -ql .
962 '''
962 '''
963 opts = pycompat.byteskwargs(opts)
963 opts = pycompat.byteskwargs(opts)
964 force = opts.get('force')
964 force = opts.get('force')
965 rev = opts.get('rev')
965 rev = opts.get('rev')
966 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
966 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
967
967
968 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
968 selactions = [k for k in ['delete', 'rename', 'list'] if opts.get(k)]
969 if len(selactions) > 1:
969 if len(selactions) > 1:
970 raise error.Abort(_('--%s and --%s are incompatible')
970 raise error.Abort(_('--%s and --%s are incompatible')
971 % tuple(selactions[:2]))
971 % tuple(selactions[:2]))
972 if selactions:
972 if selactions:
973 action = selactions[0]
973 action = selactions[0]
974 elif names or rev:
974 elif names or rev:
975 action = 'add'
975 action = 'add'
976 elif inactive:
976 elif inactive:
977 action = 'inactive' # meaning deactivate
977 action = 'inactive' # meaning deactivate
978 else:
978 else:
979 action = 'list'
979 action = 'list'
980
980
981 if rev and action in {'delete', 'rename', 'list'}:
981 if rev and action in {'delete', 'rename', 'list'}:
982 raise error.Abort(_("--rev is incompatible with --%s") % action)
982 raise error.Abort(_("--rev is incompatible with --%s") % action)
983 if inactive and action in {'delete', 'list'}:
983 if inactive and action in {'delete', 'list'}:
984 raise error.Abort(_("--inactive is incompatible with --%s") % action)
984 raise error.Abort(_("--inactive is incompatible with --%s") % action)
985 if not names and action in {'add', 'delete'}:
985 if not names and action in {'add', 'delete'}:
986 raise error.Abort(_("bookmark name required"))
986 raise error.Abort(_("bookmark name required"))
987
987
988 if action in {'add', 'delete', 'rename', 'inactive'}:
988 if action in {'add', 'delete', 'rename', 'inactive'}:
989 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
989 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
990 if action == 'delete':
990 if action == 'delete':
991 names = pycompat.maplist(repo._bookmarks.expandname, names)
991 names = pycompat.maplist(repo._bookmarks.expandname, names)
992 bookmarks.delete(repo, tr, names)
992 bookmarks.delete(repo, tr, names)
993 elif action == 'rename':
993 elif action == 'rename':
994 if not names:
994 if not names:
995 raise error.Abort(_("new bookmark name required"))
995 raise error.Abort(_("new bookmark name required"))
996 elif len(names) > 1:
996 elif len(names) > 1:
997 raise error.Abort(_("only one new bookmark name allowed"))
997 raise error.Abort(_("only one new bookmark name allowed"))
998 oldname = repo._bookmarks.expandname(opts['rename'])
998 oldname = repo._bookmarks.expandname(opts['rename'])
999 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
999 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1000 elif action == 'add':
1000 elif action == 'add':
1001 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1001 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1002 elif action == 'inactive':
1002 elif action == 'inactive':
1003 if len(repo._bookmarks) == 0:
1003 if len(repo._bookmarks) == 0:
1004 ui.status(_("no bookmarks set\n"))
1004 ui.status(_("no bookmarks set\n"))
1005 elif not repo._activebookmark:
1005 elif not repo._activebookmark:
1006 ui.status(_("no active bookmark\n"))
1006 ui.status(_("no active bookmark\n"))
1007 else:
1007 else:
1008 bookmarks.deactivate(repo)
1008 bookmarks.deactivate(repo)
1009 elif action == 'list':
1009 elif action == 'list':
1010 names = pycompat.maplist(repo._bookmarks.expandname, names)
1010 names = pycompat.maplist(repo._bookmarks.expandname, names)
1011 with ui.formatter('bookmarks', opts) as fm:
1011 with ui.formatter('bookmarks', opts) as fm:
1012 bookmarks.printbookmarks(ui, repo, fm, names)
1012 bookmarks.printbookmarks(ui, repo, fm, names)
1013 else:
1013 else:
1014 raise error.ProgrammingError('invalid action: %s' % action)
1014 raise error.ProgrammingError('invalid action: %s' % action)
1015
1015
1016 @command('branch',
1016 @command('branch',
1017 [('f', 'force', None,
1017 [('f', 'force', None,
1018 _('set branch name even if it shadows an existing branch')),
1018 _('set branch name even if it shadows an existing branch')),
1019 ('C', 'clean', None, _('reset branch name to parent branch name')),
1019 ('C', 'clean', None, _('reset branch name to parent branch name')),
1020 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1020 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1021 ],
1021 ],
1022 _('[-fC] [NAME]'))
1022 _('[-fC] [NAME]'))
1023 def branch(ui, repo, label=None, **opts):
1023 def branch(ui, repo, label=None, **opts):
1024 """set or show the current branch name
1024 """set or show the current branch name
1025
1025
1026 .. note::
1026 .. note::
1027
1027
1028 Branch names are permanent and global. Use :hg:`bookmark` to create a
1028 Branch names are permanent and global. Use :hg:`bookmark` to create a
1029 light-weight bookmark instead. See :hg:`help glossary` for more
1029 light-weight bookmark instead. See :hg:`help glossary` for more
1030 information about named branches and bookmarks.
1030 information about named branches and bookmarks.
1031
1031
1032 With no argument, show the current branch name. With one argument,
1032 With no argument, show the current branch name. With one argument,
1033 set the working directory branch name (the branch will not exist
1033 set the working directory branch name (the branch will not exist
1034 in the repository until the next commit). Standard practice
1034 in the repository until the next commit). Standard practice
1035 recommends that primary development take place on the 'default'
1035 recommends that primary development take place on the 'default'
1036 branch.
1036 branch.
1037
1037
1038 Unless -f/--force is specified, branch will not let you set a
1038 Unless -f/--force is specified, branch will not let you set a
1039 branch name that already exists.
1039 branch name that already exists.
1040
1040
1041 Use -C/--clean to reset the working directory branch to that of
1041 Use -C/--clean to reset the working directory branch to that of
1042 the parent of the working directory, negating a previous branch
1042 the parent of the working directory, negating a previous branch
1043 change.
1043 change.
1044
1044
1045 Use the command :hg:`update` to switch to an existing branch. Use
1045 Use the command :hg:`update` to switch to an existing branch. Use
1046 :hg:`commit --close-branch` to mark this branch head as closed.
1046 :hg:`commit --close-branch` to mark this branch head as closed.
1047 When all heads of a branch are closed, the branch will be
1047 When all heads of a branch are closed, the branch will be
1048 considered closed.
1048 considered closed.
1049
1049
1050 Returns 0 on success.
1050 Returns 0 on success.
1051 """
1051 """
1052 opts = pycompat.byteskwargs(opts)
1052 opts = pycompat.byteskwargs(opts)
1053 revs = opts.get('rev')
1053 revs = opts.get('rev')
1054 if label:
1054 if label:
1055 label = label.strip()
1055 label = label.strip()
1056
1056
1057 if not opts.get('clean') and not label:
1057 if not opts.get('clean') and not label:
1058 if revs:
1058 if revs:
1059 raise error.Abort(_("no branch name specified for the revisions"))
1059 raise error.Abort(_("no branch name specified for the revisions"))
1060 ui.write("%s\n" % repo.dirstate.branch())
1060 ui.write("%s\n" % repo.dirstate.branch())
1061 return
1061 return
1062
1062
1063 with repo.wlock():
1063 with repo.wlock():
1064 if opts.get('clean'):
1064 if opts.get('clean'):
1065 label = repo[None].p1().branch()
1065 label = repo[None].p1().branch()
1066 repo.dirstate.setbranch(label)
1066 repo.dirstate.setbranch(label)
1067 ui.status(_('reset working directory to branch %s\n') % label)
1067 ui.status(_('reset working directory to branch %s\n') % label)
1068 elif label:
1068 elif label:
1069
1069
1070 scmutil.checknewlabel(repo, label, 'branch')
1070 scmutil.checknewlabel(repo, label, 'branch')
1071 if revs:
1071 if revs:
1072 return cmdutil.changebranch(ui, repo, revs, label)
1072 return cmdutil.changebranch(ui, repo, revs, label)
1073
1073
1074 if not opts.get('force') and label in repo.branchmap():
1074 if not opts.get('force') and label in repo.branchmap():
1075 if label not in [p.branch() for p in repo[None].parents()]:
1075 if label not in [p.branch() for p in repo[None].parents()]:
1076 raise error.Abort(_('a branch of the same name already'
1076 raise error.Abort(_('a branch of the same name already'
1077 ' exists'),
1077 ' exists'),
1078 # i18n: "it" refers to an existing branch
1078 # i18n: "it" refers to an existing branch
1079 hint=_("use 'hg update' to switch to it"))
1079 hint=_("use 'hg update' to switch to it"))
1080
1080
1081 repo.dirstate.setbranch(label)
1081 repo.dirstate.setbranch(label)
1082 ui.status(_('marked working directory as branch %s\n') % label)
1082 ui.status(_('marked working directory as branch %s\n') % label)
1083
1083
1084 # find any open named branches aside from default
1084 # find any open named branches aside from default
1085 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1085 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1086 if n != "default" and not c]
1086 if n != "default" and not c]
1087 if not others:
1087 if not others:
1088 ui.status(_('(branches are permanent and global, '
1088 ui.status(_('(branches are permanent and global, '
1089 'did you want a bookmark?)\n'))
1089 'did you want a bookmark?)\n'))
1090
1090
1091 @command('branches',
1091 @command('branches',
1092 [('a', 'active', False,
1092 [('a', 'active', False,
1093 _('show only branches that have unmerged heads (DEPRECATED)')),
1093 _('show only branches that have unmerged heads (DEPRECATED)')),
1094 ('c', 'closed', False, _('show normal and closed branches')),
1094 ('c', 'closed', False, _('show normal and closed branches')),
1095 ] + formatteropts,
1095 ] + formatteropts,
1096 _('[-c]'),
1096 _('[-c]'),
1097 intents={INTENT_READONLY})
1097 intents={INTENT_READONLY})
1098 def branches(ui, repo, active=False, closed=False, **opts):
1098 def branches(ui, repo, active=False, closed=False, **opts):
1099 """list repository named branches
1099 """list repository named branches
1100
1100
1101 List the repository's named branches, indicating which ones are
1101 List the repository's named branches, indicating which ones are
1102 inactive. If -c/--closed is specified, also list branches which have
1102 inactive. If -c/--closed is specified, also list branches which have
1103 been marked closed (see :hg:`commit --close-branch`).
1103 been marked closed (see :hg:`commit --close-branch`).
1104
1104
1105 Use the command :hg:`update` to switch to an existing branch.
1105 Use the command :hg:`update` to switch to an existing branch.
1106
1106
1107 Returns 0.
1107 Returns 0.
1108 """
1108 """
1109
1109
1110 opts = pycompat.byteskwargs(opts)
1110 opts = pycompat.byteskwargs(opts)
1111 ui.pager('branches')
1111 ui.pager('branches')
1112 fm = ui.formatter('branches', opts)
1112 fm = ui.formatter('branches', opts)
1113 hexfunc = fm.hexfunc
1113 hexfunc = fm.hexfunc
1114
1114
1115 allheads = set(repo.heads())
1115 allheads = set(repo.heads())
1116 branches = []
1116 branches = []
1117 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1117 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1118 isactive = False
1118 isactive = False
1119 if not isclosed:
1119 if not isclosed:
1120 openheads = set(repo.branchmap().iteropen(heads))
1120 openheads = set(repo.branchmap().iteropen(heads))
1121 isactive = bool(openheads & allheads)
1121 isactive = bool(openheads & allheads)
1122 branches.append((tag, repo[tip], isactive, not isclosed))
1122 branches.append((tag, repo[tip], isactive, not isclosed))
1123 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1123 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1124 reverse=True)
1124 reverse=True)
1125
1125
1126 for tag, ctx, isactive, isopen in branches:
1126 for tag, ctx, isactive, isopen in branches:
1127 if active and not isactive:
1127 if active and not isactive:
1128 continue
1128 continue
1129 if isactive:
1129 if isactive:
1130 label = 'branches.active'
1130 label = 'branches.active'
1131 notice = ''
1131 notice = ''
1132 elif not isopen:
1132 elif not isopen:
1133 if not closed:
1133 if not closed:
1134 continue
1134 continue
1135 label = 'branches.closed'
1135 label = 'branches.closed'
1136 notice = _(' (closed)')
1136 notice = _(' (closed)')
1137 else:
1137 else:
1138 label = 'branches.inactive'
1138 label = 'branches.inactive'
1139 notice = _(' (inactive)')
1139 notice = _(' (inactive)')
1140 current = (tag == repo.dirstate.branch())
1140 current = (tag == repo.dirstate.branch())
1141 if current:
1141 if current:
1142 label = 'branches.current'
1142 label = 'branches.current'
1143
1143
1144 fm.startitem()
1144 fm.startitem()
1145 fm.write('branch', '%s', tag, label=label)
1145 fm.write('branch', '%s', tag, label=label)
1146 rev = ctx.rev()
1146 rev = ctx.rev()
1147 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1147 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1148 fmt = ' ' * padsize + ' %d:%s'
1148 fmt = ' ' * padsize + ' %d:%s'
1149 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1149 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1150 label='log.changeset changeset.%s' % ctx.phasestr())
1150 label='log.changeset changeset.%s' % ctx.phasestr())
1151 fm.context(ctx=ctx)
1151 fm.context(ctx=ctx)
1152 fm.data(active=isactive, closed=not isopen, current=current)
1152 fm.data(active=isactive, closed=not isopen, current=current)
1153 if not ui.quiet:
1153 if not ui.quiet:
1154 fm.plain(notice)
1154 fm.plain(notice)
1155 fm.plain('\n')
1155 fm.plain('\n')
1156 fm.end()
1156 fm.end()
1157
1157
1158 @command('bundle',
1158 @command('bundle',
1159 [('f', 'force', None, _('run even when the destination is unrelated')),
1159 [('f', 'force', None, _('run even when the destination is unrelated')),
1160 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1160 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1161 _('REV')),
1161 _('REV')),
1162 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1162 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1163 _('BRANCH')),
1163 _('BRANCH')),
1164 ('', 'base', [],
1164 ('', 'base', [],
1165 _('a base changeset assumed to be available at the destination'),
1165 _('a base changeset assumed to be available at the destination'),
1166 _('REV')),
1166 _('REV')),
1167 ('a', 'all', None, _('bundle all changesets in the repository')),
1167 ('a', 'all', None, _('bundle all changesets in the repository')),
1168 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1168 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1169 ] + remoteopts,
1169 ] + remoteopts,
1170 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1170 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1171 def bundle(ui, repo, fname, dest=None, **opts):
1171 def bundle(ui, repo, fname, dest=None, **opts):
1172 """create a bundle file
1172 """create a bundle file
1173
1173
1174 Generate a bundle file containing data to be transferred to another
1174 Generate a bundle file containing data to be transferred to another
1175 repository.
1175 repository.
1176
1176
1177 To create a bundle containing all changesets, use -a/--all
1177 To create a bundle containing all changesets, use -a/--all
1178 (or --base null). Otherwise, hg assumes the destination will have
1178 (or --base null). Otherwise, hg assumes the destination will have
1179 all the nodes you specify with --base parameters. Otherwise, hg
1179 all the nodes you specify with --base parameters. Otherwise, hg
1180 will assume the repository has all the nodes in destination, or
1180 will assume the repository has all the nodes in destination, or
1181 default-push/default if no destination is specified, where destination
1181 default-push/default if no destination is specified, where destination
1182 is the repository you provide through DEST option.
1182 is the repository you provide through DEST option.
1183
1183
1184 You can change bundle format with the -t/--type option. See
1184 You can change bundle format with the -t/--type option. See
1185 :hg:`help bundlespec` for documentation on this format. By default,
1185 :hg:`help bundlespec` for documentation on this format. By default,
1186 the most appropriate format is used and compression defaults to
1186 the most appropriate format is used and compression defaults to
1187 bzip2.
1187 bzip2.
1188
1188
1189 The bundle file can then be transferred using conventional means
1189 The bundle file can then be transferred using conventional means
1190 and applied to another repository with the unbundle or pull
1190 and applied to another repository with the unbundle or pull
1191 command. This is useful when direct push and pull are not
1191 command. This is useful when direct push and pull are not
1192 available or when exporting an entire repository is undesirable.
1192 available or when exporting an entire repository is undesirable.
1193
1193
1194 Applying bundles preserves all changeset contents including
1194 Applying bundles preserves all changeset contents including
1195 permissions, copy/rename information, and revision history.
1195 permissions, copy/rename information, and revision history.
1196
1196
1197 Returns 0 on success, 1 if no changes found.
1197 Returns 0 on success, 1 if no changes found.
1198 """
1198 """
1199 opts = pycompat.byteskwargs(opts)
1199 opts = pycompat.byteskwargs(opts)
1200 revs = None
1200 revs = None
1201 if 'rev' in opts:
1201 if 'rev' in opts:
1202 revstrings = opts['rev']
1202 revstrings = opts['rev']
1203 revs = scmutil.revrange(repo, revstrings)
1203 revs = scmutil.revrange(repo, revstrings)
1204 if revstrings and not revs:
1204 if revstrings and not revs:
1205 raise error.Abort(_('no commits to bundle'))
1205 raise error.Abort(_('no commits to bundle'))
1206
1206
1207 bundletype = opts.get('type', 'bzip2').lower()
1207 bundletype = opts.get('type', 'bzip2').lower()
1208 try:
1208 try:
1209 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1209 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1210 except error.UnsupportedBundleSpecification as e:
1210 except error.UnsupportedBundleSpecification as e:
1211 raise error.Abort(pycompat.bytestr(e),
1211 raise error.Abort(pycompat.bytestr(e),
1212 hint=_("see 'hg help bundlespec' for supported "
1212 hint=_("see 'hg help bundlespec' for supported "
1213 "values for --type"))
1213 "values for --type"))
1214 cgversion = bundlespec.contentopts["cg.version"]
1214 cgversion = bundlespec.contentopts["cg.version"]
1215
1215
1216 # Packed bundles are a pseudo bundle format for now.
1216 # Packed bundles are a pseudo bundle format for now.
1217 if cgversion == 's1':
1217 if cgversion == 's1':
1218 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1218 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1219 hint=_("use 'hg debugcreatestreamclonebundle'"))
1219 hint=_("use 'hg debugcreatestreamclonebundle'"))
1220
1220
1221 if opts.get('all'):
1221 if opts.get('all'):
1222 if dest:
1222 if dest:
1223 raise error.Abort(_("--all is incompatible with specifying "
1223 raise error.Abort(_("--all is incompatible with specifying "
1224 "a destination"))
1224 "a destination"))
1225 if opts.get('base'):
1225 if opts.get('base'):
1226 ui.warn(_("ignoring --base because --all was specified\n"))
1226 ui.warn(_("ignoring --base because --all was specified\n"))
1227 base = [nullrev]
1227 base = [nullrev]
1228 else:
1228 else:
1229 base = scmutil.revrange(repo, opts.get('base'))
1229 base = scmutil.revrange(repo, opts.get('base'))
1230 if cgversion not in changegroup.supportedoutgoingversions(repo):
1230 if cgversion not in changegroup.supportedoutgoingversions(repo):
1231 raise error.Abort(_("repository does not support bundle version %s") %
1231 raise error.Abort(_("repository does not support bundle version %s") %
1232 cgversion)
1232 cgversion)
1233
1233
1234 if base:
1234 if base:
1235 if dest:
1235 if dest:
1236 raise error.Abort(_("--base is incompatible with specifying "
1236 raise error.Abort(_("--base is incompatible with specifying "
1237 "a destination"))
1237 "a destination"))
1238 common = [repo[rev].node() for rev in base]
1238 common = [repo[rev].node() for rev in base]
1239 heads = [repo[r].node() for r in revs] if revs else None
1239 heads = [repo[r].node() for r in revs] if revs else None
1240 outgoing = discovery.outgoing(repo, common, heads)
1240 outgoing = discovery.outgoing(repo, common, heads)
1241 else:
1241 else:
1242 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1242 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1243 dest, branches = hg.parseurl(dest, opts.get('branch'))
1243 dest, branches = hg.parseurl(dest, opts.get('branch'))
1244 other = hg.peer(repo, opts, dest)
1244 other = hg.peer(repo, opts, dest)
1245 revs = [repo[r].hex() for r in revs]
1245 revs = [repo[r].hex() for r in revs]
1246 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1246 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1247 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1247 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1248 outgoing = discovery.findcommonoutgoing(repo, other,
1248 outgoing = discovery.findcommonoutgoing(repo, other,
1249 onlyheads=heads,
1249 onlyheads=heads,
1250 force=opts.get('force'),
1250 force=opts.get('force'),
1251 portable=True)
1251 portable=True)
1252
1252
1253 if not outgoing.missing:
1253 if not outgoing.missing:
1254 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1254 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1255 return 1
1255 return 1
1256
1256
1257 if cgversion == '01': #bundle1
1257 if cgversion == '01': #bundle1
1258 bversion = 'HG10' + bundlespec.wirecompression
1258 bversion = 'HG10' + bundlespec.wirecompression
1259 bcompression = None
1259 bcompression = None
1260 elif cgversion in ('02', '03'):
1260 elif cgversion in ('02', '03'):
1261 bversion = 'HG20'
1261 bversion = 'HG20'
1262 bcompression = bundlespec.wirecompression
1262 bcompression = bundlespec.wirecompression
1263 else:
1263 else:
1264 raise error.ProgrammingError(
1264 raise error.ProgrammingError(
1265 'bundle: unexpected changegroup version %s' % cgversion)
1265 'bundle: unexpected changegroup version %s' % cgversion)
1266
1266
1267 # TODO compression options should be derived from bundlespec parsing.
1267 # TODO compression options should be derived from bundlespec parsing.
1268 # This is a temporary hack to allow adjusting bundle compression
1268 # This is a temporary hack to allow adjusting bundle compression
1269 # level without a) formalizing the bundlespec changes to declare it
1269 # level without a) formalizing the bundlespec changes to declare it
1270 # b) introducing a command flag.
1270 # b) introducing a command flag.
1271 compopts = {}
1271 compopts = {}
1272 complevel = ui.configint('experimental',
1272 complevel = ui.configint('experimental',
1273 'bundlecomplevel.' + bundlespec.compression)
1273 'bundlecomplevel.' + bundlespec.compression)
1274 if complevel is None:
1274 if complevel is None:
1275 complevel = ui.configint('experimental', 'bundlecomplevel')
1275 complevel = ui.configint('experimental', 'bundlecomplevel')
1276 if complevel is not None:
1276 if complevel is not None:
1277 compopts['level'] = complevel
1277 compopts['level'] = complevel
1278
1278
1279 # Allow overriding the bundling of obsmarker in phases through
1279 # Allow overriding the bundling of obsmarker in phases through
1280 # configuration while we don't have a bundle version that include them
1280 # configuration while we don't have a bundle version that include them
1281 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1281 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1282 bundlespec.contentopts['obsolescence'] = True
1282 bundlespec.contentopts['obsolescence'] = True
1283 if repo.ui.configbool('experimental', 'bundle-phases'):
1283 if repo.ui.configbool('experimental', 'bundle-phases'):
1284 bundlespec.contentopts['phases'] = True
1284 bundlespec.contentopts['phases'] = True
1285
1285
1286 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1286 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1287 bundlespec.contentopts, compression=bcompression,
1287 bundlespec.contentopts, compression=bcompression,
1288 compopts=compopts)
1288 compopts=compopts)
1289
1289
1290 @command('cat',
1290 @command('cat',
1291 [('o', 'output', '',
1291 [('o', 'output', '',
1292 _('print output to file with formatted name'), _('FORMAT')),
1292 _('print output to file with formatted name'), _('FORMAT')),
1293 ('r', 'rev', '', _('print the given revision'), _('REV')),
1293 ('r', 'rev', '', _('print the given revision'), _('REV')),
1294 ('', 'decode', None, _('apply any matching decode filter')),
1294 ('', 'decode', None, _('apply any matching decode filter')),
1295 ] + walkopts + formatteropts,
1295 ] + walkopts + formatteropts,
1296 _('[OPTION]... FILE...'),
1296 _('[OPTION]... FILE...'),
1297 inferrepo=True,
1297 inferrepo=True,
1298 intents={INTENT_READONLY})
1298 intents={INTENT_READONLY})
1299 def cat(ui, repo, file1, *pats, **opts):
1299 def cat(ui, repo, file1, *pats, **opts):
1300 """output the current or given revision of files
1300 """output the current or given revision of files
1301
1301
1302 Print the specified files as they were at the given revision. If
1302 Print the specified files as they were at the given revision. If
1303 no revision is given, the parent of the working directory is used.
1303 no revision is given, the parent of the working directory is used.
1304
1304
1305 Output may be to a file, in which case the name of the file is
1305 Output may be to a file, in which case the name of the file is
1306 given using a template string. See :hg:`help templates`. In addition
1306 given using a template string. See :hg:`help templates`. In addition
1307 to the common template keywords, the following formatting rules are
1307 to the common template keywords, the following formatting rules are
1308 supported:
1308 supported:
1309
1309
1310 :``%%``: literal "%" character
1310 :``%%``: literal "%" character
1311 :``%s``: basename of file being printed
1311 :``%s``: basename of file being printed
1312 :``%d``: dirname of file being printed, or '.' if in repository root
1312 :``%d``: dirname of file being printed, or '.' if in repository root
1313 :``%p``: root-relative path name of file being printed
1313 :``%p``: root-relative path name of file being printed
1314 :``%H``: changeset hash (40 hexadecimal digits)
1314 :``%H``: changeset hash (40 hexadecimal digits)
1315 :``%R``: changeset revision number
1315 :``%R``: changeset revision number
1316 :``%h``: short-form changeset hash (12 hexadecimal digits)
1316 :``%h``: short-form changeset hash (12 hexadecimal digits)
1317 :``%r``: zero-padded changeset revision number
1317 :``%r``: zero-padded changeset revision number
1318 :``%b``: basename of the exporting repository
1318 :``%b``: basename of the exporting repository
1319 :``\\``: literal "\\" character
1319 :``\\``: literal "\\" character
1320
1320
1321 Returns 0 on success.
1321 Returns 0 on success.
1322 """
1322 """
1323 opts = pycompat.byteskwargs(opts)
1323 opts = pycompat.byteskwargs(opts)
1324 rev = opts.get('rev')
1324 rev = opts.get('rev')
1325 if rev:
1325 if rev:
1326 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1326 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1327 ctx = scmutil.revsingle(repo, rev)
1327 ctx = scmutil.revsingle(repo, rev)
1328 m = scmutil.match(ctx, (file1,) + pats, opts)
1328 m = scmutil.match(ctx, (file1,) + pats, opts)
1329 fntemplate = opts.pop('output', '')
1329 fntemplate = opts.pop('output', '')
1330 if cmdutil.isstdiofilename(fntemplate):
1330 if cmdutil.isstdiofilename(fntemplate):
1331 fntemplate = ''
1331 fntemplate = ''
1332
1332
1333 if fntemplate:
1333 if fntemplate:
1334 fm = formatter.nullformatter(ui, 'cat', opts)
1334 fm = formatter.nullformatter(ui, 'cat', opts)
1335 else:
1335 else:
1336 ui.pager('cat')
1336 ui.pager('cat')
1337 fm = ui.formatter('cat', opts)
1337 fm = ui.formatter('cat', opts)
1338 with fm:
1338 with fm:
1339 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1339 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1340 **pycompat.strkwargs(opts))
1340 **pycompat.strkwargs(opts))
1341
1341
1342 @command('^clone',
1342 @command('^clone',
1343 [('U', 'noupdate', None, _('the clone will include an empty working '
1343 [('U', 'noupdate', None, _('the clone will include an empty working '
1344 'directory (only a repository)')),
1344 'directory (only a repository)')),
1345 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1345 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1346 _('REV')),
1346 _('REV')),
1347 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1347 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1348 ' and its ancestors'), _('REV')),
1348 ' and its ancestors'), _('REV')),
1349 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1349 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1350 ' changesets and their ancestors'), _('BRANCH')),
1350 ' changesets and their ancestors'), _('BRANCH')),
1351 ('', 'pull', None, _('use pull protocol to copy metadata')),
1351 ('', 'pull', None, _('use pull protocol to copy metadata')),
1352 ('', 'uncompressed', None,
1352 ('', 'uncompressed', None,
1353 _('an alias to --stream (DEPRECATED)')),
1353 _('an alias to --stream (DEPRECATED)')),
1354 ('', 'stream', None,
1354 ('', 'stream', None,
1355 _('clone with minimal data processing')),
1355 _('clone with minimal data processing')),
1356 ] + remoteopts,
1356 ] + remoteopts,
1357 _('[OPTION]... SOURCE [DEST]'),
1357 _('[OPTION]... SOURCE [DEST]'),
1358 norepo=True)
1358 norepo=True)
1359 def clone(ui, source, dest=None, **opts):
1359 def clone(ui, source, dest=None, **opts):
1360 """make a copy of an existing repository
1360 """make a copy of an existing repository
1361
1361
1362 Create a copy of an existing repository in a new directory.
1362 Create a copy of an existing repository in a new directory.
1363
1363
1364 If no destination directory name is specified, it defaults to the
1364 If no destination directory name is specified, it defaults to the
1365 basename of the source.
1365 basename of the source.
1366
1366
1367 The location of the source is added to the new repository's
1367 The location of the source is added to the new repository's
1368 ``.hg/hgrc`` file, as the default to be used for future pulls.
1368 ``.hg/hgrc`` file, as the default to be used for future pulls.
1369
1369
1370 Only local paths and ``ssh://`` URLs are supported as
1370 Only local paths and ``ssh://`` URLs are supported as
1371 destinations. For ``ssh://`` destinations, no working directory or
1371 destinations. For ``ssh://`` destinations, no working directory or
1372 ``.hg/hgrc`` will be created on the remote side.
1372 ``.hg/hgrc`` will be created on the remote side.
1373
1373
1374 If the source repository has a bookmark called '@' set, that
1374 If the source repository has a bookmark called '@' set, that
1375 revision will be checked out in the new repository by default.
1375 revision will be checked out in the new repository by default.
1376
1376
1377 To check out a particular version, use -u/--update, or
1377 To check out a particular version, use -u/--update, or
1378 -U/--noupdate to create a clone with no working directory.
1378 -U/--noupdate to create a clone with no working directory.
1379
1379
1380 To pull only a subset of changesets, specify one or more revisions
1380 To pull only a subset of changesets, specify one or more revisions
1381 identifiers with -r/--rev or branches with -b/--branch. The
1381 identifiers with -r/--rev or branches with -b/--branch. The
1382 resulting clone will contain only the specified changesets and
1382 resulting clone will contain only the specified changesets and
1383 their ancestors. These options (or 'clone src#rev dest') imply
1383 their ancestors. These options (or 'clone src#rev dest') imply
1384 --pull, even for local source repositories.
1384 --pull, even for local source repositories.
1385
1385
1386 In normal clone mode, the remote normalizes repository data into a common
1386 In normal clone mode, the remote normalizes repository data into a common
1387 exchange format and the receiving end translates this data into its local
1387 exchange format and the receiving end translates this data into its local
1388 storage format. --stream activates a different clone mode that essentially
1388 storage format. --stream activates a different clone mode that essentially
1389 copies repository files from the remote with minimal data processing. This
1389 copies repository files from the remote with minimal data processing. This
1390 significantly reduces the CPU cost of a clone both remotely and locally.
1390 significantly reduces the CPU cost of a clone both remotely and locally.
1391 However, it often increases the transferred data size by 30-40%. This can
1391 However, it often increases the transferred data size by 30-40%. This can
1392 result in substantially faster clones where I/O throughput is plentiful,
1392 result in substantially faster clones where I/O throughput is plentiful,
1393 especially for larger repositories. A side-effect of --stream clones is
1393 especially for larger repositories. A side-effect of --stream clones is
1394 that storage settings and requirements on the remote are applied locally:
1394 that storage settings and requirements on the remote are applied locally:
1395 a modern client may inherit legacy or inefficient storage used by the
1395 a modern client may inherit legacy or inefficient storage used by the
1396 remote or a legacy Mercurial client may not be able to clone from a
1396 remote or a legacy Mercurial client may not be able to clone from a
1397 modern Mercurial remote.
1397 modern Mercurial remote.
1398
1398
1399 .. note::
1399 .. note::
1400
1400
1401 Specifying a tag will include the tagged changeset but not the
1401 Specifying a tag will include the tagged changeset but not the
1402 changeset containing the tag.
1402 changeset containing the tag.
1403
1403
1404 .. container:: verbose
1404 .. container:: verbose
1405
1405
1406 For efficiency, hardlinks are used for cloning whenever the
1406 For efficiency, hardlinks are used for cloning whenever the
1407 source and destination are on the same filesystem (note this
1407 source and destination are on the same filesystem (note this
1408 applies only to the repository data, not to the working
1408 applies only to the repository data, not to the working
1409 directory). Some filesystems, such as AFS, implement hardlinking
1409 directory). Some filesystems, such as AFS, implement hardlinking
1410 incorrectly, but do not report errors. In these cases, use the
1410 incorrectly, but do not report errors. In these cases, use the
1411 --pull option to avoid hardlinking.
1411 --pull option to avoid hardlinking.
1412
1412
1413 Mercurial will update the working directory to the first applicable
1413 Mercurial will update the working directory to the first applicable
1414 revision from this list:
1414 revision from this list:
1415
1415
1416 a) null if -U or the source repository has no changesets
1416 a) null if -U or the source repository has no changesets
1417 b) if -u . and the source repository is local, the first parent of
1417 b) if -u . and the source repository is local, the first parent of
1418 the source repository's working directory
1418 the source repository's working directory
1419 c) the changeset specified with -u (if a branch name, this means the
1419 c) the changeset specified with -u (if a branch name, this means the
1420 latest head of that branch)
1420 latest head of that branch)
1421 d) the changeset specified with -r
1421 d) the changeset specified with -r
1422 e) the tipmost head specified with -b
1422 e) the tipmost head specified with -b
1423 f) the tipmost head specified with the url#branch source syntax
1423 f) the tipmost head specified with the url#branch source syntax
1424 g) the revision marked with the '@' bookmark, if present
1424 g) the revision marked with the '@' bookmark, if present
1425 h) the tipmost head of the default branch
1425 h) the tipmost head of the default branch
1426 i) tip
1426 i) tip
1427
1427
1428 When cloning from servers that support it, Mercurial may fetch
1428 When cloning from servers that support it, Mercurial may fetch
1429 pre-generated data from a server-advertised URL or inline from the
1429 pre-generated data from a server-advertised URL or inline from the
1430 same stream. When this is done, hooks operating on incoming changesets
1430 same stream. When this is done, hooks operating on incoming changesets
1431 and changegroups may fire more than once, once for each pre-generated
1431 and changegroups may fire more than once, once for each pre-generated
1432 bundle and as well as for any additional remaining data. In addition,
1432 bundle and as well as for any additional remaining data. In addition,
1433 if an error occurs, the repository may be rolled back to a partial
1433 if an error occurs, the repository may be rolled back to a partial
1434 clone. This behavior may change in future releases.
1434 clone. This behavior may change in future releases.
1435 See :hg:`help -e clonebundles` for more.
1435 See :hg:`help -e clonebundles` for more.
1436
1436
1437 Examples:
1437 Examples:
1438
1438
1439 - clone a remote repository to a new directory named hg/::
1439 - clone a remote repository to a new directory named hg/::
1440
1440
1441 hg clone https://www.mercurial-scm.org/repo/hg/
1441 hg clone https://www.mercurial-scm.org/repo/hg/
1442
1442
1443 - create a lightweight local clone::
1443 - create a lightweight local clone::
1444
1444
1445 hg clone project/ project-feature/
1445 hg clone project/ project-feature/
1446
1446
1447 - clone from an absolute path on an ssh server (note double-slash)::
1447 - clone from an absolute path on an ssh server (note double-slash)::
1448
1448
1449 hg clone ssh://user@server//home/projects/alpha/
1449 hg clone ssh://user@server//home/projects/alpha/
1450
1450
1451 - do a streaming clone while checking out a specified version::
1451 - do a streaming clone while checking out a specified version::
1452
1452
1453 hg clone --stream http://server/repo -u 1.5
1453 hg clone --stream http://server/repo -u 1.5
1454
1454
1455 - create a repository without changesets after a particular revision::
1455 - create a repository without changesets after a particular revision::
1456
1456
1457 hg clone -r 04e544 experimental/ good/
1457 hg clone -r 04e544 experimental/ good/
1458
1458
1459 - clone (and track) a particular named branch::
1459 - clone (and track) a particular named branch::
1460
1460
1461 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1461 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1462
1462
1463 See :hg:`help urls` for details on specifying URLs.
1463 See :hg:`help urls` for details on specifying URLs.
1464
1464
1465 Returns 0 on success.
1465 Returns 0 on success.
1466 """
1466 """
1467 opts = pycompat.byteskwargs(opts)
1467 opts = pycompat.byteskwargs(opts)
1468 if opts.get('noupdate') and opts.get('updaterev'):
1468 if opts.get('noupdate') and opts.get('updaterev'):
1469 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1469 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1470
1470
1471 # --include/--exclude can come from narrow or sparse.
1471 # --include/--exclude can come from narrow or sparse.
1472 includepats, excludepats = None, None
1472 includepats, excludepats = None, None
1473
1473
1474 # hg.clone() differentiates between None and an empty set. So make sure
1474 # hg.clone() differentiates between None and an empty set. So make sure
1475 # patterns are sets if narrow is requested without patterns.
1475 # patterns are sets if narrow is requested without patterns.
1476 if opts.get('narrow'):
1476 if opts.get('narrow'):
1477 includepats = set()
1477 includepats = set()
1478 excludepats = set()
1478 excludepats = set()
1479
1479
1480 if opts.get('include'):
1480 if opts.get('include'):
1481 includepats = narrowspec.parsepatterns(opts.get('include'))
1481 includepats = narrowspec.parsepatterns(opts.get('include'))
1482 if opts.get('exclude'):
1482 if opts.get('exclude'):
1483 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1483 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1484
1484
1485 r = hg.clone(ui, opts, source, dest,
1485 r = hg.clone(ui, opts, source, dest,
1486 pull=opts.get('pull'),
1486 pull=opts.get('pull'),
1487 stream=opts.get('stream') or opts.get('uncompressed'),
1487 stream=opts.get('stream') or opts.get('uncompressed'),
1488 revs=opts.get('rev'),
1488 revs=opts.get('rev'),
1489 update=opts.get('updaterev') or not opts.get('noupdate'),
1489 update=opts.get('updaterev') or not opts.get('noupdate'),
1490 branch=opts.get('branch'),
1490 branch=opts.get('branch'),
1491 shareopts=opts.get('shareopts'),
1491 shareopts=opts.get('shareopts'),
1492 storeincludepats=includepats,
1492 storeincludepats=includepats,
1493 storeexcludepats=excludepats)
1493 storeexcludepats=excludepats)
1494
1494
1495 return r is None
1495 return r is None
1496
1496
1497 @command('^commit|ci',
1497 @command('^commit|ci',
1498 [('A', 'addremove', None,
1498 [('A', 'addremove', None,
1499 _('mark new/missing files as added/removed before committing')),
1499 _('mark new/missing files as added/removed before committing')),
1500 ('', 'close-branch', None,
1500 ('', 'close-branch', None,
1501 _('mark a branch head as closed')),
1501 _('mark a branch head as closed')),
1502 ('', 'amend', None, _('amend the parent of the working directory')),
1502 ('', 'amend', None, _('amend the parent of the working directory')),
1503 ('s', 'secret', None, _('use the secret phase for committing')),
1503 ('s', 'secret', None, _('use the secret phase for committing')),
1504 ('e', 'edit', None, _('invoke editor on commit messages')),
1504 ('e', 'edit', None, _('invoke editor on commit messages')),
1505 ('i', 'interactive', None, _('use interactive mode')),
1505 ('i', 'interactive', None, _('use interactive mode')),
1506 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1506 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1507 _('[OPTION]... [FILE]...'),
1507 _('[OPTION]... [FILE]...'),
1508 inferrepo=True)
1508 inferrepo=True)
1509 def commit(ui, repo, *pats, **opts):
1509 def commit(ui, repo, *pats, **opts):
1510 """commit the specified files or all outstanding changes
1510 """commit the specified files or all outstanding changes
1511
1511
1512 Commit changes to the given files into the repository. Unlike a
1512 Commit changes to the given files into the repository. Unlike a
1513 centralized SCM, this operation is a local operation. See
1513 centralized SCM, this operation is a local operation. See
1514 :hg:`push` for a way to actively distribute your changes.
1514 :hg:`push` for a way to actively distribute your changes.
1515
1515
1516 If a list of files is omitted, all changes reported by :hg:`status`
1516 If a list of files is omitted, all changes reported by :hg:`status`
1517 will be committed.
1517 will be committed.
1518
1518
1519 If you are committing the result of a merge, do not provide any
1519 If you are committing the result of a merge, do not provide any
1520 filenames or -I/-X filters.
1520 filenames or -I/-X filters.
1521
1521
1522 If no commit message is specified, Mercurial starts your
1522 If no commit message is specified, Mercurial starts your
1523 configured editor where you can enter a message. In case your
1523 configured editor where you can enter a message. In case your
1524 commit fails, you will find a backup of your message in
1524 commit fails, you will find a backup of your message in
1525 ``.hg/last-message.txt``.
1525 ``.hg/last-message.txt``.
1526
1526
1527 The --close-branch flag can be used to mark the current branch
1527 The --close-branch flag can be used to mark the current branch
1528 head closed. When all heads of a branch are closed, the branch
1528 head closed. When all heads of a branch are closed, the branch
1529 will be considered closed and no longer listed.
1529 will be considered closed and no longer listed.
1530
1530
1531 The --amend flag can be used to amend the parent of the
1531 The --amend flag can be used to amend the parent of the
1532 working directory with a new commit that contains the changes
1532 working directory with a new commit that contains the changes
1533 in the parent in addition to those currently reported by :hg:`status`,
1533 in the parent in addition to those currently reported by :hg:`status`,
1534 if there are any. The old commit is stored in a backup bundle in
1534 if there are any. The old commit is stored in a backup bundle in
1535 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1535 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1536 on how to restore it).
1536 on how to restore it).
1537
1537
1538 Message, user and date are taken from the amended commit unless
1538 Message, user and date are taken from the amended commit unless
1539 specified. When a message isn't specified on the command line,
1539 specified. When a message isn't specified on the command line,
1540 the editor will open with the message of the amended commit.
1540 the editor will open with the message of the amended commit.
1541
1541
1542 It is not possible to amend public changesets (see :hg:`help phases`)
1542 It is not possible to amend public changesets (see :hg:`help phases`)
1543 or changesets that have children.
1543 or changesets that have children.
1544
1544
1545 See :hg:`help dates` for a list of formats valid for -d/--date.
1545 See :hg:`help dates` for a list of formats valid for -d/--date.
1546
1546
1547 Returns 0 on success, 1 if nothing changed.
1547 Returns 0 on success, 1 if nothing changed.
1548
1548
1549 .. container:: verbose
1549 .. container:: verbose
1550
1550
1551 Examples:
1551 Examples:
1552
1552
1553 - commit all files ending in .py::
1553 - commit all files ending in .py::
1554
1554
1555 hg commit --include "set:**.py"
1555 hg commit --include "set:**.py"
1556
1556
1557 - commit all non-binary files::
1557 - commit all non-binary files::
1558
1558
1559 hg commit --exclude "set:binary()"
1559 hg commit --exclude "set:binary()"
1560
1560
1561 - amend the current commit and set the date to now::
1561 - amend the current commit and set the date to now::
1562
1562
1563 hg commit --amend --date now
1563 hg commit --amend --date now
1564 """
1564 """
1565 with repo.wlock(), repo.lock():
1565 with repo.wlock(), repo.lock():
1566 return _docommit(ui, repo, *pats, **opts)
1566 return _docommit(ui, repo, *pats, **opts)
1567
1567
1568 def _docommit(ui, repo, *pats, **opts):
1568 def _docommit(ui, repo, *pats, **opts):
1569 if opts.get(r'interactive'):
1569 if opts.get(r'interactive'):
1570 opts.pop(r'interactive')
1570 opts.pop(r'interactive')
1571 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1571 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1572 cmdutil.recordfilter, *pats,
1572 cmdutil.recordfilter, *pats,
1573 **opts)
1573 **opts)
1574 # ret can be 0 (no changes to record) or the value returned by
1574 # ret can be 0 (no changes to record) or the value returned by
1575 # commit(), 1 if nothing changed or None on success.
1575 # commit(), 1 if nothing changed or None on success.
1576 return 1 if ret == 0 else ret
1576 return 1 if ret == 0 else ret
1577
1577
1578 opts = pycompat.byteskwargs(opts)
1578 opts = pycompat.byteskwargs(opts)
1579 if opts.get('subrepos'):
1579 if opts.get('subrepos'):
1580 if opts.get('amend'):
1580 if opts.get('amend'):
1581 raise error.Abort(_('cannot amend with --subrepos'))
1581 raise error.Abort(_('cannot amend with --subrepos'))
1582 # Let --subrepos on the command line override config setting.
1582 # Let --subrepos on the command line override config setting.
1583 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1583 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1584
1584
1585 cmdutil.checkunfinished(repo, commit=True)
1585 cmdutil.checkunfinished(repo, commit=True)
1586
1586
1587 branch = repo[None].branch()
1587 branch = repo[None].branch()
1588 bheads = repo.branchheads(branch)
1588 bheads = repo.branchheads(branch)
1589
1589
1590 extra = {}
1590 extra = {}
1591 if opts.get('close_branch'):
1591 if opts.get('close_branch'):
1592 extra['close'] = '1'
1592 extra['close'] = '1'
1593
1593
1594 if not bheads:
1594 if not bheads:
1595 raise error.Abort(_('can only close branch heads'))
1595 raise error.Abort(_('can only close branch heads'))
1596 elif opts.get('amend'):
1596 elif opts.get('amend'):
1597 if repo[None].parents()[0].p1().branch() != branch and \
1597 if repo[None].parents()[0].p1().branch() != branch and \
1598 repo[None].parents()[0].p2().branch() != branch:
1598 repo[None].parents()[0].p2().branch() != branch:
1599 raise error.Abort(_('can only close branch heads'))
1599 raise error.Abort(_('can only close branch heads'))
1600
1600
1601 if opts.get('amend'):
1601 if opts.get('amend'):
1602 if ui.configbool('ui', 'commitsubrepos'):
1602 if ui.configbool('ui', 'commitsubrepos'):
1603 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1603 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1604
1604
1605 old = repo['.']
1605 old = repo['.']
1606 rewriteutil.precheck(repo, [old.rev()], 'amend')
1606 rewriteutil.precheck(repo, [old.rev()], 'amend')
1607
1607
1608 # Currently histedit gets confused if an amend happens while histedit
1608 # Currently histedit gets confused if an amend happens while histedit
1609 # is in progress. Since we have a checkunfinished command, we are
1609 # is in progress. Since we have a checkunfinished command, we are
1610 # temporarily honoring it.
1610 # temporarily honoring it.
1611 #
1611 #
1612 # Note: eventually this guard will be removed. Please do not expect
1612 # Note: eventually this guard will be removed. Please do not expect
1613 # this behavior to remain.
1613 # this behavior to remain.
1614 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1614 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1615 cmdutil.checkunfinished(repo)
1615 cmdutil.checkunfinished(repo)
1616
1616
1617 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1617 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1618 if node == old.node():
1618 if node == old.node():
1619 ui.status(_("nothing changed\n"))
1619 ui.status(_("nothing changed\n"))
1620 return 1
1620 return 1
1621 else:
1621 else:
1622 def commitfunc(ui, repo, message, match, opts):
1622 def commitfunc(ui, repo, message, match, opts):
1623 overrides = {}
1623 overrides = {}
1624 if opts.get('secret'):
1624 if opts.get('secret'):
1625 overrides[('phases', 'new-commit')] = 'secret'
1625 overrides[('phases', 'new-commit')] = 'secret'
1626
1626
1627 baseui = repo.baseui
1627 baseui = repo.baseui
1628 with baseui.configoverride(overrides, 'commit'):
1628 with baseui.configoverride(overrides, 'commit'):
1629 with ui.configoverride(overrides, 'commit'):
1629 with ui.configoverride(overrides, 'commit'):
1630 editform = cmdutil.mergeeditform(repo[None],
1630 editform = cmdutil.mergeeditform(repo[None],
1631 'commit.normal')
1631 'commit.normal')
1632 editor = cmdutil.getcommiteditor(
1632 editor = cmdutil.getcommiteditor(
1633 editform=editform, **pycompat.strkwargs(opts))
1633 editform=editform, **pycompat.strkwargs(opts))
1634 return repo.commit(message,
1634 return repo.commit(message,
1635 opts.get('user'),
1635 opts.get('user'),
1636 opts.get('date'),
1636 opts.get('date'),
1637 match,
1637 match,
1638 editor=editor,
1638 editor=editor,
1639 extra=extra)
1639 extra=extra)
1640
1640
1641 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1641 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1642
1642
1643 if not node:
1643 if not node:
1644 stat = cmdutil.postcommitstatus(repo, pats, opts)
1644 stat = cmdutil.postcommitstatus(repo, pats, opts)
1645 if stat[3]:
1645 if stat[3]:
1646 ui.status(_("nothing changed (%d missing files, see "
1646 ui.status(_("nothing changed (%d missing files, see "
1647 "'hg status')\n") % len(stat[3]))
1647 "'hg status')\n") % len(stat[3]))
1648 else:
1648 else:
1649 ui.status(_("nothing changed\n"))
1649 ui.status(_("nothing changed\n"))
1650 return 1
1650 return 1
1651
1651
1652 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1652 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1653
1653
1654 @command('config|showconfig|debugconfig',
1654 @command('config|showconfig|debugconfig',
1655 [('u', 'untrusted', None, _('show untrusted configuration options')),
1655 [('u', 'untrusted', None, _('show untrusted configuration options')),
1656 ('e', 'edit', None, _('edit user config')),
1656 ('e', 'edit', None, _('edit user config')),
1657 ('l', 'local', None, _('edit repository config')),
1657 ('l', 'local', None, _('edit repository config')),
1658 ('g', 'global', None, _('edit global config'))] + formatteropts,
1658 ('g', 'global', None, _('edit global config'))] + formatteropts,
1659 _('[-u] [NAME]...'),
1659 _('[-u] [NAME]...'),
1660 optionalrepo=True,
1660 optionalrepo=True,
1661 intents={INTENT_READONLY})
1661 intents={INTENT_READONLY})
1662 def config(ui, repo, *values, **opts):
1662 def config(ui, repo, *values, **opts):
1663 """show combined config settings from all hgrc files
1663 """show combined config settings from all hgrc files
1664
1664
1665 With no arguments, print names and values of all config items.
1665 With no arguments, print names and values of all config items.
1666
1666
1667 With one argument of the form section.name, print just the value
1667 With one argument of the form section.name, print just the value
1668 of that config item.
1668 of that config item.
1669
1669
1670 With multiple arguments, print names and values of all config
1670 With multiple arguments, print names and values of all config
1671 items with matching section names or section.names.
1671 items with matching section names or section.names.
1672
1672
1673 With --edit, start an editor on the user-level config file. With
1673 With --edit, start an editor on the user-level config file. With
1674 --global, edit the system-wide config file. With --local, edit the
1674 --global, edit the system-wide config file. With --local, edit the
1675 repository-level config file.
1675 repository-level config file.
1676
1676
1677 With --debug, the source (filename and line number) is printed
1677 With --debug, the source (filename and line number) is printed
1678 for each config item.
1678 for each config item.
1679
1679
1680 See :hg:`help config` for more information about config files.
1680 See :hg:`help config` for more information about config files.
1681
1681
1682 Returns 0 on success, 1 if NAME does not exist.
1682 Returns 0 on success, 1 if NAME does not exist.
1683
1683
1684 """
1684 """
1685
1685
1686 opts = pycompat.byteskwargs(opts)
1686 opts = pycompat.byteskwargs(opts)
1687 if opts.get('edit') or opts.get('local') or opts.get('global'):
1687 if opts.get('edit') or opts.get('local') or opts.get('global'):
1688 if opts.get('local') and opts.get('global'):
1688 if opts.get('local') and opts.get('global'):
1689 raise error.Abort(_("can't use --local and --global together"))
1689 raise error.Abort(_("can't use --local and --global together"))
1690
1690
1691 if opts.get('local'):
1691 if opts.get('local'):
1692 if not repo:
1692 if not repo:
1693 raise error.Abort(_("can't use --local outside a repository"))
1693 raise error.Abort(_("can't use --local outside a repository"))
1694 paths = [repo.vfs.join('hgrc')]
1694 paths = [repo.vfs.join('hgrc')]
1695 elif opts.get('global'):
1695 elif opts.get('global'):
1696 paths = rcutil.systemrcpath()
1696 paths = rcutil.systemrcpath()
1697 else:
1697 else:
1698 paths = rcutil.userrcpath()
1698 paths = rcutil.userrcpath()
1699
1699
1700 for f in paths:
1700 for f in paths:
1701 if os.path.exists(f):
1701 if os.path.exists(f):
1702 break
1702 break
1703 else:
1703 else:
1704 if opts.get('global'):
1704 if opts.get('global'):
1705 samplehgrc = uimod.samplehgrcs['global']
1705 samplehgrc = uimod.samplehgrcs['global']
1706 elif opts.get('local'):
1706 elif opts.get('local'):
1707 samplehgrc = uimod.samplehgrcs['local']
1707 samplehgrc = uimod.samplehgrcs['local']
1708 else:
1708 else:
1709 samplehgrc = uimod.samplehgrcs['user']
1709 samplehgrc = uimod.samplehgrcs['user']
1710
1710
1711 f = paths[0]
1711 f = paths[0]
1712 fp = open(f, "wb")
1712 fp = open(f, "wb")
1713 fp.write(util.tonativeeol(samplehgrc))
1713 fp.write(util.tonativeeol(samplehgrc))
1714 fp.close()
1714 fp.close()
1715
1715
1716 editor = ui.geteditor()
1716 editor = ui.geteditor()
1717 ui.system("%s \"%s\"" % (editor, f),
1717 ui.system("%s \"%s\"" % (editor, f),
1718 onerr=error.Abort, errprefix=_("edit failed"),
1718 onerr=error.Abort, errprefix=_("edit failed"),
1719 blockedtag='config_edit')
1719 blockedtag='config_edit')
1720 return
1720 return
1721 ui.pager('config')
1721 ui.pager('config')
1722 fm = ui.formatter('config', opts)
1722 fm = ui.formatter('config', opts)
1723 for t, f in rcutil.rccomponents():
1723 for t, f in rcutil.rccomponents():
1724 if t == 'path':
1724 if t == 'path':
1725 ui.debug('read config from: %s\n' % f)
1725 ui.debug('read config from: %s\n' % f)
1726 elif t == 'items':
1726 elif t == 'items':
1727 for section, name, value, source in f:
1727 for section, name, value, source in f:
1728 ui.debug('set config by: %s\n' % source)
1728 ui.debug('set config by: %s\n' % source)
1729 else:
1729 else:
1730 raise error.ProgrammingError('unknown rctype: %s' % t)
1730 raise error.ProgrammingError('unknown rctype: %s' % t)
1731 untrusted = bool(opts.get('untrusted'))
1731 untrusted = bool(opts.get('untrusted'))
1732
1732
1733 selsections = selentries = []
1733 selsections = selentries = []
1734 if values:
1734 if values:
1735 selsections = [v for v in values if '.' not in v]
1735 selsections = [v for v in values if '.' not in v]
1736 selentries = [v for v in values if '.' in v]
1736 selentries = [v for v in values if '.' in v]
1737 uniquesel = (len(selentries) == 1 and not selsections)
1737 uniquesel = (len(selentries) == 1 and not selsections)
1738 selsections = set(selsections)
1738 selsections = set(selsections)
1739 selentries = set(selentries)
1739 selentries = set(selentries)
1740
1740
1741 matched = False
1741 matched = False
1742 for section, name, value in ui.walkconfig(untrusted=untrusted):
1742 for section, name, value in ui.walkconfig(untrusted=untrusted):
1743 source = ui.configsource(section, name, untrusted)
1743 source = ui.configsource(section, name, untrusted)
1744 value = pycompat.bytestr(value)
1744 value = pycompat.bytestr(value)
1745 if fm.isplain():
1745 if fm.isplain():
1746 source = source or 'none'
1746 source = source or 'none'
1747 value = value.replace('\n', '\\n')
1747 value = value.replace('\n', '\\n')
1748 entryname = section + '.' + name
1748 entryname = section + '.' + name
1749 if values and not (section in selsections or entryname in selentries):
1749 if values and not (section in selsections or entryname in selentries):
1750 continue
1750 continue
1751 fm.startitem()
1751 fm.startitem()
1752 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1752 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1753 if uniquesel:
1753 if uniquesel:
1754 fm.data(name=entryname)
1754 fm.data(name=entryname)
1755 fm.write('value', '%s\n', value)
1755 fm.write('value', '%s\n', value)
1756 else:
1756 else:
1757 fm.write('name value', '%s=%s\n', entryname, value)
1757 fm.write('name value', '%s=%s\n', entryname, value)
1758 matched = True
1758 matched = True
1759 fm.end()
1759 fm.end()
1760 if matched:
1760 if matched:
1761 return 0
1761 return 0
1762 return 1
1762 return 1
1763
1763
1764 @command('copy|cp',
1764 @command('copy|cp',
1765 [('A', 'after', None, _('record a copy that has already occurred')),
1765 [('A', 'after', None, _('record a copy that has already occurred')),
1766 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1766 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1767 ] + walkopts + dryrunopts,
1767 ] + walkopts + dryrunopts,
1768 _('[OPTION]... [SOURCE]... DEST'))
1768 _('[OPTION]... [SOURCE]... DEST'))
1769 def copy(ui, repo, *pats, **opts):
1769 def copy(ui, repo, *pats, **opts):
1770 """mark files as copied for the next commit
1770 """mark files as copied for the next commit
1771
1771
1772 Mark dest as having copies of source files. If dest is a
1772 Mark dest as having copies of source files. If dest is a
1773 directory, copies are put in that directory. If dest is a file,
1773 directory, copies are put in that directory. If dest is a file,
1774 the source must be a single file.
1774 the source must be a single file.
1775
1775
1776 By default, this command copies the contents of files as they
1776 By default, this command copies the contents of files as they
1777 exist in the working directory. If invoked with -A/--after, the
1777 exist in the working directory. If invoked with -A/--after, the
1778 operation is recorded, but no copying is performed.
1778 operation is recorded, but no copying is performed.
1779
1779
1780 This command takes effect with the next commit. To undo a copy
1780 This command takes effect with the next commit. To undo a copy
1781 before that, see :hg:`revert`.
1781 before that, see :hg:`revert`.
1782
1782
1783 Returns 0 on success, 1 if errors are encountered.
1783 Returns 0 on success, 1 if errors are encountered.
1784 """
1784 """
1785 opts = pycompat.byteskwargs(opts)
1785 opts = pycompat.byteskwargs(opts)
1786 with repo.wlock(False):
1786 with repo.wlock(False):
1787 return cmdutil.copy(ui, repo, pats, opts)
1787 return cmdutil.copy(ui, repo, pats, opts)
1788
1788
1789 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1789 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1790 def debugcommands(ui, cmd='', *args):
1790 def debugcommands(ui, cmd='', *args):
1791 """list all available commands and options"""
1791 """list all available commands and options"""
1792 for cmd, vals in sorted(table.iteritems()):
1792 for cmd, vals in sorted(table.iteritems()):
1793 cmd = cmd.split('|')[0].strip('^')
1793 cmd = cmd.split('|')[0].strip('^')
1794 opts = ', '.join([i[1] for i in vals[1]])
1794 opts = ', '.join([i[1] for i in vals[1]])
1795 ui.write('%s: %s\n' % (cmd, opts))
1795 ui.write('%s: %s\n' % (cmd, opts))
1796
1796
1797 @command('debugcomplete',
1797 @command('debugcomplete',
1798 [('o', 'options', None, _('show the command options'))],
1798 [('o', 'options', None, _('show the command options'))],
1799 _('[-o] CMD'),
1799 _('[-o] CMD'),
1800 norepo=True)
1800 norepo=True)
1801 def debugcomplete(ui, cmd='', **opts):
1801 def debugcomplete(ui, cmd='', **opts):
1802 """returns the completion list associated with the given command"""
1802 """returns the completion list associated with the given command"""
1803
1803
1804 if opts.get(r'options'):
1804 if opts.get(r'options'):
1805 options = []
1805 options = []
1806 otables = [globalopts]
1806 otables = [globalopts]
1807 if cmd:
1807 if cmd:
1808 aliases, entry = cmdutil.findcmd(cmd, table, False)
1808 aliases, entry = cmdutil.findcmd(cmd, table, False)
1809 otables.append(entry[1])
1809 otables.append(entry[1])
1810 for t in otables:
1810 for t in otables:
1811 for o in t:
1811 for o in t:
1812 if "(DEPRECATED)" in o[3]:
1812 if "(DEPRECATED)" in o[3]:
1813 continue
1813 continue
1814 if o[0]:
1814 if o[0]:
1815 options.append('-%s' % o[0])
1815 options.append('-%s' % o[0])
1816 options.append('--%s' % o[1])
1816 options.append('--%s' % o[1])
1817 ui.write("%s\n" % "\n".join(options))
1817 ui.write("%s\n" % "\n".join(options))
1818 return
1818 return
1819
1819
1820 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1820 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1821 if ui.verbose:
1821 if ui.verbose:
1822 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1822 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1823 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1823 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1824
1824
1825 @command('^diff',
1825 @command('^diff',
1826 [('r', 'rev', [], _('revision'), _('REV')),
1826 [('r', 'rev', [], _('revision'), _('REV')),
1827 ('c', 'change', '', _('change made by revision'), _('REV'))
1827 ('c', 'change', '', _('change made by revision'), _('REV'))
1828 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1828 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1829 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1829 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1830 inferrepo=True,
1830 inferrepo=True,
1831 intents={INTENT_READONLY})
1831 intents={INTENT_READONLY})
1832 def diff(ui, repo, *pats, **opts):
1832 def diff(ui, repo, *pats, **opts):
1833 """diff repository (or selected files)
1833 """diff repository (or selected files)
1834
1834
1835 Show differences between revisions for the specified files.
1835 Show differences between revisions for the specified files.
1836
1836
1837 Differences between files are shown using the unified diff format.
1837 Differences between files are shown using the unified diff format.
1838
1838
1839 .. note::
1839 .. note::
1840
1840
1841 :hg:`diff` may generate unexpected results for merges, as it will
1841 :hg:`diff` may generate unexpected results for merges, as it will
1842 default to comparing against the working directory's first
1842 default to comparing against the working directory's first
1843 parent changeset if no revisions are specified.
1843 parent changeset if no revisions are specified.
1844
1844
1845 When two revision arguments are given, then changes are shown
1845 When two revision arguments are given, then changes are shown
1846 between those revisions. If only one revision is specified then
1846 between those revisions. If only one revision is specified then
1847 that revision is compared to the working directory, and, when no
1847 that revision is compared to the working directory, and, when no
1848 revisions are specified, the working directory files are compared
1848 revisions are specified, the working directory files are compared
1849 to its first parent.
1849 to its first parent.
1850
1850
1851 Alternatively you can specify -c/--change with a revision to see
1851 Alternatively you can specify -c/--change with a revision to see
1852 the changes in that changeset relative to its first parent.
1852 the changes in that changeset relative to its first parent.
1853
1853
1854 Without the -a/--text option, diff will avoid generating diffs of
1854 Without the -a/--text option, diff will avoid generating diffs of
1855 files it detects as binary. With -a, diff will generate a diff
1855 files it detects as binary. With -a, diff will generate a diff
1856 anyway, probably with undesirable results.
1856 anyway, probably with undesirable results.
1857
1857
1858 Use the -g/--git option to generate diffs in the git extended diff
1858 Use the -g/--git option to generate diffs in the git extended diff
1859 format. For more information, read :hg:`help diffs`.
1859 format. For more information, read :hg:`help diffs`.
1860
1860
1861 .. container:: verbose
1861 .. container:: verbose
1862
1862
1863 Examples:
1863 Examples:
1864
1864
1865 - compare a file in the current working directory to its parent::
1865 - compare a file in the current working directory to its parent::
1866
1866
1867 hg diff foo.c
1867 hg diff foo.c
1868
1868
1869 - compare two historical versions of a directory, with rename info::
1869 - compare two historical versions of a directory, with rename info::
1870
1870
1871 hg diff --git -r 1.0:1.2 lib/
1871 hg diff --git -r 1.0:1.2 lib/
1872
1872
1873 - get change stats relative to the last change on some date::
1873 - get change stats relative to the last change on some date::
1874
1874
1875 hg diff --stat -r "date('may 2')"
1875 hg diff --stat -r "date('may 2')"
1876
1876
1877 - diff all newly-added files that contain a keyword::
1877 - diff all newly-added files that contain a keyword::
1878
1878
1879 hg diff "set:added() and grep(GNU)"
1879 hg diff "set:added() and grep(GNU)"
1880
1880
1881 - compare a revision and its parents::
1881 - compare a revision and its parents::
1882
1882
1883 hg diff -c 9353 # compare against first parent
1883 hg diff -c 9353 # compare against first parent
1884 hg diff -r 9353^:9353 # same using revset syntax
1884 hg diff -r 9353^:9353 # same using revset syntax
1885 hg diff -r 9353^2:9353 # compare against the second parent
1885 hg diff -r 9353^2:9353 # compare against the second parent
1886
1886
1887 Returns 0 on success.
1887 Returns 0 on success.
1888 """
1888 """
1889
1889
1890 opts = pycompat.byteskwargs(opts)
1890 opts = pycompat.byteskwargs(opts)
1891 revs = opts.get('rev')
1891 revs = opts.get('rev')
1892 change = opts.get('change')
1892 change = opts.get('change')
1893 stat = opts.get('stat')
1893 stat = opts.get('stat')
1894 reverse = opts.get('reverse')
1894 reverse = opts.get('reverse')
1895
1895
1896 if revs and change:
1896 if revs and change:
1897 msg = _('cannot specify --rev and --change at the same time')
1897 msg = _('cannot specify --rev and --change at the same time')
1898 raise error.Abort(msg)
1898 raise error.Abort(msg)
1899 elif change:
1899 elif change:
1900 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1900 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1901 ctx2 = scmutil.revsingle(repo, change, None)
1901 ctx2 = scmutil.revsingle(repo, change, None)
1902 ctx1 = ctx2.p1()
1902 ctx1 = ctx2.p1()
1903 else:
1903 else:
1904 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1904 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1905 ctx1, ctx2 = scmutil.revpair(repo, revs)
1905 ctx1, ctx2 = scmutil.revpair(repo, revs)
1906 node1, node2 = ctx1.node(), ctx2.node()
1906 node1, node2 = ctx1.node(), ctx2.node()
1907
1907
1908 if reverse:
1908 if reverse:
1909 node1, node2 = node2, node1
1909 node1, node2 = node2, node1
1910
1910
1911 diffopts = patch.diffallopts(ui, opts)
1911 diffopts = patch.diffallopts(ui, opts)
1912 m = scmutil.match(ctx2, pats, opts)
1912 m = scmutil.match(ctx2, pats, opts)
1913 m = matchmod.intersectmatchers(m, repo.narrowmatch())
1913 m = matchmod.intersectmatchers(m, repo.narrowmatch())
1914 ui.pager('diff')
1914 ui.pager('diff')
1915 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1915 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1916 listsubrepos=opts.get('subrepos'),
1916 listsubrepos=opts.get('subrepos'),
1917 root=opts.get('root'))
1917 root=opts.get('root'))
1918
1918
1919 @command('^export',
1919 @command('^export',
1920 [('B', 'bookmark', '',
1920 [('B', 'bookmark', '',
1921 _('export changes only reachable by given bookmark')),
1921 _('export changes only reachable by given bookmark')),
1922 ('o', 'output', '',
1922 ('o', 'output', '',
1923 _('print output to file with formatted name'), _('FORMAT')),
1923 _('print output to file with formatted name'), _('FORMAT')),
1924 ('', 'switch-parent', None, _('diff against the second parent')),
1924 ('', 'switch-parent', None, _('diff against the second parent')),
1925 ('r', 'rev', [], _('revisions to export'), _('REV')),
1925 ('r', 'rev', [], _('revisions to export'), _('REV')),
1926 ] + diffopts + formatteropts,
1926 ] + diffopts + formatteropts,
1927 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1927 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1928 intents={INTENT_READONLY})
1928 intents={INTENT_READONLY})
1929 def export(ui, repo, *changesets, **opts):
1929 def export(ui, repo, *changesets, **opts):
1930 """dump the header and diffs for one or more changesets
1930 """dump the header and diffs for one or more changesets
1931
1931
1932 Print the changeset header and diffs for one or more revisions.
1932 Print the changeset header and diffs for one or more revisions.
1933 If no revision is given, the parent of the working directory is used.
1933 If no revision is given, the parent of the working directory is used.
1934
1934
1935 The information shown in the changeset header is: author, date,
1935 The information shown in the changeset header is: author, date,
1936 branch name (if non-default), changeset hash, parent(s) and commit
1936 branch name (if non-default), changeset hash, parent(s) and commit
1937 comment.
1937 comment.
1938
1938
1939 .. note::
1939 .. note::
1940
1940
1941 :hg:`export` may generate unexpected diff output for merge
1941 :hg:`export` may generate unexpected diff output for merge
1942 changesets, as it will compare the merge changeset against its
1942 changesets, as it will compare the merge changeset against its
1943 first parent only.
1943 first parent only.
1944
1944
1945 Output may be to a file, in which case the name of the file is
1945 Output may be to a file, in which case the name of the file is
1946 given using a template string. See :hg:`help templates`. In addition
1946 given using a template string. See :hg:`help templates`. In addition
1947 to the common template keywords, the following formatting rules are
1947 to the common template keywords, the following formatting rules are
1948 supported:
1948 supported:
1949
1949
1950 :``%%``: literal "%" character
1950 :``%%``: literal "%" character
1951 :``%H``: changeset hash (40 hexadecimal digits)
1951 :``%H``: changeset hash (40 hexadecimal digits)
1952 :``%N``: number of patches being generated
1952 :``%N``: number of patches being generated
1953 :``%R``: changeset revision number
1953 :``%R``: changeset revision number
1954 :``%b``: basename of the exporting repository
1954 :``%b``: basename of the exporting repository
1955 :``%h``: short-form changeset hash (12 hexadecimal digits)
1955 :``%h``: short-form changeset hash (12 hexadecimal digits)
1956 :``%m``: first line of the commit message (only alphanumeric characters)
1956 :``%m``: first line of the commit message (only alphanumeric characters)
1957 :``%n``: zero-padded sequence number, starting at 1
1957 :``%n``: zero-padded sequence number, starting at 1
1958 :``%r``: zero-padded changeset revision number
1958 :``%r``: zero-padded changeset revision number
1959 :``\\``: literal "\\" character
1959 :``\\``: literal "\\" character
1960
1960
1961 Without the -a/--text option, export will avoid generating diffs
1961 Without the -a/--text option, export will avoid generating diffs
1962 of files it detects as binary. With -a, export will generate a
1962 of files it detects as binary. With -a, export will generate a
1963 diff anyway, probably with undesirable results.
1963 diff anyway, probably with undesirable results.
1964
1964
1965 With -B/--bookmark changesets reachable by the given bookmark are
1965 With -B/--bookmark changesets reachable by the given bookmark are
1966 selected.
1966 selected.
1967
1967
1968 Use the -g/--git option to generate diffs in the git extended diff
1968 Use the -g/--git option to generate diffs in the git extended diff
1969 format. See :hg:`help diffs` for more information.
1969 format. See :hg:`help diffs` for more information.
1970
1970
1971 With the --switch-parent option, the diff will be against the
1971 With the --switch-parent option, the diff will be against the
1972 second parent. It can be useful to review a merge.
1972 second parent. It can be useful to review a merge.
1973
1973
1974 .. container:: verbose
1974 .. container:: verbose
1975
1975
1976 Examples:
1976 Examples:
1977
1977
1978 - use export and import to transplant a bugfix to the current
1978 - use export and import to transplant a bugfix to the current
1979 branch::
1979 branch::
1980
1980
1981 hg export -r 9353 | hg import -
1981 hg export -r 9353 | hg import -
1982
1982
1983 - export all the changesets between two revisions to a file with
1983 - export all the changesets between two revisions to a file with
1984 rename information::
1984 rename information::
1985
1985
1986 hg export --git -r 123:150 > changes.txt
1986 hg export --git -r 123:150 > changes.txt
1987
1987
1988 - split outgoing changes into a series of patches with
1988 - split outgoing changes into a series of patches with
1989 descriptive names::
1989 descriptive names::
1990
1990
1991 hg export -r "outgoing()" -o "%n-%m.patch"
1991 hg export -r "outgoing()" -o "%n-%m.patch"
1992
1992
1993 Returns 0 on success.
1993 Returns 0 on success.
1994 """
1994 """
1995 opts = pycompat.byteskwargs(opts)
1995 opts = pycompat.byteskwargs(opts)
1996 bookmark = opts.get('bookmark')
1996 bookmark = opts.get('bookmark')
1997 changesets += tuple(opts.get('rev', []))
1997 changesets += tuple(opts.get('rev', []))
1998
1998
1999 if bookmark and changesets:
1999 if bookmark and changesets:
2000 raise error.Abort(_("-r and -B are mutually exclusive"))
2000 raise error.Abort(_("-r and -B are mutually exclusive"))
2001
2001
2002 if bookmark:
2002 if bookmark:
2003 if bookmark not in repo._bookmarks:
2003 if bookmark not in repo._bookmarks:
2004 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2004 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2005
2005
2006 revs = scmutil.bookmarkrevs(repo, bookmark)
2006 revs = scmutil.bookmarkrevs(repo, bookmark)
2007 else:
2007 else:
2008 if not changesets:
2008 if not changesets:
2009 changesets = ['.']
2009 changesets = ['.']
2010
2010
2011 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2011 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2012 revs = scmutil.revrange(repo, changesets)
2012 revs = scmutil.revrange(repo, changesets)
2013
2013
2014 if not revs:
2014 if not revs:
2015 raise error.Abort(_("export requires at least one changeset"))
2015 raise error.Abort(_("export requires at least one changeset"))
2016 if len(revs) > 1:
2016 if len(revs) > 1:
2017 ui.note(_('exporting patches:\n'))
2017 ui.note(_('exporting patches:\n'))
2018 else:
2018 else:
2019 ui.note(_('exporting patch:\n'))
2019 ui.note(_('exporting patch:\n'))
2020
2020
2021 fntemplate = opts.get('output')
2021 fntemplate = opts.get('output')
2022 if cmdutil.isstdiofilename(fntemplate):
2022 if cmdutil.isstdiofilename(fntemplate):
2023 fntemplate = ''
2023 fntemplate = ''
2024
2024
2025 if fntemplate:
2025 if fntemplate:
2026 fm = formatter.nullformatter(ui, 'export', opts)
2026 fm = formatter.nullformatter(ui, 'export', opts)
2027 else:
2027 else:
2028 ui.pager('export')
2028 ui.pager('export')
2029 fm = ui.formatter('export', opts)
2029 fm = ui.formatter('export', opts)
2030 with fm:
2030 with fm:
2031 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2031 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2032 switch_parent=opts.get('switch_parent'),
2032 switch_parent=opts.get('switch_parent'),
2033 opts=patch.diffallopts(ui, opts))
2033 opts=patch.diffallopts(ui, opts))
2034
2034
2035 @command('files',
2035 @command('files',
2036 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2036 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2037 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2037 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2038 ] + walkopts + formatteropts + subrepoopts,
2038 ] + walkopts + formatteropts + subrepoopts,
2039 _('[OPTION]... [FILE]...'),
2039 _('[OPTION]... [FILE]...'),
2040 intents={INTENT_READONLY})
2040 intents={INTENT_READONLY})
2041 def files(ui, repo, *pats, **opts):
2041 def files(ui, repo, *pats, **opts):
2042 """list tracked files
2042 """list tracked files
2043
2043
2044 Print files under Mercurial control in the working directory or
2044 Print files under Mercurial control in the working directory or
2045 specified revision for given files (excluding removed files).
2045 specified revision for given files (excluding removed files).
2046 Files can be specified as filenames or filesets.
2046 Files can be specified as filenames or filesets.
2047
2047
2048 If no files are given to match, this command prints the names
2048 If no files are given to match, this command prints the names
2049 of all files under Mercurial control.
2049 of all files under Mercurial control.
2050
2050
2051 .. container:: verbose
2051 .. container:: verbose
2052
2052
2053 Examples:
2053 Examples:
2054
2054
2055 - list all files under the current directory::
2055 - list all files under the current directory::
2056
2056
2057 hg files .
2057 hg files .
2058
2058
2059 - shows sizes and flags for current revision::
2059 - shows sizes and flags for current revision::
2060
2060
2061 hg files -vr .
2061 hg files -vr .
2062
2062
2063 - list all files named README::
2063 - list all files named README::
2064
2064
2065 hg files -I "**/README"
2065 hg files -I "**/README"
2066
2066
2067 - list all binary files::
2067 - list all binary files::
2068
2068
2069 hg files "set:binary()"
2069 hg files "set:binary()"
2070
2070
2071 - find files containing a regular expression::
2071 - find files containing a regular expression::
2072
2072
2073 hg files "set:grep('bob')"
2073 hg files "set:grep('bob')"
2074
2074
2075 - search tracked file contents with xargs and grep::
2075 - search tracked file contents with xargs and grep::
2076
2076
2077 hg files -0 | xargs -0 grep foo
2077 hg files -0 | xargs -0 grep foo
2078
2078
2079 See :hg:`help patterns` and :hg:`help filesets` for more information
2079 See :hg:`help patterns` and :hg:`help filesets` for more information
2080 on specifying file patterns.
2080 on specifying file patterns.
2081
2081
2082 Returns 0 if a match is found, 1 otherwise.
2082 Returns 0 if a match is found, 1 otherwise.
2083
2083
2084 """
2084 """
2085
2085
2086 opts = pycompat.byteskwargs(opts)
2086 opts = pycompat.byteskwargs(opts)
2087 rev = opts.get('rev')
2087 rev = opts.get('rev')
2088 if rev:
2088 if rev:
2089 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2089 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2090 ctx = scmutil.revsingle(repo, rev, None)
2090 ctx = scmutil.revsingle(repo, rev, None)
2091
2091
2092 end = '\n'
2092 end = '\n'
2093 if opts.get('print0'):
2093 if opts.get('print0'):
2094 end = '\0'
2094 end = '\0'
2095 fmt = '%s' + end
2095 fmt = '%s' + end
2096
2096
2097 m = scmutil.match(ctx, pats, opts)
2097 m = scmutil.match(ctx, pats, opts)
2098 ui.pager('files')
2098 ui.pager('files')
2099 with ui.formatter('files', opts) as fm:
2099 with ui.formatter('files', opts) as fm:
2100 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2100 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2101
2101
2102 @command(
2102 @command(
2103 '^forget',
2103 '^forget',
2104 [('i', 'interactive', None, _('use interactive mode')),
2104 [('i', 'interactive', None, _('use interactive mode')),
2105 ] + walkopts + dryrunopts,
2105 ] + walkopts + dryrunopts,
2106 _('[OPTION]... FILE...'), inferrepo=True)
2106 _('[OPTION]... FILE...'), inferrepo=True)
2107 def forget(ui, repo, *pats, **opts):
2107 def forget(ui, repo, *pats, **opts):
2108 """forget the specified files on the next commit
2108 """forget the specified files on the next commit
2109
2109
2110 Mark the specified files so they will no longer be tracked
2110 Mark the specified files so they will no longer be tracked
2111 after the next commit.
2111 after the next commit.
2112
2112
2113 This only removes files from the current branch, not from the
2113 This only removes files from the current branch, not from the
2114 entire project history, and it does not delete them from the
2114 entire project history, and it does not delete them from the
2115 working directory.
2115 working directory.
2116
2116
2117 To delete the file from the working directory, see :hg:`remove`.
2117 To delete the file from the working directory, see :hg:`remove`.
2118
2118
2119 To undo a forget before the next commit, see :hg:`add`.
2119 To undo a forget before the next commit, see :hg:`add`.
2120
2120
2121 .. container:: verbose
2121 .. container:: verbose
2122
2122
2123 Examples:
2123 Examples:
2124
2124
2125 - forget newly-added binary files::
2125 - forget newly-added binary files::
2126
2126
2127 hg forget "set:added() and binary()"
2127 hg forget "set:added() and binary()"
2128
2128
2129 - forget files that would be excluded by .hgignore::
2129 - forget files that would be excluded by .hgignore::
2130
2130
2131 hg forget "set:hgignore()"
2131 hg forget "set:hgignore()"
2132
2132
2133 Returns 0 on success.
2133 Returns 0 on success.
2134 """
2134 """
2135
2135
2136 opts = pycompat.byteskwargs(opts)
2136 opts = pycompat.byteskwargs(opts)
2137 if not pats:
2137 if not pats:
2138 raise error.Abort(_('no files specified'))
2138 raise error.Abort(_('no files specified'))
2139
2139
2140 m = scmutil.match(repo[None], pats, opts)
2140 m = scmutil.match(repo[None], pats, opts)
2141 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2141 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2142 rejected = cmdutil.forget(ui, repo, m, prefix="",
2142 rejected = cmdutil.forget(ui, repo, m, prefix="",
2143 explicitonly=False, dryrun=dryrun,
2143 explicitonly=False, dryrun=dryrun,
2144 interactive=interactive)[0]
2144 interactive=interactive)[0]
2145 return rejected and 1 or 0
2145 return rejected and 1 or 0
2146
2146
2147 @command(
2147 @command(
2148 'graft',
2148 'graft',
2149 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2149 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2150 ('c', 'continue', False, _('resume interrupted graft')),
2150 ('c', 'continue', False, _('resume interrupted graft')),
2151 ('', 'stop', False, _('stop interrupted graft')),
2151 ('', 'stop', False, _('stop interrupted graft')),
2152 ('', 'abort', False, _('abort interrupted graft')),
2152 ('', 'abort', False, _('abort interrupted graft')),
2153 ('e', 'edit', False, _('invoke editor on commit messages')),
2153 ('e', 'edit', False, _('invoke editor on commit messages')),
2154 ('', 'log', None, _('append graft info to log message')),
2154 ('', 'log', None, _('append graft info to log message')),
2155 ('', 'no-commit', None,
2155 ('', 'no-commit', None,
2156 _("don't commit, just apply the changes in working directory")),
2156 _("don't commit, just apply the changes in working directory")),
2157 ('f', 'force', False, _('force graft')),
2157 ('f', 'force', False, _('force graft')),
2158 ('D', 'currentdate', False,
2158 ('D', 'currentdate', False,
2159 _('record the current date as commit date')),
2159 _('record the current date as commit date')),
2160 ('U', 'currentuser', False,
2160 ('U', 'currentuser', False,
2161 _('record the current user as committer'), _('DATE'))]
2161 _('record the current user as committer'), _('DATE'))]
2162 + commitopts2 + mergetoolopts + dryrunopts,
2162 + commitopts2 + mergetoolopts + dryrunopts,
2163 _('[OPTION]... [-r REV]... REV...'))
2163 _('[OPTION]... [-r REV]... REV...'))
2164 def graft(ui, repo, *revs, **opts):
2164 def graft(ui, repo, *revs, **opts):
2165 '''copy changes from other branches onto the current branch
2165 '''copy changes from other branches onto the current branch
2166
2166
2167 This command uses Mercurial's merge logic to copy individual
2167 This command uses Mercurial's merge logic to copy individual
2168 changes from other branches without merging branches in the
2168 changes from other branches without merging branches in the
2169 history graph. This is sometimes known as 'backporting' or
2169 history graph. This is sometimes known as 'backporting' or
2170 'cherry-picking'. By default, graft will copy user, date, and
2170 'cherry-picking'. By default, graft will copy user, date, and
2171 description from the source changesets.
2171 description from the source changesets.
2172
2172
2173 Changesets that are ancestors of the current revision, that have
2173 Changesets that are ancestors of the current revision, that have
2174 already been grafted, or that are merges will be skipped.
2174 already been grafted, or that are merges will be skipped.
2175
2175
2176 If --log is specified, log messages will have a comment appended
2176 If --log is specified, log messages will have a comment appended
2177 of the form::
2177 of the form::
2178
2178
2179 (grafted from CHANGESETHASH)
2179 (grafted from CHANGESETHASH)
2180
2180
2181 If --force is specified, revisions will be grafted even if they
2181 If --force is specified, revisions will be grafted even if they
2182 are already ancestors of, or have been grafted to, the destination.
2182 are already ancestors of, or have been grafted to, the destination.
2183 This is useful when the revisions have since been backed out.
2183 This is useful when the revisions have since been backed out.
2184
2184
2185 If a graft merge results in conflicts, the graft process is
2185 If a graft merge results in conflicts, the graft process is
2186 interrupted so that the current merge can be manually resolved.
2186 interrupted so that the current merge can be manually resolved.
2187 Once all conflicts are addressed, the graft process can be
2187 Once all conflicts are addressed, the graft process can be
2188 continued with the -c/--continue option.
2188 continued with the -c/--continue option.
2189
2189
2190 The -c/--continue option reapplies all the earlier options.
2190 The -c/--continue option reapplies all the earlier options.
2191
2191
2192 .. container:: verbose
2192 .. container:: verbose
2193
2193
2194 Examples:
2194 Examples:
2195
2195
2196 - copy a single change to the stable branch and edit its description::
2196 - copy a single change to the stable branch and edit its description::
2197
2197
2198 hg update stable
2198 hg update stable
2199 hg graft --edit 9393
2199 hg graft --edit 9393
2200
2200
2201 - graft a range of changesets with one exception, updating dates::
2201 - graft a range of changesets with one exception, updating dates::
2202
2202
2203 hg graft -D "2085::2093 and not 2091"
2203 hg graft -D "2085::2093 and not 2091"
2204
2204
2205 - continue a graft after resolving conflicts::
2205 - continue a graft after resolving conflicts::
2206
2206
2207 hg graft -c
2207 hg graft -c
2208
2208
2209 - show the source of a grafted changeset::
2209 - show the source of a grafted changeset::
2210
2210
2211 hg log --debug -r .
2211 hg log --debug -r .
2212
2212
2213 - show revisions sorted by date::
2213 - show revisions sorted by date::
2214
2214
2215 hg log -r "sort(all(), date)"
2215 hg log -r "sort(all(), date)"
2216
2216
2217 See :hg:`help revisions` for more about specifying revisions.
2217 See :hg:`help revisions` for more about specifying revisions.
2218
2218
2219 Returns 0 on successful completion.
2219 Returns 0 on successful completion.
2220 '''
2220 '''
2221 with repo.wlock():
2221 with repo.wlock():
2222 return _dograft(ui, repo, *revs, **opts)
2222 return _dograft(ui, repo, *revs, **opts)
2223
2223
2224 def _dograft(ui, repo, *revs, **opts):
2224 def _dograft(ui, repo, *revs, **opts):
2225 opts = pycompat.byteskwargs(opts)
2225 opts = pycompat.byteskwargs(opts)
2226 if revs and opts.get('rev'):
2226 if revs and opts.get('rev'):
2227 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2227 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2228 'revision ordering!\n'))
2228 'revision ordering!\n'))
2229
2229
2230 revs = list(revs)
2230 revs = list(revs)
2231 revs.extend(opts.get('rev'))
2231 revs.extend(opts.get('rev'))
2232 # a dict of data to be stored in state file
2232 # a dict of data to be stored in state file
2233 statedata = {}
2233 statedata = {}
2234 # list of new nodes created by ongoing graft
2234 # list of new nodes created by ongoing graft
2235 statedata['newnodes'] = []
2235 statedata['newnodes'] = []
2236
2236
2237 if not opts.get('user') and opts.get('currentuser'):
2237 if not opts.get('user') and opts.get('currentuser'):
2238 opts['user'] = ui.username()
2238 opts['user'] = ui.username()
2239 if not opts.get('date') and opts.get('currentdate'):
2239 if not opts.get('date') and opts.get('currentdate'):
2240 opts['date'] = "%d %d" % dateutil.makedate()
2240 opts['date'] = "%d %d" % dateutil.makedate()
2241
2241
2242 editor = cmdutil.getcommiteditor(editform='graft',
2242 editor = cmdutil.getcommiteditor(editform='graft',
2243 **pycompat.strkwargs(opts))
2243 **pycompat.strkwargs(opts))
2244
2244
2245 cont = False
2245 cont = False
2246 if opts.get('no_commit'):
2246 if opts.get('no_commit'):
2247 if opts.get('edit'):
2247 if opts.get('edit'):
2248 raise error.Abort(_("cannot specify --no-commit and "
2248 raise error.Abort(_("cannot specify --no-commit and "
2249 "--edit together"))
2249 "--edit together"))
2250 if opts.get('currentuser'):
2250 if opts.get('currentuser'):
2251 raise error.Abort(_("cannot specify --no-commit and "
2251 raise error.Abort(_("cannot specify --no-commit and "
2252 "--currentuser together"))
2252 "--currentuser together"))
2253 if opts.get('currentdate'):
2253 if opts.get('currentdate'):
2254 raise error.Abort(_("cannot specify --no-commit and "
2254 raise error.Abort(_("cannot specify --no-commit and "
2255 "--currentdate together"))
2255 "--currentdate together"))
2256 if opts.get('log'):
2256 if opts.get('log'):
2257 raise error.Abort(_("cannot specify --no-commit and "
2257 raise error.Abort(_("cannot specify --no-commit and "
2258 "--log together"))
2258 "--log together"))
2259
2259
2260 graftstate = statemod.cmdstate(repo, 'graftstate')
2260 graftstate = statemod.cmdstate(repo, 'graftstate')
2261
2261
2262 if opts.get('stop'):
2262 if opts.get('stop'):
2263 if opts.get('continue'):
2263 if opts.get('continue'):
2264 raise error.Abort(_("cannot use '--continue' and "
2264 raise error.Abort(_("cannot use '--continue' and "
2265 "'--stop' together"))
2265 "'--stop' together"))
2266 if opts.get('abort'):
2266 if opts.get('abort'):
2267 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2267 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2268
2268
2269 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2269 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2270 opts.get('date'), opts.get('currentdate'),
2270 opts.get('date'), opts.get('currentdate'),
2271 opts.get('currentuser'), opts.get('rev'))):
2271 opts.get('currentuser'), opts.get('rev'))):
2272 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2272 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2273 return _stopgraft(ui, repo, graftstate)
2273 return _stopgraft(ui, repo, graftstate)
2274 elif opts.get('abort'):
2274 elif opts.get('abort'):
2275 if opts.get('continue'):
2275 if opts.get('continue'):
2276 raise error.Abort(_("cannot use '--continue' and "
2276 raise error.Abort(_("cannot use '--continue' and "
2277 "'--abort' together"))
2277 "'--abort' together"))
2278 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2278 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2279 opts.get('date'), opts.get('currentdate'),
2279 opts.get('date'), opts.get('currentdate'),
2280 opts.get('currentuser'), opts.get('rev'))):
2280 opts.get('currentuser'), opts.get('rev'))):
2281 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2281 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2282
2282
2283 return _abortgraft(ui, repo, graftstate)
2283 return _abortgraft(ui, repo, graftstate)
2284 elif opts.get('continue'):
2284 elif opts.get('continue'):
2285 cont = True
2285 cont = True
2286 if revs:
2286 if revs:
2287 raise error.Abort(_("can't specify --continue and revisions"))
2287 raise error.Abort(_("can't specify --continue and revisions"))
2288 # read in unfinished revisions
2288 # read in unfinished revisions
2289 if graftstate.exists():
2289 if graftstate.exists():
2290 statedata = _readgraftstate(repo, graftstate)
2290 statedata = _readgraftstate(repo, graftstate)
2291 if statedata.get('date'):
2291 if statedata.get('date'):
2292 opts['date'] = statedata['date']
2292 opts['date'] = statedata['date']
2293 if statedata.get('user'):
2293 if statedata.get('user'):
2294 opts['user'] = statedata['user']
2294 opts['user'] = statedata['user']
2295 if statedata.get('log'):
2295 if statedata.get('log'):
2296 opts['log'] = True
2296 opts['log'] = True
2297 if statedata.get('no_commit'):
2297 if statedata.get('no_commit'):
2298 opts['no_commit'] = statedata.get('no_commit')
2298 opts['no_commit'] = statedata.get('no_commit')
2299 nodes = statedata['nodes']
2299 nodes = statedata['nodes']
2300 revs = [repo[node].rev() for node in nodes]
2300 revs = [repo[node].rev() for node in nodes]
2301 else:
2301 else:
2302 cmdutil.wrongtooltocontinue(repo, _('graft'))
2302 cmdutil.wrongtooltocontinue(repo, _('graft'))
2303 else:
2303 else:
2304 if not revs:
2304 if not revs:
2305 raise error.Abort(_('no revisions specified'))
2305 raise error.Abort(_('no revisions specified'))
2306 cmdutil.checkunfinished(repo)
2306 cmdutil.checkunfinished(repo)
2307 cmdutil.bailifchanged(repo)
2307 cmdutil.bailifchanged(repo)
2308 revs = scmutil.revrange(repo, revs)
2308 revs = scmutil.revrange(repo, revs)
2309
2309
2310 skipped = set()
2310 skipped = set()
2311 # check for merges
2311 # check for merges
2312 for rev in repo.revs('%ld and merge()', revs):
2312 for rev in repo.revs('%ld and merge()', revs):
2313 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2313 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2314 skipped.add(rev)
2314 skipped.add(rev)
2315 revs = [r for r in revs if r not in skipped]
2315 revs = [r for r in revs if r not in skipped]
2316 if not revs:
2316 if not revs:
2317 return -1
2317 return -1
2318
2318
2319 # Don't check in the --continue case, in effect retaining --force across
2319 # Don't check in the --continue case, in effect retaining --force across
2320 # --continues. That's because without --force, any revisions we decided to
2320 # --continues. That's because without --force, any revisions we decided to
2321 # skip would have been filtered out here, so they wouldn't have made their
2321 # skip would have been filtered out here, so they wouldn't have made their
2322 # way to the graftstate. With --force, any revisions we would have otherwise
2322 # way to the graftstate. With --force, any revisions we would have otherwise
2323 # skipped would not have been filtered out, and if they hadn't been applied
2323 # skipped would not have been filtered out, and if they hadn't been applied
2324 # already, they'd have been in the graftstate.
2324 # already, they'd have been in the graftstate.
2325 if not (cont or opts.get('force')):
2325 if not (cont or opts.get('force')):
2326 # check for ancestors of dest branch
2326 # check for ancestors of dest branch
2327 crev = repo['.'].rev()
2327 crev = repo['.'].rev()
2328 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2328 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2329 # XXX make this lazy in the future
2329 # XXX make this lazy in the future
2330 # don't mutate while iterating, create a copy
2330 # don't mutate while iterating, create a copy
2331 for rev in list(revs):
2331 for rev in list(revs):
2332 if rev in ancestors:
2332 if rev in ancestors:
2333 ui.warn(_('skipping ancestor revision %d:%s\n') %
2333 ui.warn(_('skipping ancestor revision %d:%s\n') %
2334 (rev, repo[rev]))
2334 (rev, repo[rev]))
2335 # XXX remove on list is slow
2335 # XXX remove on list is slow
2336 revs.remove(rev)
2336 revs.remove(rev)
2337 if not revs:
2337 if not revs:
2338 return -1
2338 return -1
2339
2339
2340 # analyze revs for earlier grafts
2340 # analyze revs for earlier grafts
2341 ids = {}
2341 ids = {}
2342 for ctx in repo.set("%ld", revs):
2342 for ctx in repo.set("%ld", revs):
2343 ids[ctx.hex()] = ctx.rev()
2343 ids[ctx.hex()] = ctx.rev()
2344 n = ctx.extra().get('source')
2344 n = ctx.extra().get('source')
2345 if n:
2345 if n:
2346 ids[n] = ctx.rev()
2346 ids[n] = ctx.rev()
2347
2347
2348 # check ancestors for earlier grafts
2348 # check ancestors for earlier grafts
2349 ui.debug('scanning for duplicate grafts\n')
2349 ui.debug('scanning for duplicate grafts\n')
2350
2350
2351 # The only changesets we can be sure doesn't contain grafts of any
2351 # The only changesets we can be sure doesn't contain grafts of any
2352 # revs, are the ones that are common ancestors of *all* revs:
2352 # revs, are the ones that are common ancestors of *all* revs:
2353 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2353 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2354 ctx = repo[rev]
2354 ctx = repo[rev]
2355 n = ctx.extra().get('source')
2355 n = ctx.extra().get('source')
2356 if n in ids:
2356 if n in ids:
2357 try:
2357 try:
2358 r = repo[n].rev()
2358 r = repo[n].rev()
2359 except error.RepoLookupError:
2359 except error.RepoLookupError:
2360 r = None
2360 r = None
2361 if r in revs:
2361 if r in revs:
2362 ui.warn(_('skipping revision %d:%s '
2362 ui.warn(_('skipping revision %d:%s '
2363 '(already grafted to %d:%s)\n')
2363 '(already grafted to %d:%s)\n')
2364 % (r, repo[r], rev, ctx))
2364 % (r, repo[r], rev, ctx))
2365 revs.remove(r)
2365 revs.remove(r)
2366 elif ids[n] in revs:
2366 elif ids[n] in revs:
2367 if r is None:
2367 if r is None:
2368 ui.warn(_('skipping already grafted revision %d:%s '
2368 ui.warn(_('skipping already grafted revision %d:%s '
2369 '(%d:%s also has unknown origin %s)\n')
2369 '(%d:%s also has unknown origin %s)\n')
2370 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2370 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2371 else:
2371 else:
2372 ui.warn(_('skipping already grafted revision %d:%s '
2372 ui.warn(_('skipping already grafted revision %d:%s '
2373 '(%d:%s also has origin %d:%s)\n')
2373 '(%d:%s also has origin %d:%s)\n')
2374 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2374 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2375 revs.remove(ids[n])
2375 revs.remove(ids[n])
2376 elif ctx.hex() in ids:
2376 elif ctx.hex() in ids:
2377 r = ids[ctx.hex()]
2377 r = ids[ctx.hex()]
2378 ui.warn(_('skipping already grafted revision %d:%s '
2378 ui.warn(_('skipping already grafted revision %d:%s '
2379 '(was grafted from %d:%s)\n') %
2379 '(was grafted from %d:%s)\n') %
2380 (r, repo[r], rev, ctx))
2380 (r, repo[r], rev, ctx))
2381 revs.remove(r)
2381 revs.remove(r)
2382 if not revs:
2382 if not revs:
2383 return -1
2383 return -1
2384
2384
2385 if opts.get('no_commit'):
2385 if opts.get('no_commit'):
2386 statedata['no_commit'] = True
2386 statedata['no_commit'] = True
2387 for pos, ctx in enumerate(repo.set("%ld", revs)):
2387 for pos, ctx in enumerate(repo.set("%ld", revs)):
2388 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2388 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2389 ctx.description().split('\n', 1)[0])
2389 ctx.description().split('\n', 1)[0])
2390 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2390 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2391 if names:
2391 if names:
2392 desc += ' (%s)' % ' '.join(names)
2392 desc += ' (%s)' % ' '.join(names)
2393 ui.status(_('grafting %s\n') % desc)
2393 ui.status(_('grafting %s\n') % desc)
2394 if opts.get('dry_run'):
2394 if opts.get('dry_run'):
2395 continue
2395 continue
2396
2396
2397 source = ctx.extra().get('source')
2397 source = ctx.extra().get('source')
2398 extra = {}
2398 extra = {}
2399 if source:
2399 if source:
2400 extra['source'] = source
2400 extra['source'] = source
2401 extra['intermediate-source'] = ctx.hex()
2401 extra['intermediate-source'] = ctx.hex()
2402 else:
2402 else:
2403 extra['source'] = ctx.hex()
2403 extra['source'] = ctx.hex()
2404 user = ctx.user()
2404 user = ctx.user()
2405 if opts.get('user'):
2405 if opts.get('user'):
2406 user = opts['user']
2406 user = opts['user']
2407 statedata['user'] = user
2407 statedata['user'] = user
2408 date = ctx.date()
2408 date = ctx.date()
2409 if opts.get('date'):
2409 if opts.get('date'):
2410 date = opts['date']
2410 date = opts['date']
2411 statedata['date'] = date
2411 statedata['date'] = date
2412 message = ctx.description()
2412 message = ctx.description()
2413 if opts.get('log'):
2413 if opts.get('log'):
2414 message += '\n(grafted from %s)' % ctx.hex()
2414 message += '\n(grafted from %s)' % ctx.hex()
2415 statedata['log'] = True
2415 statedata['log'] = True
2416
2416
2417 # we don't merge the first commit when continuing
2417 # we don't merge the first commit when continuing
2418 if not cont:
2418 if not cont:
2419 # perform the graft merge with p1(rev) as 'ancestor'
2419 # perform the graft merge with p1(rev) as 'ancestor'
2420 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2420 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2421 with ui.configoverride(overrides, 'graft'):
2421 with ui.configoverride(overrides, 'graft'):
2422 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2422 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2423 # report any conflicts
2423 # report any conflicts
2424 if stats.unresolvedcount > 0:
2424 if stats.unresolvedcount > 0:
2425 # write out state for --continue
2425 # write out state for --continue
2426 nodes = [repo[rev].hex() for rev in revs[pos:]]
2426 nodes = [repo[rev].hex() for rev in revs[pos:]]
2427 statedata['nodes'] = nodes
2427 statedata['nodes'] = nodes
2428 stateversion = 1
2428 stateversion = 1
2429 graftstate.save(stateversion, statedata)
2429 graftstate.save(stateversion, statedata)
2430 hint = _("use 'hg resolve' and 'hg graft --continue'")
2430 hint = _("use 'hg resolve' and 'hg graft --continue'")
2431 raise error.Abort(
2431 raise error.Abort(
2432 _("unresolved conflicts, can't continue"),
2432 _("unresolved conflicts, can't continue"),
2433 hint=hint)
2433 hint=hint)
2434 else:
2434 else:
2435 cont = False
2435 cont = False
2436
2436
2437 # commit if --no-commit is false
2437 # commit if --no-commit is false
2438 if not opts.get('no_commit'):
2438 if not opts.get('no_commit'):
2439 node = repo.commit(text=message, user=user, date=date, extra=extra,
2439 node = repo.commit(text=message, user=user, date=date, extra=extra,
2440 editor=editor)
2440 editor=editor)
2441 if node is None:
2441 if node is None:
2442 ui.warn(
2442 ui.warn(
2443 _('note: graft of %d:%s created no changes to commit\n') %
2443 _('note: graft of %d:%s created no changes to commit\n') %
2444 (ctx.rev(), ctx))
2444 (ctx.rev(), ctx))
2445 # checking that newnodes exist because old state files won't have it
2445 # checking that newnodes exist because old state files won't have it
2446 elif statedata.get('newnodes') is not None:
2446 elif statedata.get('newnodes') is not None:
2447 statedata['newnodes'].append(node)
2447 statedata['newnodes'].append(node)
2448
2448
2449 # remove state when we complete successfully
2449 # remove state when we complete successfully
2450 if not opts.get('dry_run'):
2450 if not opts.get('dry_run'):
2451 graftstate.delete()
2451 graftstate.delete()
2452
2452
2453 return 0
2453 return 0
2454
2454
2455 def _abortgraft(ui, repo, graftstate):
2455 def _abortgraft(ui, repo, graftstate):
2456 """abort the interrupted graft and rollbacks to the state before interrupted
2456 """abort the interrupted graft and rollbacks to the state before interrupted
2457 graft"""
2457 graft"""
2458 if not graftstate.exists():
2458 if not graftstate.exists():
2459 raise error.Abort(_("no interrupted graft to abort"))
2459 raise error.Abort(_("no interrupted graft to abort"))
2460 statedata = _readgraftstate(repo, graftstate)
2460 statedata = _readgraftstate(repo, graftstate)
2461 newnodes = statedata.get('newnodes')
2461 newnodes = statedata.get('newnodes')
2462 if newnodes is None:
2462 if newnodes is None:
2463 # and old graft state which does not have all the data required to abort
2463 # and old graft state which does not have all the data required to abort
2464 # the graft
2464 # the graft
2465 raise error.Abort(_("cannot abort using an old graftstate"))
2465 raise error.Abort(_("cannot abort using an old graftstate"))
2466
2466
2467 # changeset from which graft operation was started
2467 # changeset from which graft operation was started
2468 startctx = None
2468 startctx = None
2469 if len(newnodes) > 0:
2469 if len(newnodes) > 0:
2470 startctx = repo[newnodes[0]].p1()
2470 startctx = repo[newnodes[0]].p1()
2471 else:
2471 else:
2472 startctx = repo['.']
2472 startctx = repo['.']
2473 # whether to strip or not
2473 # whether to strip or not
2474 cleanup = False
2474 cleanup = False
2475 if newnodes:
2475 if newnodes:
2476 newnodes = [repo[r].rev() for r in newnodes]
2476 newnodes = [repo[r].rev() for r in newnodes]
2477 cleanup = True
2477 cleanup = True
2478 # checking that none of the newnodes turned public or is public
2478 # checking that none of the newnodes turned public or is public
2479 immutable = [c for c in newnodes if not repo[c].mutable()]
2479 immutable = [c for c in newnodes if not repo[c].mutable()]
2480 if immutable:
2480 if immutable:
2481 repo.ui.warn(_("cannot clean up public changesets %s\n")
2481 repo.ui.warn(_("cannot clean up public changesets %s\n")
2482 % ', '.join(bytes(repo[r]) for r in immutable),
2482 % ', '.join(bytes(repo[r]) for r in immutable),
2483 hint=_("see 'hg help phases' for details"))
2483 hint=_("see 'hg help phases' for details"))
2484 cleanup = False
2484 cleanup = False
2485
2485
2486 # checking that no new nodes are created on top of grafted revs
2486 # checking that no new nodes are created on top of grafted revs
2487 desc = set(repo.changelog.descendants(newnodes))
2487 desc = set(repo.changelog.descendants(newnodes))
2488 if desc - set(newnodes):
2488 if desc - set(newnodes):
2489 repo.ui.warn(_("new changesets detected on destination "
2489 repo.ui.warn(_("new changesets detected on destination "
2490 "branch, can't strip\n"))
2490 "branch, can't strip\n"))
2491 cleanup = False
2491 cleanup = False
2492
2492
2493 if cleanup:
2493 if cleanup:
2494 with repo.wlock(), repo.lock():
2494 with repo.wlock(), repo.lock():
2495 hg.updaterepo(repo, startctx.node(), overwrite=True)
2495 hg.updaterepo(repo, startctx.node(), overwrite=True)
2496 # stripping the new nodes created
2496 # stripping the new nodes created
2497 strippoints = [c.node() for c in repo.set("roots(%ld)",
2497 strippoints = [c.node() for c in repo.set("roots(%ld)",
2498 newnodes)]
2498 newnodes)]
2499 repair.strip(repo.ui, repo, strippoints, backup=False)
2499 repair.strip(repo.ui, repo, strippoints, backup=False)
2500
2500
2501 if not cleanup:
2501 if not cleanup:
2502 # we don't update to the startnode if we can't strip
2502 # we don't update to the startnode if we can't strip
2503 startctx = repo['.']
2503 startctx = repo['.']
2504 hg.updaterepo(repo, startctx.node(), overwrite=True)
2504 hg.updaterepo(repo, startctx.node(), overwrite=True)
2505
2505
2506 ui.status(_("graft aborted\n"))
2506 ui.status(_("graft aborted\n"))
2507 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2507 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
2508 graftstate.delete()
2508 graftstate.delete()
2509 return 0
2509 return 0
2510
2510
2511 def _readgraftstate(repo, graftstate):
2511 def _readgraftstate(repo, graftstate):
2512 """read the graft state file and return a dict of the data stored in it"""
2512 """read the graft state file and return a dict of the data stored in it"""
2513 try:
2513 try:
2514 return graftstate.read()
2514 return graftstate.read()
2515 except error.CorruptedState:
2515 except error.CorruptedState:
2516 nodes = repo.vfs.read('graftstate').splitlines()
2516 nodes = repo.vfs.read('graftstate').splitlines()
2517 return {'nodes': nodes}
2517 return {'nodes': nodes}
2518
2518
2519 def _stopgraft(ui, repo, graftstate):
2519 def _stopgraft(ui, repo, graftstate):
2520 """stop the interrupted graft"""
2520 """stop the interrupted graft"""
2521 if not graftstate.exists():
2521 if not graftstate.exists():
2522 raise error.Abort(_("no interrupted graft found"))
2522 raise error.Abort(_("no interrupted graft found"))
2523 pctx = repo['.']
2523 pctx = repo['.']
2524 hg.updaterepo(repo, pctx.node(), overwrite=True)
2524 hg.updaterepo(repo, pctx.node(), overwrite=True)
2525 graftstate.delete()
2525 graftstate.delete()
2526 ui.status(_("stopped the interrupted graft\n"))
2526 ui.status(_("stopped the interrupted graft\n"))
2527 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2527 ui.status(_("working directory is now at %s\n") % pctx.hex()[:12])
2528 return 0
2528 return 0
2529
2529
2530 @command('grep',
2530 @command('grep',
2531 [('0', 'print0', None, _('end fields with NUL')),
2531 [('0', 'print0', None, _('end fields with NUL')),
2532 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2532 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2533 ('', 'diff', None, _('print all revisions when the term was introduced '
2533 ('', 'diff', None, _('print all revisions when the term was introduced '
2534 'or removed')),
2534 'or removed')),
2535 ('a', 'text', None, _('treat all files as text')),
2535 ('a', 'text', None, _('treat all files as text')),
2536 ('f', 'follow', None,
2536 ('f', 'follow', None,
2537 _('follow changeset history,'
2537 _('follow changeset history,'
2538 ' or file history across copies and renames')),
2538 ' or file history across copies and renames')),
2539 ('i', 'ignore-case', None, _('ignore case when matching')),
2539 ('i', 'ignore-case', None, _('ignore case when matching')),
2540 ('l', 'files-with-matches', None,
2540 ('l', 'files-with-matches', None,
2541 _('print only filenames and revisions that match')),
2541 _('print only filenames and revisions that match')),
2542 ('n', 'line-number', None, _('print matching line numbers')),
2542 ('n', 'line-number', None, _('print matching line numbers')),
2543 ('r', 'rev', [],
2543 ('r', 'rev', [],
2544 _('only search files changed within revision range'), _('REV')),
2544 _('only search files changed within revision range'), _('REV')),
2545 ('', 'all-files', None,
2545 ('', 'all-files', None,
2546 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2546 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2547 ('u', 'user', None, _('list the author (long with -v)')),
2547 ('u', 'user', None, _('list the author (long with -v)')),
2548 ('d', 'date', None, _('list the date (short with -q)')),
2548 ('d', 'date', None, _('list the date (short with -q)')),
2549 ] + formatteropts + walkopts,
2549 ] + formatteropts + walkopts,
2550 _('[OPTION]... PATTERN [FILE]...'),
2550 _('[OPTION]... PATTERN [FILE]...'),
2551 inferrepo=True,
2551 inferrepo=True,
2552 intents={INTENT_READONLY})
2552 intents={INTENT_READONLY})
2553 def grep(ui, repo, pattern, *pats, **opts):
2553 def grep(ui, repo, pattern, *pats, **opts):
2554 """search revision history for a pattern in specified files
2554 """search revision history for a pattern in specified files
2555
2555
2556 Search revision history for a regular expression in the specified
2556 Search revision history for a regular expression in the specified
2557 files or the entire project.
2557 files or the entire project.
2558
2558
2559 By default, grep prints the most recent revision number for each
2559 By default, grep prints the most recent revision number for each
2560 file in which it finds a match. To get it to print every revision
2560 file in which it finds a match. To get it to print every revision
2561 that contains a change in match status ("-" for a match that becomes
2561 that contains a change in match status ("-" for a match that becomes
2562 a non-match, or "+" for a non-match that becomes a match), use the
2562 a non-match, or "+" for a non-match that becomes a match), use the
2563 --diff flag.
2563 --diff flag.
2564
2564
2565 PATTERN can be any Python (roughly Perl-compatible) regular
2565 PATTERN can be any Python (roughly Perl-compatible) regular
2566 expression.
2566 expression.
2567
2567
2568 If no FILEs are specified (and -f/--follow isn't set), all files in
2568 If no FILEs are specified (and -f/--follow isn't set), all files in
2569 the repository are searched, including those that don't exist in the
2569 the repository are searched, including those that don't exist in the
2570 current branch or have been deleted in a prior changeset.
2570 current branch or have been deleted in a prior changeset.
2571
2571
2572 Returns 0 if a match is found, 1 otherwise.
2572 Returns 0 if a match is found, 1 otherwise.
2573 """
2573 """
2574 opts = pycompat.byteskwargs(opts)
2574 opts = pycompat.byteskwargs(opts)
2575 diff = opts.get('all') or opts.get('diff')
2575 diff = opts.get('all') or opts.get('diff')
2576 all_files = opts.get('all_files')
2576 all_files = opts.get('all_files')
2577 if diff and opts.get('all_files'):
2577 if diff and opts.get('all_files'):
2578 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2578 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2579 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2579 # TODO: remove "not opts.get('rev')" if --all-files -rMULTIREV gets working
2580 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2580 if opts.get('all_files') is None and not opts.get('rev') and not diff:
2581 # experimental config: commands.grep.all-files
2581 # experimental config: commands.grep.all-files
2582 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2582 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2583 plaingrep = opts.get('all_files') and not opts.get('rev')
2583 plaingrep = opts.get('all_files') and not opts.get('rev')
2584 if plaingrep:
2584 if plaingrep:
2585 opts['rev'] = ['wdir()']
2585 opts['rev'] = ['wdir()']
2586
2586
2587 reflags = re.M
2587 reflags = re.M
2588 if opts.get('ignore_case'):
2588 if opts.get('ignore_case'):
2589 reflags |= re.I
2589 reflags |= re.I
2590 try:
2590 try:
2591 regexp = util.re.compile(pattern, reflags)
2591 regexp = util.re.compile(pattern, reflags)
2592 except re.error as inst:
2592 except re.error as inst:
2593 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2593 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2594 return 1
2594 return 1
2595 sep, eol = ':', '\n'
2595 sep, eol = ':', '\n'
2596 if opts.get('print0'):
2596 if opts.get('print0'):
2597 sep = eol = '\0'
2597 sep = eol = '\0'
2598
2598
2599 getfile = util.lrucachefunc(repo.file)
2599 getfile = util.lrucachefunc(repo.file)
2600
2600
2601 def matchlines(body):
2601 def matchlines(body):
2602 begin = 0
2602 begin = 0
2603 linenum = 0
2603 linenum = 0
2604 while begin < len(body):
2604 while begin < len(body):
2605 match = regexp.search(body, begin)
2605 match = regexp.search(body, begin)
2606 if not match:
2606 if not match:
2607 break
2607 break
2608 mstart, mend = match.span()
2608 mstart, mend = match.span()
2609 linenum += body.count('\n', begin, mstart) + 1
2609 linenum += body.count('\n', begin, mstart) + 1
2610 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2610 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2611 begin = body.find('\n', mend) + 1 or len(body) + 1
2611 begin = body.find('\n', mend) + 1 or len(body) + 1
2612 lend = begin - 1
2612 lend = begin - 1
2613 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2613 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2614
2614
2615 class linestate(object):
2615 class linestate(object):
2616 def __init__(self, line, linenum, colstart, colend):
2616 def __init__(self, line, linenum, colstart, colend):
2617 self.line = line
2617 self.line = line
2618 self.linenum = linenum
2618 self.linenum = linenum
2619 self.colstart = colstart
2619 self.colstart = colstart
2620 self.colend = colend
2620 self.colend = colend
2621
2621
2622 def __hash__(self):
2622 def __hash__(self):
2623 return hash((self.linenum, self.line))
2623 return hash((self.linenum, self.line))
2624
2624
2625 def __eq__(self, other):
2625 def __eq__(self, other):
2626 return self.line == other.line
2626 return self.line == other.line
2627
2627
2628 def findpos(self):
2628 def findpos(self):
2629 """Iterate all (start, end) indices of matches"""
2629 """Iterate all (start, end) indices of matches"""
2630 yield self.colstart, self.colend
2630 yield self.colstart, self.colend
2631 p = self.colend
2631 p = self.colend
2632 while p < len(self.line):
2632 while p < len(self.line):
2633 m = regexp.search(self.line, p)
2633 m = regexp.search(self.line, p)
2634 if not m:
2634 if not m:
2635 break
2635 break
2636 yield m.span()
2636 yield m.span()
2637 p = m.end()
2637 p = m.end()
2638
2638
2639 matches = {}
2639 matches = {}
2640 copies = {}
2640 copies = {}
2641 def grepbody(fn, rev, body):
2641 def grepbody(fn, rev, body):
2642 matches[rev].setdefault(fn, [])
2642 matches[rev].setdefault(fn, [])
2643 m = matches[rev][fn]
2643 m = matches[rev][fn]
2644 for lnum, cstart, cend, line in matchlines(body):
2644 for lnum, cstart, cend, line in matchlines(body):
2645 s = linestate(line, lnum, cstart, cend)
2645 s = linestate(line, lnum, cstart, cend)
2646 m.append(s)
2646 m.append(s)
2647
2647
2648 def difflinestates(a, b):
2648 def difflinestates(a, b):
2649 sm = difflib.SequenceMatcher(None, a, b)
2649 sm = difflib.SequenceMatcher(None, a, b)
2650 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2650 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2651 if tag == r'insert':
2651 if tag == r'insert':
2652 for i in pycompat.xrange(blo, bhi):
2652 for i in pycompat.xrange(blo, bhi):
2653 yield ('+', b[i])
2653 yield ('+', b[i])
2654 elif tag == r'delete':
2654 elif tag == r'delete':
2655 for i in pycompat.xrange(alo, ahi):
2655 for i in pycompat.xrange(alo, ahi):
2656 yield ('-', a[i])
2656 yield ('-', a[i])
2657 elif tag == r'replace':
2657 elif tag == r'replace':
2658 for i in pycompat.xrange(alo, ahi):
2658 for i in pycompat.xrange(alo, ahi):
2659 yield ('-', a[i])
2659 yield ('-', a[i])
2660 for i in pycompat.xrange(blo, bhi):
2660 for i in pycompat.xrange(blo, bhi):
2661 yield ('+', b[i])
2661 yield ('+', b[i])
2662
2662
2663 def display(fm, fn, ctx, pstates, states):
2663 def display(fm, fn, ctx, pstates, states):
2664 rev = scmutil.intrev(ctx)
2664 rev = scmutil.intrev(ctx)
2665 if fm.isplain():
2665 if fm.isplain():
2666 formatuser = ui.shortuser
2666 formatuser = ui.shortuser
2667 else:
2667 else:
2668 formatuser = pycompat.bytestr
2668 formatuser = pycompat.bytestr
2669 if ui.quiet:
2669 if ui.quiet:
2670 datefmt = '%Y-%m-%d'
2670 datefmt = '%Y-%m-%d'
2671 else:
2671 else:
2672 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2672 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2673 found = False
2673 found = False
2674 @util.cachefunc
2674 @util.cachefunc
2675 def binary():
2675 def binary():
2676 flog = getfile(fn)
2676 flog = getfile(fn)
2677 try:
2677 try:
2678 return stringutil.binary(flog.read(ctx.filenode(fn)))
2678 return stringutil.binary(flog.read(ctx.filenode(fn)))
2679 except error.WdirUnsupported:
2679 except error.WdirUnsupported:
2680 return ctx[fn].isbinary()
2680 return ctx[fn].isbinary()
2681
2681
2682 fieldnamemap = {'filename': 'path', 'linenumber': 'line_number'}
2682 fieldnamemap = {'filename': 'path', 'linenumber': 'line_number'}
2683 if diff:
2683 if diff:
2684 iter = difflinestates(pstates, states)
2684 iter = difflinestates(pstates, states)
2685 else:
2685 else:
2686 iter = [('', l) for l in states]
2686 iter = [('', l) for l in states]
2687 for change, l in iter:
2687 for change, l in iter:
2688 fm.startitem()
2688 fm.startitem()
2689 fm.context(ctx=ctx)
2689 fm.context(ctx=ctx)
2690 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2690 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2691
2691
2692 cols = [
2692 cols = [
2693 ('filename', '%s', fn, True),
2693 ('filename', '%s', fn, True),
2694 ('rev', '%d', rev, not plaingrep),
2694 ('rev', '%d', rev, not plaingrep),
2695 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2695 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2696 ]
2696 ]
2697 if diff:
2697 if diff:
2698 cols.append(('change', '%s', change, True))
2698 cols.append(('change', '%s', change, True))
2699 cols.extend([
2699 cols.extend([
2700 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2700 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2701 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2701 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2702 opts.get('date')),
2702 opts.get('date')),
2703 ])
2703 ])
2704 lastcol = next(
2704 lastcol = next(
2705 name for name, fmt, data, cond in reversed(cols) if cond)
2705 name for name, fmt, data, cond in reversed(cols) if cond)
2706 for name, fmt, data, cond in cols:
2706 for name, fmt, data, cond in cols:
2707 field = fieldnamemap.get(name, name)
2707 field = fieldnamemap.get(name, name)
2708 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2708 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2709 if cond and name != lastcol:
2709 if cond and name != lastcol:
2710 fm.plain(sep, label='grep.sep')
2710 fm.plain(sep, label='grep.sep')
2711 if not opts.get('files_with_matches'):
2711 if not opts.get('files_with_matches'):
2712 fm.plain(sep, label='grep.sep')
2712 fm.plain(sep, label='grep.sep')
2713 if not opts.get('text') and binary():
2713 if not opts.get('text') and binary():
2714 fm.plain(_(" Binary file matches"))
2714 fm.plain(_(" Binary file matches"))
2715 else:
2715 else:
2716 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2716 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2717 fm.plain(eol)
2717 fm.plain(eol)
2718 found = True
2718 found = True
2719 if opts.get('files_with_matches'):
2719 if opts.get('files_with_matches'):
2720 break
2720 break
2721 return found
2721 return found
2722
2722
2723 def displaymatches(fm, l):
2723 def displaymatches(fm, l):
2724 p = 0
2724 p = 0
2725 for s, e in l.findpos():
2725 for s, e in l.findpos():
2726 if p < s:
2726 if p < s:
2727 fm.startitem()
2727 fm.startitem()
2728 fm.write('text', '%s', l.line[p:s])
2728 fm.write('text', '%s', l.line[p:s])
2729 fm.data(matched=False)
2729 fm.data(matched=False)
2730 fm.startitem()
2730 fm.startitem()
2731 fm.write('text', '%s', l.line[s:e], label='grep.match')
2731 fm.write('text', '%s', l.line[s:e], label='grep.match')
2732 fm.data(matched=True)
2732 fm.data(matched=True)
2733 p = e
2733 p = e
2734 if p < len(l.line):
2734 if p < len(l.line):
2735 fm.startitem()
2735 fm.startitem()
2736 fm.write('text', '%s', l.line[p:])
2736 fm.write('text', '%s', l.line[p:])
2737 fm.data(matched=False)
2737 fm.data(matched=False)
2738 fm.end()
2738 fm.end()
2739
2739
2740 skip = {}
2740 skip = {}
2741 revfiles = {}
2741 revfiles = {}
2742 match = scmutil.match(repo[None], pats, opts)
2742 match = scmutil.match(repo[None], pats, opts)
2743 found = False
2743 found = False
2744 follow = opts.get('follow')
2744 follow = opts.get('follow')
2745
2745
2746 def prep(ctx, fns):
2746 def prep(ctx, fns):
2747 rev = ctx.rev()
2747 rev = ctx.rev()
2748 pctx = ctx.p1()
2748 pctx = ctx.p1()
2749 parent = pctx.rev()
2749 parent = pctx.rev()
2750 matches.setdefault(rev, {})
2750 matches.setdefault(rev, {})
2751 matches.setdefault(parent, {})
2751 matches.setdefault(parent, {})
2752 files = revfiles.setdefault(rev, [])
2752 files = revfiles.setdefault(rev, [])
2753 for fn in fns:
2753 for fn in fns:
2754 flog = getfile(fn)
2754 flog = getfile(fn)
2755 try:
2755 try:
2756 fnode = ctx.filenode(fn)
2756 fnode = ctx.filenode(fn)
2757 except error.LookupError:
2757 except error.LookupError:
2758 continue
2758 continue
2759 try:
2759 try:
2760 copied = flog.renamed(fnode)
2760 copied = flog.renamed(fnode)
2761 except error.WdirUnsupported:
2761 except error.WdirUnsupported:
2762 copied = ctx[fn].renamed()
2762 copied = ctx[fn].renamed()
2763 copy = follow and copied and copied[0]
2763 copy = follow and copied and copied[0]
2764 if copy:
2764 if copy:
2765 copies.setdefault(rev, {})[fn] = copy
2765 copies.setdefault(rev, {})[fn] = copy
2766 if fn in skip:
2766 if fn in skip:
2767 if copy:
2767 if copy:
2768 skip[copy] = True
2768 skip[copy] = True
2769 continue
2769 continue
2770 files.append(fn)
2770 files.append(fn)
2771
2771
2772 if fn not in matches[rev]:
2772 if fn not in matches[rev]:
2773 try:
2773 try:
2774 content = flog.read(fnode)
2774 content = flog.read(fnode)
2775 except error.WdirUnsupported:
2775 except error.WdirUnsupported:
2776 content = ctx[fn].data()
2776 content = ctx[fn].data()
2777 grepbody(fn, rev, content)
2777 grepbody(fn, rev, content)
2778
2778
2779 pfn = copy or fn
2779 pfn = copy or fn
2780 if pfn not in matches[parent]:
2780 if pfn not in matches[parent]:
2781 try:
2781 try:
2782 fnode = pctx.filenode(pfn)
2782 fnode = pctx.filenode(pfn)
2783 grepbody(pfn, parent, flog.read(fnode))
2783 grepbody(pfn, parent, flog.read(fnode))
2784 except error.LookupError:
2784 except error.LookupError:
2785 pass
2785 pass
2786
2786
2787 ui.pager('grep')
2787 ui.pager('grep')
2788 fm = ui.formatter('grep', opts)
2788 fm = ui.formatter('grep', opts)
2789 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2789 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2790 rev = ctx.rev()
2790 rev = ctx.rev()
2791 parent = ctx.p1().rev()
2791 parent = ctx.p1().rev()
2792 for fn in sorted(revfiles.get(rev, [])):
2792 for fn in sorted(revfiles.get(rev, [])):
2793 states = matches[rev][fn]
2793 states = matches[rev][fn]
2794 copy = copies.get(rev, {}).get(fn)
2794 copy = copies.get(rev, {}).get(fn)
2795 if fn in skip:
2795 if fn in skip:
2796 if copy:
2796 if copy:
2797 skip[copy] = True
2797 skip[copy] = True
2798 continue
2798 continue
2799 pstates = matches.get(parent, {}).get(copy or fn, [])
2799 pstates = matches.get(parent, {}).get(copy or fn, [])
2800 if pstates or states:
2800 if pstates or states:
2801 r = display(fm, fn, ctx, pstates, states)
2801 r = display(fm, fn, ctx, pstates, states)
2802 found = found or r
2802 found = found or r
2803 if r and not diff and not all_files:
2803 if r and not diff and not all_files:
2804 skip[fn] = True
2804 skip[fn] = True
2805 if copy:
2805 if copy:
2806 skip[copy] = True
2806 skip[copy] = True
2807 del revfiles[rev]
2807 del revfiles[rev]
2808 # We will keep the matches dict for the duration of the window
2808 # We will keep the matches dict for the duration of the window
2809 # clear the matches dict once the window is over
2809 # clear the matches dict once the window is over
2810 if not revfiles:
2810 if not revfiles:
2811 matches.clear()
2811 matches.clear()
2812 fm.end()
2812 fm.end()
2813
2813
2814 return not found
2814 return not found
2815
2815
2816 @command('heads',
2816 @command('heads',
2817 [('r', 'rev', '',
2817 [('r', 'rev', '',
2818 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2818 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2819 ('t', 'topo', False, _('show topological heads only')),
2819 ('t', 'topo', False, _('show topological heads only')),
2820 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2820 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2821 ('c', 'closed', False, _('show normal and closed branch heads')),
2821 ('c', 'closed', False, _('show normal and closed branch heads')),
2822 ] + templateopts,
2822 ] + templateopts,
2823 _('[-ct] [-r STARTREV] [REV]...'),
2823 _('[-ct] [-r STARTREV] [REV]...'),
2824 intents={INTENT_READONLY})
2824 intents={INTENT_READONLY})
2825 def heads(ui, repo, *branchrevs, **opts):
2825 def heads(ui, repo, *branchrevs, **opts):
2826 """show branch heads
2826 """show branch heads
2827
2827
2828 With no arguments, show all open branch heads in the repository.
2828 With no arguments, show all open branch heads in the repository.
2829 Branch heads are changesets that have no descendants on the
2829 Branch heads are changesets that have no descendants on the
2830 same branch. They are where development generally takes place and
2830 same branch. They are where development generally takes place and
2831 are the usual targets for update and merge operations.
2831 are the usual targets for update and merge operations.
2832
2832
2833 If one or more REVs are given, only open branch heads on the
2833 If one or more REVs are given, only open branch heads on the
2834 branches associated with the specified changesets are shown. This
2834 branches associated with the specified changesets are shown. This
2835 means that you can use :hg:`heads .` to see the heads on the
2835 means that you can use :hg:`heads .` to see the heads on the
2836 currently checked-out branch.
2836 currently checked-out branch.
2837
2837
2838 If -c/--closed is specified, also show branch heads marked closed
2838 If -c/--closed is specified, also show branch heads marked closed
2839 (see :hg:`commit --close-branch`).
2839 (see :hg:`commit --close-branch`).
2840
2840
2841 If STARTREV is specified, only those heads that are descendants of
2841 If STARTREV is specified, only those heads that are descendants of
2842 STARTREV will be displayed.
2842 STARTREV will be displayed.
2843
2843
2844 If -t/--topo is specified, named branch mechanics will be ignored and only
2844 If -t/--topo is specified, named branch mechanics will be ignored and only
2845 topological heads (changesets with no children) will be shown.
2845 topological heads (changesets with no children) will be shown.
2846
2846
2847 Returns 0 if matching heads are found, 1 if not.
2847 Returns 0 if matching heads are found, 1 if not.
2848 """
2848 """
2849
2849
2850 opts = pycompat.byteskwargs(opts)
2850 opts = pycompat.byteskwargs(opts)
2851 start = None
2851 start = None
2852 rev = opts.get('rev')
2852 rev = opts.get('rev')
2853 if rev:
2853 if rev:
2854 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2854 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2855 start = scmutil.revsingle(repo, rev, None).node()
2855 start = scmutil.revsingle(repo, rev, None).node()
2856
2856
2857 if opts.get('topo'):
2857 if opts.get('topo'):
2858 heads = [repo[h] for h in repo.heads(start)]
2858 heads = [repo[h] for h in repo.heads(start)]
2859 else:
2859 else:
2860 heads = []
2860 heads = []
2861 for branch in repo.branchmap():
2861 for branch in repo.branchmap():
2862 heads += repo.branchheads(branch, start, opts.get('closed'))
2862 heads += repo.branchheads(branch, start, opts.get('closed'))
2863 heads = [repo[h] for h in heads]
2863 heads = [repo[h] for h in heads]
2864
2864
2865 if branchrevs:
2865 if branchrevs:
2866 branches = set(repo[r].branch()
2866 branches = set(repo[r].branch()
2867 for r in scmutil.revrange(repo, branchrevs))
2867 for r in scmutil.revrange(repo, branchrevs))
2868 heads = [h for h in heads if h.branch() in branches]
2868 heads = [h for h in heads if h.branch() in branches]
2869
2869
2870 if opts.get('active') and branchrevs:
2870 if opts.get('active') and branchrevs:
2871 dagheads = repo.heads(start)
2871 dagheads = repo.heads(start)
2872 heads = [h for h in heads if h.node() in dagheads]
2872 heads = [h for h in heads if h.node() in dagheads]
2873
2873
2874 if branchrevs:
2874 if branchrevs:
2875 haveheads = set(h.branch() for h in heads)
2875 haveheads = set(h.branch() for h in heads)
2876 if branches - haveheads:
2876 if branches - haveheads:
2877 headless = ', '.join(b for b in branches - haveheads)
2877 headless = ', '.join(b for b in branches - haveheads)
2878 msg = _('no open branch heads found on branches %s')
2878 msg = _('no open branch heads found on branches %s')
2879 if opts.get('rev'):
2879 if opts.get('rev'):
2880 msg += _(' (started at %s)') % opts['rev']
2880 msg += _(' (started at %s)') % opts['rev']
2881 ui.warn((msg + '\n') % headless)
2881 ui.warn((msg + '\n') % headless)
2882
2882
2883 if not heads:
2883 if not heads:
2884 return 1
2884 return 1
2885
2885
2886 ui.pager('heads')
2886 ui.pager('heads')
2887 heads = sorted(heads, key=lambda x: -x.rev())
2887 heads = sorted(heads, key=lambda x: -x.rev())
2888 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2888 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2889 for ctx in heads:
2889 for ctx in heads:
2890 displayer.show(ctx)
2890 displayer.show(ctx)
2891 displayer.close()
2891 displayer.close()
2892
2892
2893 @command('help',
2893 @command('help',
2894 [('e', 'extension', None, _('show only help for extensions')),
2894 [('e', 'extension', None, _('show only help for extensions')),
2895 ('c', 'command', None, _('show only help for commands')),
2895 ('c', 'command', None, _('show only help for commands')),
2896 ('k', 'keyword', None, _('show topics matching keyword')),
2896 ('k', 'keyword', None, _('show topics matching keyword')),
2897 ('s', 'system', [], _('show help for specific platform(s)')),
2897 ('s', 'system', [], _('show help for specific platform(s)')),
2898 ],
2898 ],
2899 _('[-ecks] [TOPIC]'),
2899 _('[-ecks] [TOPIC]'),
2900 norepo=True,
2900 norepo=True,
2901 intents={INTENT_READONLY})
2901 intents={INTENT_READONLY})
2902 def help_(ui, name=None, **opts):
2902 def help_(ui, name=None, **opts):
2903 """show help for a given topic or a help overview
2903 """show help for a given topic or a help overview
2904
2904
2905 With no arguments, print a list of commands with short help messages.
2905 With no arguments, print a list of commands with short help messages.
2906
2906
2907 Given a topic, extension, or command name, print help for that
2907 Given a topic, extension, or command name, print help for that
2908 topic.
2908 topic.
2909
2909
2910 Returns 0 if successful.
2910 Returns 0 if successful.
2911 """
2911 """
2912
2912
2913 keep = opts.get(r'system') or []
2913 keep = opts.get(r'system') or []
2914 if len(keep) == 0:
2914 if len(keep) == 0:
2915 if pycompat.sysplatform.startswith('win'):
2915 if pycompat.sysplatform.startswith('win'):
2916 keep.append('windows')
2916 keep.append('windows')
2917 elif pycompat.sysplatform == 'OpenVMS':
2917 elif pycompat.sysplatform == 'OpenVMS':
2918 keep.append('vms')
2918 keep.append('vms')
2919 elif pycompat.sysplatform == 'plan9':
2919 elif pycompat.sysplatform == 'plan9':
2920 keep.append('plan9')
2920 keep.append('plan9')
2921 else:
2921 else:
2922 keep.append('unix')
2922 keep.append('unix')
2923 keep.append(pycompat.sysplatform.lower())
2923 keep.append(pycompat.sysplatform.lower())
2924 if ui.verbose:
2924 if ui.verbose:
2925 keep.append('verbose')
2925 keep.append('verbose')
2926
2926
2927 commands = sys.modules[__name__]
2927 commands = sys.modules[__name__]
2928 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2928 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2929 ui.pager('help')
2929 ui.pager('help')
2930 ui.write(formatted)
2930 ui.write(formatted)
2931
2931
2932
2932
2933 @command('identify|id',
2933 @command('identify|id',
2934 [('r', 'rev', '',
2934 [('r', 'rev', '',
2935 _('identify the specified revision'), _('REV')),
2935 _('identify the specified revision'), _('REV')),
2936 ('n', 'num', None, _('show local revision number')),
2936 ('n', 'num', None, _('show local revision number')),
2937 ('i', 'id', None, _('show global revision id')),
2937 ('i', 'id', None, _('show global revision id')),
2938 ('b', 'branch', None, _('show branch')),
2938 ('b', 'branch', None, _('show branch')),
2939 ('t', 'tags', None, _('show tags')),
2939 ('t', 'tags', None, _('show tags')),
2940 ('B', 'bookmarks', None, _('show bookmarks')),
2940 ('B', 'bookmarks', None, _('show bookmarks')),
2941 ] + remoteopts + formatteropts,
2941 ] + remoteopts + formatteropts,
2942 _('[-nibtB] [-r REV] [SOURCE]'),
2942 _('[-nibtB] [-r REV] [SOURCE]'),
2943 optionalrepo=True,
2943 optionalrepo=True,
2944 intents={INTENT_READONLY})
2944 intents={INTENT_READONLY})
2945 def identify(ui, repo, source=None, rev=None,
2945 def identify(ui, repo, source=None, rev=None,
2946 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2946 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2947 """identify the working directory or specified revision
2947 """identify the working directory or specified revision
2948
2948
2949 Print a summary identifying the repository state at REV using one or
2949 Print a summary identifying the repository state at REV using one or
2950 two parent hash identifiers, followed by a "+" if the working
2950 two parent hash identifiers, followed by a "+" if the working
2951 directory has uncommitted changes, the branch name (if not default),
2951 directory has uncommitted changes, the branch name (if not default),
2952 a list of tags, and a list of bookmarks.
2952 a list of tags, and a list of bookmarks.
2953
2953
2954 When REV is not given, print a summary of the current state of the
2954 When REV is not given, print a summary of the current state of the
2955 repository including the working directory. Specify -r. to get information
2955 repository including the working directory. Specify -r. to get information
2956 of the working directory parent without scanning uncommitted changes.
2956 of the working directory parent without scanning uncommitted changes.
2957
2957
2958 Specifying a path to a repository root or Mercurial bundle will
2958 Specifying a path to a repository root or Mercurial bundle will
2959 cause lookup to operate on that repository/bundle.
2959 cause lookup to operate on that repository/bundle.
2960
2960
2961 .. container:: verbose
2961 .. container:: verbose
2962
2962
2963 Examples:
2963 Examples:
2964
2964
2965 - generate a build identifier for the working directory::
2965 - generate a build identifier for the working directory::
2966
2966
2967 hg id --id > build-id.dat
2967 hg id --id > build-id.dat
2968
2968
2969 - find the revision corresponding to a tag::
2969 - find the revision corresponding to a tag::
2970
2970
2971 hg id -n -r 1.3
2971 hg id -n -r 1.3
2972
2972
2973 - check the most recent revision of a remote repository::
2973 - check the most recent revision of a remote repository::
2974
2974
2975 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2975 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2976
2976
2977 See :hg:`log` for generating more information about specific revisions,
2977 See :hg:`log` for generating more information about specific revisions,
2978 including full hash identifiers.
2978 including full hash identifiers.
2979
2979
2980 Returns 0 if successful.
2980 Returns 0 if successful.
2981 """
2981 """
2982
2982
2983 opts = pycompat.byteskwargs(opts)
2983 opts = pycompat.byteskwargs(opts)
2984 if not repo and not source:
2984 if not repo and not source:
2985 raise error.Abort(_("there is no Mercurial repository here "
2985 raise error.Abort(_("there is no Mercurial repository here "
2986 "(.hg not found)"))
2986 "(.hg not found)"))
2987
2987
2988 default = not (num or id or branch or tags or bookmarks)
2988 default = not (num or id or branch or tags or bookmarks)
2989 output = []
2989 output = []
2990 revs = []
2990 revs = []
2991
2991
2992 if source:
2992 if source:
2993 source, branches = hg.parseurl(ui.expandpath(source))
2993 source, branches = hg.parseurl(ui.expandpath(source))
2994 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2994 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2995 repo = peer.local()
2995 repo = peer.local()
2996 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2996 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2997
2997
2998 fm = ui.formatter('identify', opts)
2998 fm = ui.formatter('identify', opts)
2999 fm.startitem()
2999 fm.startitem()
3000
3000
3001 if not repo:
3001 if not repo:
3002 if num or branch or tags:
3002 if num or branch or tags:
3003 raise error.Abort(
3003 raise error.Abort(
3004 _("can't query remote revision number, branch, or tags"))
3004 _("can't query remote revision number, branch, or tags"))
3005 if not rev and revs:
3005 if not rev and revs:
3006 rev = revs[0]
3006 rev = revs[0]
3007 if not rev:
3007 if not rev:
3008 rev = "tip"
3008 rev = "tip"
3009
3009
3010 remoterev = peer.lookup(rev)
3010 remoterev = peer.lookup(rev)
3011 hexrev = fm.hexfunc(remoterev)
3011 hexrev = fm.hexfunc(remoterev)
3012 if default or id:
3012 if default or id:
3013 output = [hexrev]
3013 output = [hexrev]
3014 fm.data(id=hexrev)
3014 fm.data(id=hexrev)
3015
3015
3016 def getbms():
3016 def getbms():
3017 bms = []
3017 bms = []
3018
3018
3019 if 'bookmarks' in peer.listkeys('namespaces'):
3019 if 'bookmarks' in peer.listkeys('namespaces'):
3020 hexremoterev = hex(remoterev)
3020 hexremoterev = hex(remoterev)
3021 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3021 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3022 if bmr == hexremoterev]
3022 if bmr == hexremoterev]
3023
3023
3024 return sorted(bms)
3024 return sorted(bms)
3025
3025
3026 bms = getbms()
3026 bms = getbms()
3027 if bookmarks:
3027 if bookmarks:
3028 output.extend(bms)
3028 output.extend(bms)
3029 elif default and not ui.quiet:
3029 elif default and not ui.quiet:
3030 # multiple bookmarks for a single parent separated by '/'
3030 # multiple bookmarks for a single parent separated by '/'
3031 bm = '/'.join(bms)
3031 bm = '/'.join(bms)
3032 if bm:
3032 if bm:
3033 output.append(bm)
3033 output.append(bm)
3034
3034
3035 fm.data(node=hex(remoterev))
3035 fm.data(node=hex(remoterev))
3036 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
3036 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
3037 else:
3037 else:
3038 if rev:
3038 if rev:
3039 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3039 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3040 ctx = scmutil.revsingle(repo, rev, None)
3040 ctx = scmutil.revsingle(repo, rev, None)
3041
3041
3042 if ctx.rev() is None:
3042 if ctx.rev() is None:
3043 ctx = repo[None]
3043 ctx = repo[None]
3044 parents = ctx.parents()
3044 parents = ctx.parents()
3045 taglist = []
3045 taglist = []
3046 for p in parents:
3046 for p in parents:
3047 taglist.extend(p.tags())
3047 taglist.extend(p.tags())
3048
3048
3049 dirty = ""
3049 dirty = ""
3050 if ctx.dirty(missing=True, merge=False, branch=False):
3050 if ctx.dirty(missing=True, merge=False, branch=False):
3051 dirty = '+'
3051 dirty = '+'
3052 fm.data(dirty=dirty)
3052 fm.data(dirty=dirty)
3053
3053
3054 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3054 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3055 if default or id:
3055 if default or id:
3056 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3056 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3057 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3057 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3058
3058
3059 if num:
3059 if num:
3060 numoutput = ["%d" % p.rev() for p in parents]
3060 numoutput = ["%d" % p.rev() for p in parents]
3061 output.append("%s%s" % ('+'.join(numoutput), dirty))
3061 output.append("%s%s" % ('+'.join(numoutput), dirty))
3062
3062
3063 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3063 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3064 for p in parents], name='node'))
3064 for p in parents], name='node'))
3065 else:
3065 else:
3066 hexoutput = fm.hexfunc(ctx.node())
3066 hexoutput = fm.hexfunc(ctx.node())
3067 if default or id:
3067 if default or id:
3068 output = [hexoutput]
3068 output = [hexoutput]
3069 fm.data(id=hexoutput)
3069 fm.data(id=hexoutput)
3070
3070
3071 if num:
3071 if num:
3072 output.append(pycompat.bytestr(ctx.rev()))
3072 output.append(pycompat.bytestr(ctx.rev()))
3073 taglist = ctx.tags()
3073 taglist = ctx.tags()
3074
3074
3075 if default and not ui.quiet:
3075 if default and not ui.quiet:
3076 b = ctx.branch()
3076 b = ctx.branch()
3077 if b != 'default':
3077 if b != 'default':
3078 output.append("(%s)" % b)
3078 output.append("(%s)" % b)
3079
3079
3080 # multiple tags for a single parent separated by '/'
3080 # multiple tags for a single parent separated by '/'
3081 t = '/'.join(taglist)
3081 t = '/'.join(taglist)
3082 if t:
3082 if t:
3083 output.append(t)
3083 output.append(t)
3084
3084
3085 # multiple bookmarks for a single parent separated by '/'
3085 # multiple bookmarks for a single parent separated by '/'
3086 bm = '/'.join(ctx.bookmarks())
3086 bm = '/'.join(ctx.bookmarks())
3087 if bm:
3087 if bm:
3088 output.append(bm)
3088 output.append(bm)
3089 else:
3089 else:
3090 if branch:
3090 if branch:
3091 output.append(ctx.branch())
3091 output.append(ctx.branch())
3092
3092
3093 if tags:
3093 if tags:
3094 output.extend(taglist)
3094 output.extend(taglist)
3095
3095
3096 if bookmarks:
3096 if bookmarks:
3097 output.extend(ctx.bookmarks())
3097 output.extend(ctx.bookmarks())
3098
3098
3099 fm.data(node=ctx.hex())
3099 fm.data(node=ctx.hex())
3100 fm.data(branch=ctx.branch())
3100 fm.data(branch=ctx.branch())
3101 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3101 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3102 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3102 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3103 fm.context(ctx=ctx)
3103 fm.context(ctx=ctx)
3104
3104
3105 fm.plain("%s\n" % ' '.join(output))
3105 fm.plain("%s\n" % ' '.join(output))
3106 fm.end()
3106 fm.end()
3107
3107
3108 @command('import|patch',
3108 @command('import|patch',
3109 [('p', 'strip', 1,
3109 [('p', 'strip', 1,
3110 _('directory strip option for patch. This has the same '
3110 _('directory strip option for patch. This has the same '
3111 'meaning as the corresponding patch option'), _('NUM')),
3111 'meaning as the corresponding patch option'), _('NUM')),
3112 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3112 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3113 ('e', 'edit', False, _('invoke editor on commit messages')),
3113 ('e', 'edit', False, _('invoke editor on commit messages')),
3114 ('f', 'force', None,
3114 ('f', 'force', None,
3115 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3115 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3116 ('', 'no-commit', None,
3116 ('', 'no-commit', None,
3117 _("don't commit, just update the working directory")),
3117 _("don't commit, just update the working directory")),
3118 ('', 'bypass', None,
3118 ('', 'bypass', None,
3119 _("apply patch without touching the working directory")),
3119 _("apply patch without touching the working directory")),
3120 ('', 'partial', None,
3120 ('', 'partial', None,
3121 _('commit even if some hunks fail')),
3121 _('commit even if some hunks fail')),
3122 ('', 'exact', None,
3122 ('', 'exact', None,
3123 _('abort if patch would apply lossily')),
3123 _('abort if patch would apply lossily')),
3124 ('', 'prefix', '',
3124 ('', 'prefix', '',
3125 _('apply patch to subdirectory'), _('DIR')),
3125 _('apply patch to subdirectory'), _('DIR')),
3126 ('', 'import-branch', None,
3126 ('', 'import-branch', None,
3127 _('use any branch information in patch (implied by --exact)'))] +
3127 _('use any branch information in patch (implied by --exact)'))] +
3128 commitopts + commitopts2 + similarityopts,
3128 commitopts + commitopts2 + similarityopts,
3129 _('[OPTION]... PATCH...'))
3129 _('[OPTION]... PATCH...'))
3130 def import_(ui, repo, patch1=None, *patches, **opts):
3130 def import_(ui, repo, patch1=None, *patches, **opts):
3131 """import an ordered set of patches
3131 """import an ordered set of patches
3132
3132
3133 Import a list of patches and commit them individually (unless
3133 Import a list of patches and commit them individually (unless
3134 --no-commit is specified).
3134 --no-commit is specified).
3135
3135
3136 To read a patch from standard input (stdin), use "-" as the patch
3136 To read a patch from standard input (stdin), use "-" as the patch
3137 name. If a URL is specified, the patch will be downloaded from
3137 name. If a URL is specified, the patch will be downloaded from
3138 there.
3138 there.
3139
3139
3140 Import first applies changes to the working directory (unless
3140 Import first applies changes to the working directory (unless
3141 --bypass is specified), import will abort if there are outstanding
3141 --bypass is specified), import will abort if there are outstanding
3142 changes.
3142 changes.
3143
3143
3144 Use --bypass to apply and commit patches directly to the
3144 Use --bypass to apply and commit patches directly to the
3145 repository, without affecting the working directory. Without
3145 repository, without affecting the working directory. Without
3146 --exact, patches will be applied on top of the working directory
3146 --exact, patches will be applied on top of the working directory
3147 parent revision.
3147 parent revision.
3148
3148
3149 You can import a patch straight from a mail message. Even patches
3149 You can import a patch straight from a mail message. Even patches
3150 as attachments work (to use the body part, it must have type
3150 as attachments work (to use the body part, it must have type
3151 text/plain or text/x-patch). From and Subject headers of email
3151 text/plain or text/x-patch). From and Subject headers of email
3152 message are used as default committer and commit message. All
3152 message are used as default committer and commit message. All
3153 text/plain body parts before first diff are added to the commit
3153 text/plain body parts before first diff are added to the commit
3154 message.
3154 message.
3155
3155
3156 If the imported patch was generated by :hg:`export`, user and
3156 If the imported patch was generated by :hg:`export`, user and
3157 description from patch override values from message headers and
3157 description from patch override values from message headers and
3158 body. Values given on command line with -m/--message and -u/--user
3158 body. Values given on command line with -m/--message and -u/--user
3159 override these.
3159 override these.
3160
3160
3161 If --exact is specified, import will set the working directory to
3161 If --exact is specified, import will set the working directory to
3162 the parent of each patch before applying it, and will abort if the
3162 the parent of each patch before applying it, and will abort if the
3163 resulting changeset has a different ID than the one recorded in
3163 resulting changeset has a different ID than the one recorded in
3164 the patch. This will guard against various ways that portable
3164 the patch. This will guard against various ways that portable
3165 patch formats and mail systems might fail to transfer Mercurial
3165 patch formats and mail systems might fail to transfer Mercurial
3166 data or metadata. See :hg:`bundle` for lossless transmission.
3166 data or metadata. See :hg:`bundle` for lossless transmission.
3167
3167
3168 Use --partial to ensure a changeset will be created from the patch
3168 Use --partial to ensure a changeset will be created from the patch
3169 even if some hunks fail to apply. Hunks that fail to apply will be
3169 even if some hunks fail to apply. Hunks that fail to apply will be
3170 written to a <target-file>.rej file. Conflicts can then be resolved
3170 written to a <target-file>.rej file. Conflicts can then be resolved
3171 by hand before :hg:`commit --amend` is run to update the created
3171 by hand before :hg:`commit --amend` is run to update the created
3172 changeset. This flag exists to let people import patches that
3172 changeset. This flag exists to let people import patches that
3173 partially apply without losing the associated metadata (author,
3173 partially apply without losing the associated metadata (author,
3174 date, description, ...).
3174 date, description, ...).
3175
3175
3176 .. note::
3176 .. note::
3177
3177
3178 When no hunks apply cleanly, :hg:`import --partial` will create
3178 When no hunks apply cleanly, :hg:`import --partial` will create
3179 an empty changeset, importing only the patch metadata.
3179 an empty changeset, importing only the patch metadata.
3180
3180
3181 With -s/--similarity, hg will attempt to discover renames and
3181 With -s/--similarity, hg will attempt to discover renames and
3182 copies in the patch in the same way as :hg:`addremove`.
3182 copies in the patch in the same way as :hg:`addremove`.
3183
3183
3184 It is possible to use external patch programs to perform the patch
3184 It is possible to use external patch programs to perform the patch
3185 by setting the ``ui.patch`` configuration option. For the default
3185 by setting the ``ui.patch`` configuration option. For the default
3186 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3186 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3187 See :hg:`help config` for more information about configuration
3187 See :hg:`help config` for more information about configuration
3188 files and how to use these options.
3188 files and how to use these options.
3189
3189
3190 See :hg:`help dates` for a list of formats valid for -d/--date.
3190 See :hg:`help dates` for a list of formats valid for -d/--date.
3191
3191
3192 .. container:: verbose
3192 .. container:: verbose
3193
3193
3194 Examples:
3194 Examples:
3195
3195
3196 - import a traditional patch from a website and detect renames::
3196 - import a traditional patch from a website and detect renames::
3197
3197
3198 hg import -s 80 http://example.com/bugfix.patch
3198 hg import -s 80 http://example.com/bugfix.patch
3199
3199
3200 - import a changeset from an hgweb server::
3200 - import a changeset from an hgweb server::
3201
3201
3202 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3202 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3203
3203
3204 - import all the patches in an Unix-style mbox::
3204 - import all the patches in an Unix-style mbox::
3205
3205
3206 hg import incoming-patches.mbox
3206 hg import incoming-patches.mbox
3207
3207
3208 - import patches from stdin::
3208 - import patches from stdin::
3209
3209
3210 hg import -
3210 hg import -
3211
3211
3212 - attempt to exactly restore an exported changeset (not always
3212 - attempt to exactly restore an exported changeset (not always
3213 possible)::
3213 possible)::
3214
3214
3215 hg import --exact proposed-fix.patch
3215 hg import --exact proposed-fix.patch
3216
3216
3217 - use an external tool to apply a patch which is too fuzzy for
3217 - use an external tool to apply a patch which is too fuzzy for
3218 the default internal tool.
3218 the default internal tool.
3219
3219
3220 hg import --config ui.patch="patch --merge" fuzzy.patch
3220 hg import --config ui.patch="patch --merge" fuzzy.patch
3221
3221
3222 - change the default fuzzing from 2 to a less strict 7
3222 - change the default fuzzing from 2 to a less strict 7
3223
3223
3224 hg import --config ui.fuzz=7 fuzz.patch
3224 hg import --config ui.fuzz=7 fuzz.patch
3225
3225
3226 Returns 0 on success, 1 on partial success (see --partial).
3226 Returns 0 on success, 1 on partial success (see --partial).
3227 """
3227 """
3228
3228
3229 opts = pycompat.byteskwargs(opts)
3229 opts = pycompat.byteskwargs(opts)
3230 if not patch1:
3230 if not patch1:
3231 raise error.Abort(_('need at least one patch to import'))
3231 raise error.Abort(_('need at least one patch to import'))
3232
3232
3233 patches = (patch1,) + patches
3233 patches = (patch1,) + patches
3234
3234
3235 date = opts.get('date')
3235 date = opts.get('date')
3236 if date:
3236 if date:
3237 opts['date'] = dateutil.parsedate(date)
3237 opts['date'] = dateutil.parsedate(date)
3238
3238
3239 exact = opts.get('exact')
3239 exact = opts.get('exact')
3240 update = not opts.get('bypass')
3240 update = not opts.get('bypass')
3241 if not update and opts.get('no_commit'):
3241 if not update and opts.get('no_commit'):
3242 raise error.Abort(_('cannot use --no-commit with --bypass'))
3242 raise error.Abort(_('cannot use --no-commit with --bypass'))
3243 try:
3243 try:
3244 sim = float(opts.get('similarity') or 0)
3244 sim = float(opts.get('similarity') or 0)
3245 except ValueError:
3245 except ValueError:
3246 raise error.Abort(_('similarity must be a number'))
3246 raise error.Abort(_('similarity must be a number'))
3247 if sim < 0 or sim > 100:
3247 if sim < 0 or sim > 100:
3248 raise error.Abort(_('similarity must be between 0 and 100'))
3248 raise error.Abort(_('similarity must be between 0 and 100'))
3249 if sim and not update:
3249 if sim and not update:
3250 raise error.Abort(_('cannot use --similarity with --bypass'))
3250 raise error.Abort(_('cannot use --similarity with --bypass'))
3251 if exact:
3251 if exact:
3252 if opts.get('edit'):
3252 if opts.get('edit'):
3253 raise error.Abort(_('cannot use --exact with --edit'))
3253 raise error.Abort(_('cannot use --exact with --edit'))
3254 if opts.get('prefix'):
3254 if opts.get('prefix'):
3255 raise error.Abort(_('cannot use --exact with --prefix'))
3255 raise error.Abort(_('cannot use --exact with --prefix'))
3256
3256
3257 base = opts["base"]
3257 base = opts["base"]
3258 msgs = []
3258 msgs = []
3259 ret = 0
3259 ret = 0
3260
3260
3261 with repo.wlock():
3261 with repo.wlock():
3262 if update:
3262 if update:
3263 cmdutil.checkunfinished(repo)
3263 cmdutil.checkunfinished(repo)
3264 if (exact or not opts.get('force')):
3264 if (exact or not opts.get('force')):
3265 cmdutil.bailifchanged(repo)
3265 cmdutil.bailifchanged(repo)
3266
3266
3267 if not opts.get('no_commit'):
3267 if not opts.get('no_commit'):
3268 lock = repo.lock
3268 lock = repo.lock
3269 tr = lambda: repo.transaction('import')
3269 tr = lambda: repo.transaction('import')
3270 dsguard = util.nullcontextmanager
3270 dsguard = util.nullcontextmanager
3271 else:
3271 else:
3272 lock = util.nullcontextmanager
3272 lock = util.nullcontextmanager
3273 tr = util.nullcontextmanager
3273 tr = util.nullcontextmanager
3274 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3274 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3275 with lock(), tr(), dsguard():
3275 with lock(), tr(), dsguard():
3276 parents = repo[None].parents()
3276 parents = repo[None].parents()
3277 for patchurl in patches:
3277 for patchurl in patches:
3278 if patchurl == '-':
3278 if patchurl == '-':
3279 ui.status(_('applying patch from stdin\n'))
3279 ui.status(_('applying patch from stdin\n'))
3280 patchfile = ui.fin
3280 patchfile = ui.fin
3281 patchurl = 'stdin' # for error message
3281 patchurl = 'stdin' # for error message
3282 else:
3282 else:
3283 patchurl = os.path.join(base, patchurl)
3283 patchurl = os.path.join(base, patchurl)
3284 ui.status(_('applying %s\n') % patchurl)
3284 ui.status(_('applying %s\n') % patchurl)
3285 patchfile = hg.openpath(ui, patchurl)
3285 patchfile = hg.openpath(ui, patchurl)
3286
3286
3287 haspatch = False
3287 haspatch = False
3288 for hunk in patch.split(patchfile):
3288 for hunk in patch.split(patchfile):
3289 with patch.extract(ui, hunk) as patchdata:
3289 with patch.extract(ui, hunk) as patchdata:
3290 msg, node, rej = cmdutil.tryimportone(ui, repo,
3290 msg, node, rej = cmdutil.tryimportone(ui, repo,
3291 patchdata,
3291 patchdata,
3292 parents, opts,
3292 parents, opts,
3293 msgs, hg.clean)
3293 msgs, hg.clean)
3294 if msg:
3294 if msg:
3295 haspatch = True
3295 haspatch = True
3296 ui.note(msg + '\n')
3296 ui.note(msg + '\n')
3297 if update or exact:
3297 if update or exact:
3298 parents = repo[None].parents()
3298 parents = repo[None].parents()
3299 else:
3299 else:
3300 parents = [repo[node]]
3300 parents = [repo[node]]
3301 if rej:
3301 if rej:
3302 ui.write_err(_("patch applied partially\n"))
3302 ui.write_err(_("patch applied partially\n"))
3303 ui.write_err(_("(fix the .rej files and run "
3303 ui.write_err(_("(fix the .rej files and run "
3304 "`hg commit --amend`)\n"))
3304 "`hg commit --amend`)\n"))
3305 ret = 1
3305 ret = 1
3306 break
3306 break
3307
3307
3308 if not haspatch:
3308 if not haspatch:
3309 raise error.Abort(_('%s: no diffs found') % patchurl)
3309 raise error.Abort(_('%s: no diffs found') % patchurl)
3310
3310
3311 if msgs:
3311 if msgs:
3312 repo.savecommitmessage('\n* * *\n'.join(msgs))
3312 repo.savecommitmessage('\n* * *\n'.join(msgs))
3313 return ret
3313 return ret
3314
3314
3315 @command('incoming|in',
3315 @command('incoming|in',
3316 [('f', 'force', None,
3316 [('f', 'force', None,
3317 _('run even if remote repository is unrelated')),
3317 _('run even if remote repository is unrelated')),
3318 ('n', 'newest-first', None, _('show newest record first')),
3318 ('n', 'newest-first', None, _('show newest record first')),
3319 ('', 'bundle', '',
3319 ('', 'bundle', '',
3320 _('file to store the bundles into'), _('FILE')),
3320 _('file to store the bundles into'), _('FILE')),
3321 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3321 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3322 ('B', 'bookmarks', False, _("compare bookmarks")),
3322 ('B', 'bookmarks', False, _("compare bookmarks")),
3323 ('b', 'branch', [],
3323 ('b', 'branch', [],
3324 _('a specific branch you would like to pull'), _('BRANCH')),
3324 _('a specific branch you would like to pull'), _('BRANCH')),
3325 ] + logopts + remoteopts + subrepoopts,
3325 ] + logopts + remoteopts + subrepoopts,
3326 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3326 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3327 def incoming(ui, repo, source="default", **opts):
3327 def incoming(ui, repo, source="default", **opts):
3328 """show new changesets found in source
3328 """show new changesets found in source
3329
3329
3330 Show new changesets found in the specified path/URL or the default
3330 Show new changesets found in the specified path/URL or the default
3331 pull location. These are the changesets that would have been pulled
3331 pull location. These are the changesets that would have been pulled
3332 by :hg:`pull` at the time you issued this command.
3332 by :hg:`pull` at the time you issued this command.
3333
3333
3334 See pull for valid source format details.
3334 See pull for valid source format details.
3335
3335
3336 .. container:: verbose
3336 .. container:: verbose
3337
3337
3338 With -B/--bookmarks, the result of bookmark comparison between
3338 With -B/--bookmarks, the result of bookmark comparison between
3339 local and remote repositories is displayed. With -v/--verbose,
3339 local and remote repositories is displayed. With -v/--verbose,
3340 status is also displayed for each bookmark like below::
3340 status is also displayed for each bookmark like below::
3341
3341
3342 BM1 01234567890a added
3342 BM1 01234567890a added
3343 BM2 1234567890ab advanced
3343 BM2 1234567890ab advanced
3344 BM3 234567890abc diverged
3344 BM3 234567890abc diverged
3345 BM4 34567890abcd changed
3345 BM4 34567890abcd changed
3346
3346
3347 The action taken locally when pulling depends on the
3347 The action taken locally when pulling depends on the
3348 status of each bookmark:
3348 status of each bookmark:
3349
3349
3350 :``added``: pull will create it
3350 :``added``: pull will create it
3351 :``advanced``: pull will update it
3351 :``advanced``: pull will update it
3352 :``diverged``: pull will create a divergent bookmark
3352 :``diverged``: pull will create a divergent bookmark
3353 :``changed``: result depends on remote changesets
3353 :``changed``: result depends on remote changesets
3354
3354
3355 From the point of view of pulling behavior, bookmark
3355 From the point of view of pulling behavior, bookmark
3356 existing only in the remote repository are treated as ``added``,
3356 existing only in the remote repository are treated as ``added``,
3357 even if it is in fact locally deleted.
3357 even if it is in fact locally deleted.
3358
3358
3359 .. container:: verbose
3359 .. container:: verbose
3360
3360
3361 For remote repository, using --bundle avoids downloading the
3361 For remote repository, using --bundle avoids downloading the
3362 changesets twice if the incoming is followed by a pull.
3362 changesets twice if the incoming is followed by a pull.
3363
3363
3364 Examples:
3364 Examples:
3365
3365
3366 - show incoming changes with patches and full description::
3366 - show incoming changes with patches and full description::
3367
3367
3368 hg incoming -vp
3368 hg incoming -vp
3369
3369
3370 - show incoming changes excluding merges, store a bundle::
3370 - show incoming changes excluding merges, store a bundle::
3371
3371
3372 hg in -vpM --bundle incoming.hg
3372 hg in -vpM --bundle incoming.hg
3373 hg pull incoming.hg
3373 hg pull incoming.hg
3374
3374
3375 - briefly list changes inside a bundle::
3375 - briefly list changes inside a bundle::
3376
3376
3377 hg in changes.hg -T "{desc|firstline}\\n"
3377 hg in changes.hg -T "{desc|firstline}\\n"
3378
3378
3379 Returns 0 if there are incoming changes, 1 otherwise.
3379 Returns 0 if there are incoming changes, 1 otherwise.
3380 """
3380 """
3381 opts = pycompat.byteskwargs(opts)
3381 opts = pycompat.byteskwargs(opts)
3382 if opts.get('graph'):
3382 if opts.get('graph'):
3383 logcmdutil.checkunsupportedgraphflags([], opts)
3383 logcmdutil.checkunsupportedgraphflags([], opts)
3384 def display(other, chlist, displayer):
3384 def display(other, chlist, displayer):
3385 revdag = logcmdutil.graphrevs(other, chlist, opts)
3385 revdag = logcmdutil.graphrevs(other, chlist, opts)
3386 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3386 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3387 graphmod.asciiedges)
3387 graphmod.asciiedges)
3388
3388
3389 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3389 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3390 return 0
3390 return 0
3391
3391
3392 if opts.get('bundle') and opts.get('subrepos'):
3392 if opts.get('bundle') and opts.get('subrepos'):
3393 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3393 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3394
3394
3395 if opts.get('bookmarks'):
3395 if opts.get('bookmarks'):
3396 source, branches = hg.parseurl(ui.expandpath(source),
3396 source, branches = hg.parseurl(ui.expandpath(source),
3397 opts.get('branch'))
3397 opts.get('branch'))
3398 other = hg.peer(repo, opts, source)
3398 other = hg.peer(repo, opts, source)
3399 if 'bookmarks' not in other.listkeys('namespaces'):
3399 if 'bookmarks' not in other.listkeys('namespaces'):
3400 ui.warn(_("remote doesn't support bookmarks\n"))
3400 ui.warn(_("remote doesn't support bookmarks\n"))
3401 return 0
3401 return 0
3402 ui.pager('incoming')
3402 ui.pager('incoming')
3403 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3403 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3404 return bookmarks.incoming(ui, repo, other)
3404 return bookmarks.incoming(ui, repo, other)
3405
3405
3406 repo._subtoppath = ui.expandpath(source)
3406 repo._subtoppath = ui.expandpath(source)
3407 try:
3407 try:
3408 return hg.incoming(ui, repo, source, opts)
3408 return hg.incoming(ui, repo, source, opts)
3409 finally:
3409 finally:
3410 del repo._subtoppath
3410 del repo._subtoppath
3411
3411
3412
3412
3413 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3413 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3414 norepo=True)
3414 norepo=True)
3415 def init(ui, dest=".", **opts):
3415 def init(ui, dest=".", **opts):
3416 """create a new repository in the given directory
3416 """create a new repository in the given directory
3417
3417
3418 Initialize a new repository in the given directory. If the given
3418 Initialize a new repository in the given directory. If the given
3419 directory does not exist, it will be created.
3419 directory does not exist, it will be created.
3420
3420
3421 If no directory is given, the current directory is used.
3421 If no directory is given, the current directory is used.
3422
3422
3423 It is possible to specify an ``ssh://`` URL as the destination.
3423 It is possible to specify an ``ssh://`` URL as the destination.
3424 See :hg:`help urls` for more information.
3424 See :hg:`help urls` for more information.
3425
3425
3426 Returns 0 on success.
3426 Returns 0 on success.
3427 """
3427 """
3428 opts = pycompat.byteskwargs(opts)
3428 opts = pycompat.byteskwargs(opts)
3429 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3429 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3430
3430
3431 @command('locate',
3431 @command('locate',
3432 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3432 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3433 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3433 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3434 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3434 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3435 ] + walkopts,
3435 ] + walkopts,
3436 _('[OPTION]... [PATTERN]...'))
3436 _('[OPTION]... [PATTERN]...'))
3437 def locate(ui, repo, *pats, **opts):
3437 def locate(ui, repo, *pats, **opts):
3438 """locate files matching specific patterns (DEPRECATED)
3438 """locate files matching specific patterns (DEPRECATED)
3439
3439
3440 Print files under Mercurial control in the working directory whose
3440 Print files under Mercurial control in the working directory whose
3441 names match the given patterns.
3441 names match the given patterns.
3442
3442
3443 By default, this command searches all directories in the working
3443 By default, this command searches all directories in the working
3444 directory. To search just the current directory and its
3444 directory. To search just the current directory and its
3445 subdirectories, use "--include .".
3445 subdirectories, use "--include .".
3446
3446
3447 If no patterns are given to match, this command prints the names
3447 If no patterns are given to match, this command prints the names
3448 of all files under Mercurial control in the working directory.
3448 of all files under Mercurial control in the working directory.
3449
3449
3450 If you want to feed the output of this command into the "xargs"
3450 If you want to feed the output of this command into the "xargs"
3451 command, use the -0 option to both this command and "xargs". This
3451 command, use the -0 option to both this command and "xargs". This
3452 will avoid the problem of "xargs" treating single filenames that
3452 will avoid the problem of "xargs" treating single filenames that
3453 contain whitespace as multiple filenames.
3453 contain whitespace as multiple filenames.
3454
3454
3455 See :hg:`help files` for a more versatile command.
3455 See :hg:`help files` for a more versatile command.
3456
3456
3457 Returns 0 if a match is found, 1 otherwise.
3457 Returns 0 if a match is found, 1 otherwise.
3458 """
3458 """
3459 opts = pycompat.byteskwargs(opts)
3459 opts = pycompat.byteskwargs(opts)
3460 if opts.get('print0'):
3460 if opts.get('print0'):
3461 end = '\0'
3461 end = '\0'
3462 else:
3462 else:
3463 end = '\n'
3463 end = '\n'
3464 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3464 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3465
3465
3466 ret = 1
3466 ret = 1
3467 m = scmutil.match(ctx, pats, opts, default='relglob',
3467 m = scmutil.match(ctx, pats, opts, default='relglob',
3468 badfn=lambda x, y: False)
3468 badfn=lambda x, y: False)
3469
3469
3470 ui.pager('locate')
3470 ui.pager('locate')
3471 if ctx.rev() is None:
3471 if ctx.rev() is None:
3472 # When run on the working copy, "locate" includes removed files, so
3472 # When run on the working copy, "locate" includes removed files, so
3473 # we get the list of files from the dirstate.
3473 # we get the list of files from the dirstate.
3474 filesgen = sorted(repo.dirstate.matches(m))
3474 filesgen = sorted(repo.dirstate.matches(m))
3475 else:
3475 else:
3476 filesgen = ctx.matches(m)
3476 filesgen = ctx.matches(m)
3477 for abs in filesgen:
3477 for abs in filesgen:
3478 if opts.get('fullpath'):
3478 if opts.get('fullpath'):
3479 ui.write(repo.wjoin(abs), end)
3479 ui.write(repo.wjoin(abs), end)
3480 else:
3480 else:
3481 ui.write(((pats and m.rel(abs)) or abs), end)
3481 ui.write(((pats and m.rel(abs)) or abs), end)
3482 ret = 0
3482 ret = 0
3483
3483
3484 return ret
3484 return ret
3485
3485
3486 @command('^log|history',
3486 @command('^log|history',
3487 [('f', 'follow', None,
3487 [('f', 'follow', None,
3488 _('follow changeset history, or file history across copies and renames')),
3488 _('follow changeset history, or file history across copies and renames')),
3489 ('', 'follow-first', None,
3489 ('', 'follow-first', None,
3490 _('only follow the first parent of merge changesets (DEPRECATED)')),
3490 _('only follow the first parent of merge changesets (DEPRECATED)')),
3491 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3491 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3492 ('C', 'copies', None, _('show copied files')),
3492 ('C', 'copies', None, _('show copied files')),
3493 ('k', 'keyword', [],
3493 ('k', 'keyword', [],
3494 _('do case-insensitive search for a given text'), _('TEXT')),
3494 _('do case-insensitive search for a given text'), _('TEXT')),
3495 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3495 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3496 ('L', 'line-range', [],
3496 ('L', 'line-range', [],
3497 _('follow line range of specified file (EXPERIMENTAL)'),
3497 _('follow line range of specified file (EXPERIMENTAL)'),
3498 _('FILE,RANGE')),
3498 _('FILE,RANGE')),
3499 ('', 'removed', None, _('include revisions where files were removed')),
3499 ('', 'removed', None, _('include revisions where files were removed')),
3500 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3500 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3501 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3501 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3502 ('', 'only-branch', [],
3502 ('', 'only-branch', [],
3503 _('show only changesets within the given named branch (DEPRECATED)'),
3503 _('show only changesets within the given named branch (DEPRECATED)'),
3504 _('BRANCH')),
3504 _('BRANCH')),
3505 ('b', 'branch', [],
3505 ('b', 'branch', [],
3506 _('show changesets within the given named branch'), _('BRANCH')),
3506 _('show changesets within the given named branch'), _('BRANCH')),
3507 ('P', 'prune', [],
3507 ('P', 'prune', [],
3508 _('do not display revision or any of its ancestors'), _('REV')),
3508 _('do not display revision or any of its ancestors'), _('REV')),
3509 ] + logopts + walkopts,
3509 ] + logopts + walkopts,
3510 _('[OPTION]... [FILE]'),
3510 _('[OPTION]... [FILE]'),
3511 inferrepo=True,
3511 inferrepo=True,
3512 intents={INTENT_READONLY})
3512 intents={INTENT_READONLY})
3513 def log(ui, repo, *pats, **opts):
3513 def log(ui, repo, *pats, **opts):
3514 """show revision history of entire repository or files
3514 """show revision history of entire repository or files
3515
3515
3516 Print the revision history of the specified files or the entire
3516 Print the revision history of the specified files or the entire
3517 project.
3517 project.
3518
3518
3519 If no revision range is specified, the default is ``tip:0`` unless
3519 If no revision range is specified, the default is ``tip:0`` unless
3520 --follow is set, in which case the working directory parent is
3520 --follow is set, in which case the working directory parent is
3521 used as the starting revision.
3521 used as the starting revision.
3522
3522
3523 File history is shown without following rename or copy history of
3523 File history is shown without following rename or copy history of
3524 files. Use -f/--follow with a filename to follow history across
3524 files. Use -f/--follow with a filename to follow history across
3525 renames and copies. --follow without a filename will only show
3525 renames and copies. --follow without a filename will only show
3526 ancestors of the starting revision.
3526 ancestors of the starting revision.
3527
3527
3528 By default this command prints revision number and changeset id,
3528 By default this command prints revision number and changeset id,
3529 tags, non-trivial parents, user, date and time, and a summary for
3529 tags, non-trivial parents, user, date and time, and a summary for
3530 each commit. When the -v/--verbose switch is used, the list of
3530 each commit. When the -v/--verbose switch is used, the list of
3531 changed files and full commit message are shown.
3531 changed files and full commit message are shown.
3532
3532
3533 With --graph the revisions are shown as an ASCII art DAG with the most
3533 With --graph the revisions are shown as an ASCII art DAG with the most
3534 recent changeset at the top.
3534 recent changeset at the top.
3535 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3535 'o' is a changeset, '@' is a working directory parent, '_' closes a branch,
3536 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3536 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3537 changeset from the lines below is a parent of the 'o' merge on the same
3537 changeset from the lines below is a parent of the 'o' merge on the same
3538 line.
3538 line.
3539 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3539 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3540 of a '|' indicates one or more revisions in a path are omitted.
3540 of a '|' indicates one or more revisions in a path are omitted.
3541
3541
3542 .. container:: verbose
3542 .. container:: verbose
3543
3543
3544 Use -L/--line-range FILE,M:N options to follow the history of lines
3544 Use -L/--line-range FILE,M:N options to follow the history of lines
3545 from M to N in FILE. With -p/--patch only diff hunks affecting
3545 from M to N in FILE. With -p/--patch only diff hunks affecting
3546 specified line range will be shown. This option requires --follow;
3546 specified line range will be shown. This option requires --follow;
3547 it can be specified multiple times. Currently, this option is not
3547 it can be specified multiple times. Currently, this option is not
3548 compatible with --graph. This option is experimental.
3548 compatible with --graph. This option is experimental.
3549
3549
3550 .. note::
3550 .. note::
3551
3551
3552 :hg:`log --patch` may generate unexpected diff output for merge
3552 :hg:`log --patch` may generate unexpected diff output for merge
3553 changesets, as it will only compare the merge changeset against
3553 changesets, as it will only compare the merge changeset against
3554 its first parent. Also, only files different from BOTH parents
3554 its first parent. Also, only files different from BOTH parents
3555 will appear in files:.
3555 will appear in files:.
3556
3556
3557 .. note::
3557 .. note::
3558
3558
3559 For performance reasons, :hg:`log FILE` may omit duplicate changes
3559 For performance reasons, :hg:`log FILE` may omit duplicate changes
3560 made on branches and will not show removals or mode changes. To
3560 made on branches and will not show removals or mode changes. To
3561 see all such changes, use the --removed switch.
3561 see all such changes, use the --removed switch.
3562
3562
3563 .. container:: verbose
3563 .. container:: verbose
3564
3564
3565 .. note::
3565 .. note::
3566
3566
3567 The history resulting from -L/--line-range options depends on diff
3567 The history resulting from -L/--line-range options depends on diff
3568 options; for instance if white-spaces are ignored, respective changes
3568 options; for instance if white-spaces are ignored, respective changes
3569 with only white-spaces in specified line range will not be listed.
3569 with only white-spaces in specified line range will not be listed.
3570
3570
3571 .. container:: verbose
3571 .. container:: verbose
3572
3572
3573 Some examples:
3573 Some examples:
3574
3574
3575 - changesets with full descriptions and file lists::
3575 - changesets with full descriptions and file lists::
3576
3576
3577 hg log -v
3577 hg log -v
3578
3578
3579 - changesets ancestral to the working directory::
3579 - changesets ancestral to the working directory::
3580
3580
3581 hg log -f
3581 hg log -f
3582
3582
3583 - last 10 commits on the current branch::
3583 - last 10 commits on the current branch::
3584
3584
3585 hg log -l 10 -b .
3585 hg log -l 10 -b .
3586
3586
3587 - changesets showing all modifications of a file, including removals::
3587 - changesets showing all modifications of a file, including removals::
3588
3588
3589 hg log --removed file.c
3589 hg log --removed file.c
3590
3590
3591 - all changesets that touch a directory, with diffs, excluding merges::
3591 - all changesets that touch a directory, with diffs, excluding merges::
3592
3592
3593 hg log -Mp lib/
3593 hg log -Mp lib/
3594
3594
3595 - all revision numbers that match a keyword::
3595 - all revision numbers that match a keyword::
3596
3596
3597 hg log -k bug --template "{rev}\\n"
3597 hg log -k bug --template "{rev}\\n"
3598
3598
3599 - the full hash identifier of the working directory parent::
3599 - the full hash identifier of the working directory parent::
3600
3600
3601 hg log -r . --template "{node}\\n"
3601 hg log -r . --template "{node}\\n"
3602
3602
3603 - list available log templates::
3603 - list available log templates::
3604
3604
3605 hg log -T list
3605 hg log -T list
3606
3606
3607 - check if a given changeset is included in a tagged release::
3607 - check if a given changeset is included in a tagged release::
3608
3608
3609 hg log -r "a21ccf and ancestor(1.9)"
3609 hg log -r "a21ccf and ancestor(1.9)"
3610
3610
3611 - find all changesets by some user in a date range::
3611 - find all changesets by some user in a date range::
3612
3612
3613 hg log -k alice -d "may 2008 to jul 2008"
3613 hg log -k alice -d "may 2008 to jul 2008"
3614
3614
3615 - summary of all changesets after the last tag::
3615 - summary of all changesets after the last tag::
3616
3616
3617 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3617 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3618
3618
3619 - changesets touching lines 13 to 23 for file.c::
3619 - changesets touching lines 13 to 23 for file.c::
3620
3620
3621 hg log -L file.c,13:23
3621 hg log -L file.c,13:23
3622
3622
3623 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3623 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3624 main.c with patch::
3624 main.c with patch::
3625
3625
3626 hg log -L file.c,13:23 -L main.c,2:6 -p
3626 hg log -L file.c,13:23 -L main.c,2:6 -p
3627
3627
3628 See :hg:`help dates` for a list of formats valid for -d/--date.
3628 See :hg:`help dates` for a list of formats valid for -d/--date.
3629
3629
3630 See :hg:`help revisions` for more about specifying and ordering
3630 See :hg:`help revisions` for more about specifying and ordering
3631 revisions.
3631 revisions.
3632
3632
3633 See :hg:`help templates` for more about pre-packaged styles and
3633 See :hg:`help templates` for more about pre-packaged styles and
3634 specifying custom templates. The default template used by the log
3634 specifying custom templates. The default template used by the log
3635 command can be customized via the ``ui.logtemplate`` configuration
3635 command can be customized via the ``ui.logtemplate`` configuration
3636 setting.
3636 setting.
3637
3637
3638 Returns 0 on success.
3638 Returns 0 on success.
3639
3639
3640 """
3640 """
3641 opts = pycompat.byteskwargs(opts)
3641 opts = pycompat.byteskwargs(opts)
3642 linerange = opts.get('line_range')
3642 linerange = opts.get('line_range')
3643
3643
3644 if linerange and not opts.get('follow'):
3644 if linerange and not opts.get('follow'):
3645 raise error.Abort(_('--line-range requires --follow'))
3645 raise error.Abort(_('--line-range requires --follow'))
3646
3646
3647 if linerange and pats:
3647 if linerange and pats:
3648 # TODO: take pats as patterns with no line-range filter
3648 # TODO: take pats as patterns with no line-range filter
3649 raise error.Abort(
3649 raise error.Abort(
3650 _('FILE arguments are not compatible with --line-range option')
3650 _('FILE arguments are not compatible with --line-range option')
3651 )
3651 )
3652
3652
3653 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3653 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3654 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3654 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3655 if linerange:
3655 if linerange:
3656 # TODO: should follow file history from logcmdutil._initialrevs(),
3656 # TODO: should follow file history from logcmdutil._initialrevs(),
3657 # then filter the result by logcmdutil._makerevset() and --limit
3657 # then filter the result by logcmdutil._makerevset() and --limit
3658 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3658 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3659
3659
3660 getrenamed = None
3660 getrenamed = None
3661 if opts.get('copies'):
3661 if opts.get('copies'):
3662 endrev = None
3662 endrev = None
3663 if revs:
3663 if revs:
3664 endrev = revs.max() + 1
3664 endrev = revs.max() + 1
3665 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3665 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3666
3666
3667 ui.pager('log')
3667 ui.pager('log')
3668 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3668 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3669 buffered=True)
3669 buffered=True)
3670 if opts.get('graph'):
3670 if opts.get('graph'):
3671 displayfn = logcmdutil.displaygraphrevs
3671 displayfn = logcmdutil.displaygraphrevs
3672 else:
3672 else:
3673 displayfn = logcmdutil.displayrevs
3673 displayfn = logcmdutil.displayrevs
3674 displayfn(ui, repo, revs, displayer, getrenamed)
3674 displayfn(ui, repo, revs, displayer, getrenamed)
3675
3675
3676 @command('manifest',
3676 @command('manifest',
3677 [('r', 'rev', '', _('revision to display'), _('REV')),
3677 [('r', 'rev', '', _('revision to display'), _('REV')),
3678 ('', 'all', False, _("list files from all revisions"))]
3678 ('', 'all', False, _("list files from all revisions"))]
3679 + formatteropts,
3679 + formatteropts,
3680 _('[-r REV]'),
3680 _('[-r REV]'),
3681 intents={INTENT_READONLY})
3681 intents={INTENT_READONLY})
3682 def manifest(ui, repo, node=None, rev=None, **opts):
3682 def manifest(ui, repo, node=None, rev=None, **opts):
3683 """output the current or given revision of the project manifest
3683 """output the current or given revision of the project manifest
3684
3684
3685 Print a list of version controlled files for the given revision.
3685 Print a list of version controlled files for the given revision.
3686 If no revision is given, the first parent of the working directory
3686 If no revision is given, the first parent of the working directory
3687 is used, or the null revision if no revision is checked out.
3687 is used, or the null revision if no revision is checked out.
3688
3688
3689 With -v, print file permissions, symlink and executable bits.
3689 With -v, print file permissions, symlink and executable bits.
3690 With --debug, print file revision hashes.
3690 With --debug, print file revision hashes.
3691
3691
3692 If option --all is specified, the list of all files from all revisions
3692 If option --all is specified, the list of all files from all revisions
3693 is printed. This includes deleted and renamed files.
3693 is printed. This includes deleted and renamed files.
3694
3694
3695 Returns 0 on success.
3695 Returns 0 on success.
3696 """
3696 """
3697 opts = pycompat.byteskwargs(opts)
3697 opts = pycompat.byteskwargs(opts)
3698 fm = ui.formatter('manifest', opts)
3698 fm = ui.formatter('manifest', opts)
3699
3699
3700 if opts.get('all'):
3700 if opts.get('all'):
3701 if rev or node:
3701 if rev or node:
3702 raise error.Abort(_("can't specify a revision with --all"))
3702 raise error.Abort(_("can't specify a revision with --all"))
3703
3703
3704 res = set()
3704 res = set()
3705 for rev in repo:
3705 for rev in repo:
3706 ctx = repo[rev]
3706 ctx = repo[rev]
3707 res |= set(ctx.files())
3707 res |= set(ctx.files())
3708
3708
3709 ui.pager('manifest')
3709 ui.pager('manifest')
3710 for f in sorted(res):
3710 for f in sorted(res):
3711 fm.startitem()
3711 fm.startitem()
3712 fm.write("path", '%s\n', f)
3712 fm.write("path", '%s\n', f)
3713 fm.end()
3713 fm.end()
3714 return
3714 return
3715
3715
3716 if rev and node:
3716 if rev and node:
3717 raise error.Abort(_("please specify just one revision"))
3717 raise error.Abort(_("please specify just one revision"))
3718
3718
3719 if not node:
3719 if not node:
3720 node = rev
3720 node = rev
3721
3721
3722 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3722 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3723 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3723 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3724 if node:
3724 if node:
3725 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3725 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3726 ctx = scmutil.revsingle(repo, node)
3726 ctx = scmutil.revsingle(repo, node)
3727 mf = ctx.manifest()
3727 mf = ctx.manifest()
3728 ui.pager('manifest')
3728 ui.pager('manifest')
3729 for f in ctx:
3729 for f in ctx:
3730 fm.startitem()
3730 fm.startitem()
3731 fm.context(ctx=ctx)
3731 fm.context(ctx=ctx)
3732 fl = ctx[f].flags()
3732 fl = ctx[f].flags()
3733 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3733 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3734 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3734 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3735 fm.write('path', '%s\n', f)
3735 fm.write('path', '%s\n', f)
3736 fm.end()
3736 fm.end()
3737
3737
3738 @command('^merge',
3738 @command('^merge',
3739 [('f', 'force', None,
3739 [('f', 'force', None,
3740 _('force a merge including outstanding changes (DEPRECATED)')),
3740 _('force a merge including outstanding changes (DEPRECATED)')),
3741 ('r', 'rev', '', _('revision to merge'), _('REV')),
3741 ('r', 'rev', '', _('revision to merge'), _('REV')),
3742 ('P', 'preview', None,
3742 ('P', 'preview', None,
3743 _('review revisions to merge (no merge is performed)')),
3743 _('review revisions to merge (no merge is performed)')),
3744 ('', 'abort', None, _('abort the ongoing merge')),
3744 ('', 'abort', None, _('abort the ongoing merge')),
3745 ] + mergetoolopts,
3745 ] + mergetoolopts,
3746 _('[-P] [[-r] REV]'))
3746 _('[-P] [[-r] REV]'))
3747 def merge(ui, repo, node=None, **opts):
3747 def merge(ui, repo, node=None, **opts):
3748 """merge another revision into working directory
3748 """merge another revision into working directory
3749
3749
3750 The current working directory is updated with all changes made in
3750 The current working directory is updated with all changes made in
3751 the requested revision since the last common predecessor revision.
3751 the requested revision since the last common predecessor revision.
3752
3752
3753 Files that changed between either parent are marked as changed for
3753 Files that changed between either parent are marked as changed for
3754 the next commit and a commit must be performed before any further
3754 the next commit and a commit must be performed before any further
3755 updates to the repository are allowed. The next commit will have
3755 updates to the repository are allowed. The next commit will have
3756 two parents.
3756 two parents.
3757
3757
3758 ``--tool`` can be used to specify the merge tool used for file
3758 ``--tool`` can be used to specify the merge tool used for file
3759 merges. It overrides the HGMERGE environment variable and your
3759 merges. It overrides the HGMERGE environment variable and your
3760 configuration files. See :hg:`help merge-tools` for options.
3760 configuration files. See :hg:`help merge-tools` for options.
3761
3761
3762 If no revision is specified, the working directory's parent is a
3762 If no revision is specified, the working directory's parent is a
3763 head revision, and the current branch contains exactly one other
3763 head revision, and the current branch contains exactly one other
3764 head, the other head is merged with by default. Otherwise, an
3764 head, the other head is merged with by default. Otherwise, an
3765 explicit revision with which to merge with must be provided.
3765 explicit revision with which to merge with must be provided.
3766
3766
3767 See :hg:`help resolve` for information on handling file conflicts.
3767 See :hg:`help resolve` for information on handling file conflicts.
3768
3768
3769 To undo an uncommitted merge, use :hg:`merge --abort` which
3769 To undo an uncommitted merge, use :hg:`merge --abort` which
3770 will check out a clean copy of the original merge parent, losing
3770 will check out a clean copy of the original merge parent, losing
3771 all changes.
3771 all changes.
3772
3772
3773 Returns 0 on success, 1 if there are unresolved files.
3773 Returns 0 on success, 1 if there are unresolved files.
3774 """
3774 """
3775
3775
3776 opts = pycompat.byteskwargs(opts)
3776 opts = pycompat.byteskwargs(opts)
3777 abort = opts.get('abort')
3777 abort = opts.get('abort')
3778 if abort and repo.dirstate.p2() == nullid:
3778 if abort and repo.dirstate.p2() == nullid:
3779 cmdutil.wrongtooltocontinue(repo, _('merge'))
3779 cmdutil.wrongtooltocontinue(repo, _('merge'))
3780 if abort:
3780 if abort:
3781 if node:
3781 if node:
3782 raise error.Abort(_("cannot specify a node with --abort"))
3782 raise error.Abort(_("cannot specify a node with --abort"))
3783 if opts.get('rev'):
3783 if opts.get('rev'):
3784 raise error.Abort(_("cannot specify both --rev and --abort"))
3784 raise error.Abort(_("cannot specify both --rev and --abort"))
3785 if opts.get('preview'):
3785 if opts.get('preview'):
3786 raise error.Abort(_("cannot specify --preview with --abort"))
3786 raise error.Abort(_("cannot specify --preview with --abort"))
3787 if opts.get('rev') and node:
3787 if opts.get('rev') and node:
3788 raise error.Abort(_("please specify just one revision"))
3788 raise error.Abort(_("please specify just one revision"))
3789 if not node:
3789 if not node:
3790 node = opts.get('rev')
3790 node = opts.get('rev')
3791
3791
3792 if node:
3792 if node:
3793 node = scmutil.revsingle(repo, node).node()
3793 node = scmutil.revsingle(repo, node).node()
3794
3794
3795 if not node and not abort:
3795 if not node and not abort:
3796 node = repo[destutil.destmerge(repo)].node()
3796 node = repo[destutil.destmerge(repo)].node()
3797
3797
3798 if opts.get('preview'):
3798 if opts.get('preview'):
3799 # find nodes that are ancestors of p2 but not of p1
3799 # find nodes that are ancestors of p2 but not of p1
3800 p1 = repo.lookup('.')
3800 p1 = repo.lookup('.')
3801 p2 = node
3801 p2 = node
3802 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3802 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3803
3803
3804 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3804 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3805 for node in nodes:
3805 for node in nodes:
3806 displayer.show(repo[node])
3806 displayer.show(repo[node])
3807 displayer.close()
3807 displayer.close()
3808 return 0
3808 return 0
3809
3809
3810 # ui.forcemerge is an internal variable, do not document
3810 # ui.forcemerge is an internal variable, do not document
3811 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3811 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3812 with ui.configoverride(overrides, 'merge'):
3812 with ui.configoverride(overrides, 'merge'):
3813 force = opts.get('force')
3813 force = opts.get('force')
3814 labels = ['working copy', 'merge rev']
3814 labels = ['working copy', 'merge rev']
3815 return hg.merge(repo, node, force=force, mergeforce=force,
3815 return hg.merge(repo, node, force=force, mergeforce=force,
3816 labels=labels, abort=abort)
3816 labels=labels, abort=abort)
3817
3817
3818 @command('outgoing|out',
3818 @command('outgoing|out',
3819 [('f', 'force', None, _('run even when the destination is unrelated')),
3819 [('f', 'force', None, _('run even when the destination is unrelated')),
3820 ('r', 'rev', [],
3820 ('r', 'rev', [],
3821 _('a changeset intended to be included in the destination'), _('REV')),
3821 _('a changeset intended to be included in the destination'), _('REV')),
3822 ('n', 'newest-first', None, _('show newest record first')),
3822 ('n', 'newest-first', None, _('show newest record first')),
3823 ('B', 'bookmarks', False, _('compare bookmarks')),
3823 ('B', 'bookmarks', False, _('compare bookmarks')),
3824 ('b', 'branch', [], _('a specific branch you would like to push'),
3824 ('b', 'branch', [], _('a specific branch you would like to push'),
3825 _('BRANCH')),
3825 _('BRANCH')),
3826 ] + logopts + remoteopts + subrepoopts,
3826 ] + logopts + remoteopts + subrepoopts,
3827 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3827 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3828 def outgoing(ui, repo, dest=None, **opts):
3828 def outgoing(ui, repo, dest=None, **opts):
3829 """show changesets not found in the destination
3829 """show changesets not found in the destination
3830
3830
3831 Show changesets not found in the specified destination repository
3831 Show changesets not found in the specified destination repository
3832 or the default push location. These are the changesets that would
3832 or the default push location. These are the changesets that would
3833 be pushed if a push was requested.
3833 be pushed if a push was requested.
3834
3834
3835 See pull for details of valid destination formats.
3835 See pull for details of valid destination formats.
3836
3836
3837 .. container:: verbose
3837 .. container:: verbose
3838
3838
3839 With -B/--bookmarks, the result of bookmark comparison between
3839 With -B/--bookmarks, the result of bookmark comparison between
3840 local and remote repositories is displayed. With -v/--verbose,
3840 local and remote repositories is displayed. With -v/--verbose,
3841 status is also displayed for each bookmark like below::
3841 status is also displayed for each bookmark like below::
3842
3842
3843 BM1 01234567890a added
3843 BM1 01234567890a added
3844 BM2 deleted
3844 BM2 deleted
3845 BM3 234567890abc advanced
3845 BM3 234567890abc advanced
3846 BM4 34567890abcd diverged
3846 BM4 34567890abcd diverged
3847 BM5 4567890abcde changed
3847 BM5 4567890abcde changed
3848
3848
3849 The action taken when pushing depends on the
3849 The action taken when pushing depends on the
3850 status of each bookmark:
3850 status of each bookmark:
3851
3851
3852 :``added``: push with ``-B`` will create it
3852 :``added``: push with ``-B`` will create it
3853 :``deleted``: push with ``-B`` will delete it
3853 :``deleted``: push with ``-B`` will delete it
3854 :``advanced``: push will update it
3854 :``advanced``: push will update it
3855 :``diverged``: push with ``-B`` will update it
3855 :``diverged``: push with ``-B`` will update it
3856 :``changed``: push with ``-B`` will update it
3856 :``changed``: push with ``-B`` will update it
3857
3857
3858 From the point of view of pushing behavior, bookmarks
3858 From the point of view of pushing behavior, bookmarks
3859 existing only in the remote repository are treated as
3859 existing only in the remote repository are treated as
3860 ``deleted``, even if it is in fact added remotely.
3860 ``deleted``, even if it is in fact added remotely.
3861
3861
3862 Returns 0 if there are outgoing changes, 1 otherwise.
3862 Returns 0 if there are outgoing changes, 1 otherwise.
3863 """
3863 """
3864 # hg._outgoing() needs to re-resolve the path in order to handle #branch
3864 # hg._outgoing() needs to re-resolve the path in order to handle #branch
3865 # style URLs, so don't overwrite dest.
3865 # style URLs, so don't overwrite dest.
3866 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3866 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3867 if not path:
3867 if not path:
3868 raise error.Abort(_('default repository not configured!'),
3868 raise error.Abort(_('default repository not configured!'),
3869 hint=_("see 'hg help config.paths'"))
3869 hint=_("see 'hg help config.paths'"))
3870
3870
3871 opts = pycompat.byteskwargs(opts)
3871 opts = pycompat.byteskwargs(opts)
3872 if opts.get('graph'):
3872 if opts.get('graph'):
3873 logcmdutil.checkunsupportedgraphflags([], opts)
3873 logcmdutil.checkunsupportedgraphflags([], opts)
3874 o, other = hg._outgoing(ui, repo, dest, opts)
3874 o, other = hg._outgoing(ui, repo, dest, opts)
3875 if not o:
3875 if not o:
3876 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3876 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3877 return
3877 return
3878
3878
3879 revdag = logcmdutil.graphrevs(repo, o, opts)
3879 revdag = logcmdutil.graphrevs(repo, o, opts)
3880 ui.pager('outgoing')
3880 ui.pager('outgoing')
3881 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3881 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3882 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3882 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3883 graphmod.asciiedges)
3883 graphmod.asciiedges)
3884 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3884 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3885 return 0
3885 return 0
3886
3886
3887 if opts.get('bookmarks'):
3887 if opts.get('bookmarks'):
3888 dest = path.pushloc or path.loc
3888 dest = path.pushloc or path.loc
3889 other = hg.peer(repo, opts, dest)
3889 other = hg.peer(repo, opts, dest)
3890 if 'bookmarks' not in other.listkeys('namespaces'):
3890 if 'bookmarks' not in other.listkeys('namespaces'):
3891 ui.warn(_("remote doesn't support bookmarks\n"))
3891 ui.warn(_("remote doesn't support bookmarks\n"))
3892 return 0
3892 return 0
3893 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3893 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3894 ui.pager('outgoing')
3894 ui.pager('outgoing')
3895 return bookmarks.outgoing(ui, repo, other)
3895 return bookmarks.outgoing(ui, repo, other)
3896
3896
3897 repo._subtoppath = path.pushloc or path.loc
3897 repo._subtoppath = path.pushloc or path.loc
3898 try:
3898 try:
3899 return hg.outgoing(ui, repo, dest, opts)
3899 return hg.outgoing(ui, repo, dest, opts)
3900 finally:
3900 finally:
3901 del repo._subtoppath
3901 del repo._subtoppath
3902
3902
3903 @command('parents',
3903 @command('parents',
3904 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3904 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3905 ] + templateopts,
3905 ] + templateopts,
3906 _('[-r REV] [FILE]'),
3906 _('[-r REV] [FILE]'),
3907 inferrepo=True)
3907 inferrepo=True)
3908 def parents(ui, repo, file_=None, **opts):
3908 def parents(ui, repo, file_=None, **opts):
3909 """show the parents of the working directory or revision (DEPRECATED)
3909 """show the parents of the working directory or revision (DEPRECATED)
3910
3910
3911 Print the working directory's parent revisions. If a revision is
3911 Print the working directory's parent revisions. If a revision is
3912 given via -r/--rev, the parent of that revision will be printed.
3912 given via -r/--rev, the parent of that revision will be printed.
3913 If a file argument is given, the revision in which the file was
3913 If a file argument is given, the revision in which the file was
3914 last changed (before the working directory revision or the
3914 last changed (before the working directory revision or the
3915 argument to --rev if given) is printed.
3915 argument to --rev if given) is printed.
3916
3916
3917 This command is equivalent to::
3917 This command is equivalent to::
3918
3918
3919 hg log -r "p1()+p2()" or
3919 hg log -r "p1()+p2()" or
3920 hg log -r "p1(REV)+p2(REV)" or
3920 hg log -r "p1(REV)+p2(REV)" or
3921 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3921 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3922 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3922 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3923
3923
3924 See :hg:`summary` and :hg:`help revsets` for related information.
3924 See :hg:`summary` and :hg:`help revsets` for related information.
3925
3925
3926 Returns 0 on success.
3926 Returns 0 on success.
3927 """
3927 """
3928
3928
3929 opts = pycompat.byteskwargs(opts)
3929 opts = pycompat.byteskwargs(opts)
3930 rev = opts.get('rev')
3930 rev = opts.get('rev')
3931 if rev:
3931 if rev:
3932 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3932 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3933 ctx = scmutil.revsingle(repo, rev, None)
3933 ctx = scmutil.revsingle(repo, rev, None)
3934
3934
3935 if file_:
3935 if file_:
3936 m = scmutil.match(ctx, (file_,), opts)
3936 m = scmutil.match(ctx, (file_,), opts)
3937 if m.anypats() or len(m.files()) != 1:
3937 if m.anypats() or len(m.files()) != 1:
3938 raise error.Abort(_('can only specify an explicit filename'))
3938 raise error.Abort(_('can only specify an explicit filename'))
3939 file_ = m.files()[0]
3939 file_ = m.files()[0]
3940 filenodes = []
3940 filenodes = []
3941 for cp in ctx.parents():
3941 for cp in ctx.parents():
3942 if not cp:
3942 if not cp:
3943 continue
3943 continue
3944 try:
3944 try:
3945 filenodes.append(cp.filenode(file_))
3945 filenodes.append(cp.filenode(file_))
3946 except error.LookupError:
3946 except error.LookupError:
3947 pass
3947 pass
3948 if not filenodes:
3948 if not filenodes:
3949 raise error.Abort(_("'%s' not found in manifest!") % file_)
3949 raise error.Abort(_("'%s' not found in manifest!") % file_)
3950 p = []
3950 p = []
3951 for fn in filenodes:
3951 for fn in filenodes:
3952 fctx = repo.filectx(file_, fileid=fn)
3952 fctx = repo.filectx(file_, fileid=fn)
3953 p.append(fctx.node())
3953 p.append(fctx.node())
3954 else:
3954 else:
3955 p = [cp.node() for cp in ctx.parents()]
3955 p = [cp.node() for cp in ctx.parents()]
3956
3956
3957 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3957 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3958 for n in p:
3958 for n in p:
3959 if n != nullid:
3959 if n != nullid:
3960 displayer.show(repo[n])
3960 displayer.show(repo[n])
3961 displayer.close()
3961 displayer.close()
3962
3962
3963 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3963 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3964 intents={INTENT_READONLY})
3964 intents={INTENT_READONLY})
3965 def paths(ui, repo, search=None, **opts):
3965 def paths(ui, repo, search=None, **opts):
3966 """show aliases for remote repositories
3966 """show aliases for remote repositories
3967
3967
3968 Show definition of symbolic path name NAME. If no name is given,
3968 Show definition of symbolic path name NAME. If no name is given,
3969 show definition of all available names.
3969 show definition of all available names.
3970
3970
3971 Option -q/--quiet suppresses all output when searching for NAME
3971 Option -q/--quiet suppresses all output when searching for NAME
3972 and shows only the path names when listing all definitions.
3972 and shows only the path names when listing all definitions.
3973
3973
3974 Path names are defined in the [paths] section of your
3974 Path names are defined in the [paths] section of your
3975 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3975 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3976 repository, ``.hg/hgrc`` is used, too.
3976 repository, ``.hg/hgrc`` is used, too.
3977
3977
3978 The path names ``default`` and ``default-push`` have a special
3978 The path names ``default`` and ``default-push`` have a special
3979 meaning. When performing a push or pull operation, they are used
3979 meaning. When performing a push or pull operation, they are used
3980 as fallbacks if no location is specified on the command-line.
3980 as fallbacks if no location is specified on the command-line.
3981 When ``default-push`` is set, it will be used for push and
3981 When ``default-push`` is set, it will be used for push and
3982 ``default`` will be used for pull; otherwise ``default`` is used
3982 ``default`` will be used for pull; otherwise ``default`` is used
3983 as the fallback for both. When cloning a repository, the clone
3983 as the fallback for both. When cloning a repository, the clone
3984 source is written as ``default`` in ``.hg/hgrc``.
3984 source is written as ``default`` in ``.hg/hgrc``.
3985
3985
3986 .. note::
3986 .. note::
3987
3987
3988 ``default`` and ``default-push`` apply to all inbound (e.g.
3988 ``default`` and ``default-push`` apply to all inbound (e.g.
3989 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3989 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3990 and :hg:`bundle`) operations.
3990 and :hg:`bundle`) operations.
3991
3991
3992 See :hg:`help urls` for more information.
3992 See :hg:`help urls` for more information.
3993
3993
3994 Returns 0 on success.
3994 Returns 0 on success.
3995 """
3995 """
3996
3996
3997 opts = pycompat.byteskwargs(opts)
3997 opts = pycompat.byteskwargs(opts)
3998 ui.pager('paths')
3998 ui.pager('paths')
3999 if search:
3999 if search:
4000 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4000 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4001 if name == search]
4001 if name == search]
4002 else:
4002 else:
4003 pathitems = sorted(ui.paths.iteritems())
4003 pathitems = sorted(ui.paths.iteritems())
4004
4004
4005 fm = ui.formatter('paths', opts)
4005 fm = ui.formatter('paths', opts)
4006 if fm.isplain():
4006 if fm.isplain():
4007 hidepassword = util.hidepassword
4007 hidepassword = util.hidepassword
4008 else:
4008 else:
4009 hidepassword = bytes
4009 hidepassword = bytes
4010 if ui.quiet:
4010 if ui.quiet:
4011 namefmt = '%s\n'
4011 namefmt = '%s\n'
4012 else:
4012 else:
4013 namefmt = '%s = '
4013 namefmt = '%s = '
4014 showsubopts = not search and not ui.quiet
4014 showsubopts = not search and not ui.quiet
4015
4015
4016 for name, path in pathitems:
4016 for name, path in pathitems:
4017 fm.startitem()
4017 fm.startitem()
4018 fm.condwrite(not search, 'name', namefmt, name)
4018 fm.condwrite(not search, 'name', namefmt, name)
4019 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4019 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4020 for subopt, value in sorted(path.suboptions.items()):
4020 for subopt, value in sorted(path.suboptions.items()):
4021 assert subopt not in ('name', 'url')
4021 assert subopt not in ('name', 'url')
4022 if showsubopts:
4022 if showsubopts:
4023 fm.plain('%s:%s = ' % (name, subopt))
4023 fm.plain('%s:%s = ' % (name, subopt))
4024 fm.condwrite(showsubopts, subopt, '%s\n', value)
4024 fm.condwrite(showsubopts, subopt, '%s\n', value)
4025
4025
4026 fm.end()
4026 fm.end()
4027
4027
4028 if search and not pathitems:
4028 if search and not pathitems:
4029 if not ui.quiet:
4029 if not ui.quiet:
4030 ui.warn(_("not found!\n"))
4030 ui.warn(_("not found!\n"))
4031 return 1
4031 return 1
4032 else:
4032 else:
4033 return 0
4033 return 0
4034
4034
4035 @command('phase',
4035 @command('phase',
4036 [('p', 'public', False, _('set changeset phase to public')),
4036 [('p', 'public', False, _('set changeset phase to public')),
4037 ('d', 'draft', False, _('set changeset phase to draft')),
4037 ('d', 'draft', False, _('set changeset phase to draft')),
4038 ('s', 'secret', False, _('set changeset phase to secret')),
4038 ('s', 'secret', False, _('set changeset phase to secret')),
4039 ('f', 'force', False, _('allow to move boundary backward')),
4039 ('f', 'force', False, _('allow to move boundary backward')),
4040 ('r', 'rev', [], _('target revision'), _('REV')),
4040 ('r', 'rev', [], _('target revision'), _('REV')),
4041 ],
4041 ],
4042 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4042 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4043 def phase(ui, repo, *revs, **opts):
4043 def phase(ui, repo, *revs, **opts):
4044 """set or show the current phase name
4044 """set or show the current phase name
4045
4045
4046 With no argument, show the phase name of the current revision(s).
4046 With no argument, show the phase name of the current revision(s).
4047
4047
4048 With one of -p/--public, -d/--draft or -s/--secret, change the
4048 With one of -p/--public, -d/--draft or -s/--secret, change the
4049 phase value of the specified revisions.
4049 phase value of the specified revisions.
4050
4050
4051 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4051 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
4052 lower phase to a higher phase. Phases are ordered as follows::
4052 lower phase to a higher phase. Phases are ordered as follows::
4053
4053
4054 public < draft < secret
4054 public < draft < secret
4055
4055
4056 Returns 0 on success, 1 if some phases could not be changed.
4056 Returns 0 on success, 1 if some phases could not be changed.
4057
4057
4058 (For more information about the phases concept, see :hg:`help phases`.)
4058 (For more information about the phases concept, see :hg:`help phases`.)
4059 """
4059 """
4060 opts = pycompat.byteskwargs(opts)
4060 opts = pycompat.byteskwargs(opts)
4061 # search for a unique phase argument
4061 # search for a unique phase argument
4062 targetphase = None
4062 targetphase = None
4063 for idx, name in enumerate(phases.phasenames):
4063 for idx, name in enumerate(phases.phasenames):
4064 if opts.get(name, False):
4064 if opts.get(name, False):
4065 if targetphase is not None:
4065 if targetphase is not None:
4066 raise error.Abort(_('only one phase can be specified'))
4066 raise error.Abort(_('only one phase can be specified'))
4067 targetphase = idx
4067 targetphase = idx
4068
4068
4069 # look for specified revision
4069 # look for specified revision
4070 revs = list(revs)
4070 revs = list(revs)
4071 revs.extend(opts['rev'])
4071 revs.extend(opts['rev'])
4072 if not revs:
4072 if not revs:
4073 # display both parents as the second parent phase can influence
4073 # display both parents as the second parent phase can influence
4074 # the phase of a merge commit
4074 # the phase of a merge commit
4075 revs = [c.rev() for c in repo[None].parents()]
4075 revs = [c.rev() for c in repo[None].parents()]
4076
4076
4077 revs = scmutil.revrange(repo, revs)
4077 revs = scmutil.revrange(repo, revs)
4078
4078
4079 ret = 0
4079 ret = 0
4080 if targetphase is None:
4080 if targetphase is None:
4081 # display
4081 # display
4082 for r in revs:
4082 for r in revs:
4083 ctx = repo[r]
4083 ctx = repo[r]
4084 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4084 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4085 else:
4085 else:
4086 with repo.lock(), repo.transaction("phase") as tr:
4086 with repo.lock(), repo.transaction("phase") as tr:
4087 # set phase
4087 # set phase
4088 if not revs:
4088 if not revs:
4089 raise error.Abort(_('empty revision set'))
4089 raise error.Abort(_('empty revision set'))
4090 nodes = [repo[r].node() for r in revs]
4090 nodes = [repo[r].node() for r in revs]
4091 # moving revision from public to draft may hide them
4091 # moving revision from public to draft may hide them
4092 # We have to check result on an unfiltered repository
4092 # We have to check result on an unfiltered repository
4093 unfi = repo.unfiltered()
4093 unfi = repo.unfiltered()
4094 getphase = unfi._phasecache.phase
4094 getphase = unfi._phasecache.phase
4095 olddata = [getphase(unfi, r) for r in unfi]
4095 olddata = [getphase(unfi, r) for r in unfi]
4096 phases.advanceboundary(repo, tr, targetphase, nodes)
4096 phases.advanceboundary(repo, tr, targetphase, nodes)
4097 if opts['force']:
4097 if opts['force']:
4098 phases.retractboundary(repo, tr, targetphase, nodes)
4098 phases.retractboundary(repo, tr, targetphase, nodes)
4099 getphase = unfi._phasecache.phase
4099 getphase = unfi._phasecache.phase
4100 newdata = [getphase(unfi, r) for r in unfi]
4100 newdata = [getphase(unfi, r) for r in unfi]
4101 changes = sum(newdata[r] != olddata[r] for r in unfi)
4101 changes = sum(newdata[r] != olddata[r] for r in unfi)
4102 cl = unfi.changelog
4102 cl = unfi.changelog
4103 rejected = [n for n in nodes
4103 rejected = [n for n in nodes
4104 if newdata[cl.rev(n)] < targetphase]
4104 if newdata[cl.rev(n)] < targetphase]
4105 if rejected:
4105 if rejected:
4106 ui.warn(_('cannot move %i changesets to a higher '
4106 ui.warn(_('cannot move %i changesets to a higher '
4107 'phase, use --force\n') % len(rejected))
4107 'phase, use --force\n') % len(rejected))
4108 ret = 1
4108 ret = 1
4109 if changes:
4109 if changes:
4110 msg = _('phase changed for %i changesets\n') % changes
4110 msg = _('phase changed for %i changesets\n') % changes
4111 if ret:
4111 if ret:
4112 ui.status(msg)
4112 ui.status(msg)
4113 else:
4113 else:
4114 ui.note(msg)
4114 ui.note(msg)
4115 else:
4115 else:
4116 ui.warn(_('no phases changed\n'))
4116 ui.warn(_('no phases changed\n'))
4117 return ret
4117 return ret
4118
4118
4119 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4119 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4120 """Run after a changegroup has been added via pull/unbundle
4120 """Run after a changegroup has been added via pull/unbundle
4121
4121
4122 This takes arguments below:
4122 This takes arguments below:
4123
4123
4124 :modheads: change of heads by pull/unbundle
4124 :modheads: change of heads by pull/unbundle
4125 :optupdate: updating working directory is needed or not
4125 :optupdate: updating working directory is needed or not
4126 :checkout: update destination revision (or None to default destination)
4126 :checkout: update destination revision (or None to default destination)
4127 :brev: a name, which might be a bookmark to be activated after updating
4127 :brev: a name, which might be a bookmark to be activated after updating
4128 """
4128 """
4129 if modheads == 0:
4129 if modheads == 0:
4130 return
4130 return
4131 if optupdate:
4131 if optupdate:
4132 try:
4132 try:
4133 return hg.updatetotally(ui, repo, checkout, brev)
4133 return hg.updatetotally(ui, repo, checkout, brev)
4134 except error.UpdateAbort as inst:
4134 except error.UpdateAbort as inst:
4135 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4135 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4136 hint = inst.hint
4136 hint = inst.hint
4137 raise error.UpdateAbort(msg, hint=hint)
4137 raise error.UpdateAbort(msg, hint=hint)
4138 if modheads > 1:
4138 if modheads > 1:
4139 currentbranchheads = len(repo.branchheads())
4139 currentbranchheads = len(repo.branchheads())
4140 if currentbranchheads == modheads:
4140 if currentbranchheads == modheads:
4141 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4141 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4142 elif currentbranchheads > 1:
4142 elif currentbranchheads > 1:
4143 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4143 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4144 "merge)\n"))
4144 "merge)\n"))
4145 else:
4145 else:
4146 ui.status(_("(run 'hg heads' to see heads)\n"))
4146 ui.status(_("(run 'hg heads' to see heads)\n"))
4147 elif not ui.configbool('commands', 'update.requiredest'):
4147 elif not ui.configbool('commands', 'update.requiredest'):
4148 ui.status(_("(run 'hg update' to get a working copy)\n"))
4148 ui.status(_("(run 'hg update' to get a working copy)\n"))
4149
4149
4150 @command('^pull',
4150 @command('^pull',
4151 [('u', 'update', None,
4151 [('u', 'update', None,
4152 _('update to new branch head if new descendants were pulled')),
4152 _('update to new branch head if new descendants were pulled')),
4153 ('f', 'force', None, _('run even when remote repository is unrelated')),
4153 ('f', 'force', None, _('run even when remote repository is unrelated')),
4154 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4154 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4155 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4155 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4156 ('b', 'branch', [], _('a specific branch you would like to pull'),
4156 ('b', 'branch', [], _('a specific branch you would like to pull'),
4157 _('BRANCH')),
4157 _('BRANCH')),
4158 ] + remoteopts,
4158 ] + remoteopts,
4159 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4159 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4160 def pull(ui, repo, source="default", **opts):
4160 def pull(ui, repo, source="default", **opts):
4161 """pull changes from the specified source
4161 """pull changes from the specified source
4162
4162
4163 Pull changes from a remote repository to a local one.
4163 Pull changes from a remote repository to a local one.
4164
4164
4165 This finds all changes from the repository at the specified path
4165 This finds all changes from the repository at the specified path
4166 or URL and adds them to a local repository (the current one unless
4166 or URL and adds them to a local repository (the current one unless
4167 -R is specified). By default, this does not update the copy of the
4167 -R is specified). By default, this does not update the copy of the
4168 project in the working directory.
4168 project in the working directory.
4169
4169
4170 When cloning from servers that support it, Mercurial may fetch
4170 When cloning from servers that support it, Mercurial may fetch
4171 pre-generated data. When this is done, hooks operating on incoming
4171 pre-generated data. When this is done, hooks operating on incoming
4172 changesets and changegroups may fire more than once, once for each
4172 changesets and changegroups may fire more than once, once for each
4173 pre-generated bundle and as well as for any additional remaining
4173 pre-generated bundle and as well as for any additional remaining
4174 data. See :hg:`help -e clonebundles` for more.
4174 data. See :hg:`help -e clonebundles` for more.
4175
4175
4176 Use :hg:`incoming` if you want to see what would have been added
4176 Use :hg:`incoming` if you want to see what would have been added
4177 by a pull at the time you issued this command. If you then decide
4177 by a pull at the time you issued this command. If you then decide
4178 to add those changes to the repository, you should use :hg:`pull
4178 to add those changes to the repository, you should use :hg:`pull
4179 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4179 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4180
4180
4181 If SOURCE is omitted, the 'default' path will be used.
4181 If SOURCE is omitted, the 'default' path will be used.
4182 See :hg:`help urls` for more information.
4182 See :hg:`help urls` for more information.
4183
4183
4184 Specifying bookmark as ``.`` is equivalent to specifying the active
4184 Specifying bookmark as ``.`` is equivalent to specifying the active
4185 bookmark's name.
4185 bookmark's name.
4186
4186
4187 Returns 0 on success, 1 if an update had unresolved files.
4187 Returns 0 on success, 1 if an update had unresolved files.
4188 """
4188 """
4189
4189
4190 opts = pycompat.byteskwargs(opts)
4190 opts = pycompat.byteskwargs(opts)
4191 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4191 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4192 msg = _('update destination required by configuration')
4192 msg = _('update destination required by configuration')
4193 hint = _('use hg pull followed by hg update DEST')
4193 hint = _('use hg pull followed by hg update DEST')
4194 raise error.Abort(msg, hint=hint)
4194 raise error.Abort(msg, hint=hint)
4195
4195
4196 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4196 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4197 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4197 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4198 other = hg.peer(repo, opts, source)
4198 other = hg.peer(repo, opts, source)
4199 try:
4199 try:
4200 revs, checkout = hg.addbranchrevs(repo, other, branches,
4200 revs, checkout = hg.addbranchrevs(repo, other, branches,
4201 opts.get('rev'))
4201 opts.get('rev'))
4202
4202
4203
4203
4204 pullopargs = {}
4204 pullopargs = {}
4205 if opts.get('bookmark'):
4205 if opts.get('bookmark'):
4206 if not revs:
4206 if not revs:
4207 revs = []
4207 revs = []
4208 # The list of bookmark used here is not the one used to actually
4208 # The list of bookmark used here is not the one used to actually
4209 # update the bookmark name. This can result in the revision pulled
4209 # update the bookmark name. This can result in the revision pulled
4210 # not ending up with the name of the bookmark because of a race
4210 # not ending up with the name of the bookmark because of a race
4211 # condition on the server. (See issue 4689 for details)
4211 # condition on the server. (See issue 4689 for details)
4212 remotebookmarks = other.listkeys('bookmarks')
4212 remotebookmarks = other.listkeys('bookmarks')
4213 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4213 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4214 pullopargs['remotebookmarks'] = remotebookmarks
4214 pullopargs['remotebookmarks'] = remotebookmarks
4215 for b in opts['bookmark']:
4215 for b in opts['bookmark']:
4216 b = repo._bookmarks.expandname(b)
4216 b = repo._bookmarks.expandname(b)
4217 if b not in remotebookmarks:
4217 if b not in remotebookmarks:
4218 raise error.Abort(_('remote bookmark %s not found!') % b)
4218 raise error.Abort(_('remote bookmark %s not found!') % b)
4219 revs.append(hex(remotebookmarks[b]))
4219 revs.append(hex(remotebookmarks[b]))
4220
4220
4221 if revs:
4221 if revs:
4222 try:
4222 try:
4223 # When 'rev' is a bookmark name, we cannot guarantee that it
4223 # When 'rev' is a bookmark name, we cannot guarantee that it
4224 # will be updated with that name because of a race condition
4224 # will be updated with that name because of a race condition
4225 # server side. (See issue 4689 for details)
4225 # server side. (See issue 4689 for details)
4226 oldrevs = revs
4226 oldrevs = revs
4227 revs = [] # actually, nodes
4227 revs = [] # actually, nodes
4228 for r in oldrevs:
4228 for r in oldrevs:
4229 with other.commandexecutor() as e:
4229 with other.commandexecutor() as e:
4230 node = e.callcommand('lookup', {'key': r}).result()
4230 node = e.callcommand('lookup', {'key': r}).result()
4231
4231
4232 revs.append(node)
4232 revs.append(node)
4233 if r == checkout:
4233 if r == checkout:
4234 checkout = node
4234 checkout = node
4235 except error.CapabilityError:
4235 except error.CapabilityError:
4236 err = _("other repository doesn't support revision lookup, "
4236 err = _("other repository doesn't support revision lookup, "
4237 "so a rev cannot be specified.")
4237 "so a rev cannot be specified.")
4238 raise error.Abort(err)
4238 raise error.Abort(err)
4239
4239
4240 wlock = util.nullcontextmanager()
4240 wlock = util.nullcontextmanager()
4241 if opts.get('update'):
4241 if opts.get('update'):
4242 wlock = repo.wlock()
4242 wlock = repo.wlock()
4243 with wlock:
4243 with wlock:
4244 pullopargs.update(opts.get('opargs', {}))
4244 pullopargs.update(opts.get('opargs', {}))
4245 modheads = exchange.pull(repo, other, heads=revs,
4245 modheads = exchange.pull(repo, other, heads=revs,
4246 force=opts.get('force'),
4246 force=opts.get('force'),
4247 bookmarks=opts.get('bookmark', ()),
4247 bookmarks=opts.get('bookmark', ()),
4248 opargs=pullopargs).cgresult
4248 opargs=pullopargs).cgresult
4249
4249
4250 # brev is a name, which might be a bookmark to be activated at
4250 # brev is a name, which might be a bookmark to be activated at
4251 # the end of the update. In other words, it is an explicit
4251 # the end of the update. In other words, it is an explicit
4252 # destination of the update
4252 # destination of the update
4253 brev = None
4253 brev = None
4254
4254
4255 if checkout:
4255 if checkout:
4256 checkout = repo.changelog.rev(checkout)
4256 checkout = repo.changelog.rev(checkout)
4257
4257
4258 # order below depends on implementation of
4258 # order below depends on implementation of
4259 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4259 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4260 # because 'checkout' is determined without it.
4260 # because 'checkout' is determined without it.
4261 if opts.get('rev'):
4261 if opts.get('rev'):
4262 brev = opts['rev'][0]
4262 brev = opts['rev'][0]
4263 elif opts.get('branch'):
4263 elif opts.get('branch'):
4264 brev = opts['branch'][0]
4264 brev = opts['branch'][0]
4265 else:
4265 else:
4266 brev = branches[0]
4266 brev = branches[0]
4267 repo._subtoppath = source
4267 repo._subtoppath = source
4268 try:
4268 try:
4269 ret = postincoming(ui, repo, modheads, opts.get('update'),
4269 ret = postincoming(ui, repo, modheads, opts.get('update'),
4270 checkout, brev)
4270 checkout, brev)
4271
4271
4272 finally:
4272 finally:
4273 del repo._subtoppath
4273 del repo._subtoppath
4274
4274
4275 finally:
4275 finally:
4276 other.close()
4276 other.close()
4277 return ret
4277 return ret
4278
4278
4279 @command('^push',
4279 @command('^push',
4280 [('f', 'force', None, _('force push')),
4280 [('f', 'force', None, _('force push')),
4281 ('r', 'rev', [],
4281 ('r', 'rev', [],
4282 _('a changeset intended to be included in the destination'),
4282 _('a changeset intended to be included in the destination'),
4283 _('REV')),
4283 _('REV')),
4284 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4284 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4285 ('b', 'branch', [],
4285 ('b', 'branch', [],
4286 _('a specific branch you would like to push'), _('BRANCH')),
4286 _('a specific branch you would like to push'), _('BRANCH')),
4287 ('', 'new-branch', False, _('allow pushing a new branch')),
4287 ('', 'new-branch', False, _('allow pushing a new branch')),
4288 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4288 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4289 ] + remoteopts,
4289 ] + remoteopts,
4290 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4290 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4291 def push(ui, repo, dest=None, **opts):
4291 def push(ui, repo, dest=None, **opts):
4292 """push changes to the specified destination
4292 """push changes to the specified destination
4293
4293
4294 Push changesets from the local repository to the specified
4294 Push changesets from the local repository to the specified
4295 destination.
4295 destination.
4296
4296
4297 This operation is symmetrical to pull: it is identical to a pull
4297 This operation is symmetrical to pull: it is identical to a pull
4298 in the destination repository from the current one.
4298 in the destination repository from the current one.
4299
4299
4300 By default, push will not allow creation of new heads at the
4300 By default, push will not allow creation of new heads at the
4301 destination, since multiple heads would make it unclear which head
4301 destination, since multiple heads would make it unclear which head
4302 to use. In this situation, it is recommended to pull and merge
4302 to use. In this situation, it is recommended to pull and merge
4303 before pushing.
4303 before pushing.
4304
4304
4305 Use --new-branch if you want to allow push to create a new named
4305 Use --new-branch if you want to allow push to create a new named
4306 branch that is not present at the destination. This allows you to
4306 branch that is not present at the destination. This allows you to
4307 only create a new branch without forcing other changes.
4307 only create a new branch without forcing other changes.
4308
4308
4309 .. note::
4309 .. note::
4310
4310
4311 Extra care should be taken with the -f/--force option,
4311 Extra care should be taken with the -f/--force option,
4312 which will push all new heads on all branches, an action which will
4312 which will push all new heads on all branches, an action which will
4313 almost always cause confusion for collaborators.
4313 almost always cause confusion for collaborators.
4314
4314
4315 If -r/--rev is used, the specified revision and all its ancestors
4315 If -r/--rev is used, the specified revision and all its ancestors
4316 will be pushed to the remote repository.
4316 will be pushed to the remote repository.
4317
4317
4318 If -B/--bookmark is used, the specified bookmarked revision, its
4318 If -B/--bookmark is used, the specified bookmarked revision, its
4319 ancestors, and the bookmark will be pushed to the remote
4319 ancestors, and the bookmark will be pushed to the remote
4320 repository. Specifying ``.`` is equivalent to specifying the active
4320 repository. Specifying ``.`` is equivalent to specifying the active
4321 bookmark's name.
4321 bookmark's name.
4322
4322
4323 Please see :hg:`help urls` for important details about ``ssh://``
4323 Please see :hg:`help urls` for important details about ``ssh://``
4324 URLs. If DESTINATION is omitted, a default path will be used.
4324 URLs. If DESTINATION is omitted, a default path will be used.
4325
4325
4326 .. container:: verbose
4326 .. container:: verbose
4327
4327
4328 The --pushvars option sends strings to the server that become
4328 The --pushvars option sends strings to the server that become
4329 environment variables prepended with ``HG_USERVAR_``. For example,
4329 environment variables prepended with ``HG_USERVAR_``. For example,
4330 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4330 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4331 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4331 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4332
4332
4333 pushvars can provide for user-overridable hooks as well as set debug
4333 pushvars can provide for user-overridable hooks as well as set debug
4334 levels. One example is having a hook that blocks commits containing
4334 levels. One example is having a hook that blocks commits containing
4335 conflict markers, but enables the user to override the hook if the file
4335 conflict markers, but enables the user to override the hook if the file
4336 is using conflict markers for testing purposes or the file format has
4336 is using conflict markers for testing purposes or the file format has
4337 strings that look like conflict markers.
4337 strings that look like conflict markers.
4338
4338
4339 By default, servers will ignore `--pushvars`. To enable it add the
4339 By default, servers will ignore `--pushvars`. To enable it add the
4340 following to your configuration file::
4340 following to your configuration file::
4341
4341
4342 [push]
4342 [push]
4343 pushvars.server = true
4343 pushvars.server = true
4344
4344
4345 Returns 0 if push was successful, 1 if nothing to push.
4345 Returns 0 if push was successful, 1 if nothing to push.
4346 """
4346 """
4347
4347
4348 opts = pycompat.byteskwargs(opts)
4348 opts = pycompat.byteskwargs(opts)
4349 if opts.get('bookmark'):
4349 if opts.get('bookmark'):
4350 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4350 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4351 for b in opts['bookmark']:
4351 for b in opts['bookmark']:
4352 # translate -B options to -r so changesets get pushed
4352 # translate -B options to -r so changesets get pushed
4353 b = repo._bookmarks.expandname(b)
4353 b = repo._bookmarks.expandname(b)
4354 if b in repo._bookmarks:
4354 if b in repo._bookmarks:
4355 opts.setdefault('rev', []).append(b)
4355 opts.setdefault('rev', []).append(b)
4356 else:
4356 else:
4357 # if we try to push a deleted bookmark, translate it to null
4357 # if we try to push a deleted bookmark, translate it to null
4358 # this lets simultaneous -r, -b options continue working
4358 # this lets simultaneous -r, -b options continue working
4359 opts.setdefault('rev', []).append("null")
4359 opts.setdefault('rev', []).append("null")
4360
4360
4361 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4361 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4362 if not path:
4362 if not path:
4363 raise error.Abort(_('default repository not configured!'),
4363 raise error.Abort(_('default repository not configured!'),
4364 hint=_("see 'hg help config.paths'"))
4364 hint=_("see 'hg help config.paths'"))
4365 dest = path.pushloc or path.loc
4365 dest = path.pushloc or path.loc
4366 branches = (path.branch, opts.get('branch') or [])
4366 branches = (path.branch, opts.get('branch') or [])
4367 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4367 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4368 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4368 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4369 other = hg.peer(repo, opts, dest)
4369 other = hg.peer(repo, opts, dest)
4370
4370
4371 if revs:
4371 if revs:
4372 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4372 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4373 if not revs:
4373 if not revs:
4374 raise error.Abort(_("specified revisions evaluate to an empty set"),
4374 raise error.Abort(_("specified revisions evaluate to an empty set"),
4375 hint=_("use different revision arguments"))
4375 hint=_("use different revision arguments"))
4376 elif path.pushrev:
4376 elif path.pushrev:
4377 # It doesn't make any sense to specify ancestor revisions. So limit
4377 # It doesn't make any sense to specify ancestor revisions. So limit
4378 # to DAG heads to make discovery simpler.
4378 # to DAG heads to make discovery simpler.
4379 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4379 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4380 revs = scmutil.revrange(repo, [expr])
4380 revs = scmutil.revrange(repo, [expr])
4381 revs = [repo[rev].node() for rev in revs]
4381 revs = [repo[rev].node() for rev in revs]
4382 if not revs:
4382 if not revs:
4383 raise error.Abort(_('default push revset for path evaluates to an '
4383 raise error.Abort(_('default push revset for path evaluates to an '
4384 'empty set'))
4384 'empty set'))
4385
4385
4386 repo._subtoppath = dest
4386 repo._subtoppath = dest
4387 try:
4387 try:
4388 # push subrepos depth-first for coherent ordering
4388 # push subrepos depth-first for coherent ordering
4389 c = repo['.']
4389 c = repo['.']
4390 subs = c.substate # only repos that are committed
4390 subs = c.substate # only repos that are committed
4391 for s in sorted(subs):
4391 for s in sorted(subs):
4392 result = c.sub(s).push(opts)
4392 result = c.sub(s).push(opts)
4393 if result == 0:
4393 if result == 0:
4394 return not result
4394 return not result
4395 finally:
4395 finally:
4396 del repo._subtoppath
4396 del repo._subtoppath
4397
4397
4398 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4398 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4399 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4399 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4400
4400
4401 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4401 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4402 newbranch=opts.get('new_branch'),
4402 newbranch=opts.get('new_branch'),
4403 bookmarks=opts.get('bookmark', ()),
4403 bookmarks=opts.get('bookmark', ()),
4404 opargs=opargs)
4404 opargs=opargs)
4405
4405
4406 result = not pushop.cgresult
4406 result = not pushop.cgresult
4407
4407
4408 if pushop.bkresult is not None:
4408 if pushop.bkresult is not None:
4409 if pushop.bkresult == 2:
4409 if pushop.bkresult == 2:
4410 result = 2
4410 result = 2
4411 elif not result and pushop.bkresult:
4411 elif not result and pushop.bkresult:
4412 result = 2
4412 result = 2
4413
4413
4414 return result
4414 return result
4415
4415
4416 @command('recover', [])
4416 @command('recover', [])
4417 def recover(ui, repo):
4417 def recover(ui, repo):
4418 """roll back an interrupted transaction
4418 """roll back an interrupted transaction
4419
4419
4420 Recover from an interrupted commit or pull.
4420 Recover from an interrupted commit or pull.
4421
4421
4422 This command tries to fix the repository status after an
4422 This command tries to fix the repository status after an
4423 interrupted operation. It should only be necessary when Mercurial
4423 interrupted operation. It should only be necessary when Mercurial
4424 suggests it.
4424 suggests it.
4425
4425
4426 Returns 0 if successful, 1 if nothing to recover or verify fails.
4426 Returns 0 if successful, 1 if nothing to recover or verify fails.
4427 """
4427 """
4428 if repo.recover():
4428 if repo.recover():
4429 return hg.verify(repo)
4429 return hg.verify(repo)
4430 return 1
4430 return 1
4431
4431
4432 @command('^remove|rm',
4432 @command('^remove|rm',
4433 [('A', 'after', None, _('record delete for missing files')),
4433 [('A', 'after', None, _('record delete for missing files')),
4434 ('f', 'force', None,
4434 ('f', 'force', None,
4435 _('forget added files, delete modified files')),
4435 _('forget added files, delete modified files')),
4436 ] + subrepoopts + walkopts + dryrunopts,
4436 ] + subrepoopts + walkopts + dryrunopts,
4437 _('[OPTION]... FILE...'),
4437 _('[OPTION]... FILE...'),
4438 inferrepo=True)
4438 inferrepo=True)
4439 def remove(ui, repo, *pats, **opts):
4439 def remove(ui, repo, *pats, **opts):
4440 """remove the specified files on the next commit
4440 """remove the specified files on the next commit
4441
4441
4442 Schedule the indicated files for removal from the current branch.
4442 Schedule the indicated files for removal from the current branch.
4443
4443
4444 This command schedules the files to be removed at the next commit.
4444 This command schedules the files to be removed at the next commit.
4445 To undo a remove before that, see :hg:`revert`. To undo added
4445 To undo a remove before that, see :hg:`revert`. To undo added
4446 files, see :hg:`forget`.
4446 files, see :hg:`forget`.
4447
4447
4448 .. container:: verbose
4448 .. container:: verbose
4449
4449
4450 -A/--after can be used to remove only files that have already
4450 -A/--after can be used to remove only files that have already
4451 been deleted, -f/--force can be used to force deletion, and -Af
4451 been deleted, -f/--force can be used to force deletion, and -Af
4452 can be used to remove files from the next revision without
4452 can be used to remove files from the next revision without
4453 deleting them from the working directory.
4453 deleting them from the working directory.
4454
4454
4455 The following table details the behavior of remove for different
4455 The following table details the behavior of remove for different
4456 file states (columns) and option combinations (rows). The file
4456 file states (columns) and option combinations (rows). The file
4457 states are Added [A], Clean [C], Modified [M] and Missing [!]
4457 states are Added [A], Clean [C], Modified [M] and Missing [!]
4458 (as reported by :hg:`status`). The actions are Warn, Remove
4458 (as reported by :hg:`status`). The actions are Warn, Remove
4459 (from branch) and Delete (from disk):
4459 (from branch) and Delete (from disk):
4460
4460
4461 ========= == == == ==
4461 ========= == == == ==
4462 opt/state A C M !
4462 opt/state A C M !
4463 ========= == == == ==
4463 ========= == == == ==
4464 none W RD W R
4464 none W RD W R
4465 -f R RD RD R
4465 -f R RD RD R
4466 -A W W W R
4466 -A W W W R
4467 -Af R R R R
4467 -Af R R R R
4468 ========= == == == ==
4468 ========= == == == ==
4469
4469
4470 .. note::
4470 .. note::
4471
4471
4472 :hg:`remove` never deletes files in Added [A] state from the
4472 :hg:`remove` never deletes files in Added [A] state from the
4473 working directory, not even if ``--force`` is specified.
4473 working directory, not even if ``--force`` is specified.
4474
4474
4475 Returns 0 on success, 1 if any warnings encountered.
4475 Returns 0 on success, 1 if any warnings encountered.
4476 """
4476 """
4477
4477
4478 opts = pycompat.byteskwargs(opts)
4478 opts = pycompat.byteskwargs(opts)
4479 after, force = opts.get('after'), opts.get('force')
4479 after, force = opts.get('after'), opts.get('force')
4480 dryrun = opts.get('dry_run')
4480 dryrun = opts.get('dry_run')
4481 if not pats and not after:
4481 if not pats and not after:
4482 raise error.Abort(_('no files specified'))
4482 raise error.Abort(_('no files specified'))
4483
4483
4484 m = scmutil.match(repo[None], pats, opts)
4484 m = scmutil.match(repo[None], pats, opts)
4485 subrepos = opts.get('subrepos')
4485 subrepos = opts.get('subrepos')
4486 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4486 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4487 dryrun=dryrun)
4487 dryrun=dryrun)
4488
4488
4489 @command('rename|move|mv',
4489 @command('rename|move|mv',
4490 [('A', 'after', None, _('record a rename that has already occurred')),
4490 [('A', 'after', None, _('record a rename that has already occurred')),
4491 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4491 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4492 ] + walkopts + dryrunopts,
4492 ] + walkopts + dryrunopts,
4493 _('[OPTION]... SOURCE... DEST'))
4493 _('[OPTION]... SOURCE... DEST'))
4494 def rename(ui, repo, *pats, **opts):
4494 def rename(ui, repo, *pats, **opts):
4495 """rename files; equivalent of copy + remove
4495 """rename files; equivalent of copy + remove
4496
4496
4497 Mark dest as copies of sources; mark sources for deletion. If dest
4497 Mark dest as copies of sources; mark sources for deletion. If dest
4498 is a directory, copies are put in that directory. If dest is a
4498 is a directory, copies are put in that directory. If dest is a
4499 file, there can only be one source.
4499 file, there can only be one source.
4500
4500
4501 By default, this command copies the contents of files as they
4501 By default, this command copies the contents of files as they
4502 exist in the working directory. If invoked with -A/--after, the
4502 exist in the working directory. If invoked with -A/--after, the
4503 operation is recorded, but no copying is performed.
4503 operation is recorded, but no copying is performed.
4504
4504
4505 This command takes effect at the next commit. To undo a rename
4505 This command takes effect at the next commit. To undo a rename
4506 before that, see :hg:`revert`.
4506 before that, see :hg:`revert`.
4507
4507
4508 Returns 0 on success, 1 if errors are encountered.
4508 Returns 0 on success, 1 if errors are encountered.
4509 """
4509 """
4510 opts = pycompat.byteskwargs(opts)
4510 opts = pycompat.byteskwargs(opts)
4511 with repo.wlock(False):
4511 with repo.wlock(False):
4512 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4512 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4513
4513
4514 @command('resolve',
4514 @command('resolve',
4515 [('a', 'all', None, _('select all unresolved files')),
4515 [('a', 'all', None, _('select all unresolved files')),
4516 ('l', 'list', None, _('list state of files needing merge')),
4516 ('l', 'list', None, _('list state of files needing merge')),
4517 ('m', 'mark', None, _('mark files as resolved')),
4517 ('m', 'mark', None, _('mark files as resolved')),
4518 ('u', 'unmark', None, _('mark files as unresolved')),
4518 ('u', 'unmark', None, _('mark files as unresolved')),
4519 ('n', 'no-status', None, _('hide status prefix')),
4519 ('n', 'no-status', None, _('hide status prefix')),
4520 ('', 're-merge', None, _('re-merge files'))]
4520 ('', 're-merge', None, _('re-merge files'))]
4521 + mergetoolopts + walkopts + formatteropts,
4521 + mergetoolopts + walkopts + formatteropts,
4522 _('[OPTION]... [FILE]...'),
4522 _('[OPTION]... [FILE]...'),
4523 inferrepo=True)
4523 inferrepo=True)
4524 def resolve(ui, repo, *pats, **opts):
4524 def resolve(ui, repo, *pats, **opts):
4525 """redo merges or set/view the merge status of files
4525 """redo merges or set/view the merge status of files
4526
4526
4527 Merges with unresolved conflicts are often the result of
4527 Merges with unresolved conflicts are often the result of
4528 non-interactive merging using the ``internal:merge`` configuration
4528 non-interactive merging using the ``internal:merge`` configuration
4529 setting, or a command-line merge tool like ``diff3``. The resolve
4529 setting, or a command-line merge tool like ``diff3``. The resolve
4530 command is used to manage the files involved in a merge, after
4530 command is used to manage the files involved in a merge, after
4531 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4531 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4532 working directory must have two parents). See :hg:`help
4532 working directory must have two parents). See :hg:`help
4533 merge-tools` for information on configuring merge tools.
4533 merge-tools` for information on configuring merge tools.
4534
4534
4535 The resolve command can be used in the following ways:
4535 The resolve command can be used in the following ways:
4536
4536
4537 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4537 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4538 the specified files, discarding any previous merge attempts. Re-merging
4538 the specified files, discarding any previous merge attempts. Re-merging
4539 is not performed for files already marked as resolved. Use ``--all/-a``
4539 is not performed for files already marked as resolved. Use ``--all/-a``
4540 to select all unresolved files. ``--tool`` can be used to specify
4540 to select all unresolved files. ``--tool`` can be used to specify
4541 the merge tool used for the given files. It overrides the HGMERGE
4541 the merge tool used for the given files. It overrides the HGMERGE
4542 environment variable and your configuration files. Previous file
4542 environment variable and your configuration files. Previous file
4543 contents are saved with a ``.orig`` suffix.
4543 contents are saved with a ``.orig`` suffix.
4544
4544
4545 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4545 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4546 (e.g. after having manually fixed-up the files). The default is
4546 (e.g. after having manually fixed-up the files). The default is
4547 to mark all unresolved files.
4547 to mark all unresolved files.
4548
4548
4549 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4549 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4550 default is to mark all resolved files.
4550 default is to mark all resolved files.
4551
4551
4552 - :hg:`resolve -l`: list files which had or still have conflicts.
4552 - :hg:`resolve -l`: list files which had or still have conflicts.
4553 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4553 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4554 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4554 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4555 the list. See :hg:`help filesets` for details.
4555 the list. See :hg:`help filesets` for details.
4556
4556
4557 .. note::
4557 .. note::
4558
4558
4559 Mercurial will not let you commit files with unresolved merge
4559 Mercurial will not let you commit files with unresolved merge
4560 conflicts. You must use :hg:`resolve -m ...` before you can
4560 conflicts. You must use :hg:`resolve -m ...` before you can
4561 commit after a conflicting merge.
4561 commit after a conflicting merge.
4562
4562
4563 Returns 0 on success, 1 if any files fail a resolve attempt.
4563 Returns 0 on success, 1 if any files fail a resolve attempt.
4564 """
4564 """
4565
4565
4566 opts = pycompat.byteskwargs(opts)
4566 opts = pycompat.byteskwargs(opts)
4567 confirm = ui.configbool('commands', 'resolve.confirm')
4567 confirm = ui.configbool('commands', 'resolve.confirm')
4568 flaglist = 'all mark unmark list no_status re_merge'.split()
4568 flaglist = 'all mark unmark list no_status re_merge'.split()
4569 all, mark, unmark, show, nostatus, remerge = \
4569 all, mark, unmark, show, nostatus, remerge = \
4570 [opts.get(o) for o in flaglist]
4570 [opts.get(o) for o in flaglist]
4571
4571
4572 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4572 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4573 if actioncount > 1:
4573 if actioncount > 1:
4574 raise error.Abort(_("too many actions specified"))
4574 raise error.Abort(_("too many actions specified"))
4575 elif (actioncount == 0
4575 elif (actioncount == 0
4576 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4576 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4577 hint = _('use --mark, --unmark, --list or --re-merge')
4577 hint = _('use --mark, --unmark, --list or --re-merge')
4578 raise error.Abort(_('no action specified'), hint=hint)
4578 raise error.Abort(_('no action specified'), hint=hint)
4579 if pats and all:
4579 if pats and all:
4580 raise error.Abort(_("can't specify --all and patterns"))
4580 raise error.Abort(_("can't specify --all and patterns"))
4581 if not (all or pats or show or mark or unmark):
4581 if not (all or pats or show or mark or unmark):
4582 raise error.Abort(_('no files or directories specified'),
4582 raise error.Abort(_('no files or directories specified'),
4583 hint=('use --all to re-merge all unresolved files'))
4583 hint=('use --all to re-merge all unresolved files'))
4584
4584
4585 if confirm:
4585 if confirm:
4586 if all:
4586 if all:
4587 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4587 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4588 b'$$ &Yes $$ &No')):
4588 b'$$ &Yes $$ &No')):
4589 raise error.Abort(_('user quit'))
4589 raise error.Abort(_('user quit'))
4590 if mark and not pats:
4590 if mark and not pats:
4591 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4591 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4592 b'$$ &Yes $$ &No')):
4592 b'$$ &Yes $$ &No')):
4593 raise error.Abort(_('user quit'))
4593 raise error.Abort(_('user quit'))
4594 if unmark and not pats:
4594 if unmark and not pats:
4595 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4595 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4596 b'$$ &Yes $$ &No')):
4596 b'$$ &Yes $$ &No')):
4597 raise error.Abort(_('user quit'))
4597 raise error.Abort(_('user quit'))
4598
4598
4599 if show:
4599 if show:
4600 ui.pager('resolve')
4600 ui.pager('resolve')
4601 fm = ui.formatter('resolve', opts)
4601 fm = ui.formatter('resolve', opts)
4602 ms = mergemod.mergestate.read(repo)
4602 ms = mergemod.mergestate.read(repo)
4603 wctx = repo[None]
4603 wctx = repo[None]
4604 m = scmutil.match(wctx, pats, opts)
4604 m = scmutil.match(wctx, pats, opts)
4605
4605
4606 # Labels and keys based on merge state. Unresolved path conflicts show
4606 # Labels and keys based on merge state. Unresolved path conflicts show
4607 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4607 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4608 # resolved conflicts.
4608 # resolved conflicts.
4609 mergestateinfo = {
4609 mergestateinfo = {
4610 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4610 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4611 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4611 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4612 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4612 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4613 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4613 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4614 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4614 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4615 'D'),
4615 'D'),
4616 }
4616 }
4617
4617
4618 for f in ms:
4618 for f in ms:
4619 if not m(f):
4619 if not m(f):
4620 continue
4620 continue
4621
4621
4622 label, key = mergestateinfo[ms[f]]
4622 label, key = mergestateinfo[ms[f]]
4623 fm.startitem()
4623 fm.startitem()
4624 fm.context(ctx=wctx)
4624 fm.context(ctx=wctx)
4625 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4625 fm.condwrite(not nostatus, 'mergestatus', '%s ', key, label=label)
4626 fm.write('path', '%s\n', f, label=label)
4626 fm.write('path', '%s\n', f, label=label)
4627 fm.end()
4627 fm.end()
4628 return 0
4628 return 0
4629
4629
4630 with repo.wlock():
4630 with repo.wlock():
4631 ms = mergemod.mergestate.read(repo)
4631 ms = mergemod.mergestate.read(repo)
4632
4632
4633 if not (ms.active() or repo.dirstate.p2() != nullid):
4633 if not (ms.active() or repo.dirstate.p2() != nullid):
4634 raise error.Abort(
4634 raise error.Abort(
4635 _('resolve command not applicable when not merging'))
4635 _('resolve command not applicable when not merging'))
4636
4636
4637 wctx = repo[None]
4637 wctx = repo[None]
4638
4638
4639 if (ms.mergedriver
4639 if (ms.mergedriver
4640 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4640 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4641 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4641 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4642 ms.commit()
4642 ms.commit()
4643 # allow mark and unmark to go through
4643 # allow mark and unmark to go through
4644 if not mark and not unmark and not proceed:
4644 if not mark and not unmark and not proceed:
4645 return 1
4645 return 1
4646
4646
4647 m = scmutil.match(wctx, pats, opts)
4647 m = scmutil.match(wctx, pats, opts)
4648 ret = 0
4648 ret = 0
4649 didwork = False
4649 didwork = False
4650 runconclude = False
4650 runconclude = False
4651
4651
4652 tocomplete = []
4652 tocomplete = []
4653 hasconflictmarkers = []
4653 hasconflictmarkers = []
4654 if mark:
4654 if mark:
4655 markcheck = ui.config('commands', 'resolve.mark-check')
4655 markcheck = ui.config('commands', 'resolve.mark-check')
4656 if markcheck not in ['warn', 'abort']:
4656 if markcheck not in ['warn', 'abort']:
4657 # Treat all invalid / unrecognized values as 'none'.
4657 # Treat all invalid / unrecognized values as 'none'.
4658 markcheck = False
4658 markcheck = False
4659 for f in ms:
4659 for f in ms:
4660 if not m(f):
4660 if not m(f):
4661 continue
4661 continue
4662
4662
4663 didwork = True
4663 didwork = True
4664
4664
4665 # don't let driver-resolved files be marked, and run the conclude
4665 # don't let driver-resolved files be marked, and run the conclude
4666 # step if asked to resolve
4666 # step if asked to resolve
4667 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4667 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4668 exact = m.exact(f)
4668 exact = m.exact(f)
4669 if mark:
4669 if mark:
4670 if exact:
4670 if exact:
4671 ui.warn(_('not marking %s as it is driver-resolved\n')
4671 ui.warn(_('not marking %s as it is driver-resolved\n')
4672 % f)
4672 % f)
4673 elif unmark:
4673 elif unmark:
4674 if exact:
4674 if exact:
4675 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4675 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4676 % f)
4676 % f)
4677 else:
4677 else:
4678 runconclude = True
4678 runconclude = True
4679 continue
4679 continue
4680
4680
4681 # path conflicts must be resolved manually
4681 # path conflicts must be resolved manually
4682 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4682 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4683 mergemod.MERGE_RECORD_RESOLVED_PATH):
4683 mergemod.MERGE_RECORD_RESOLVED_PATH):
4684 if mark:
4684 if mark:
4685 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4685 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4686 elif unmark:
4686 elif unmark:
4687 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4687 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4688 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4688 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4689 ui.warn(_('%s: path conflict must be resolved manually\n')
4689 ui.warn(_('%s: path conflict must be resolved manually\n')
4690 % f)
4690 % f)
4691 continue
4691 continue
4692
4692
4693 if mark:
4693 if mark:
4694 if markcheck:
4694 if markcheck:
4695 with repo.wvfs(f) as fobj:
4695 with repo.wvfs(f) as fobj:
4696 fdata = fobj.read()
4696 fdata = fobj.read()
4697 if filemerge.hasconflictmarkers(fdata) and \
4697 if filemerge.hasconflictmarkers(fdata) and \
4698 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4698 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4699 hasconflictmarkers.append(f)
4699 hasconflictmarkers.append(f)
4700 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4700 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4701 elif unmark:
4701 elif unmark:
4702 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4702 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4703 else:
4703 else:
4704 # backup pre-resolve (merge uses .orig for its own purposes)
4704 # backup pre-resolve (merge uses .orig for its own purposes)
4705 a = repo.wjoin(f)
4705 a = repo.wjoin(f)
4706 try:
4706 try:
4707 util.copyfile(a, a + ".resolve")
4707 util.copyfile(a, a + ".resolve")
4708 except (IOError, OSError) as inst:
4708 except (IOError, OSError) as inst:
4709 if inst.errno != errno.ENOENT:
4709 if inst.errno != errno.ENOENT:
4710 raise
4710 raise
4711
4711
4712 try:
4712 try:
4713 # preresolve file
4713 # preresolve file
4714 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4714 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4715 with ui.configoverride(overrides, 'resolve'):
4715 with ui.configoverride(overrides, 'resolve'):
4716 complete, r = ms.preresolve(f, wctx)
4716 complete, r = ms.preresolve(f, wctx)
4717 if not complete:
4717 if not complete:
4718 tocomplete.append(f)
4718 tocomplete.append(f)
4719 elif r:
4719 elif r:
4720 ret = 1
4720 ret = 1
4721 finally:
4721 finally:
4722 ms.commit()
4722 ms.commit()
4723
4723
4724 # replace filemerge's .orig file with our resolve file, but only
4724 # replace filemerge's .orig file with our resolve file, but only
4725 # for merges that are complete
4725 # for merges that are complete
4726 if complete:
4726 if complete:
4727 try:
4727 try:
4728 util.rename(a + ".resolve",
4728 util.rename(a + ".resolve",
4729 scmutil.origpath(ui, repo, a))
4729 scmutil.origpath(ui, repo, a))
4730 except OSError as inst:
4730 except OSError as inst:
4731 if inst.errno != errno.ENOENT:
4731 if inst.errno != errno.ENOENT:
4732 raise
4732 raise
4733
4733
4734 if hasconflictmarkers:
4734 if hasconflictmarkers:
4735 ui.warn(_('warning: the following files still have conflict '
4735 ui.warn(_('warning: the following files still have conflict '
4736 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4736 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4737 if markcheck == 'abort' and not all:
4737 if markcheck == 'abort' and not all:
4738 raise error.Abort(_('conflict markers detected'),
4738 raise error.Abort(_('conflict markers detected'),
4739 hint=_('use --all to mark anyway'))
4739 hint=_('use --all to mark anyway'))
4740
4740
4741 for f in tocomplete:
4741 for f in tocomplete:
4742 try:
4742 try:
4743 # resolve file
4743 # resolve file
4744 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4744 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4745 with ui.configoverride(overrides, 'resolve'):
4745 with ui.configoverride(overrides, 'resolve'):
4746 r = ms.resolve(f, wctx)
4746 r = ms.resolve(f, wctx)
4747 if r:
4747 if r:
4748 ret = 1
4748 ret = 1
4749 finally:
4749 finally:
4750 ms.commit()
4750 ms.commit()
4751
4751
4752 # replace filemerge's .orig file with our resolve file
4752 # replace filemerge's .orig file with our resolve file
4753 a = repo.wjoin(f)
4753 a = repo.wjoin(f)
4754 try:
4754 try:
4755 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4755 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4756 except OSError as inst:
4756 except OSError as inst:
4757 if inst.errno != errno.ENOENT:
4757 if inst.errno != errno.ENOENT:
4758 raise
4758 raise
4759
4759
4760 ms.commit()
4760 ms.commit()
4761 ms.recordactions()
4761 ms.recordactions()
4762
4762
4763 if not didwork and pats:
4763 if not didwork and pats:
4764 hint = None
4764 hint = None
4765 if not any([p for p in pats if p.find(':') >= 0]):
4765 if not any([p for p in pats if p.find(':') >= 0]):
4766 pats = ['path:%s' % p for p in pats]
4766 pats = ['path:%s' % p for p in pats]
4767 m = scmutil.match(wctx, pats, opts)
4767 m = scmutil.match(wctx, pats, opts)
4768 for f in ms:
4768 for f in ms:
4769 if not m(f):
4769 if not m(f):
4770 continue
4770 continue
4771 def flag(o):
4771 def flag(o):
4772 if o == 're_merge':
4772 if o == 're_merge':
4773 return '--re-merge '
4773 return '--re-merge '
4774 return '-%s ' % o[0:1]
4774 return '-%s ' % o[0:1]
4775 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4775 flags = ''.join([flag(o) for o in flaglist if opts.get(o)])
4776 hint = _("(try: hg resolve %s%s)\n") % (
4776 hint = _("(try: hg resolve %s%s)\n") % (
4777 flags,
4777 flags,
4778 ' '.join(pats))
4778 ' '.join(pats))
4779 break
4779 break
4780 ui.warn(_("arguments do not match paths that need resolving\n"))
4780 ui.warn(_("arguments do not match paths that need resolving\n"))
4781 if hint:
4781 if hint:
4782 ui.warn(hint)
4782 ui.warn(hint)
4783 elif ms.mergedriver and ms.mdstate() != 's':
4783 elif ms.mergedriver and ms.mdstate() != 's':
4784 # run conclude step when either a driver-resolved file is requested
4784 # run conclude step when either a driver-resolved file is requested
4785 # or there are no driver-resolved files
4785 # or there are no driver-resolved files
4786 # we can't use 'ret' to determine whether any files are unresolved
4786 # we can't use 'ret' to determine whether any files are unresolved
4787 # because we might not have tried to resolve some
4787 # because we might not have tried to resolve some
4788 if ((runconclude or not list(ms.driverresolved()))
4788 if ((runconclude or not list(ms.driverresolved()))
4789 and not list(ms.unresolved())):
4789 and not list(ms.unresolved())):
4790 proceed = mergemod.driverconclude(repo, ms, wctx)
4790 proceed = mergemod.driverconclude(repo, ms, wctx)
4791 ms.commit()
4791 ms.commit()
4792 if not proceed:
4792 if not proceed:
4793 return 1
4793 return 1
4794
4794
4795 # Nudge users into finishing an unfinished operation
4795 # Nudge users into finishing an unfinished operation
4796 unresolvedf = list(ms.unresolved())
4796 unresolvedf = list(ms.unresolved())
4797 driverresolvedf = list(ms.driverresolved())
4797 driverresolvedf = list(ms.driverresolved())
4798 if not unresolvedf and not driverresolvedf:
4798 if not unresolvedf and not driverresolvedf:
4799 ui.status(_('(no more unresolved files)\n'))
4799 ui.status(_('(no more unresolved files)\n'))
4800 cmdutil.checkafterresolved(repo)
4800 cmdutil.checkafterresolved(repo)
4801 elif not unresolvedf:
4801 elif not unresolvedf:
4802 ui.status(_('(no more unresolved files -- '
4802 ui.status(_('(no more unresolved files -- '
4803 'run "hg resolve --all" to conclude)\n'))
4803 'run "hg resolve --all" to conclude)\n'))
4804
4804
4805 return ret
4805 return ret
4806
4806
4807 @command('revert',
4807 @command('revert',
4808 [('a', 'all', None, _('revert all changes when no arguments given')),
4808 [('a', 'all', None, _('revert all changes when no arguments given')),
4809 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4809 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4810 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4810 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4811 ('C', 'no-backup', None, _('do not save backup copies of files')),
4811 ('C', 'no-backup', None, _('do not save backup copies of files')),
4812 ('i', 'interactive', None, _('interactively select the changes')),
4812 ('i', 'interactive', None, _('interactively select the changes')),
4813 ] + walkopts + dryrunopts,
4813 ] + walkopts + dryrunopts,
4814 _('[OPTION]... [-r REV] [NAME]...'))
4814 _('[OPTION]... [-r REV] [NAME]...'))
4815 def revert(ui, repo, *pats, **opts):
4815 def revert(ui, repo, *pats, **opts):
4816 """restore files to their checkout state
4816 """restore files to their checkout state
4817
4817
4818 .. note::
4818 .. note::
4819
4819
4820 To check out earlier revisions, you should use :hg:`update REV`.
4820 To check out earlier revisions, you should use :hg:`update REV`.
4821 To cancel an uncommitted merge (and lose your changes),
4821 To cancel an uncommitted merge (and lose your changes),
4822 use :hg:`merge --abort`.
4822 use :hg:`merge --abort`.
4823
4823
4824 With no revision specified, revert the specified files or directories
4824 With no revision specified, revert the specified files or directories
4825 to the contents they had in the parent of the working directory.
4825 to the contents they had in the parent of the working directory.
4826 This restores the contents of files to an unmodified
4826 This restores the contents of files to an unmodified
4827 state and unschedules adds, removes, copies, and renames. If the
4827 state and unschedules adds, removes, copies, and renames. If the
4828 working directory has two parents, you must explicitly specify a
4828 working directory has two parents, you must explicitly specify a
4829 revision.
4829 revision.
4830
4830
4831 Using the -r/--rev or -d/--date options, revert the given files or
4831 Using the -r/--rev or -d/--date options, revert the given files or
4832 directories to their states as of a specific revision. Because
4832 directories to their states as of a specific revision. Because
4833 revert does not change the working directory parents, this will
4833 revert does not change the working directory parents, this will
4834 cause these files to appear modified. This can be helpful to "back
4834 cause these files to appear modified. This can be helpful to "back
4835 out" some or all of an earlier change. See :hg:`backout` for a
4835 out" some or all of an earlier change. See :hg:`backout` for a
4836 related method.
4836 related method.
4837
4837
4838 Modified files are saved with a .orig suffix before reverting.
4838 Modified files are saved with a .orig suffix before reverting.
4839 To disable these backups, use --no-backup. It is possible to store
4839 To disable these backups, use --no-backup. It is possible to store
4840 the backup files in a custom directory relative to the root of the
4840 the backup files in a custom directory relative to the root of the
4841 repository by setting the ``ui.origbackuppath`` configuration
4841 repository by setting the ``ui.origbackuppath`` configuration
4842 option.
4842 option.
4843
4843
4844 See :hg:`help dates` for a list of formats valid for -d/--date.
4844 See :hg:`help dates` for a list of formats valid for -d/--date.
4845
4845
4846 See :hg:`help backout` for a way to reverse the effect of an
4846 See :hg:`help backout` for a way to reverse the effect of an
4847 earlier changeset.
4847 earlier changeset.
4848
4848
4849 Returns 0 on success.
4849 Returns 0 on success.
4850 """
4850 """
4851
4851
4852 opts = pycompat.byteskwargs(opts)
4852 opts = pycompat.byteskwargs(opts)
4853 if opts.get("date"):
4853 if opts.get("date"):
4854 if opts.get("rev"):
4854 if opts.get("rev"):
4855 raise error.Abort(_("you can't specify a revision and a date"))
4855 raise error.Abort(_("you can't specify a revision and a date"))
4856 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4856 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4857
4857
4858 parent, p2 = repo.dirstate.parents()
4858 parent, p2 = repo.dirstate.parents()
4859 if not opts.get('rev') and p2 != nullid:
4859 if not opts.get('rev') and p2 != nullid:
4860 # revert after merge is a trap for new users (issue2915)
4860 # revert after merge is a trap for new users (issue2915)
4861 raise error.Abort(_('uncommitted merge with no revision specified'),
4861 raise error.Abort(_('uncommitted merge with no revision specified'),
4862 hint=_("use 'hg update' or see 'hg help revert'"))
4862 hint=_("use 'hg update' or see 'hg help revert'"))
4863
4863
4864 rev = opts.get('rev')
4864 rev = opts.get('rev')
4865 if rev:
4865 if rev:
4866 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4866 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4867 ctx = scmutil.revsingle(repo, rev)
4867 ctx = scmutil.revsingle(repo, rev)
4868
4868
4869 if (not (pats or opts.get('include') or opts.get('exclude') or
4869 if (not (pats or opts.get('include') or opts.get('exclude') or
4870 opts.get('all') or opts.get('interactive'))):
4870 opts.get('all') or opts.get('interactive'))):
4871 msg = _("no files or directories specified")
4871 msg = _("no files or directories specified")
4872 if p2 != nullid:
4872 if p2 != nullid:
4873 hint = _("uncommitted merge, use --all to discard all changes,"
4873 hint = _("uncommitted merge, use --all to discard all changes,"
4874 " or 'hg update -C .' to abort the merge")
4874 " or 'hg update -C .' to abort the merge")
4875 raise error.Abort(msg, hint=hint)
4875 raise error.Abort(msg, hint=hint)
4876 dirty = any(repo.status())
4876 dirty = any(repo.status())
4877 node = ctx.node()
4877 node = ctx.node()
4878 if node != parent:
4878 if node != parent:
4879 if dirty:
4879 if dirty:
4880 hint = _("uncommitted changes, use --all to discard all"
4880 hint = _("uncommitted changes, use --all to discard all"
4881 " changes, or 'hg update %d' to update") % ctx.rev()
4881 " changes, or 'hg update %d' to update") % ctx.rev()
4882 else:
4882 else:
4883 hint = _("use --all to revert all files,"
4883 hint = _("use --all to revert all files,"
4884 " or 'hg update %d' to update") % ctx.rev()
4884 " or 'hg update %d' to update") % ctx.rev()
4885 elif dirty:
4885 elif dirty:
4886 hint = _("uncommitted changes, use --all to discard all changes")
4886 hint = _("uncommitted changes, use --all to discard all changes")
4887 else:
4887 else:
4888 hint = _("use --all to revert all files")
4888 hint = _("use --all to revert all files")
4889 raise error.Abort(msg, hint=hint)
4889 raise error.Abort(msg, hint=hint)
4890
4890
4891 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4891 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4892 **pycompat.strkwargs(opts))
4892 **pycompat.strkwargs(opts))
4893
4893
4894 @command('rollback', dryrunopts +
4894 @command('rollback', dryrunopts +
4895 [('f', 'force', False, _('ignore safety measures'))])
4895 [('f', 'force', False, _('ignore safety measures'))])
4896 def rollback(ui, repo, **opts):
4896 def rollback(ui, repo, **opts):
4897 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4897 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4898
4898
4899 Please use :hg:`commit --amend` instead of rollback to correct
4899 Please use :hg:`commit --amend` instead of rollback to correct
4900 mistakes in the last commit.
4900 mistakes in the last commit.
4901
4901
4902 This command should be used with care. There is only one level of
4902 This command should be used with care. There is only one level of
4903 rollback, and there is no way to undo a rollback. It will also
4903 rollback, and there is no way to undo a rollback. It will also
4904 restore the dirstate at the time of the last transaction, losing
4904 restore the dirstate at the time of the last transaction, losing
4905 any dirstate changes since that time. This command does not alter
4905 any dirstate changes since that time. This command does not alter
4906 the working directory.
4906 the working directory.
4907
4907
4908 Transactions are used to encapsulate the effects of all commands
4908 Transactions are used to encapsulate the effects of all commands
4909 that create new changesets or propagate existing changesets into a
4909 that create new changesets or propagate existing changesets into a
4910 repository.
4910 repository.
4911
4911
4912 .. container:: verbose
4912 .. container:: verbose
4913
4913
4914 For example, the following commands are transactional, and their
4914 For example, the following commands are transactional, and their
4915 effects can be rolled back:
4915 effects can be rolled back:
4916
4916
4917 - commit
4917 - commit
4918 - import
4918 - import
4919 - pull
4919 - pull
4920 - push (with this repository as the destination)
4920 - push (with this repository as the destination)
4921 - unbundle
4921 - unbundle
4922
4922
4923 To avoid permanent data loss, rollback will refuse to rollback a
4923 To avoid permanent data loss, rollback will refuse to rollback a
4924 commit transaction if it isn't checked out. Use --force to
4924 commit transaction if it isn't checked out. Use --force to
4925 override this protection.
4925 override this protection.
4926
4926
4927 The rollback command can be entirely disabled by setting the
4927 The rollback command can be entirely disabled by setting the
4928 ``ui.rollback`` configuration setting to false. If you're here
4928 ``ui.rollback`` configuration setting to false. If you're here
4929 because you want to use rollback and it's disabled, you can
4929 because you want to use rollback and it's disabled, you can
4930 re-enable the command by setting ``ui.rollback`` to true.
4930 re-enable the command by setting ``ui.rollback`` to true.
4931
4931
4932 This command is not intended for use on public repositories. Once
4932 This command is not intended for use on public repositories. Once
4933 changes are visible for pull by other users, rolling a transaction
4933 changes are visible for pull by other users, rolling a transaction
4934 back locally is ineffective (someone else may already have pulled
4934 back locally is ineffective (someone else may already have pulled
4935 the changes). Furthermore, a race is possible with readers of the
4935 the changes). Furthermore, a race is possible with readers of the
4936 repository; for example an in-progress pull from the repository
4936 repository; for example an in-progress pull from the repository
4937 may fail if a rollback is performed.
4937 may fail if a rollback is performed.
4938
4938
4939 Returns 0 on success, 1 if no rollback data is available.
4939 Returns 0 on success, 1 if no rollback data is available.
4940 """
4940 """
4941 if not ui.configbool('ui', 'rollback'):
4941 if not ui.configbool('ui', 'rollback'):
4942 raise error.Abort(_('rollback is disabled because it is unsafe'),
4942 raise error.Abort(_('rollback is disabled because it is unsafe'),
4943 hint=('see `hg help -v rollback` for information'))
4943 hint=('see `hg help -v rollback` for information'))
4944 return repo.rollback(dryrun=opts.get(r'dry_run'),
4944 return repo.rollback(dryrun=opts.get(r'dry_run'),
4945 force=opts.get(r'force'))
4945 force=opts.get(r'force'))
4946
4946
4947 @command('root', [], intents={INTENT_READONLY})
4947 @command('root', [], intents={INTENT_READONLY})
4948 def root(ui, repo):
4948 def root(ui, repo):
4949 """print the root (top) of the current working directory
4949 """print the root (top) of the current working directory
4950
4950
4951 Print the root directory of the current repository.
4951 Print the root directory of the current repository.
4952
4952
4953 Returns 0 on success.
4953 Returns 0 on success.
4954 """
4954 """
4955 ui.write(repo.root + "\n")
4955 ui.write(repo.root + "\n")
4956
4956
4957 @command('^serve',
4957 @command('^serve',
4958 [('A', 'accesslog', '', _('name of access log file to write to'),
4958 [('A', 'accesslog', '', _('name of access log file to write to'),
4959 _('FILE')),
4959 _('FILE')),
4960 ('d', 'daemon', None, _('run server in background')),
4960 ('d', 'daemon', None, _('run server in background')),
4961 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4961 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4962 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4962 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4963 # use string type, then we can check if something was passed
4963 # use string type, then we can check if something was passed
4964 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4964 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4965 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4965 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4966 _('ADDR')),
4966 _('ADDR')),
4967 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4967 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4968 _('PREFIX')),
4968 _('PREFIX')),
4969 ('n', 'name', '',
4969 ('n', 'name', '',
4970 _('name to show in web pages (default: working directory)'), _('NAME')),
4970 _('name to show in web pages (default: working directory)'), _('NAME')),
4971 ('', 'web-conf', '',
4971 ('', 'web-conf', '',
4972 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4972 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4973 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4973 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4974 _('FILE')),
4974 _('FILE')),
4975 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4975 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4976 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4976 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4977 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4977 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4978 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4978 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4979 ('', 'style', '', _('template style to use'), _('STYLE')),
4979 ('', 'style', '', _('template style to use'), _('STYLE')),
4980 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4980 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4981 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
4981 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
4982 ('', 'print-url', None, _('start and print only the URL'))]
4982 ('', 'print-url', None, _('start and print only the URL'))]
4983 + subrepoopts,
4983 + subrepoopts,
4984 _('[OPTION]...'),
4984 _('[OPTION]...'),
4985 optionalrepo=True)
4985 optionalrepo=True)
4986 def serve(ui, repo, **opts):
4986 def serve(ui, repo, **opts):
4987 """start stand-alone webserver
4987 """start stand-alone webserver
4988
4988
4989 Start a local HTTP repository browser and pull server. You can use
4989 Start a local HTTP repository browser and pull server. You can use
4990 this for ad-hoc sharing and browsing of repositories. It is
4990 this for ad-hoc sharing and browsing of repositories. It is
4991 recommended to use a real web server to serve a repository for
4991 recommended to use a real web server to serve a repository for
4992 longer periods of time.
4992 longer periods of time.
4993
4993
4994 Please note that the server does not implement access control.
4994 Please note that the server does not implement access control.
4995 This means that, by default, anybody can read from the server and
4995 This means that, by default, anybody can read from the server and
4996 nobody can write to it by default. Set the ``web.allow-push``
4996 nobody can write to it by default. Set the ``web.allow-push``
4997 option to ``*`` to allow everybody to push to the server. You
4997 option to ``*`` to allow everybody to push to the server. You
4998 should use a real web server if you need to authenticate users.
4998 should use a real web server if you need to authenticate users.
4999
4999
5000 By default, the server logs accesses to stdout and errors to
5000 By default, the server logs accesses to stdout and errors to
5001 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5001 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5002 files.
5002 files.
5003
5003
5004 To have the server choose a free port number to listen on, specify
5004 To have the server choose a free port number to listen on, specify
5005 a port number of 0; in this case, the server will print the port
5005 a port number of 0; in this case, the server will print the port
5006 number it uses.
5006 number it uses.
5007
5007
5008 Returns 0 on success.
5008 Returns 0 on success.
5009 """
5009 """
5010
5010
5011 opts = pycompat.byteskwargs(opts)
5011 opts = pycompat.byteskwargs(opts)
5012 if opts["stdio"] and opts["cmdserver"]:
5012 if opts["stdio"] and opts["cmdserver"]:
5013 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5013 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5014 if opts["print_url"] and ui.verbose:
5014 if opts["print_url"] and ui.verbose:
5015 raise error.Abort(_("cannot use --print-url with --verbose"))
5015 raise error.Abort(_("cannot use --print-url with --verbose"))
5016
5016
5017 if opts["stdio"]:
5017 if opts["stdio"]:
5018 if repo is None:
5018 if repo is None:
5019 raise error.RepoError(_("there is no Mercurial repository here"
5019 raise error.RepoError(_("there is no Mercurial repository here"
5020 " (.hg not found)"))
5020 " (.hg not found)"))
5021 s = wireprotoserver.sshserver(ui, repo)
5021 s = wireprotoserver.sshserver(ui, repo)
5022 s.serve_forever()
5022 s.serve_forever()
5023
5023
5024 service = server.createservice(ui, repo, opts)
5024 service = server.createservice(ui, repo, opts)
5025 return server.runservice(opts, initfn=service.init, runfn=service.run)
5025 return server.runservice(opts, initfn=service.init, runfn=service.run)
5026
5026
5027 _NOTTERSE = 'nothing'
5027 _NOTTERSE = 'nothing'
5028
5028
5029 @command('^status|st',
5029 @command('^status|st',
5030 [('A', 'all', None, _('show status of all files')),
5030 [('A', 'all', None, _('show status of all files')),
5031 ('m', 'modified', None, _('show only modified files')),
5031 ('m', 'modified', None, _('show only modified files')),
5032 ('a', 'added', None, _('show only added files')),
5032 ('a', 'added', None, _('show only added files')),
5033 ('r', 'removed', None, _('show only removed files')),
5033 ('r', 'removed', None, _('show only removed files')),
5034 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5034 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5035 ('c', 'clean', None, _('show only files without changes')),
5035 ('c', 'clean', None, _('show only files without changes')),
5036 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5036 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5037 ('i', 'ignored', None, _('show only ignored files')),
5037 ('i', 'ignored', None, _('show only ignored files')),
5038 ('n', 'no-status', None, _('hide status prefix')),
5038 ('n', 'no-status', None, _('hide status prefix')),
5039 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5039 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5040 ('C', 'copies', None, _('show source of copied files')),
5040 ('C', 'copies', None, _('show source of copied files')),
5041 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5041 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5042 ('', 'rev', [], _('show difference from revision'), _('REV')),
5042 ('', 'rev', [], _('show difference from revision'), _('REV')),
5043 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5043 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5044 ] + walkopts + subrepoopts + formatteropts,
5044 ] + walkopts + subrepoopts + formatteropts,
5045 _('[OPTION]... [FILE]...'),
5045 _('[OPTION]... [FILE]...'),
5046 inferrepo=True,
5046 inferrepo=True,
5047 intents={INTENT_READONLY})
5047 intents={INTENT_READONLY})
5048 def status(ui, repo, *pats, **opts):
5048 def status(ui, repo, *pats, **opts):
5049 """show changed files in the working directory
5049 """show changed files in the working directory
5050
5050
5051 Show status of files in the repository. If names are given, only
5051 Show status of files in the repository. If names are given, only
5052 files that match are shown. Files that are clean or ignored or
5052 files that match are shown. Files that are clean or ignored or
5053 the source of a copy/move operation, are not listed unless
5053 the source of a copy/move operation, are not listed unless
5054 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5054 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5055 Unless options described with "show only ..." are given, the
5055 Unless options described with "show only ..." are given, the
5056 options -mardu are used.
5056 options -mardu are used.
5057
5057
5058 Option -q/--quiet hides untracked (unknown and ignored) files
5058 Option -q/--quiet hides untracked (unknown and ignored) files
5059 unless explicitly requested with -u/--unknown or -i/--ignored.
5059 unless explicitly requested with -u/--unknown or -i/--ignored.
5060
5060
5061 .. note::
5061 .. note::
5062
5062
5063 :hg:`status` may appear to disagree with diff if permissions have
5063 :hg:`status` may appear to disagree with diff if permissions have
5064 changed or a merge has occurred. The standard diff format does
5064 changed or a merge has occurred. The standard diff format does
5065 not report permission changes and diff only reports changes
5065 not report permission changes and diff only reports changes
5066 relative to one merge parent.
5066 relative to one merge parent.
5067
5067
5068 If one revision is given, it is used as the base revision.
5068 If one revision is given, it is used as the base revision.
5069 If two revisions are given, the differences between them are
5069 If two revisions are given, the differences between them are
5070 shown. The --change option can also be used as a shortcut to list
5070 shown. The --change option can also be used as a shortcut to list
5071 the changed files of a revision from its first parent.
5071 the changed files of a revision from its first parent.
5072
5072
5073 The codes used to show the status of files are::
5073 The codes used to show the status of files are::
5074
5074
5075 M = modified
5075 M = modified
5076 A = added
5076 A = added
5077 R = removed
5077 R = removed
5078 C = clean
5078 C = clean
5079 ! = missing (deleted by non-hg command, but still tracked)
5079 ! = missing (deleted by non-hg command, but still tracked)
5080 ? = not tracked
5080 ? = not tracked
5081 I = ignored
5081 I = ignored
5082 = origin of the previous file (with --copies)
5082 = origin of the previous file (with --copies)
5083
5083
5084 .. container:: verbose
5084 .. container:: verbose
5085
5085
5086 The -t/--terse option abbreviates the output by showing only the directory
5086 The -t/--terse option abbreviates the output by showing only the directory
5087 name if all the files in it share the same status. The option takes an
5087 name if all the files in it share the same status. The option takes an
5088 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5088 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5089 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5089 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
5090 for 'ignored' and 'c' for clean.
5090 for 'ignored' and 'c' for clean.
5091
5091
5092 It abbreviates only those statuses which are passed. Note that clean and
5092 It abbreviates only those statuses which are passed. Note that clean and
5093 ignored files are not displayed with '--terse ic' unless the -c/--clean
5093 ignored files are not displayed with '--terse ic' unless the -c/--clean
5094 and -i/--ignored options are also used.
5094 and -i/--ignored options are also used.
5095
5095
5096 The -v/--verbose option shows information when the repository is in an
5096 The -v/--verbose option shows information when the repository is in an
5097 unfinished merge, shelve, rebase state etc. You can have this behavior
5097 unfinished merge, shelve, rebase state etc. You can have this behavior
5098 turned on by default by enabling the ``commands.status.verbose`` option.
5098 turned on by default by enabling the ``commands.status.verbose`` option.
5099
5099
5100 You can skip displaying some of these states by setting
5100 You can skip displaying some of these states by setting
5101 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5101 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5102 'histedit', 'merge', 'rebase', or 'unshelve'.
5102 'histedit', 'merge', 'rebase', or 'unshelve'.
5103
5103
5104 Examples:
5104 Examples:
5105
5105
5106 - show changes in the working directory relative to a
5106 - show changes in the working directory relative to a
5107 changeset::
5107 changeset::
5108
5108
5109 hg status --rev 9353
5109 hg status --rev 9353
5110
5110
5111 - show changes in the working directory relative to the
5111 - show changes in the working directory relative to the
5112 current directory (see :hg:`help patterns` for more information)::
5112 current directory (see :hg:`help patterns` for more information)::
5113
5113
5114 hg status re:
5114 hg status re:
5115
5115
5116 - show all changes including copies in an existing changeset::
5116 - show all changes including copies in an existing changeset::
5117
5117
5118 hg status --copies --change 9353
5118 hg status --copies --change 9353
5119
5119
5120 - get a NUL separated list of added files, suitable for xargs::
5120 - get a NUL separated list of added files, suitable for xargs::
5121
5121
5122 hg status -an0
5122 hg status -an0
5123
5123
5124 - show more information about the repository status, abbreviating
5124 - show more information about the repository status, abbreviating
5125 added, removed, modified, deleted, and untracked paths::
5125 added, removed, modified, deleted, and untracked paths::
5126
5126
5127 hg status -v -t mardu
5127 hg status -v -t mardu
5128
5128
5129 Returns 0 on success.
5129 Returns 0 on success.
5130
5130
5131 """
5131 """
5132
5132
5133 opts = pycompat.byteskwargs(opts)
5133 opts = pycompat.byteskwargs(opts)
5134 revs = opts.get('rev')
5134 revs = opts.get('rev')
5135 change = opts.get('change')
5135 change = opts.get('change')
5136 terse = opts.get('terse')
5136 terse = opts.get('terse')
5137 if terse is _NOTTERSE:
5137 if terse is _NOTTERSE:
5138 if revs:
5138 if revs:
5139 terse = ''
5139 terse = ''
5140 else:
5140 else:
5141 terse = ui.config('commands', 'status.terse')
5141 terse = ui.config('commands', 'status.terse')
5142
5142
5143 if revs and change:
5143 if revs and change:
5144 msg = _('cannot specify --rev and --change at the same time')
5144 msg = _('cannot specify --rev and --change at the same time')
5145 raise error.Abort(msg)
5145 raise error.Abort(msg)
5146 elif revs and terse:
5146 elif revs and terse:
5147 msg = _('cannot use --terse with --rev')
5147 msg = _('cannot use --terse with --rev')
5148 raise error.Abort(msg)
5148 raise error.Abort(msg)
5149 elif change:
5149 elif change:
5150 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5150 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5151 ctx2 = scmutil.revsingle(repo, change, None)
5151 ctx2 = scmutil.revsingle(repo, change, None)
5152 ctx1 = ctx2.p1()
5152 ctx1 = ctx2.p1()
5153 else:
5153 else:
5154 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5154 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5155 ctx1, ctx2 = scmutil.revpair(repo, revs)
5155 ctx1, ctx2 = scmutil.revpair(repo, revs)
5156
5156
5157 if pats or ui.configbool('commands', 'status.relative'):
5157 if pats or ui.configbool('commands', 'status.relative'):
5158 cwd = repo.getcwd()
5158 cwd = repo.getcwd()
5159 else:
5159 else:
5160 cwd = ''
5160 cwd = ''
5161
5161
5162 if opts.get('print0'):
5162 if opts.get('print0'):
5163 end = '\0'
5163 end = '\0'
5164 else:
5164 else:
5165 end = '\n'
5165 end = '\n'
5166 copy = {}
5166 copy = {}
5167 states = 'modified added removed deleted unknown ignored clean'.split()
5167 states = 'modified added removed deleted unknown ignored clean'.split()
5168 show = [k for k in states if opts.get(k)]
5168 show = [k for k in states if opts.get(k)]
5169 if opts.get('all'):
5169 if opts.get('all'):
5170 show += ui.quiet and (states[:4] + ['clean']) or states
5170 show += ui.quiet and (states[:4] + ['clean']) or states
5171
5171
5172 if not show:
5172 if not show:
5173 if ui.quiet:
5173 if ui.quiet:
5174 show = states[:4]
5174 show = states[:4]
5175 else:
5175 else:
5176 show = states[:5]
5176 show = states[:5]
5177
5177
5178 m = scmutil.match(ctx2, pats, opts)
5178 m = scmutil.match(ctx2, pats, opts)
5179 if terse:
5179 if terse:
5180 # we need to compute clean and unknown to terse
5180 # we need to compute clean and unknown to terse
5181 stat = repo.status(ctx1.node(), ctx2.node(), m,
5181 stat = repo.status(ctx1.node(), ctx2.node(), m,
5182 'ignored' in show or 'i' in terse,
5182 'ignored' in show or 'i' in terse,
5183 clean=True, unknown=True,
5183 clean=True, unknown=True,
5184 listsubrepos=opts.get('subrepos'))
5184 listsubrepos=opts.get('subrepos'))
5185
5185
5186 stat = cmdutil.tersedir(stat, terse)
5186 stat = cmdutil.tersedir(stat, terse)
5187 else:
5187 else:
5188 stat = repo.status(ctx1.node(), ctx2.node(), m,
5188 stat = repo.status(ctx1.node(), ctx2.node(), m,
5189 'ignored' in show, 'clean' in show,
5189 'ignored' in show, 'clean' in show,
5190 'unknown' in show, opts.get('subrepos'))
5190 'unknown' in show, opts.get('subrepos'))
5191
5191
5192 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5192 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5193
5193
5194 if (opts.get('all') or opts.get('copies')
5194 if (opts.get('all') or opts.get('copies')
5195 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5195 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5196 copy = copies.pathcopies(ctx1, ctx2, m)
5196 copy = copies.pathcopies(ctx1, ctx2, m)
5197
5197
5198 ui.pager('status')
5198 ui.pager('status')
5199 fm = ui.formatter('status', opts)
5199 fm = ui.formatter('status', opts)
5200 fmt = '%s' + end
5200 fmt = '%s' + end
5201 showchar = not opts.get('no_status')
5201 showchar = not opts.get('no_status')
5202
5202
5203 for state, char, files in changestates:
5203 for state, char, files in changestates:
5204 if state in show:
5204 if state in show:
5205 label = 'status.' + state
5205 label = 'status.' + state
5206 for f in files:
5206 for f in files:
5207 fm.startitem()
5207 fm.startitem()
5208 fm.context(ctx=ctx2)
5208 fm.context(ctx=ctx2)
5209 fm.data(path=f)
5209 fm.data(path=f)
5210 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5210 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5211 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5211 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5212 if f in copy:
5212 if f in copy:
5213 fm.data(source=copy[f])
5213 fm.data(source=copy[f])
5214 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5214 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5215 label='status.copied')
5215 label='status.copied')
5216
5216
5217 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5217 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5218 and not ui.plain()):
5218 and not ui.plain()):
5219 cmdutil.morestatus(repo, fm)
5219 cmdutil.morestatus(repo, fm)
5220 fm.end()
5220 fm.end()
5221
5221
5222 @command('^summary|sum',
5222 @command('^summary|sum',
5223 [('', 'remote', None, _('check for push and pull'))],
5223 [('', 'remote', None, _('check for push and pull'))],
5224 '[--remote]',
5224 '[--remote]',
5225 intents={INTENT_READONLY})
5225 intents={INTENT_READONLY})
5226 def summary(ui, repo, **opts):
5226 def summary(ui, repo, **opts):
5227 """summarize working directory state
5227 """summarize working directory state
5228
5228
5229 This generates a brief summary of the working directory state,
5229 This generates a brief summary of the working directory state,
5230 including parents, branch, commit status, phase and available updates.
5230 including parents, branch, commit status, phase and available updates.
5231
5231
5232 With the --remote option, this will check the default paths for
5232 With the --remote option, this will check the default paths for
5233 incoming and outgoing changes. This can be time-consuming.
5233 incoming and outgoing changes. This can be time-consuming.
5234
5234
5235 Returns 0 on success.
5235 Returns 0 on success.
5236 """
5236 """
5237
5237
5238 opts = pycompat.byteskwargs(opts)
5238 opts = pycompat.byteskwargs(opts)
5239 ui.pager('summary')
5239 ui.pager('summary')
5240 ctx = repo[None]
5240 ctx = repo[None]
5241 parents = ctx.parents()
5241 parents = ctx.parents()
5242 pnode = parents[0].node()
5242 pnode = parents[0].node()
5243 marks = []
5243 marks = []
5244
5244
5245 ms = None
5245 ms = None
5246 try:
5246 try:
5247 ms = mergemod.mergestate.read(repo)
5247 ms = mergemod.mergestate.read(repo)
5248 except error.UnsupportedMergeRecords as e:
5248 except error.UnsupportedMergeRecords as e:
5249 s = ' '.join(e.recordtypes)
5249 s = ' '.join(e.recordtypes)
5250 ui.warn(
5250 ui.warn(
5251 _('warning: merge state has unsupported record types: %s\n') % s)
5251 _('warning: merge state has unsupported record types: %s\n') % s)
5252 unresolved = []
5252 unresolved = []
5253 else:
5253 else:
5254 unresolved = list(ms.unresolved())
5254 unresolved = list(ms.unresolved())
5255
5255
5256 for p in parents:
5256 for p in parents:
5257 # label with log.changeset (instead of log.parent) since this
5257 # label with log.changeset (instead of log.parent) since this
5258 # shows a working directory parent *changeset*:
5258 # shows a working directory parent *changeset*:
5259 # i18n: column positioning for "hg summary"
5259 # i18n: column positioning for "hg summary"
5260 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5260 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5261 label=logcmdutil.changesetlabels(p))
5261 label=logcmdutil.changesetlabels(p))
5262 ui.write(' '.join(p.tags()), label='log.tag')
5262 ui.write(' '.join(p.tags()), label='log.tag')
5263 if p.bookmarks():
5263 if p.bookmarks():
5264 marks.extend(p.bookmarks())
5264 marks.extend(p.bookmarks())
5265 if p.rev() == -1:
5265 if p.rev() == -1:
5266 if not len(repo):
5266 if not len(repo):
5267 ui.write(_(' (empty repository)'))
5267 ui.write(_(' (empty repository)'))
5268 else:
5268 else:
5269 ui.write(_(' (no revision checked out)'))
5269 ui.write(_(' (no revision checked out)'))
5270 if p.obsolete():
5270 if p.obsolete():
5271 ui.write(_(' (obsolete)'))
5271 ui.write(_(' (obsolete)'))
5272 if p.isunstable():
5272 if p.isunstable():
5273 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5273 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5274 for instability in p.instabilities())
5274 for instability in p.instabilities())
5275 ui.write(' ('
5275 ui.write(' ('
5276 + ', '.join(instabilities)
5276 + ', '.join(instabilities)
5277 + ')')
5277 + ')')
5278 ui.write('\n')
5278 ui.write('\n')
5279 if p.description():
5279 if p.description():
5280 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5280 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5281 label='log.summary')
5281 label='log.summary')
5282
5282
5283 branch = ctx.branch()
5283 branch = ctx.branch()
5284 bheads = repo.branchheads(branch)
5284 bheads = repo.branchheads(branch)
5285 # i18n: column positioning for "hg summary"
5285 # i18n: column positioning for "hg summary"
5286 m = _('branch: %s\n') % branch
5286 m = _('branch: %s\n') % branch
5287 if branch != 'default':
5287 if branch != 'default':
5288 ui.write(m, label='log.branch')
5288 ui.write(m, label='log.branch')
5289 else:
5289 else:
5290 ui.status(m, label='log.branch')
5290 ui.status(m, label='log.branch')
5291
5291
5292 if marks:
5292 if marks:
5293 active = repo._activebookmark
5293 active = repo._activebookmark
5294 # i18n: column positioning for "hg summary"
5294 # i18n: column positioning for "hg summary"
5295 ui.write(_('bookmarks:'), label='log.bookmark')
5295 ui.write(_('bookmarks:'), label='log.bookmark')
5296 if active is not None:
5296 if active is not None:
5297 if active in marks:
5297 if active in marks:
5298 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5298 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5299 marks.remove(active)
5299 marks.remove(active)
5300 else:
5300 else:
5301 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5301 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5302 for m in marks:
5302 for m in marks:
5303 ui.write(' ' + m, label='log.bookmark')
5303 ui.write(' ' + m, label='log.bookmark')
5304 ui.write('\n', label='log.bookmark')
5304 ui.write('\n', label='log.bookmark')
5305
5305
5306 status = repo.status(unknown=True)
5306 status = repo.status(unknown=True)
5307
5307
5308 c = repo.dirstate.copies()
5308 c = repo.dirstate.copies()
5309 copied, renamed = [], []
5309 copied, renamed = [], []
5310 for d, s in c.iteritems():
5310 for d, s in c.iteritems():
5311 if s in status.removed:
5311 if s in status.removed:
5312 status.removed.remove(s)
5312 status.removed.remove(s)
5313 renamed.append(d)
5313 renamed.append(d)
5314 else:
5314 else:
5315 copied.append(d)
5315 copied.append(d)
5316 if d in status.added:
5316 if d in status.added:
5317 status.added.remove(d)
5317 status.added.remove(d)
5318
5318
5319 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5319 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5320
5320
5321 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5321 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5322 (ui.label(_('%d added'), 'status.added'), status.added),
5322 (ui.label(_('%d added'), 'status.added'), status.added),
5323 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5323 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5324 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5324 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5325 (ui.label(_('%d copied'), 'status.copied'), copied),
5325 (ui.label(_('%d copied'), 'status.copied'), copied),
5326 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5326 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5327 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5327 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5328 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5328 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5329 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5329 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5330 t = []
5330 t = []
5331 for l, s in labels:
5331 for l, s in labels:
5332 if s:
5332 if s:
5333 t.append(l % len(s))
5333 t.append(l % len(s))
5334
5334
5335 t = ', '.join(t)
5335 t = ', '.join(t)
5336 cleanworkdir = False
5336 cleanworkdir = False
5337
5337
5338 if repo.vfs.exists('graftstate'):
5338 if repo.vfs.exists('graftstate'):
5339 t += _(' (graft in progress)')
5339 t += _(' (graft in progress)')
5340 if repo.vfs.exists('updatestate'):
5340 if repo.vfs.exists('updatestate'):
5341 t += _(' (interrupted update)')
5341 t += _(' (interrupted update)')
5342 elif len(parents) > 1:
5342 elif len(parents) > 1:
5343 t += _(' (merge)')
5343 t += _(' (merge)')
5344 elif branch != parents[0].branch():
5344 elif branch != parents[0].branch():
5345 t += _(' (new branch)')
5345 t += _(' (new branch)')
5346 elif (parents[0].closesbranch() and
5346 elif (parents[0].closesbranch() and
5347 pnode in repo.branchheads(branch, closed=True)):
5347 pnode in repo.branchheads(branch, closed=True)):
5348 t += _(' (head closed)')
5348 t += _(' (head closed)')
5349 elif not (status.modified or status.added or status.removed or renamed or
5349 elif not (status.modified or status.added or status.removed or renamed or
5350 copied or subs):
5350 copied or subs):
5351 t += _(' (clean)')
5351 t += _(' (clean)')
5352 cleanworkdir = True
5352 cleanworkdir = True
5353 elif pnode not in bheads:
5353 elif pnode not in bheads:
5354 t += _(' (new branch head)')
5354 t += _(' (new branch head)')
5355
5355
5356 if parents:
5356 if parents:
5357 pendingphase = max(p.phase() for p in parents)
5357 pendingphase = max(p.phase() for p in parents)
5358 else:
5358 else:
5359 pendingphase = phases.public
5359 pendingphase = phases.public
5360
5360
5361 if pendingphase > phases.newcommitphase(ui):
5361 if pendingphase > phases.newcommitphase(ui):
5362 t += ' (%s)' % phases.phasenames[pendingphase]
5362 t += ' (%s)' % phases.phasenames[pendingphase]
5363
5363
5364 if cleanworkdir:
5364 if cleanworkdir:
5365 # i18n: column positioning for "hg summary"
5365 # i18n: column positioning for "hg summary"
5366 ui.status(_('commit: %s\n') % t.strip())
5366 ui.status(_('commit: %s\n') % t.strip())
5367 else:
5367 else:
5368 # i18n: column positioning for "hg summary"
5368 # i18n: column positioning for "hg summary"
5369 ui.write(_('commit: %s\n') % t.strip())
5369 ui.write(_('commit: %s\n') % t.strip())
5370
5370
5371 # all ancestors of branch heads - all ancestors of parent = new csets
5371 # all ancestors of branch heads - all ancestors of parent = new csets
5372 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5372 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5373 bheads))
5373 bheads))
5374
5374
5375 if new == 0:
5375 if new == 0:
5376 # i18n: column positioning for "hg summary"
5376 # i18n: column positioning for "hg summary"
5377 ui.status(_('update: (current)\n'))
5377 ui.status(_('update: (current)\n'))
5378 elif pnode not in bheads:
5378 elif pnode not in bheads:
5379 # i18n: column positioning for "hg summary"
5379 # i18n: column positioning for "hg summary"
5380 ui.write(_('update: %d new changesets (update)\n') % new)
5380 ui.write(_('update: %d new changesets (update)\n') % new)
5381 else:
5381 else:
5382 # i18n: column positioning for "hg summary"
5382 # i18n: column positioning for "hg summary"
5383 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5383 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5384 (new, len(bheads)))
5384 (new, len(bheads)))
5385
5385
5386 t = []
5386 t = []
5387 draft = len(repo.revs('draft()'))
5387 draft = len(repo.revs('draft()'))
5388 if draft:
5388 if draft:
5389 t.append(_('%d draft') % draft)
5389 t.append(_('%d draft') % draft)
5390 secret = len(repo.revs('secret()'))
5390 secret = len(repo.revs('secret()'))
5391 if secret:
5391 if secret:
5392 t.append(_('%d secret') % secret)
5392 t.append(_('%d secret') % secret)
5393
5393
5394 if draft or secret:
5394 if draft or secret:
5395 ui.status(_('phases: %s\n') % ', '.join(t))
5395 ui.status(_('phases: %s\n') % ', '.join(t))
5396
5396
5397 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5397 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5398 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5398 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5399 numtrouble = len(repo.revs(trouble + "()"))
5399 numtrouble = len(repo.revs(trouble + "()"))
5400 # We write all the possibilities to ease translation
5400 # We write all the possibilities to ease translation
5401 troublemsg = {
5401 troublemsg = {
5402 "orphan": _("orphan: %d changesets"),
5402 "orphan": _("orphan: %d changesets"),
5403 "contentdivergent": _("content-divergent: %d changesets"),
5403 "contentdivergent": _("content-divergent: %d changesets"),
5404 "phasedivergent": _("phase-divergent: %d changesets"),
5404 "phasedivergent": _("phase-divergent: %d changesets"),
5405 }
5405 }
5406 if numtrouble > 0:
5406 if numtrouble > 0:
5407 ui.status(troublemsg[trouble] % numtrouble + "\n")
5407 ui.status(troublemsg[trouble] % numtrouble + "\n")
5408
5408
5409 cmdutil.summaryhooks(ui, repo)
5409 cmdutil.summaryhooks(ui, repo)
5410
5410
5411 if opts.get('remote'):
5411 if opts.get('remote'):
5412 needsincoming, needsoutgoing = True, True
5412 needsincoming, needsoutgoing = True, True
5413 else:
5413 else:
5414 needsincoming, needsoutgoing = False, False
5414 needsincoming, needsoutgoing = False, False
5415 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5415 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5416 if i:
5416 if i:
5417 needsincoming = True
5417 needsincoming = True
5418 if o:
5418 if o:
5419 needsoutgoing = True
5419 needsoutgoing = True
5420 if not needsincoming and not needsoutgoing:
5420 if not needsincoming and not needsoutgoing:
5421 return
5421 return
5422
5422
5423 def getincoming():
5423 def getincoming():
5424 source, branches = hg.parseurl(ui.expandpath('default'))
5424 source, branches = hg.parseurl(ui.expandpath('default'))
5425 sbranch = branches[0]
5425 sbranch = branches[0]
5426 try:
5426 try:
5427 other = hg.peer(repo, {}, source)
5427 other = hg.peer(repo, {}, source)
5428 except error.RepoError:
5428 except error.RepoError:
5429 if opts.get('remote'):
5429 if opts.get('remote'):
5430 raise
5430 raise
5431 return source, sbranch, None, None, None
5431 return source, sbranch, None, None, None
5432 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5432 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5433 if revs:
5433 if revs:
5434 revs = [other.lookup(rev) for rev in revs]
5434 revs = [other.lookup(rev) for rev in revs]
5435 ui.debug('comparing with %s\n' % util.hidepassword(source))
5435 ui.debug('comparing with %s\n' % util.hidepassword(source))
5436 repo.ui.pushbuffer()
5436 repo.ui.pushbuffer()
5437 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5437 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5438 repo.ui.popbuffer()
5438 repo.ui.popbuffer()
5439 return source, sbranch, other, commoninc, commoninc[1]
5439 return source, sbranch, other, commoninc, commoninc[1]
5440
5440
5441 if needsincoming:
5441 if needsincoming:
5442 source, sbranch, sother, commoninc, incoming = getincoming()
5442 source, sbranch, sother, commoninc, incoming = getincoming()
5443 else:
5443 else:
5444 source = sbranch = sother = commoninc = incoming = None
5444 source = sbranch = sother = commoninc = incoming = None
5445
5445
5446 def getoutgoing():
5446 def getoutgoing():
5447 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5447 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5448 dbranch = branches[0]
5448 dbranch = branches[0]
5449 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5449 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5450 if source != dest:
5450 if source != dest:
5451 try:
5451 try:
5452 dother = hg.peer(repo, {}, dest)
5452 dother = hg.peer(repo, {}, dest)
5453 except error.RepoError:
5453 except error.RepoError:
5454 if opts.get('remote'):
5454 if opts.get('remote'):
5455 raise
5455 raise
5456 return dest, dbranch, None, None
5456 return dest, dbranch, None, None
5457 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5457 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5458 elif sother is None:
5458 elif sother is None:
5459 # there is no explicit destination peer, but source one is invalid
5459 # there is no explicit destination peer, but source one is invalid
5460 return dest, dbranch, None, None
5460 return dest, dbranch, None, None
5461 else:
5461 else:
5462 dother = sother
5462 dother = sother
5463 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5463 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5464 common = None
5464 common = None
5465 else:
5465 else:
5466 common = commoninc
5466 common = commoninc
5467 if revs:
5467 if revs:
5468 revs = [repo.lookup(rev) for rev in revs]
5468 revs = [repo.lookup(rev) for rev in revs]
5469 repo.ui.pushbuffer()
5469 repo.ui.pushbuffer()
5470 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5470 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5471 commoninc=common)
5471 commoninc=common)
5472 repo.ui.popbuffer()
5472 repo.ui.popbuffer()
5473 return dest, dbranch, dother, outgoing
5473 return dest, dbranch, dother, outgoing
5474
5474
5475 if needsoutgoing:
5475 if needsoutgoing:
5476 dest, dbranch, dother, outgoing = getoutgoing()
5476 dest, dbranch, dother, outgoing = getoutgoing()
5477 else:
5477 else:
5478 dest = dbranch = dother = outgoing = None
5478 dest = dbranch = dother = outgoing = None
5479
5479
5480 if opts.get('remote'):
5480 if opts.get('remote'):
5481 t = []
5481 t = []
5482 if incoming:
5482 if incoming:
5483 t.append(_('1 or more incoming'))
5483 t.append(_('1 or more incoming'))
5484 o = outgoing.missing
5484 o = outgoing.missing
5485 if o:
5485 if o:
5486 t.append(_('%d outgoing') % len(o))
5486 t.append(_('%d outgoing') % len(o))
5487 other = dother or sother
5487 other = dother or sother
5488 if 'bookmarks' in other.listkeys('namespaces'):
5488 if 'bookmarks' in other.listkeys('namespaces'):
5489 counts = bookmarks.summary(repo, other)
5489 counts = bookmarks.summary(repo, other)
5490 if counts[0] > 0:
5490 if counts[0] > 0:
5491 t.append(_('%d incoming bookmarks') % counts[0])
5491 t.append(_('%d incoming bookmarks') % counts[0])
5492 if counts[1] > 0:
5492 if counts[1] > 0:
5493 t.append(_('%d outgoing bookmarks') % counts[1])
5493 t.append(_('%d outgoing bookmarks') % counts[1])
5494
5494
5495 if t:
5495 if t:
5496 # i18n: column positioning for "hg summary"
5496 # i18n: column positioning for "hg summary"
5497 ui.write(_('remote: %s\n') % (', '.join(t)))
5497 ui.write(_('remote: %s\n') % (', '.join(t)))
5498 else:
5498 else:
5499 # i18n: column positioning for "hg summary"
5499 # i18n: column positioning for "hg summary"
5500 ui.status(_('remote: (synced)\n'))
5500 ui.status(_('remote: (synced)\n'))
5501
5501
5502 cmdutil.summaryremotehooks(ui, repo, opts,
5502 cmdutil.summaryremotehooks(ui, repo, opts,
5503 ((source, sbranch, sother, commoninc),
5503 ((source, sbranch, sother, commoninc),
5504 (dest, dbranch, dother, outgoing)))
5504 (dest, dbranch, dother, outgoing)))
5505
5505
5506 @command('tag',
5506 @command('tag',
5507 [('f', 'force', None, _('force tag')),
5507 [('f', 'force', None, _('force tag')),
5508 ('l', 'local', None, _('make the tag local')),
5508 ('l', 'local', None, _('make the tag local')),
5509 ('r', 'rev', '', _('revision to tag'), _('REV')),
5509 ('r', 'rev', '', _('revision to tag'), _('REV')),
5510 ('', 'remove', None, _('remove a tag')),
5510 ('', 'remove', None, _('remove a tag')),
5511 # -l/--local is already there, commitopts cannot be used
5511 # -l/--local is already there, commitopts cannot be used
5512 ('e', 'edit', None, _('invoke editor on commit messages')),
5512 ('e', 'edit', None, _('invoke editor on commit messages')),
5513 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5513 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5514 ] + commitopts2,
5514 ] + commitopts2,
5515 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5515 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5516 def tag(ui, repo, name1, *names, **opts):
5516 def tag(ui, repo, name1, *names, **opts):
5517 """add one or more tags for the current or given revision
5517 """add one or more tags for the current or given revision
5518
5518
5519 Name a particular revision using <name>.
5519 Name a particular revision using <name>.
5520
5520
5521 Tags are used to name particular revisions of the repository and are
5521 Tags are used to name particular revisions of the repository and are
5522 very useful to compare different revisions, to go back to significant
5522 very useful to compare different revisions, to go back to significant
5523 earlier versions or to mark branch points as releases, etc. Changing
5523 earlier versions or to mark branch points as releases, etc. Changing
5524 an existing tag is normally disallowed; use -f/--force to override.
5524 an existing tag is normally disallowed; use -f/--force to override.
5525
5525
5526 If no revision is given, the parent of the working directory is
5526 If no revision is given, the parent of the working directory is
5527 used.
5527 used.
5528
5528
5529 To facilitate version control, distribution, and merging of tags,
5529 To facilitate version control, distribution, and merging of tags,
5530 they are stored as a file named ".hgtags" which is managed similarly
5530 they are stored as a file named ".hgtags" which is managed similarly
5531 to other project files and can be hand-edited if necessary. This
5531 to other project files and can be hand-edited if necessary. This
5532 also means that tagging creates a new commit. The file
5532 also means that tagging creates a new commit. The file
5533 ".hg/localtags" is used for local tags (not shared among
5533 ".hg/localtags" is used for local tags (not shared among
5534 repositories).
5534 repositories).
5535
5535
5536 Tag commits are usually made at the head of a branch. If the parent
5536 Tag commits are usually made at the head of a branch. If the parent
5537 of the working directory is not a branch head, :hg:`tag` aborts; use
5537 of the working directory is not a branch head, :hg:`tag` aborts; use
5538 -f/--force to force the tag commit to be based on a non-head
5538 -f/--force to force the tag commit to be based on a non-head
5539 changeset.
5539 changeset.
5540
5540
5541 See :hg:`help dates` for a list of formats valid for -d/--date.
5541 See :hg:`help dates` for a list of formats valid for -d/--date.
5542
5542
5543 Since tag names have priority over branch names during revision
5543 Since tag names have priority over branch names during revision
5544 lookup, using an existing branch name as a tag name is discouraged.
5544 lookup, using an existing branch name as a tag name is discouraged.
5545
5545
5546 Returns 0 on success.
5546 Returns 0 on success.
5547 """
5547 """
5548 opts = pycompat.byteskwargs(opts)
5548 opts = pycompat.byteskwargs(opts)
5549 with repo.wlock(), repo.lock():
5549 with repo.wlock(), repo.lock():
5550 rev_ = "."
5550 rev_ = "."
5551 names = [t.strip() for t in (name1,) + names]
5551 names = [t.strip() for t in (name1,) + names]
5552 if len(names) != len(set(names)):
5552 if len(names) != len(set(names)):
5553 raise error.Abort(_('tag names must be unique'))
5553 raise error.Abort(_('tag names must be unique'))
5554 for n in names:
5554 for n in names:
5555 scmutil.checknewlabel(repo, n, 'tag')
5555 scmutil.checknewlabel(repo, n, 'tag')
5556 if not n:
5556 if not n:
5557 raise error.Abort(_('tag names cannot consist entirely of '
5557 raise error.Abort(_('tag names cannot consist entirely of '
5558 'whitespace'))
5558 'whitespace'))
5559 if opts.get('rev') and opts.get('remove'):
5559 if opts.get('rev') and opts.get('remove'):
5560 raise error.Abort(_("--rev and --remove are incompatible"))
5560 raise error.Abort(_("--rev and --remove are incompatible"))
5561 if opts.get('rev'):
5561 if opts.get('rev'):
5562 rev_ = opts['rev']
5562 rev_ = opts['rev']
5563 message = opts.get('message')
5563 message = opts.get('message')
5564 if opts.get('remove'):
5564 if opts.get('remove'):
5565 if opts.get('local'):
5565 if opts.get('local'):
5566 expectedtype = 'local'
5566 expectedtype = 'local'
5567 else:
5567 else:
5568 expectedtype = 'global'
5568 expectedtype = 'global'
5569
5569
5570 for n in names:
5570 for n in names:
5571 if not repo.tagtype(n):
5571 if not repo.tagtype(n):
5572 raise error.Abort(_("tag '%s' does not exist") % n)
5572 raise error.Abort(_("tag '%s' does not exist") % n)
5573 if repo.tagtype(n) != expectedtype:
5573 if repo.tagtype(n) != expectedtype:
5574 if expectedtype == 'global':
5574 if expectedtype == 'global':
5575 raise error.Abort(_("tag '%s' is not a global tag") % n)
5575 raise error.Abort(_("tag '%s' is not a global tag") % n)
5576 else:
5576 else:
5577 raise error.Abort(_("tag '%s' is not a local tag") % n)
5577 raise error.Abort(_("tag '%s' is not a local tag") % n)
5578 rev_ = 'null'
5578 rev_ = 'null'
5579 if not message:
5579 if not message:
5580 # we don't translate commit messages
5580 # we don't translate commit messages
5581 message = 'Removed tag %s' % ', '.join(names)
5581 message = 'Removed tag %s' % ', '.join(names)
5582 elif not opts.get('force'):
5582 elif not opts.get('force'):
5583 for n in names:
5583 for n in names:
5584 if n in repo.tags():
5584 if n in repo.tags():
5585 raise error.Abort(_("tag '%s' already exists "
5585 raise error.Abort(_("tag '%s' already exists "
5586 "(use -f to force)") % n)
5586 "(use -f to force)") % n)
5587 if not opts.get('local'):
5587 if not opts.get('local'):
5588 p1, p2 = repo.dirstate.parents()
5588 p1, p2 = repo.dirstate.parents()
5589 if p2 != nullid:
5589 if p2 != nullid:
5590 raise error.Abort(_('uncommitted merge'))
5590 raise error.Abort(_('uncommitted merge'))
5591 bheads = repo.branchheads()
5591 bheads = repo.branchheads()
5592 if not opts.get('force') and bheads and p1 not in bheads:
5592 if not opts.get('force') and bheads and p1 not in bheads:
5593 raise error.Abort(_('working directory is not at a branch head '
5593 raise error.Abort(_('working directory is not at a branch head '
5594 '(use -f to force)'))
5594 '(use -f to force)'))
5595 node = scmutil.revsingle(repo, rev_).node()
5595 node = scmutil.revsingle(repo, rev_).node()
5596
5596
5597 if not message:
5597 if not message:
5598 # we don't translate commit messages
5598 # we don't translate commit messages
5599 message = ('Added tag %s for changeset %s' %
5599 message = ('Added tag %s for changeset %s' %
5600 (', '.join(names), short(node)))
5600 (', '.join(names), short(node)))
5601
5601
5602 date = opts.get('date')
5602 date = opts.get('date')
5603 if date:
5603 if date:
5604 date = dateutil.parsedate(date)
5604 date = dateutil.parsedate(date)
5605
5605
5606 if opts.get('remove'):
5606 if opts.get('remove'):
5607 editform = 'tag.remove'
5607 editform = 'tag.remove'
5608 else:
5608 else:
5609 editform = 'tag.add'
5609 editform = 'tag.add'
5610 editor = cmdutil.getcommiteditor(editform=editform,
5610 editor = cmdutil.getcommiteditor(editform=editform,
5611 **pycompat.strkwargs(opts))
5611 **pycompat.strkwargs(opts))
5612
5612
5613 # don't allow tagging the null rev
5613 # don't allow tagging the null rev
5614 if (not opts.get('remove') and
5614 if (not opts.get('remove') and
5615 scmutil.revsingle(repo, rev_).rev() == nullrev):
5615 scmutil.revsingle(repo, rev_).rev() == nullrev):
5616 raise error.Abort(_("cannot tag null revision"))
5616 raise error.Abort(_("cannot tag null revision"))
5617
5617
5618 tagsmod.tag(repo, names, node, message, opts.get('local'),
5618 tagsmod.tag(repo, names, node, message, opts.get('local'),
5619 opts.get('user'), date, editor=editor)
5619 opts.get('user'), date, editor=editor)
5620
5620
5621 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5621 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5622 def tags(ui, repo, **opts):
5622 def tags(ui, repo, **opts):
5623 """list repository tags
5623 """list repository tags
5624
5624
5625 This lists both regular and local tags. When the -v/--verbose
5625 This lists both regular and local tags. When the -v/--verbose
5626 switch is used, a third column "local" is printed for local tags.
5626 switch is used, a third column "local" is printed for local tags.
5627 When the -q/--quiet switch is used, only the tag name is printed.
5627 When the -q/--quiet switch is used, only the tag name is printed.
5628
5628
5629 Returns 0 on success.
5629 Returns 0 on success.
5630 """
5630 """
5631
5631
5632 opts = pycompat.byteskwargs(opts)
5632 opts = pycompat.byteskwargs(opts)
5633 ui.pager('tags')
5633 ui.pager('tags')
5634 fm = ui.formatter('tags', opts)
5634 fm = ui.formatter('tags', opts)
5635 hexfunc = fm.hexfunc
5635 hexfunc = fm.hexfunc
5636 tagtype = ""
5636 tagtype = ""
5637
5637
5638 for t, n in reversed(repo.tagslist()):
5638 for t, n in reversed(repo.tagslist()):
5639 hn = hexfunc(n)
5639 hn = hexfunc(n)
5640 label = 'tags.normal'
5640 label = 'tags.normal'
5641 tagtype = ''
5641 tagtype = ''
5642 if repo.tagtype(t) == 'local':
5642 if repo.tagtype(t) == 'local':
5643 label = 'tags.local'
5643 label = 'tags.local'
5644 tagtype = 'local'
5644 tagtype = 'local'
5645
5645
5646 fm.startitem()
5646 fm.startitem()
5647 fm.context(repo=repo)
5647 fm.context(repo=repo)
5648 fm.write('tag', '%s', t, label=label)
5648 fm.write('tag', '%s', t, label=label)
5649 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5649 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5650 fm.condwrite(not ui.quiet, 'rev node', fmt,
5650 fm.condwrite(not ui.quiet, 'rev node', fmt,
5651 repo.changelog.rev(n), hn, label=label)
5651 repo.changelog.rev(n), hn, label=label)
5652 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5652 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5653 tagtype, label=label)
5653 tagtype, label=label)
5654 fm.plain('\n')
5654 fm.plain('\n')
5655 fm.end()
5655 fm.end()
5656
5656
5657 @command('tip',
5657 @command('tip',
5658 [('p', 'patch', None, _('show patch')),
5658 [('p', 'patch', None, _('show patch')),
5659 ('g', 'git', None, _('use git extended diff format')),
5659 ('g', 'git', None, _('use git extended diff format')),
5660 ] + templateopts,
5660 ] + templateopts,
5661 _('[-p] [-g]'))
5661 _('[-p] [-g]'))
5662 def tip(ui, repo, **opts):
5662 def tip(ui, repo, **opts):
5663 """show the tip revision (DEPRECATED)
5663 """show the tip revision (DEPRECATED)
5664
5664
5665 The tip revision (usually just called the tip) is the changeset
5665 The tip revision (usually just called the tip) is the changeset
5666 most recently added to the repository (and therefore the most
5666 most recently added to the repository (and therefore the most
5667 recently changed head).
5667 recently changed head).
5668
5668
5669 If you have just made a commit, that commit will be the tip. If
5669 If you have just made a commit, that commit will be the tip. If
5670 you have just pulled changes from another repository, the tip of
5670 you have just pulled changes from another repository, the tip of
5671 that repository becomes the current tip. The "tip" tag is special
5671 that repository becomes the current tip. The "tip" tag is special
5672 and cannot be renamed or assigned to a different changeset.
5672 and cannot be renamed or assigned to a different changeset.
5673
5673
5674 This command is deprecated, please use :hg:`heads` instead.
5674 This command is deprecated, please use :hg:`heads` instead.
5675
5675
5676 Returns 0 on success.
5676 Returns 0 on success.
5677 """
5677 """
5678 opts = pycompat.byteskwargs(opts)
5678 opts = pycompat.byteskwargs(opts)
5679 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5679 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5680 displayer.show(repo['tip'])
5680 displayer.show(repo['tip'])
5681 displayer.close()
5681 displayer.close()
5682
5682
5683 @command('unbundle',
5683 @command('unbundle',
5684 [('u', 'update', None,
5684 [('u', 'update', None,
5685 _('update to new branch head if changesets were unbundled'))],
5685 _('update to new branch head if changesets were unbundled'))],
5686 _('[-u] FILE...'))
5686 _('[-u] FILE...'))
5687 def unbundle(ui, repo, fname1, *fnames, **opts):
5687 def unbundle(ui, repo, fname1, *fnames, **opts):
5688 """apply one or more bundle files
5688 """apply one or more bundle files
5689
5689
5690 Apply one or more bundle files generated by :hg:`bundle`.
5690 Apply one or more bundle files generated by :hg:`bundle`.
5691
5691
5692 Returns 0 on success, 1 if an update has unresolved files.
5692 Returns 0 on success, 1 if an update has unresolved files.
5693 """
5693 """
5694 fnames = (fname1,) + fnames
5694 fnames = (fname1,) + fnames
5695
5695
5696 with repo.lock():
5696 with repo.lock():
5697 for fname in fnames:
5697 for fname in fnames:
5698 f = hg.openpath(ui, fname)
5698 f = hg.openpath(ui, fname)
5699 gen = exchange.readbundle(ui, f, fname)
5699 gen = exchange.readbundle(ui, f, fname)
5700 if isinstance(gen, streamclone.streamcloneapplier):
5700 if isinstance(gen, streamclone.streamcloneapplier):
5701 raise error.Abort(
5701 raise error.Abort(
5702 _('packed bundles cannot be applied with '
5702 _('packed bundles cannot be applied with '
5703 '"hg unbundle"'),
5703 '"hg unbundle"'),
5704 hint=_('use "hg debugapplystreamclonebundle"'))
5704 hint=_('use "hg debugapplystreamclonebundle"'))
5705 url = 'bundle:' + fname
5705 url = 'bundle:' + fname
5706 try:
5706 try:
5707 txnname = 'unbundle'
5707 txnname = 'unbundle'
5708 if not isinstance(gen, bundle2.unbundle20):
5708 if not isinstance(gen, bundle2.unbundle20):
5709 txnname = 'unbundle\n%s' % util.hidepassword(url)
5709 txnname = 'unbundle\n%s' % util.hidepassword(url)
5710 with repo.transaction(txnname) as tr:
5710 with repo.transaction(txnname) as tr:
5711 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5711 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5712 url=url)
5712 url=url)
5713 except error.BundleUnknownFeatureError as exc:
5713 except error.BundleUnknownFeatureError as exc:
5714 raise error.Abort(
5714 raise error.Abort(
5715 _('%s: unknown bundle feature, %s') % (fname, exc),
5715 _('%s: unknown bundle feature, %s') % (fname, exc),
5716 hint=_("see https://mercurial-scm.org/"
5716 hint=_("see https://mercurial-scm.org/"
5717 "wiki/BundleFeature for more "
5717 "wiki/BundleFeature for more "
5718 "information"))
5718 "information"))
5719 modheads = bundle2.combinechangegroupresults(op)
5719 modheads = bundle2.combinechangegroupresults(op)
5720
5720
5721 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5721 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5722
5722
5723 @command('^update|up|checkout|co',
5723 @command('^update|up|checkout|co',
5724 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5724 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5725 ('c', 'check', None, _('require clean working directory')),
5725 ('c', 'check', None, _('require clean working directory')),
5726 ('m', 'merge', None, _('merge uncommitted changes')),
5726 ('m', 'merge', None, _('merge uncommitted changes')),
5727 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5727 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5728 ('r', 'rev', '', _('revision'), _('REV'))
5728 ('r', 'rev', '', _('revision'), _('REV'))
5729 ] + mergetoolopts,
5729 ] + mergetoolopts,
5730 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5730 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5731 def update(ui, repo, node=None, **opts):
5731 def update(ui, repo, node=None, **opts):
5732 """update working directory (or switch revisions)
5732 """update working directory (or switch revisions)
5733
5733
5734 Update the repository's working directory to the specified
5734 Update the repository's working directory to the specified
5735 changeset. If no changeset is specified, update to the tip of the
5735 changeset. If no changeset is specified, update to the tip of the
5736 current named branch and move the active bookmark (see :hg:`help
5736 current named branch and move the active bookmark (see :hg:`help
5737 bookmarks`).
5737 bookmarks`).
5738
5738
5739 Update sets the working directory's parent revision to the specified
5739 Update sets the working directory's parent revision to the specified
5740 changeset (see :hg:`help parents`).
5740 changeset (see :hg:`help parents`).
5741
5741
5742 If the changeset is not a descendant or ancestor of the working
5742 If the changeset is not a descendant or ancestor of the working
5743 directory's parent and there are uncommitted changes, the update is
5743 directory's parent and there are uncommitted changes, the update is
5744 aborted. With the -c/--check option, the working directory is checked
5744 aborted. With the -c/--check option, the working directory is checked
5745 for uncommitted changes; if none are found, the working directory is
5745 for uncommitted changes; if none are found, the working directory is
5746 updated to the specified changeset.
5746 updated to the specified changeset.
5747
5747
5748 .. container:: verbose
5748 .. container:: verbose
5749
5749
5750 The -C/--clean, -c/--check, and -m/--merge options control what
5750 The -C/--clean, -c/--check, and -m/--merge options control what
5751 happens if the working directory contains uncommitted changes.
5751 happens if the working directory contains uncommitted changes.
5752 At most of one of them can be specified.
5752 At most of one of them can be specified.
5753
5753
5754 1. If no option is specified, and if
5754 1. If no option is specified, and if
5755 the requested changeset is an ancestor or descendant of
5755 the requested changeset is an ancestor or descendant of
5756 the working directory's parent, the uncommitted changes
5756 the working directory's parent, the uncommitted changes
5757 are merged into the requested changeset and the merged
5757 are merged into the requested changeset and the merged
5758 result is left uncommitted. If the requested changeset is
5758 result is left uncommitted. If the requested changeset is
5759 not an ancestor or descendant (that is, it is on another
5759 not an ancestor or descendant (that is, it is on another
5760 branch), the update is aborted and the uncommitted changes
5760 branch), the update is aborted and the uncommitted changes
5761 are preserved.
5761 are preserved.
5762
5762
5763 2. With the -m/--merge option, the update is allowed even if the
5763 2. With the -m/--merge option, the update is allowed even if the
5764 requested changeset is not an ancestor or descendant of
5764 requested changeset is not an ancestor or descendant of
5765 the working directory's parent.
5765 the working directory's parent.
5766
5766
5767 3. With the -c/--check option, the update is aborted and the
5767 3. With the -c/--check option, the update is aborted and the
5768 uncommitted changes are preserved.
5768 uncommitted changes are preserved.
5769
5769
5770 4. With the -C/--clean option, uncommitted changes are discarded and
5770 4. With the -C/--clean option, uncommitted changes are discarded and
5771 the working directory is updated to the requested changeset.
5771 the working directory is updated to the requested changeset.
5772
5772
5773 To cancel an uncommitted merge (and lose your changes), use
5773 To cancel an uncommitted merge (and lose your changes), use
5774 :hg:`merge --abort`.
5774 :hg:`merge --abort`.
5775
5775
5776 Use null as the changeset to remove the working directory (like
5776 Use null as the changeset to remove the working directory (like
5777 :hg:`clone -U`).
5777 :hg:`clone -U`).
5778
5778
5779 If you want to revert just one file to an older revision, use
5779 If you want to revert just one file to an older revision, use
5780 :hg:`revert [-r REV] NAME`.
5780 :hg:`revert [-r REV] NAME`.
5781
5781
5782 See :hg:`help dates` for a list of formats valid for -d/--date.
5782 See :hg:`help dates` for a list of formats valid for -d/--date.
5783
5783
5784 Returns 0 on success, 1 if there are unresolved files.
5784 Returns 0 on success, 1 if there are unresolved files.
5785 """
5785 """
5786 rev = opts.get(r'rev')
5786 rev = opts.get(r'rev')
5787 date = opts.get(r'date')
5787 date = opts.get(r'date')
5788 clean = opts.get(r'clean')
5788 clean = opts.get(r'clean')
5789 check = opts.get(r'check')
5789 check = opts.get(r'check')
5790 merge = opts.get(r'merge')
5790 merge = opts.get(r'merge')
5791 if rev and node:
5791 if rev and node:
5792 raise error.Abort(_("please specify just one revision"))
5792 raise error.Abort(_("please specify just one revision"))
5793
5793
5794 if ui.configbool('commands', 'update.requiredest'):
5794 if ui.configbool('commands', 'update.requiredest'):
5795 if not node and not rev and not date:
5795 if not node and not rev and not date:
5796 raise error.Abort(_('you must specify a destination'),
5796 raise error.Abort(_('you must specify a destination'),
5797 hint=_('for example: hg update ".::"'))
5797 hint=_('for example: hg update ".::"'))
5798
5798
5799 if rev is None or rev == '':
5799 if rev is None or rev == '':
5800 rev = node
5800 rev = node
5801
5801
5802 if date and rev is not None:
5802 if date and rev is not None:
5803 raise error.Abort(_("you can't specify a revision and a date"))
5803 raise error.Abort(_("you can't specify a revision and a date"))
5804
5804
5805 if len([x for x in (clean, check, merge) if x]) > 1:
5805 if len([x for x in (clean, check, merge) if x]) > 1:
5806 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5806 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5807 "or -m/--merge"))
5807 "or -m/--merge"))
5808
5808
5809 updatecheck = None
5809 updatecheck = None
5810 if check:
5810 if check:
5811 updatecheck = 'abort'
5811 updatecheck = 'abort'
5812 elif merge:
5812 elif merge:
5813 updatecheck = 'none'
5813 updatecheck = 'none'
5814
5814
5815 with repo.wlock():
5815 with repo.wlock():
5816 cmdutil.clearunfinished(repo)
5816 cmdutil.clearunfinished(repo)
5817
5817
5818 if date:
5818 if date:
5819 rev = cmdutil.finddate(ui, repo, date)
5819 rev = cmdutil.finddate(ui, repo, date)
5820
5820
5821 # if we defined a bookmark, we have to remember the original name
5821 # if we defined a bookmark, we have to remember the original name
5822 brev = rev
5822 brev = rev
5823 if rev:
5823 if rev:
5824 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5824 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5825 ctx = scmutil.revsingle(repo, rev, rev)
5825 ctx = scmutil.revsingle(repo, rev, rev)
5826 rev = ctx.rev()
5826 rev = ctx.rev()
5827 hidden = ctx.hidden()
5827 hidden = ctx.hidden()
5828 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
5828 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
5829 with ui.configoverride(overrides, 'update'):
5829 with ui.configoverride(overrides, 'update'):
5830 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
5830 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
5831 updatecheck=updatecheck)
5831 updatecheck=updatecheck)
5832 if hidden:
5832 if hidden:
5833 ctxstr = ctx.hex()[:12]
5833 ctxstr = ctx.hex()[:12]
5834 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
5834 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
5835
5835
5836 if ctx.obsolete():
5836 if ctx.obsolete():
5837 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5837 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5838 ui.warn("(%s)\n" % obsfatemsg)
5838 ui.warn("(%s)\n" % obsfatemsg)
5839 return ret
5839 return ret
5840
5840
5841 @command('verify', [])
5841 @command('verify', [])
5842 def verify(ui, repo):
5842 def verify(ui, repo):
5843 """verify the integrity of the repository
5843 """verify the integrity of the repository
5844
5844
5845 Verify the integrity of the current repository.
5845 Verify the integrity of the current repository.
5846
5846
5847 This will perform an extensive check of the repository's
5847 This will perform an extensive check of the repository's
5848 integrity, validating the hashes and checksums of each entry in
5848 integrity, validating the hashes and checksums of each entry in
5849 the changelog, manifest, and tracked files, as well as the
5849 the changelog, manifest, and tracked files, as well as the
5850 integrity of their crosslinks and indices.
5850 integrity of their crosslinks and indices.
5851
5851
5852 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5852 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5853 for more information about recovery from corruption of the
5853 for more information about recovery from corruption of the
5854 repository.
5854 repository.
5855
5855
5856 Returns 0 on success, 1 if errors are encountered.
5856 Returns 0 on success, 1 if errors are encountered.
5857 """
5857 """
5858 return hg.verify(repo)
5858 return hg.verify(repo)
5859
5859
5860 @command('version', [] + formatteropts, norepo=True,
5860 @command('version', [] + formatteropts, norepo=True,
5861 intents={INTENT_READONLY})
5861 intents={INTENT_READONLY})
5862 def version_(ui, **opts):
5862 def version_(ui, **opts):
5863 """output version and copyright information"""
5863 """output version and copyright information"""
5864 opts = pycompat.byteskwargs(opts)
5864 opts = pycompat.byteskwargs(opts)
5865 if ui.verbose:
5865 if ui.verbose:
5866 ui.pager('version')
5866 ui.pager('version')
5867 fm = ui.formatter("version", opts)
5867 fm = ui.formatter("version", opts)
5868 fm.startitem()
5868 fm.startitem()
5869 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5869 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5870 util.version())
5870 util.version())
5871 license = _(
5871 license = _(
5872 "(see https://mercurial-scm.org for more information)\n"
5872 "(see https://mercurial-scm.org for more information)\n"
5873 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5873 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5874 "This is free software; see the source for copying conditions. "
5874 "This is free software; see the source for copying conditions. "
5875 "There is NO\nwarranty; "
5875 "There is NO\nwarranty; "
5876 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5876 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5877 )
5877 )
5878 if not ui.quiet:
5878 if not ui.quiet:
5879 fm.plain(license)
5879 fm.plain(license)
5880
5880
5881 if ui.verbose:
5881 if ui.verbose:
5882 fm.plain(_("\nEnabled extensions:\n\n"))
5882 fm.plain(_("\nEnabled extensions:\n\n"))
5883 # format names and versions into columns
5883 # format names and versions into columns
5884 names = []
5884 names = []
5885 vers = []
5885 vers = []
5886 isinternals = []
5886 isinternals = []
5887 for name, module in extensions.extensions():
5887 for name, module in extensions.extensions():
5888 names.append(name)
5888 names.append(name)
5889 vers.append(extensions.moduleversion(module) or None)
5889 vers.append(extensions.moduleversion(module) or None)
5890 isinternals.append(extensions.ismoduleinternal(module))
5890 isinternals.append(extensions.ismoduleinternal(module))
5891 fn = fm.nested("extensions", tmpl='{name}\n')
5891 fn = fm.nested("extensions", tmpl='{name}\n')
5892 if names:
5892 if names:
5893 namefmt = " %%-%ds " % max(len(n) for n in names)
5893 namefmt = " %%-%ds " % max(len(n) for n in names)
5894 places = [_("external"), _("internal")]
5894 places = [_("external"), _("internal")]
5895 for n, v, p in zip(names, vers, isinternals):
5895 for n, v, p in zip(names, vers, isinternals):
5896 fn.startitem()
5896 fn.startitem()
5897 fn.condwrite(ui.verbose, "name", namefmt, n)
5897 fn.condwrite(ui.verbose, "name", namefmt, n)
5898 if ui.verbose:
5898 if ui.verbose:
5899 fn.plain("%s " % places[p])
5899 fn.plain("%s " % places[p])
5900 fn.data(bundled=p)
5900 fn.data(bundled=p)
5901 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5901 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5902 if ui.verbose:
5902 if ui.verbose:
5903 fn.plain("\n")
5903 fn.plain("\n")
5904 fn.end()
5904 fn.end()
5905 fm.end()
5905 fm.end()
5906
5906
5907 def loadcmdtable(ui, name, cmdtable):
5907 def loadcmdtable(ui, name, cmdtable):
5908 """Load command functions from specified cmdtable
5908 """Load command functions from specified cmdtable
5909 """
5909 """
5910 overrides = [cmd for cmd in cmdtable if cmd in table]
5910 overrides = [cmd for cmd in cmdtable if cmd in table]
5911 if overrides:
5911 if overrides:
5912 ui.warn(_("extension '%s' overrides commands: %s\n")
5912 ui.warn(_("extension '%s' overrides commands: %s\n")
5913 % (name, " ".join(overrides)))
5913 % (name, " ".join(overrides)))
5914 table.update(cmdtable)
5914 table.update(cmdtable)
@@ -1,616 +1,616 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 "path": "file1",
159 "mergestatus": "R",
160 "status": "R"
160 "path": "file1"
161 },
161 },
162 {
162 {
163 "path": "file2",
163 "mergestatus": "U",
164 "status": "U"
164 "path": "file2"
165 }
165 }
166 ]
166 ]
167
167
168 $ hg resolve -l -T '{path} {status} {p1rev} {p2rev}\n'
168 $ hg resolve -l -T '{path} {mergestatus} {status} {p1rev} {p2rev}\n'
169 file1 R 2 1
169 file1 R M 2 1
170 file2 U 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 Testing the --re-merge flag
448 Testing the --re-merge flag
449 $ hg resolve --unmark file1
449 $ hg resolve --unmark file1
450 $ hg resolve -l
450 $ hg resolve -l
451 U file1
451 U file1
452 R file2
452 R file2
453 $ hg resolve --mark --re-merge
453 $ hg resolve --mark --re-merge
454 abort: too many actions specified
454 abort: too many actions specified
455 [255]
455 [255]
456 $ hg resolve --re-merge --all
456 $ hg resolve --re-merge --all
457 merging file1
457 merging file1
458 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
458 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
459 [1]
459 [1]
460 Explicit re-merge
460 Explicit re-merge
461 $ hg resolve --unmark file1
461 $ hg resolve --unmark file1
462 $ hg resolve --config commands.resolve.explicit-re-merge=1 --all
462 $ hg resolve --config commands.resolve.explicit-re-merge=1 --all
463 abort: no action specified
463 abort: no action specified
464 (use --mark, --unmark, --list or --re-merge)
464 (use --mark, --unmark, --list or --re-merge)
465 [255]
465 [255]
466 $ hg resolve --config commands.resolve.explicit-re-merge=1 --re-merge --all
466 $ hg resolve --config commands.resolve.explicit-re-merge=1 --re-merge --all
467 merging file1
467 merging file1
468 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
468 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
469 [1]
469 [1]
470
470
471 $ cd ..
471 $ cd ..
472
472
473 ======================================================
473 ======================================================
474 Test 'hg resolve' confirm config option functionality |
474 Test 'hg resolve' confirm config option functionality |
475 ======================================================
475 ======================================================
476 $ cat >> $HGRCPATH << EOF
476 $ cat >> $HGRCPATH << EOF
477 > [extensions]
477 > [extensions]
478 > rebase=
478 > rebase=
479 > EOF
479 > EOF
480
480
481 $ hg init repo2
481 $ hg init repo2
482 $ cd repo2
482 $ cd repo2
483
483
484 $ echo boss > boss
484 $ echo boss > boss
485 $ hg ci -Am "add boss"
485 $ hg ci -Am "add boss"
486 adding boss
486 adding boss
487
487
488 $ for emp in emp1 emp2 emp3; do echo work > $emp; done;
488 $ for emp in emp1 emp2 emp3; do echo work > $emp; done;
489 $ hg ci -Aqm "added emp1 emp2 emp3"
489 $ hg ci -Aqm "added emp1 emp2 emp3"
490
490
491 $ hg up 0
491 $ hg up 0
492 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
492 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
493
493
494 $ for emp in emp1 emp2 emp3; do echo nowork > $emp; done;
494 $ for emp in emp1 emp2 emp3; do echo nowork > $emp; done;
495 $ hg ci -Aqm "added lazy emp1 emp2 emp3"
495 $ hg ci -Aqm "added lazy emp1 emp2 emp3"
496
496
497 $ hg log -GT "{rev} {node|short} {firstline(desc)}\n"
497 $ hg log -GT "{rev} {node|short} {firstline(desc)}\n"
498 @ 2 0acfd4a49af0 added lazy emp1 emp2 emp3
498 @ 2 0acfd4a49af0 added lazy emp1 emp2 emp3
499 |
499 |
500 | o 1 f30f98a8181f added emp1 emp2 emp3
500 | o 1 f30f98a8181f added emp1 emp2 emp3
501 |/
501 |/
502 o 0 88660038d466 add boss
502 o 0 88660038d466 add boss
503
503
504 $ hg rebase -s 1 -d 2
504 $ hg rebase -s 1 -d 2
505 rebasing 1:f30f98a8181f "added emp1 emp2 emp3"
505 rebasing 1:f30f98a8181f "added emp1 emp2 emp3"
506 merging emp1
506 merging emp1
507 merging emp2
507 merging emp2
508 merging emp3
508 merging emp3
509 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
509 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
510 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
510 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
511 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
511 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
512 unresolved conflicts (see hg resolve, then hg rebase --continue)
512 unresolved conflicts (see hg resolve, then hg rebase --continue)
513 [1]
513 [1]
514
514
515 Test when commands.resolve.confirm config option is not set:
515 Test when commands.resolve.confirm config option is not set:
516 ===========================================================
516 ===========================================================
517 $ hg resolve --all
517 $ hg resolve --all
518 merging emp1
518 merging emp1
519 merging emp2
519 merging emp2
520 merging emp3
520 merging emp3
521 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
521 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
522 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
522 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
523 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
523 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
524 [1]
524 [1]
525
525
526 Test when config option is set:
526 Test when config option is set:
527 ==============================
527 ==============================
528 $ cat >> $HGRCPATH << EOF
528 $ cat >> $HGRCPATH << EOF
529 > [ui]
529 > [ui]
530 > interactive = True
530 > interactive = True
531 > [commands]
531 > [commands]
532 > resolve.confirm = True
532 > resolve.confirm = True
533 > EOF
533 > EOF
534
534
535 $ hg resolve
535 $ hg resolve
536 abort: no files or directories specified
536 abort: no files or directories specified
537 (use --all to re-merge all unresolved files)
537 (use --all to re-merge all unresolved files)
538 [255]
538 [255]
539 $ hg resolve --all << EOF
539 $ hg resolve --all << EOF
540 > n
540 > n
541 > EOF
541 > EOF
542 re-merge all unresolved files (yn)? n
542 re-merge all unresolved files (yn)? n
543 abort: user quit
543 abort: user quit
544 [255]
544 [255]
545
545
546 $ hg resolve --all << EOF
546 $ hg resolve --all << EOF
547 > y
547 > y
548 > EOF
548 > EOF
549 re-merge all unresolved files (yn)? y
549 re-merge all unresolved files (yn)? y
550 merging emp1
550 merging emp1
551 merging emp2
551 merging emp2
552 merging emp3
552 merging emp3
553 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
553 warning: conflicts while merging emp1! (edit, then use 'hg resolve --mark')
554 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
554 warning: conflicts while merging emp2! (edit, then use 'hg resolve --mark')
555 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
555 warning: conflicts while merging emp3! (edit, then use 'hg resolve --mark')
556 [1]
556 [1]
557
557
558 Test that commands.resolve.confirm respect --mark option (only when no patterns args are given):
558 Test that commands.resolve.confirm respect --mark option (only when no patterns args are given):
559 ===============================================================================================
559 ===============================================================================================
560
560
561 $ hg resolve -m emp1
561 $ hg resolve -m emp1
562 $ hg resolve -l
562 $ hg resolve -l
563 R emp1
563 R emp1
564 U emp2
564 U emp2
565 U emp3
565 U emp3
566
566
567 $ hg resolve -m << EOF
567 $ hg resolve -m << EOF
568 > n
568 > n
569 > EOF
569 > EOF
570 mark all unresolved files as resolved (yn)? n
570 mark all unresolved files as resolved (yn)? n
571 abort: user quit
571 abort: user quit
572 [255]
572 [255]
573
573
574 $ hg resolve -m << EOF
574 $ hg resolve -m << EOF
575 > y
575 > y
576 > EOF
576 > EOF
577 mark all unresolved files as resolved (yn)? y
577 mark all unresolved files as resolved (yn)? y
578 (no more unresolved files)
578 (no more unresolved files)
579 continue: hg rebase --continue
579 continue: hg rebase --continue
580 $ hg resolve -l
580 $ hg resolve -l
581 R emp1
581 R emp1
582 R emp2
582 R emp2
583 R emp3
583 R emp3
584
584
585 Test that commands.resolve.confirm respect --unmark option (only when no patterns args are given):
585 Test that commands.resolve.confirm respect --unmark option (only when no patterns args are given):
586 ===============================================================================================
586 ===============================================================================================
587
587
588 $ hg resolve -u emp1
588 $ hg resolve -u emp1
589
589
590 $ hg resolve -l
590 $ hg resolve -l
591 U emp1
591 U emp1
592 R emp2
592 R emp2
593 R emp3
593 R emp3
594
594
595 $ hg resolve -u << EOF
595 $ hg resolve -u << EOF
596 > n
596 > n
597 > EOF
597 > EOF
598 mark all resolved files as unresolved (yn)? n
598 mark all resolved files as unresolved (yn)? n
599 abort: user quit
599 abort: user quit
600 [255]
600 [255]
601
601
602 $ hg resolve -m << EOF
602 $ hg resolve -m << EOF
603 > y
603 > y
604 > EOF
604 > EOF
605 mark all unresolved files as resolved (yn)? y
605 mark all unresolved files as resolved (yn)? y
606 (no more unresolved files)
606 (no more unresolved files)
607 continue: hg rebase --continue
607 continue: hg rebase --continue
608
608
609 $ hg resolve -l
609 $ hg resolve -l
610 R emp1
610 R emp1
611 R emp2
611 R emp2
612 R emp3
612 R emp3
613
613
614 $ hg rebase --abort
614 $ hg rebase --abort
615 rebase aborted
615 rebase aborted
616 $ cd ..
616 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now