##// END OF EJS Templates
annotate: pass in wdir rev and node to formatter (BC)...
Yuya Nishihara -
r39834:ddca3894 default
parent child Browse files
Show More
@@ -1,5918 +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,
23 wdirrev,
22 )
24 )
23 from . import (
25 from . import (
24 archival,
26 archival,
25 bookmarks,
27 bookmarks,
26 bundle2,
28 bundle2,
27 changegroup,
29 changegroup,
28 cmdutil,
30 cmdutil,
29 copies,
31 copies,
30 debugcommands as debugcommandsmod,
32 debugcommands as debugcommandsmod,
31 destutil,
33 destutil,
32 dirstateguard,
34 dirstateguard,
33 discovery,
35 discovery,
34 encoding,
36 encoding,
35 error,
37 error,
36 exchange,
38 exchange,
37 extensions,
39 extensions,
38 filemerge,
40 filemerge,
39 formatter,
41 formatter,
40 graphmod,
42 graphmod,
41 hbisect,
43 hbisect,
42 help,
44 help,
43 hg,
45 hg,
44 logcmdutil,
46 logcmdutil,
45 match as matchmod,
47 match as matchmod,
46 merge as mergemod,
48 merge as mergemod,
47 narrowspec,
49 narrowspec,
48 obsolete,
50 obsolete,
49 obsutil,
51 obsutil,
50 patch,
52 patch,
51 phases,
53 phases,
52 pycompat,
54 pycompat,
53 rcutil,
55 rcutil,
54 registrar,
56 registrar,
55 repair,
57 repair,
56 revsetlang,
58 revsetlang,
57 rewriteutil,
59 rewriteutil,
58 scmutil,
60 scmutil,
59 server,
61 server,
60 state as statemod,
62 state as statemod,
61 streamclone,
63 streamclone,
62 tags as tagsmod,
64 tags as tagsmod,
63 templatekw,
65 templatekw,
64 ui as uimod,
66 ui as uimod,
65 util,
67 util,
66 wireprotoserver,
68 wireprotoserver,
67 )
69 )
68 from .utils import (
70 from .utils import (
69 dateutil,
71 dateutil,
70 stringutil,
72 stringutil,
71 )
73 )
72
74
73 table = {}
75 table = {}
74 table.update(debugcommandsmod.command._table)
76 table.update(debugcommandsmod.command._table)
75
77
76 command = registrar.command(table)
78 command = registrar.command(table)
77 INTENT_READONLY = registrar.INTENT_READONLY
79 INTENT_READONLY = registrar.INTENT_READONLY
78
80
79 # common command options
81 # common command options
80
82
81 globalopts = [
83 globalopts = [
82 ('R', 'repository', '',
84 ('R', 'repository', '',
83 _('repository root directory or name of overlay bundle file'),
85 _('repository root directory or name of overlay bundle file'),
84 _('REPO')),
86 _('REPO')),
85 ('', 'cwd', '',
87 ('', 'cwd', '',
86 _('change working directory'), _('DIR')),
88 _('change working directory'), _('DIR')),
87 ('y', 'noninteractive', None,
89 ('y', 'noninteractive', None,
88 _('do not prompt, automatically pick the first choice for all prompts')),
90 _('do not prompt, automatically pick the first choice for all prompts')),
89 ('q', 'quiet', None, _('suppress output')),
91 ('q', 'quiet', None, _('suppress output')),
90 ('v', 'verbose', None, _('enable additional output')),
92 ('v', 'verbose', None, _('enable additional output')),
91 ('', 'color', '',
93 ('', 'color', '',
92 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
94 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
93 # and should not be translated
95 # and should not be translated
94 _("when to colorize (boolean, always, auto, never, or debug)"),
96 _("when to colorize (boolean, always, auto, never, or debug)"),
95 _('TYPE')),
97 _('TYPE')),
96 ('', 'config', [],
98 ('', 'config', [],
97 _('set/override config option (use \'section.name=value\')'),
99 _('set/override config option (use \'section.name=value\')'),
98 _('CONFIG')),
100 _('CONFIG')),
99 ('', 'debug', None, _('enable debugging output')),
101 ('', 'debug', None, _('enable debugging output')),
100 ('', 'debugger', None, _('start debugger')),
102 ('', 'debugger', None, _('start debugger')),
101 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
103 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
102 _('ENCODE')),
104 _('ENCODE')),
103 ('', 'encodingmode', encoding.encodingmode,
105 ('', 'encodingmode', encoding.encodingmode,
104 _('set the charset encoding mode'), _('MODE')),
106 _('set the charset encoding mode'), _('MODE')),
105 ('', 'traceback', None, _('always print a traceback on exception')),
107 ('', 'traceback', None, _('always print a traceback on exception')),
106 ('', 'time', None, _('time how long the command takes')),
108 ('', 'time', None, _('time how long the command takes')),
107 ('', 'profile', None, _('print command execution profile')),
109 ('', 'profile', None, _('print command execution profile')),
108 ('', 'version', None, _('output version information and exit')),
110 ('', 'version', None, _('output version information and exit')),
109 ('h', 'help', None, _('display help and exit')),
111 ('h', 'help', None, _('display help and exit')),
110 ('', 'hidden', False, _('consider hidden changesets')),
112 ('', 'hidden', False, _('consider hidden changesets')),
111 ('', 'pager', 'auto',
113 ('', 'pager', 'auto',
112 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
114 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
113 ]
115 ]
114
116
115 dryrunopts = cmdutil.dryrunopts
117 dryrunopts = cmdutil.dryrunopts
116 remoteopts = cmdutil.remoteopts
118 remoteopts = cmdutil.remoteopts
117 walkopts = cmdutil.walkopts
119 walkopts = cmdutil.walkopts
118 commitopts = cmdutil.commitopts
120 commitopts = cmdutil.commitopts
119 commitopts2 = cmdutil.commitopts2
121 commitopts2 = cmdutil.commitopts2
120 formatteropts = cmdutil.formatteropts
122 formatteropts = cmdutil.formatteropts
121 templateopts = cmdutil.templateopts
123 templateopts = cmdutil.templateopts
122 logopts = cmdutil.logopts
124 logopts = cmdutil.logopts
123 diffopts = cmdutil.diffopts
125 diffopts = cmdutil.diffopts
124 diffwsopts = cmdutil.diffwsopts
126 diffwsopts = cmdutil.diffwsopts
125 diffopts2 = cmdutil.diffopts2
127 diffopts2 = cmdutil.diffopts2
126 mergetoolopts = cmdutil.mergetoolopts
128 mergetoolopts = cmdutil.mergetoolopts
127 similarityopts = cmdutil.similarityopts
129 similarityopts = cmdutil.similarityopts
128 subrepoopts = cmdutil.subrepoopts
130 subrepoopts = cmdutil.subrepoopts
129 debugrevlogopts = cmdutil.debugrevlogopts
131 debugrevlogopts = cmdutil.debugrevlogopts
130
132
131 # Commands start here, listed alphabetically
133 # Commands start here, listed alphabetically
132
134
133 @command('^add',
135 @command('^add',
134 walkopts + subrepoopts + dryrunopts,
136 walkopts + subrepoopts + dryrunopts,
135 _('[OPTION]... [FILE]...'),
137 _('[OPTION]... [FILE]...'),
136 inferrepo=True)
138 inferrepo=True)
137 def add(ui, repo, *pats, **opts):
139 def add(ui, repo, *pats, **opts):
138 """add the specified files on the next commit
140 """add the specified files on the next commit
139
141
140 Schedule files to be version controlled and added to the
142 Schedule files to be version controlled and added to the
141 repository.
143 repository.
142
144
143 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
144 undo an add before that, see :hg:`forget`.
146 undo an add before that, see :hg:`forget`.
145
147
146 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
147 files matching ``.hgignore``).
149 files matching ``.hgignore``).
148
150
149 .. container:: verbose
151 .. container:: verbose
150
152
151 Examples:
153 Examples:
152
154
153 - New (unknown) files are added
155 - New (unknown) files are added
154 automatically by :hg:`add`::
156 automatically by :hg:`add`::
155
157
156 $ ls
158 $ ls
157 foo.c
159 foo.c
158 $ hg status
160 $ hg status
159 ? foo.c
161 ? foo.c
160 $ hg add
162 $ hg add
161 adding foo.c
163 adding foo.c
162 $ hg status
164 $ hg status
163 A foo.c
165 A foo.c
164
166
165 - Specific files to be added can be specified::
167 - Specific files to be added can be specified::
166
168
167 $ ls
169 $ ls
168 bar.c foo.c
170 bar.c foo.c
169 $ hg status
171 $ hg status
170 ? bar.c
172 ? bar.c
171 ? foo.c
173 ? foo.c
172 $ hg add bar.c
174 $ hg add bar.c
173 $ hg status
175 $ hg status
174 A bar.c
176 A bar.c
175 ? foo.c
177 ? foo.c
176
178
177 Returns 0 if all files are successfully added.
179 Returns 0 if all files are successfully added.
178 """
180 """
179
181
180 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
182 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
181 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
183 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
182 return rejected and 1 or 0
184 return rejected and 1 or 0
183
185
184 @command('addremove',
186 @command('addremove',
185 similarityopts + subrepoopts + walkopts + dryrunopts,
187 similarityopts + subrepoopts + walkopts + dryrunopts,
186 _('[OPTION]... [FILE]...'),
188 _('[OPTION]... [FILE]...'),
187 inferrepo=True)
189 inferrepo=True)
188 def addremove(ui, repo, *pats, **opts):
190 def addremove(ui, repo, *pats, **opts):
189 """add all new files, delete all missing files
191 """add all new files, delete all missing files
190
192
191 Add all new files and remove all missing files from the
193 Add all new files and remove all missing files from the
192 repository.
194 repository.
193
195
194 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
195 the patterns in ``.hgignore``. As with add, these changes take
197 the patterns in ``.hgignore``. As with add, these changes take
196 effect at the next commit.
198 effect at the next commit.
197
199
198 Use the -s/--similarity option to detect renamed files. This
200 Use the -s/--similarity option to detect renamed files. This
199 option takes a percentage between 0 (disabled) and 100 (files must
201 option takes a percentage between 0 (disabled) and 100 (files must
200 be identical) as its parameter. With a parameter greater than 0,
202 be identical) as its parameter. With a parameter greater than 0,
201 this compares every removed file with every added file and records
203 this compares every removed file with every added file and records
202 those similar enough as renames. Detecting renamed files this way
204 those similar enough as renames. Detecting renamed files this way
203 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
204 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
205 not specified, -s/--similarity defaults to 100 and only renames of
207 not specified, -s/--similarity defaults to 100 and only renames of
206 identical files are detected.
208 identical files are detected.
207
209
208 .. container:: verbose
210 .. container:: verbose
209
211
210 Examples:
212 Examples:
211
213
212 - A number of files (bar.c and foo.c) are new,
214 - A number of files (bar.c and foo.c) are new,
213 while foobar.c has been removed (without using :hg:`remove`)
215 while foobar.c has been removed (without using :hg:`remove`)
214 from the repository::
216 from the repository::
215
217
216 $ ls
218 $ ls
217 bar.c foo.c
219 bar.c foo.c
218 $ hg status
220 $ hg status
219 ! foobar.c
221 ! foobar.c
220 ? bar.c
222 ? bar.c
221 ? foo.c
223 ? foo.c
222 $ hg addremove
224 $ hg addremove
223 adding bar.c
225 adding bar.c
224 adding foo.c
226 adding foo.c
225 removing foobar.c
227 removing foobar.c
226 $ hg status
228 $ hg status
227 A bar.c
229 A bar.c
228 A foo.c
230 A foo.c
229 R foobar.c
231 R foobar.c
230
232
231 - 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`.
232 Afterwards, it was edited slightly::
234 Afterwards, it was edited slightly::
233
235
234 $ ls
236 $ ls
235 foo.c
237 foo.c
236 $ hg status
238 $ hg status
237 ! foobar.c
239 ! foobar.c
238 ? foo.c
240 ? foo.c
239 $ hg addremove --similarity 90
241 $ hg addremove --similarity 90
240 removing foobar.c
242 removing foobar.c
241 adding foo.c
243 adding foo.c
242 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)
243 $ hg status -C
245 $ hg status -C
244 A foo.c
246 A foo.c
245 foobar.c
247 foobar.c
246 R foobar.c
248 R foobar.c
247
249
248 Returns 0 if all files are successfully added.
250 Returns 0 if all files are successfully added.
249 """
251 """
250 opts = pycompat.byteskwargs(opts)
252 opts = pycompat.byteskwargs(opts)
251 if not opts.get('similarity'):
253 if not opts.get('similarity'):
252 opts['similarity'] = '100'
254 opts['similarity'] = '100'
253 matcher = scmutil.match(repo[None], pats, opts)
255 matcher = scmutil.match(repo[None], pats, opts)
254 return scmutil.addremove(repo, matcher, "", opts)
256 return scmutil.addremove(repo, matcher, "", opts)
255
257
256 @command('^annotate|blame',
258 @command('^annotate|blame',
257 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
259 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
258 ('', 'follow', None,
260 ('', 'follow', None,
259 _('follow copies/renames and list the filename (DEPRECATED)')),
261 _('follow copies/renames and list the filename (DEPRECATED)')),
260 ('', 'no-follow', None, _("don't follow copies and renames")),
262 ('', 'no-follow', None, _("don't follow copies and renames")),
261 ('a', 'text', None, _('treat all files as text')),
263 ('a', 'text', None, _('treat all files as text')),
262 ('u', 'user', None, _('list the author (long with -v)')),
264 ('u', 'user', None, _('list the author (long with -v)')),
263 ('f', 'file', None, _('list the filename')),
265 ('f', 'file', None, _('list the filename')),
264 ('d', 'date', None, _('list the date (short with -q)')),
266 ('d', 'date', None, _('list the date (short with -q)')),
265 ('n', 'number', None, _('list the revision number (default)')),
267 ('n', 'number', None, _('list the revision number (default)')),
266 ('c', 'changeset', None, _('list the changeset')),
268 ('c', 'changeset', None, _('list the changeset')),
267 ('l', 'line-number', None, _('show line number at the first appearance')),
269 ('l', 'line-number', None, _('show line number at the first appearance')),
268 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
270 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
269 ] + diffwsopts + walkopts + formatteropts,
271 ] + diffwsopts + walkopts + formatteropts,
270 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
272 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
271 inferrepo=True)
273 inferrepo=True)
272 def annotate(ui, repo, *pats, **opts):
274 def annotate(ui, repo, *pats, **opts):
273 """show changeset information by line for each file
275 """show changeset information by line for each file
274
276
275 List changes in files, showing the revision id responsible for
277 List changes in files, showing the revision id responsible for
276 each line.
278 each line.
277
279
278 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
279 by whom.
281 by whom.
280
282
281 If you include --file, --user, or --date, the revision number is
283 If you include --file, --user, or --date, the revision number is
282 suppressed unless you also include --number.
284 suppressed unless you also include --number.
283
285
284 Without the -a/--text option, annotate will avoid processing files
286 Without the -a/--text option, annotate will avoid processing files
285 it detects as binary. With -a, annotate will annotate the file
287 it detects as binary. With -a, annotate will annotate the file
286 anyway, although the results will probably be neither useful
288 anyway, although the results will probably be neither useful
287 nor desirable.
289 nor desirable.
288
290
289 Returns 0 on success.
291 Returns 0 on success.
290 """
292 """
291 opts = pycompat.byteskwargs(opts)
293 opts = pycompat.byteskwargs(opts)
292 if not pats:
294 if not pats:
293 raise error.Abort(_('at least one filename or pattern is required'))
295 raise error.Abort(_('at least one filename or pattern is required'))
294
296
295 if opts.get('follow'):
297 if opts.get('follow'):
296 # --follow is deprecated and now just an alias for -f/--file
298 # --follow is deprecated and now just an alias for -f/--file
297 # to mimic the behavior of Mercurial before version 1.5
299 # to mimic the behavior of Mercurial before version 1.5
298 opts['file'] = True
300 opts['file'] = True
299
301
300 rev = opts.get('rev')
302 rev = opts.get('rev')
301 if rev:
303 if rev:
302 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
304 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
303 ctx = scmutil.revsingle(repo, rev)
305 ctx = scmutil.revsingle(repo, rev)
304
306
305 rootfm = ui.formatter('annotate', opts)
307 rootfm = ui.formatter('annotate', opts)
306 if ui.debugflag:
308 if ui.debugflag:
307 shorthex = pycompat.identity
309 shorthex = pycompat.identity
308 else:
310 else:
309 def shorthex(h):
311 def shorthex(h):
310 return h[:12]
312 return h[:12]
311 if ui.quiet:
313 if ui.quiet:
312 datefunc = dateutil.shortdate
314 datefunc = dateutil.shortdate
313 else:
315 else:
314 datefunc = dateutil.datestr
316 datefunc = dateutil.datestr
315 if ctx.rev() is None:
317 if ctx.rev() is None:
316 def hexfn(node):
317 if node is None:
318 return None
319 else:
320 return hex(node)
321 if opts.get('changeset'):
318 if opts.get('changeset'):
322 # omit "+" suffix which is appended to node hex
319 # omit "+" suffix which is appended to node hex
323 def formatrev(rev):
320 def formatrev(rev):
324 if rev is None:
321 if rev == wdirrev:
325 return '%d' % ctx.p1().rev()
322 return '%d' % ctx.p1().rev()
326 else:
323 else:
327 return '%d' % rev
324 return '%d' % rev
328 else:
325 else:
329 def formatrev(rev):
326 def formatrev(rev):
330 if rev is None:
327 if rev == wdirrev:
331 return '%d+' % ctx.p1().rev()
328 return '%d+' % ctx.p1().rev()
332 else:
329 else:
333 return '%d ' % rev
330 return '%d ' % rev
334 def formathex(h):
331 def formathex(h):
335 if h is None:
332 if h == wdirhex:
336 return '%s+' % shorthex(hex(ctx.p1().node()))
333 return '%s+' % shorthex(hex(ctx.p1().node()))
337 else:
334 else:
338 return '%s ' % shorthex(h)
335 return '%s ' % shorthex(h)
339 else:
336 else:
340 hexfn = hex
341 formatrev = b'%d'.__mod__
337 formatrev = b'%d'.__mod__
342 formathex = shorthex
338 formathex = shorthex
343
339
344 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
340 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
345 ('rev', ' ', lambda x: x.fctx.rev(), formatrev),
341 ('rev', ' ', lambda x: scmutil.intrev(x.fctx), formatrev),
346 ('node', ' ', lambda x: hexfn(x.fctx.node()), formathex),
342 ('node', ' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
347 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
343 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
348 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
344 ('path', ' ', lambda x: x.fctx.path(), pycompat.bytestr),
349 ('line_number', ':', lambda x: x.lineno, pycompat.bytestr),
345 ('line_number', ':', lambda x: x.lineno, pycompat.bytestr),
350 ]
346 ]
351 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file'}
347 opnamemap = {'rev': 'number', 'node': 'changeset', 'path': 'file'}
352
348
353 if (not opts.get('user') and not opts.get('changeset')
349 if (not opts.get('user') and not opts.get('changeset')
354 and not opts.get('date') and not opts.get('file')):
350 and not opts.get('date') and not opts.get('file')):
355 opts['number'] = True
351 opts['number'] = True
356
352
357 linenumber = opts.get('line_number') is not None
353 linenumber = opts.get('line_number') is not None
358 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')):
359 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'))
360
356
361 ui.pager('annotate')
357 ui.pager('annotate')
362
358
363 if rootfm.isplain():
359 if rootfm.isplain():
364 def makefunc(get, fmt):
360 def makefunc(get, fmt):
365 return lambda x: fmt(get(x))
361 return lambda x: fmt(get(x))
366 else:
362 else:
367 def makefunc(get, fmt):
363 def makefunc(get, fmt):
368 return get
364 return get
369 datahint = rootfm.datahint()
365 datahint = rootfm.datahint()
370 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
371 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
367 if opts.get(opnamemap.get(fn, fn)) or fn in datahint]
372 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
373 fields = ' '.join(fn for fn, sep, get, fmt in opmap
369 fields = ' '.join(fn for fn, sep, get, fmt in opmap
374 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
370 if opts.get(opnamemap.get(fn, fn)) or fn in datahint)
375
371
376 def bad(x, y):
372 def bad(x, y):
377 raise error.Abort("%s: %s" % (x, y))
373 raise error.Abort("%s: %s" % (x, y))
378
374
379 m = scmutil.match(ctx, pats, opts, badfn=bad)
375 m = scmutil.match(ctx, pats, opts, badfn=bad)
380
376
381 follow = not opts.get('no_follow')
377 follow = not opts.get('no_follow')
382 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
378 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
383 whitespace=True)
379 whitespace=True)
384 skiprevs = opts.get('skip')
380 skiprevs = opts.get('skip')
385 if skiprevs:
381 if skiprevs:
386 skiprevs = scmutil.revrange(repo, skiprevs)
382 skiprevs = scmutil.revrange(repo, skiprevs)
387
383
388 for abs in ctx.walk(m):
384 for abs in ctx.walk(m):
389 fctx = ctx[abs]
385 fctx = ctx[abs]
390 rootfm.startitem()
386 rootfm.startitem()
391 rootfm.data(path=abs)
387 rootfm.data(path=abs)
392 if not opts.get('text') and fctx.isbinary():
388 if not opts.get('text') and fctx.isbinary():
393 rootfm.plain(_("%s: binary file\n")
389 rootfm.plain(_("%s: binary file\n")
394 % ((pats and m.rel(abs)) or abs))
390 % ((pats and m.rel(abs)) or abs))
395 continue
391 continue
396
392
397 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
393 fm = rootfm.nested('lines', tmpl='{rev}: {line}')
398 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
394 lines = fctx.annotate(follow=follow, skiprevs=skiprevs,
399 diffopts=diffopts)
395 diffopts=diffopts)
400 if not lines:
396 if not lines:
401 fm.end()
397 fm.end()
402 continue
398 continue
403 formats = []
399 formats = []
404 pieces = []
400 pieces = []
405
401
406 for f, sep in funcmap:
402 for f, sep in funcmap:
407 l = [f(n) for n in lines]
403 l = [f(n) for n in lines]
408 if fm.isplain():
404 if fm.isplain():
409 sizes = [encoding.colwidth(x) for x in l]
405 sizes = [encoding.colwidth(x) for x in l]
410 ml = max(sizes)
406 ml = max(sizes)
411 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
407 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
412 else:
408 else:
413 formats.append(['%s' for x in l])
409 formats.append(['%s' for x in l])
414 pieces.append(l)
410 pieces.append(l)
415
411
416 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
412 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
417 fm.startitem()
413 fm.startitem()
418 fm.context(fctx=n.fctx)
414 fm.context(fctx=n.fctx)
419 fm.write(fields, "".join(f), *p)
415 fm.write(fields, "".join(f), *p)
420 if n.skip:
416 if n.skip:
421 fmt = "* %s"
417 fmt = "* %s"
422 else:
418 else:
423 fmt = ": %s"
419 fmt = ": %s"
424 fm.write('line', fmt, n.text)
420 fm.write('line', fmt, n.text)
425
421
426 if not lines[-1].text.endswith('\n'):
422 if not lines[-1].text.endswith('\n'):
427 fm.plain('\n')
423 fm.plain('\n')
428 fm.end()
424 fm.end()
429
425
430 rootfm.end()
426 rootfm.end()
431
427
432 @command('archive',
428 @command('archive',
433 [('', 'no-decode', None, _('do not pass files through decoders')),
429 [('', 'no-decode', None, _('do not pass files through decoders')),
434 ('p', 'prefix', '', _('directory prefix for files in archive'),
430 ('p', 'prefix', '', _('directory prefix for files in archive'),
435 _('PREFIX')),
431 _('PREFIX')),
436 ('r', 'rev', '', _('revision to distribute'), _('REV')),
432 ('r', 'rev', '', _('revision to distribute'), _('REV')),
437 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
433 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
438 ] + subrepoopts + walkopts,
434 ] + subrepoopts + walkopts,
439 _('[OPTION]... DEST'))
435 _('[OPTION]... DEST'))
440 def archive(ui, repo, dest, **opts):
436 def archive(ui, repo, dest, **opts):
441 '''create an unversioned archive of a repository revision
437 '''create an unversioned archive of a repository revision
442
438
443 By default, the revision used is the parent of the working
439 By default, the revision used is the parent of the working
444 directory; use -r/--rev to specify a different revision.
440 directory; use -r/--rev to specify a different revision.
445
441
446 The archive type is automatically detected based on file
442 The archive type is automatically detected based on file
447 extension (to override, use -t/--type).
443 extension (to override, use -t/--type).
448
444
449 .. container:: verbose
445 .. container:: verbose
450
446
451 Examples:
447 Examples:
452
448
453 - create a zip file containing the 1.0 release::
449 - create a zip file containing the 1.0 release::
454
450
455 hg archive -r 1.0 project-1.0.zip
451 hg archive -r 1.0 project-1.0.zip
456
452
457 - create a tarball excluding .hg files::
453 - create a tarball excluding .hg files::
458
454
459 hg archive project.tar.gz -X ".hg*"
455 hg archive project.tar.gz -X ".hg*"
460
456
461 Valid types are:
457 Valid types are:
462
458
463 :``files``: a directory full of files (default)
459 :``files``: a directory full of files (default)
464 :``tar``: tar archive, uncompressed
460 :``tar``: tar archive, uncompressed
465 :``tbz2``: tar archive, compressed using bzip2
461 :``tbz2``: tar archive, compressed using bzip2
466 :``tgz``: tar archive, compressed using gzip
462 :``tgz``: tar archive, compressed using gzip
467 :``uzip``: zip archive, uncompressed
463 :``uzip``: zip archive, uncompressed
468 :``zip``: zip archive, compressed using deflate
464 :``zip``: zip archive, compressed using deflate
469
465
470 The exact name of the destination archive or directory is given
466 The exact name of the destination archive or directory is given
471 using a format string; see :hg:`help export` for details.
467 using a format string; see :hg:`help export` for details.
472
468
473 Each member added to an archive file has a directory prefix
469 Each member added to an archive file has a directory prefix
474 prepended. Use -p/--prefix to specify a format string for the
470 prepended. Use -p/--prefix to specify a format string for the
475 prefix. The default is the basename of the archive, with suffixes
471 prefix. The default is the basename of the archive, with suffixes
476 removed.
472 removed.
477
473
478 Returns 0 on success.
474 Returns 0 on success.
479 '''
475 '''
480
476
481 opts = pycompat.byteskwargs(opts)
477 opts = pycompat.byteskwargs(opts)
482 rev = opts.get('rev')
478 rev = opts.get('rev')
483 if rev:
479 if rev:
484 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
480 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
485 ctx = scmutil.revsingle(repo, rev)
481 ctx = scmutil.revsingle(repo, rev)
486 if not ctx:
482 if not ctx:
487 raise error.Abort(_('no working directory: please specify a revision'))
483 raise error.Abort(_('no working directory: please specify a revision'))
488 node = ctx.node()
484 node = ctx.node()
489 dest = cmdutil.makefilename(ctx, dest)
485 dest = cmdutil.makefilename(ctx, dest)
490 if os.path.realpath(dest) == repo.root:
486 if os.path.realpath(dest) == repo.root:
491 raise error.Abort(_('repository root cannot be destination'))
487 raise error.Abort(_('repository root cannot be destination'))
492
488
493 kind = opts.get('type') or archival.guesskind(dest) or 'files'
489 kind = opts.get('type') or archival.guesskind(dest) or 'files'
494 prefix = opts.get('prefix')
490 prefix = opts.get('prefix')
495
491
496 if dest == '-':
492 if dest == '-':
497 if kind == 'files':
493 if kind == 'files':
498 raise error.Abort(_('cannot archive plain files to stdout'))
494 raise error.Abort(_('cannot archive plain files to stdout'))
499 dest = cmdutil.makefileobj(ctx, dest)
495 dest = cmdutil.makefileobj(ctx, dest)
500 if not prefix:
496 if not prefix:
501 prefix = os.path.basename(repo.root) + '-%h'
497 prefix = os.path.basename(repo.root) + '-%h'
502
498
503 prefix = cmdutil.makefilename(ctx, prefix)
499 prefix = cmdutil.makefilename(ctx, prefix)
504 match = scmutil.match(ctx, [], opts)
500 match = scmutil.match(ctx, [], opts)
505 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
501 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
506 match, prefix, subrepos=opts.get('subrepos'))
502 match, prefix, subrepos=opts.get('subrepos'))
507
503
508 @command('backout',
504 @command('backout',
509 [('', 'merge', None, _('merge with old dirstate parent after backout')),
505 [('', 'merge', None, _('merge with old dirstate parent after backout')),
510 ('', 'commit', None,
506 ('', 'commit', None,
511 _('commit if no conflicts were encountered (DEPRECATED)')),
507 _('commit if no conflicts were encountered (DEPRECATED)')),
512 ('', 'no-commit', None, _('do not commit')),
508 ('', 'no-commit', None, _('do not commit')),
513 ('', 'parent', '',
509 ('', 'parent', '',
514 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
510 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
515 ('r', 'rev', '', _('revision to backout'), _('REV')),
511 ('r', 'rev', '', _('revision to backout'), _('REV')),
516 ('e', 'edit', False, _('invoke editor on commit messages')),
512 ('e', 'edit', False, _('invoke editor on commit messages')),
517 ] + mergetoolopts + walkopts + commitopts + commitopts2,
513 ] + mergetoolopts + walkopts + commitopts + commitopts2,
518 _('[OPTION]... [-r] REV'))
514 _('[OPTION]... [-r] REV'))
519 def backout(ui, repo, node=None, rev=None, **opts):
515 def backout(ui, repo, node=None, rev=None, **opts):
520 '''reverse effect of earlier changeset
516 '''reverse effect of earlier changeset
521
517
522 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
523 current working directory. If no conflicts were encountered,
519 current working directory. If no conflicts were encountered,
524 it will be committed immediately.
520 it will be committed immediately.
525
521
526 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
527 is committed automatically (unless --no-commit is specified).
523 is committed automatically (unless --no-commit is specified).
528
524
529 .. note::
525 .. note::
530
526
531 :hg:`backout` cannot be used to fix either an unwanted or
527 :hg:`backout` cannot be used to fix either an unwanted or
532 incorrect merge.
528 incorrect merge.
533
529
534 .. container:: verbose
530 .. container:: verbose
535
531
536 Examples:
532 Examples:
537
533
538 - Reverse the effect of the parent of the working directory.
534 - Reverse the effect of the parent of the working directory.
539 This backout will be committed immediately::
535 This backout will be committed immediately::
540
536
541 hg backout -r .
537 hg backout -r .
542
538
543 - Reverse the effect of previous bad revision 23::
539 - Reverse the effect of previous bad revision 23::
544
540
545 hg backout -r 23
541 hg backout -r 23
546
542
547 - Reverse the effect of previous bad revision 23 and
543 - Reverse the effect of previous bad revision 23 and
548 leave changes uncommitted::
544 leave changes uncommitted::
549
545
550 hg backout -r 23 --no-commit
546 hg backout -r 23 --no-commit
551 hg commit -m "Backout revision 23"
547 hg commit -m "Backout revision 23"
552
548
553 By default, the pending changeset will have one parent,
549 By default, the pending changeset will have one parent,
554 maintaining a linear history. With --merge, the pending
550 maintaining a linear history. With --merge, the pending
555 changeset will instead have two parents: the old parent of the
551 changeset will instead have two parents: the old parent of the
556 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.
557
553
558 Before version 1.7, the behavior without --merge was equivalent
554 Before version 1.7, the behavior without --merge was equivalent
559 to specifying --merge followed by :hg:`update --clean .` to
555 to specifying --merge followed by :hg:`update --clean .` to
560 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
561 merged separately.
557 merged separately.
562
558
563 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.
564
560
565 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
566 of another revision.
562 of another revision.
567
563
568 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
569 files.
565 files.
570 '''
566 '''
571 with repo.wlock(), repo.lock():
567 with repo.wlock(), repo.lock():
572 return _dobackout(ui, repo, node, rev, **opts)
568 return _dobackout(ui, repo, node, rev, **opts)
573
569
574 def _dobackout(ui, repo, node=None, rev=None, **opts):
570 def _dobackout(ui, repo, node=None, rev=None, **opts):
575 opts = pycompat.byteskwargs(opts)
571 opts = pycompat.byteskwargs(opts)
576 if opts.get('commit') and opts.get('no_commit'):
572 if opts.get('commit') and opts.get('no_commit'):
577 raise error.Abort(_("cannot use --commit with --no-commit"))
573 raise error.Abort(_("cannot use --commit with --no-commit"))
578 if opts.get('merge') and opts.get('no_commit'):
574 if opts.get('merge') and opts.get('no_commit'):
579 raise error.Abort(_("cannot use --merge with --no-commit"))
575 raise error.Abort(_("cannot use --merge with --no-commit"))
580
576
581 if rev and node:
577 if rev and node:
582 raise error.Abort(_("please specify just one revision"))
578 raise error.Abort(_("please specify just one revision"))
583
579
584 if not rev:
580 if not rev:
585 rev = node
581 rev = node
586
582
587 if not rev:
583 if not rev:
588 raise error.Abort(_("please specify a revision to backout"))
584 raise error.Abort(_("please specify a revision to backout"))
589
585
590 date = opts.get('date')
586 date = opts.get('date')
591 if date:
587 if date:
592 opts['date'] = dateutil.parsedate(date)
588 opts['date'] = dateutil.parsedate(date)
593
589
594 cmdutil.checkunfinished(repo)
590 cmdutil.checkunfinished(repo)
595 cmdutil.bailifchanged(repo)
591 cmdutil.bailifchanged(repo)
596 node = scmutil.revsingle(repo, rev).node()
592 node = scmutil.revsingle(repo, rev).node()
597
593
598 op1, op2 = repo.dirstate.parents()
594 op1, op2 = repo.dirstate.parents()
599 if not repo.changelog.isancestor(node, op1):
595 if not repo.changelog.isancestor(node, op1):
600 raise error.Abort(_('cannot backout change that is not an ancestor'))
596 raise error.Abort(_('cannot backout change that is not an ancestor'))
601
597
602 p1, p2 = repo.changelog.parents(node)
598 p1, p2 = repo.changelog.parents(node)
603 if p1 == nullid:
599 if p1 == nullid:
604 raise error.Abort(_('cannot backout a change with no parents'))
600 raise error.Abort(_('cannot backout a change with no parents'))
605 if p2 != nullid:
601 if p2 != nullid:
606 if not opts.get('parent'):
602 if not opts.get('parent'):
607 raise error.Abort(_('cannot backout a merge changeset'))
603 raise error.Abort(_('cannot backout a merge changeset'))
608 p = repo.lookup(opts['parent'])
604 p = repo.lookup(opts['parent'])
609 if p not in (p1, p2):
605 if p not in (p1, p2):
610 raise error.Abort(_('%s is not a parent of %s') %
606 raise error.Abort(_('%s is not a parent of %s') %
611 (short(p), short(node)))
607 (short(p), short(node)))
612 parent = p
608 parent = p
613 else:
609 else:
614 if opts.get('parent'):
610 if opts.get('parent'):
615 raise error.Abort(_('cannot use --parent on non-merge changeset'))
611 raise error.Abort(_('cannot use --parent on non-merge changeset'))
616 parent = p1
612 parent = p1
617
613
618 # the backout should appear on the same branch
614 # the backout should appear on the same branch
619 branch = repo.dirstate.branch()
615 branch = repo.dirstate.branch()
620 bheads = repo.branchheads(branch)
616 bheads = repo.branchheads(branch)
621 rctx = scmutil.revsingle(repo, hex(parent))
617 rctx = scmutil.revsingle(repo, hex(parent))
622 if not opts.get('merge') and op1 != node:
618 if not opts.get('merge') and op1 != node:
623 with dirstateguard.dirstateguard(repo, 'backout'):
619 with dirstateguard.dirstateguard(repo, 'backout'):
624 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
620 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
625 with ui.configoverride(overrides, 'backout'):
621 with ui.configoverride(overrides, 'backout'):
626 stats = mergemod.update(repo, parent, True, True, node, False)
622 stats = mergemod.update(repo, parent, True, True, node, False)
627 repo.setparents(op1, op2)
623 repo.setparents(op1, op2)
628 hg._showstats(repo, stats)
624 hg._showstats(repo, stats)
629 if stats.unresolvedcount:
625 if stats.unresolvedcount:
630 repo.ui.status(_("use 'hg resolve' to retry unresolved "
626 repo.ui.status(_("use 'hg resolve' to retry unresolved "
631 "file merges\n"))
627 "file merges\n"))
632 return 1
628 return 1
633 else:
629 else:
634 hg.clean(repo, node, show_stats=False)
630 hg.clean(repo, node, show_stats=False)
635 repo.dirstate.setbranch(branch)
631 repo.dirstate.setbranch(branch)
636 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
632 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
637
633
638 if opts.get('no_commit'):
634 if opts.get('no_commit'):
639 msg = _("changeset %s backed out, "
635 msg = _("changeset %s backed out, "
640 "don't forget to commit.\n")
636 "don't forget to commit.\n")
641 ui.status(msg % short(node))
637 ui.status(msg % short(node))
642 return 0
638 return 0
643
639
644 def commitfunc(ui, repo, message, match, opts):
640 def commitfunc(ui, repo, message, match, opts):
645 editform = 'backout'
641 editform = 'backout'
646 e = cmdutil.getcommiteditor(editform=editform,
642 e = cmdutil.getcommiteditor(editform=editform,
647 **pycompat.strkwargs(opts))
643 **pycompat.strkwargs(opts))
648 if not message:
644 if not message:
649 # we don't translate commit messages
645 # we don't translate commit messages
650 message = "Backed out changeset %s" % short(node)
646 message = "Backed out changeset %s" % short(node)
651 e = cmdutil.getcommiteditor(edit=True, editform=editform)
647 e = cmdutil.getcommiteditor(edit=True, editform=editform)
652 return repo.commit(message, opts.get('user'), opts.get('date'),
648 return repo.commit(message, opts.get('user'), opts.get('date'),
653 match, editor=e)
649 match, editor=e)
654 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
650 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
655 if not newnode:
651 if not newnode:
656 ui.status(_("nothing changed\n"))
652 ui.status(_("nothing changed\n"))
657 return 1
653 return 1
658 cmdutil.commitstatus(repo, newnode, branch, bheads)
654 cmdutil.commitstatus(repo, newnode, branch, bheads)
659
655
660 def nice(node):
656 def nice(node):
661 return '%d:%s' % (repo.changelog.rev(node), short(node))
657 return '%d:%s' % (repo.changelog.rev(node), short(node))
662 ui.status(_('changeset %s backs out changeset %s\n') %
658 ui.status(_('changeset %s backs out changeset %s\n') %
663 (nice(repo.changelog.tip()), nice(node)))
659 (nice(repo.changelog.tip()), nice(node)))
664 if opts.get('merge') and op1 != node:
660 if opts.get('merge') and op1 != node:
665 hg.clean(repo, op1, show_stats=False)
661 hg.clean(repo, op1, show_stats=False)
666 ui.status(_('merging with changeset %s\n')
662 ui.status(_('merging with changeset %s\n')
667 % nice(repo.changelog.tip()))
663 % nice(repo.changelog.tip()))
668 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
664 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
669 with ui.configoverride(overrides, 'backout'):
665 with ui.configoverride(overrides, 'backout'):
670 return hg.merge(repo, hex(repo.changelog.tip()))
666 return hg.merge(repo, hex(repo.changelog.tip()))
671 return 0
667 return 0
672
668
673 @command('bisect',
669 @command('bisect',
674 [('r', 'reset', False, _('reset bisect state')),
670 [('r', 'reset', False, _('reset bisect state')),
675 ('g', 'good', False, _('mark changeset good')),
671 ('g', 'good', False, _('mark changeset good')),
676 ('b', 'bad', False, _('mark changeset bad')),
672 ('b', 'bad', False, _('mark changeset bad')),
677 ('s', 'skip', False, _('skip testing changeset')),
673 ('s', 'skip', False, _('skip testing changeset')),
678 ('e', 'extend', False, _('extend the bisect range')),
674 ('e', 'extend', False, _('extend the bisect range')),
679 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
675 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
680 ('U', 'noupdate', False, _('do not update to target'))],
676 ('U', 'noupdate', False, _('do not update to target'))],
681 _("[-gbsr] [-U] [-c CMD] [REV]"))
677 _("[-gbsr] [-U] [-c CMD] [REV]"))
682 def bisect(ui, repo, rev=None, extra=None, command=None,
678 def bisect(ui, repo, rev=None, extra=None, command=None,
683 reset=None, good=None, bad=None, skip=None, extend=None,
679 reset=None, good=None, bad=None, skip=None, extend=None,
684 noupdate=None):
680 noupdate=None):
685 """subdivision search of changesets
681 """subdivision search of changesets
686
682
687 This command helps to find changesets which introduce problems. To
683 This command helps to find changesets which introduce problems. To
688 use, mark the earliest changeset you know exhibits the problem as
684 use, mark the earliest changeset you know exhibits the problem as
689 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
690 as good. Bisect will update your working directory to a revision
686 as good. Bisect will update your working directory to a revision
691 for testing (unless the -U/--noupdate option is specified). Once
687 for testing (unless the -U/--noupdate option is specified). Once
692 you have performed tests, mark the working directory as good or
688 you have performed tests, mark the working directory as good or
693 bad, and bisect will either update to another candidate changeset
689 bad, and bisect will either update to another candidate changeset
694 or announce that it has found the bad revision.
690 or announce that it has found the bad revision.
695
691
696 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
697 revision as good or bad without checking it out first.
693 revision as good or bad without checking it out first.
698
694
699 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.
700 The environment variable HG_NODE will contain the ID of the
696 The environment variable HG_NODE will contain the ID of the
701 changeset being tested. The exit status of the command will be
697 changeset being tested. The exit status of the command will be
702 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
703 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
704 bisection, and any other non-zero exit status means the revision
700 bisection, and any other non-zero exit status means the revision
705 is bad.
701 is bad.
706
702
707 .. container:: verbose
703 .. container:: verbose
708
704
709 Some examples:
705 Some examples:
710
706
711 - 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::
712
708
713 hg bisect --bad 34
709 hg bisect --bad 34
714 hg bisect --good 12
710 hg bisect --good 12
715
711
716 - advance the current bisection by marking current revision as good or
712 - advance the current bisection by marking current revision as good or
717 bad::
713 bad::
718
714
719 hg bisect --good
715 hg bisect --good
720 hg bisect --bad
716 hg bisect --bad
721
717
722 - 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
723 that revision is not usable because of another issue)::
719 that revision is not usable because of another issue)::
724
720
725 hg bisect --skip
721 hg bisect --skip
726 hg bisect --skip 23
722 hg bisect --skip 23
727
723
728 - skip all revisions that do not touch directories ``foo`` or ``bar``::
724 - skip all revisions that do not touch directories ``foo`` or ``bar``::
729
725
730 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
726 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
731
727
732 - forget the current bisection::
728 - forget the current bisection::
733
729
734 hg bisect --reset
730 hg bisect --reset
735
731
736 - use 'make && make tests' to automatically find the first broken
732 - use 'make && make tests' to automatically find the first broken
737 revision::
733 revision::
738
734
739 hg bisect --reset
735 hg bisect --reset
740 hg bisect --bad 34
736 hg bisect --bad 34
741 hg bisect --good 12
737 hg bisect --good 12
742 hg bisect --command "make && make tests"
738 hg bisect --command "make && make tests"
743
739
744 - see all changesets whose states are already known in the current
740 - see all changesets whose states are already known in the current
745 bisection::
741 bisection::
746
742
747 hg log -r "bisect(pruned)"
743 hg log -r "bisect(pruned)"
748
744
749 - see the changeset currently being bisected (especially useful
745 - see the changeset currently being bisected (especially useful
750 if running with -U/--noupdate)::
746 if running with -U/--noupdate)::
751
747
752 hg log -r "bisect(current)"
748 hg log -r "bisect(current)"
753
749
754 - see all changesets that took part in the current bisection::
750 - see all changesets that took part in the current bisection::
755
751
756 hg log -r "bisect(range)"
752 hg log -r "bisect(range)"
757
753
758 - you can even get a nice graph::
754 - you can even get a nice graph::
759
755
760 hg log --graph -r "bisect(range)"
756 hg log --graph -r "bisect(range)"
761
757
762 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
758 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
763
759
764 Returns 0 on success.
760 Returns 0 on success.
765 """
761 """
766 # backward compatibility
762 # backward compatibility
767 if rev in "good bad reset init".split():
763 if rev in "good bad reset init".split():
768 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
764 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
769 cmd, rev, extra = rev, extra, None
765 cmd, rev, extra = rev, extra, None
770 if cmd == "good":
766 if cmd == "good":
771 good = True
767 good = True
772 elif cmd == "bad":
768 elif cmd == "bad":
773 bad = True
769 bad = True
774 else:
770 else:
775 reset = True
771 reset = True
776 elif extra:
772 elif extra:
777 raise error.Abort(_('incompatible arguments'))
773 raise error.Abort(_('incompatible arguments'))
778
774
779 incompatibles = {
775 incompatibles = {
780 '--bad': bad,
776 '--bad': bad,
781 '--command': bool(command),
777 '--command': bool(command),
782 '--extend': extend,
778 '--extend': extend,
783 '--good': good,
779 '--good': good,
784 '--reset': reset,
780 '--reset': reset,
785 '--skip': skip,
781 '--skip': skip,
786 }
782 }
787
783
788 enabled = [x for x in incompatibles if incompatibles[x]]
784 enabled = [x for x in incompatibles if incompatibles[x]]
789
785
790 if len(enabled) > 1:
786 if len(enabled) > 1:
791 raise error.Abort(_('%s and %s are incompatible') %
787 raise error.Abort(_('%s and %s are incompatible') %
792 tuple(sorted(enabled)[0:2]))
788 tuple(sorted(enabled)[0:2]))
793
789
794 if reset:
790 if reset:
795 hbisect.resetstate(repo)
791 hbisect.resetstate(repo)
796 return
792 return
797
793
798 state = hbisect.load_state(repo)
794 state = hbisect.load_state(repo)
799
795
800 # update state
796 # update state
801 if good or bad or skip:
797 if good or bad or skip:
802 if rev:
798 if rev:
803 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
799 nodes = [repo[i].node() for i in scmutil.revrange(repo, [rev])]
804 else:
800 else:
805 nodes = [repo.lookup('.')]
801 nodes = [repo.lookup('.')]
806 if good:
802 if good:
807 state['good'] += nodes
803 state['good'] += nodes
808 elif bad:
804 elif bad:
809 state['bad'] += nodes
805 state['bad'] += nodes
810 elif skip:
806 elif skip:
811 state['skip'] += nodes
807 state['skip'] += nodes
812 hbisect.save_state(repo, state)
808 hbisect.save_state(repo, state)
813 if not (state['good'] and state['bad']):
809 if not (state['good'] and state['bad']):
814 return
810 return
815
811
816 def mayupdate(repo, node, show_stats=True):
812 def mayupdate(repo, node, show_stats=True):
817 """common used update sequence"""
813 """common used update sequence"""
818 if noupdate:
814 if noupdate:
819 return
815 return
820 cmdutil.checkunfinished(repo)
816 cmdutil.checkunfinished(repo)
821 cmdutil.bailifchanged(repo)
817 cmdutil.bailifchanged(repo)
822 return hg.clean(repo, node, show_stats=show_stats)
818 return hg.clean(repo, node, show_stats=show_stats)
823
819
824 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
820 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
825
821
826 if command:
822 if command:
827 changesets = 1
823 changesets = 1
828 if noupdate:
824 if noupdate:
829 try:
825 try:
830 node = state['current'][0]
826 node = state['current'][0]
831 except LookupError:
827 except LookupError:
832 raise error.Abort(_('current bisect revision is unknown - '
828 raise error.Abort(_('current bisect revision is unknown - '
833 'start a new bisect to fix'))
829 'start a new bisect to fix'))
834 else:
830 else:
835 node, p2 = repo.dirstate.parents()
831 node, p2 = repo.dirstate.parents()
836 if p2 != nullid:
832 if p2 != nullid:
837 raise error.Abort(_('current bisect revision is a merge'))
833 raise error.Abort(_('current bisect revision is a merge'))
838 if rev:
834 if rev:
839 node = repo[scmutil.revsingle(repo, rev, node)].node()
835 node = repo[scmutil.revsingle(repo, rev, node)].node()
840 try:
836 try:
841 while changesets:
837 while changesets:
842 # update state
838 # update state
843 state['current'] = [node]
839 state['current'] = [node]
844 hbisect.save_state(repo, state)
840 hbisect.save_state(repo, state)
845 status = ui.system(command, environ={'HG_NODE': hex(node)},
841 status = ui.system(command, environ={'HG_NODE': hex(node)},
846 blockedtag='bisect_check')
842 blockedtag='bisect_check')
847 if status == 125:
843 if status == 125:
848 transition = "skip"
844 transition = "skip"
849 elif status == 0:
845 elif status == 0:
850 transition = "good"
846 transition = "good"
851 # status < 0 means process was killed
847 # status < 0 means process was killed
852 elif status == 127:
848 elif status == 127:
853 raise error.Abort(_("failed to execute %s") % command)
849 raise error.Abort(_("failed to execute %s") % command)
854 elif status < 0:
850 elif status < 0:
855 raise error.Abort(_("%s killed") % command)
851 raise error.Abort(_("%s killed") % command)
856 else:
852 else:
857 transition = "bad"
853 transition = "bad"
858 state[transition].append(node)
854 state[transition].append(node)
859 ctx = repo[node]
855 ctx = repo[node]
860 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
856 ui.status(_('changeset %d:%s: %s\n') % (ctx.rev(), ctx,
861 transition))
857 transition))
862 hbisect.checkstate(state)
858 hbisect.checkstate(state)
863 # bisect
859 # bisect
864 nodes, changesets, bgood = hbisect.bisect(repo, state)
860 nodes, changesets, bgood = hbisect.bisect(repo, state)
865 # update to next check
861 # update to next check
866 node = nodes[0]
862 node = nodes[0]
867 mayupdate(repo, node, show_stats=False)
863 mayupdate(repo, node, show_stats=False)
868 finally:
864 finally:
869 state['current'] = [node]
865 state['current'] = [node]
870 hbisect.save_state(repo, state)
866 hbisect.save_state(repo, state)
871 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
867 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
872 return
868 return
873
869
874 hbisect.checkstate(state)
870 hbisect.checkstate(state)
875
871
876 # actually bisect
872 # actually bisect
877 nodes, changesets, good = hbisect.bisect(repo, state)
873 nodes, changesets, good = hbisect.bisect(repo, state)
878 if extend:
874 if extend:
879 if not changesets:
875 if not changesets:
880 extendnode = hbisect.extendrange(repo, state, nodes, good)
876 extendnode = hbisect.extendrange(repo, state, nodes, good)
881 if extendnode is not None:
877 if extendnode is not None:
882 ui.write(_("Extending search to changeset %d:%s\n")
878 ui.write(_("Extending search to changeset %d:%s\n")
883 % (extendnode.rev(), extendnode))
879 % (extendnode.rev(), extendnode))
884 state['current'] = [extendnode.node()]
880 state['current'] = [extendnode.node()]
885 hbisect.save_state(repo, state)
881 hbisect.save_state(repo, state)
886 return mayupdate(repo, extendnode.node())
882 return mayupdate(repo, extendnode.node())
887 raise error.Abort(_("nothing to extend"))
883 raise error.Abort(_("nothing to extend"))
888
884
889 if changesets == 0:
885 if changesets == 0:
890 hbisect.printresult(ui, repo, state, displayer, nodes, good)
886 hbisect.printresult(ui, repo, state, displayer, nodes, good)
891 else:
887 else:
892 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
893 node = nodes[0]
889 node = nodes[0]
894 # compute the approximate number of remaining tests
890 # compute the approximate number of remaining tests
895 tests, size = 0, 2
891 tests, size = 0, 2
896 while size <= changesets:
892 while size <= changesets:
897 tests, size = tests + 1, size * 2
893 tests, size = tests + 1, size * 2
898 rev = repo.changelog.rev(node)
894 rev = repo.changelog.rev(node)
899 ui.write(_("Testing changeset %d:%s "
895 ui.write(_("Testing changeset %d:%s "
900 "(%d changesets remaining, ~%d tests)\n")
896 "(%d changesets remaining, ~%d tests)\n")
901 % (rev, short(node), changesets, tests))
897 % (rev, short(node), changesets, tests))
902 state['current'] = [node]
898 state['current'] = [node]
903 hbisect.save_state(repo, state)
899 hbisect.save_state(repo, state)
904 return mayupdate(repo, node)
900 return mayupdate(repo, node)
905
901
906 @command('bookmarks|bookmark',
902 @command('bookmarks|bookmark',
907 [('f', 'force', False, _('force')),
903 [('f', 'force', False, _('force')),
908 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
904 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
909 ('d', 'delete', False, _('delete a given bookmark')),
905 ('d', 'delete', False, _('delete a given bookmark')),
910 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
906 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
911 ('i', 'inactive', False, _('mark a bookmark inactive')),
907 ('i', 'inactive', False, _('mark a bookmark inactive')),
912 ('l', 'list', False, _('list existing bookmarks')),
908 ('l', 'list', False, _('list existing bookmarks')),
913 ] + formatteropts,
909 ] + formatteropts,
914 _('hg bookmarks [OPTIONS]... [NAME]...'))
910 _('hg bookmarks [OPTIONS]... [NAME]...'))
915 def bookmark(ui, repo, *names, **opts):
911 def bookmark(ui, repo, *names, **opts):
916 '''create a new bookmark or list existing bookmarks
912 '''create a new bookmark or list existing bookmarks
917
913
918 Bookmarks are labels on changesets to help track lines of development.
914 Bookmarks are labels on changesets to help track lines of development.
919 Bookmarks are unversioned and can be moved, renamed and deleted.
915 Bookmarks are unversioned and can be moved, renamed and deleted.
920 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.
921
917
922 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'.
923 The active bookmark is indicated with a '*'.
919 The active bookmark is indicated with a '*'.
924 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.
925 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.
926 Updating away from a bookmark will cause it to be deactivated.
922 Updating away from a bookmark will cause it to be deactivated.
927
923
928 Bookmarks can be pushed and pulled between repositories (see
924 Bookmarks can be pushed and pulled between repositories (see
929 :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
930 diverged, a new 'divergent bookmark' of the form 'name@path' will
926 diverged, a new 'divergent bookmark' of the form 'name@path' will
931 be created. Using :hg:`merge` will resolve the divergence.
927 be created. Using :hg:`merge` will resolve the divergence.
932
928
933 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
934 the active bookmark's name.
930 the active bookmark's name.
935
931
936 A bookmark named '@' has the special property that :hg:`clone` will
932 A bookmark named '@' has the special property that :hg:`clone` will
937 check it out by default if it exists.
933 check it out by default if it exists.
938
934
939 .. container:: verbose
935 .. container:: verbose
940
936
941 Examples:
937 Examples:
942
938
943 - create an active bookmark for a new line of development::
939 - create an active bookmark for a new line of development::
944
940
945 hg book new-feature
941 hg book new-feature
946
942
947 - create an inactive bookmark as a place marker::
943 - create an inactive bookmark as a place marker::
948
944
949 hg book -i reviewed
945 hg book -i reviewed
950
946
951 - create an inactive bookmark on another changeset::
947 - create an inactive bookmark on another changeset::
952
948
953 hg book -r .^ tested
949 hg book -r .^ tested
954
950
955 - rename bookmark turkey to dinner::
951 - rename bookmark turkey to dinner::
956
952
957 hg book -m turkey dinner
953 hg book -m turkey dinner
958
954
959 - move the '@' bookmark from another branch::
955 - move the '@' bookmark from another branch::
960
956
961 hg book -f @
957 hg book -f @
962
958
963 - print only the active bookmark name::
959 - print only the active bookmark name::
964
960
965 hg book -ql .
961 hg book -ql .
966 '''
962 '''
967 opts = pycompat.byteskwargs(opts)
963 opts = pycompat.byteskwargs(opts)
968 force = opts.get('force')
964 force = opts.get('force')
969 rev = opts.get('rev')
965 rev = opts.get('rev')
970 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
966 inactive = opts.get('inactive') # meaning add/rename to inactive bookmark
971
967
972 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)]
973 if len(selactions) > 1:
969 if len(selactions) > 1:
974 raise error.Abort(_('--%s and --%s are incompatible')
970 raise error.Abort(_('--%s and --%s are incompatible')
975 % tuple(selactions[:2]))
971 % tuple(selactions[:2]))
976 if selactions:
972 if selactions:
977 action = selactions[0]
973 action = selactions[0]
978 elif names or rev:
974 elif names or rev:
979 action = 'add'
975 action = 'add'
980 elif inactive:
976 elif inactive:
981 action = 'inactive' # meaning deactivate
977 action = 'inactive' # meaning deactivate
982 else:
978 else:
983 action = 'list'
979 action = 'list'
984
980
985 if rev and action in {'delete', 'rename', 'list'}:
981 if rev and action in {'delete', 'rename', 'list'}:
986 raise error.Abort(_("--rev is incompatible with --%s") % action)
982 raise error.Abort(_("--rev is incompatible with --%s") % action)
987 if inactive and action in {'delete', 'list'}:
983 if inactive and action in {'delete', 'list'}:
988 raise error.Abort(_("--inactive is incompatible with --%s") % action)
984 raise error.Abort(_("--inactive is incompatible with --%s") % action)
989 if not names and action in {'add', 'delete'}:
985 if not names and action in {'add', 'delete'}:
990 raise error.Abort(_("bookmark name required"))
986 raise error.Abort(_("bookmark name required"))
991
987
992 if action in {'add', 'delete', 'rename', 'inactive'}:
988 if action in {'add', 'delete', 'rename', 'inactive'}:
993 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
989 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
994 if action == 'delete':
990 if action == 'delete':
995 names = pycompat.maplist(repo._bookmarks.expandname, names)
991 names = pycompat.maplist(repo._bookmarks.expandname, names)
996 bookmarks.delete(repo, tr, names)
992 bookmarks.delete(repo, tr, names)
997 elif action == 'rename':
993 elif action == 'rename':
998 if not names:
994 if not names:
999 raise error.Abort(_("new bookmark name required"))
995 raise error.Abort(_("new bookmark name required"))
1000 elif len(names) > 1:
996 elif len(names) > 1:
1001 raise error.Abort(_("only one new bookmark name allowed"))
997 raise error.Abort(_("only one new bookmark name allowed"))
1002 oldname = repo._bookmarks.expandname(opts['rename'])
998 oldname = repo._bookmarks.expandname(opts['rename'])
1003 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
999 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1004 elif action == 'add':
1000 elif action == 'add':
1005 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1001 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1006 elif action == 'inactive':
1002 elif action == 'inactive':
1007 if len(repo._bookmarks) == 0:
1003 if len(repo._bookmarks) == 0:
1008 ui.status(_("no bookmarks set\n"))
1004 ui.status(_("no bookmarks set\n"))
1009 elif not repo._activebookmark:
1005 elif not repo._activebookmark:
1010 ui.status(_("no active bookmark\n"))
1006 ui.status(_("no active bookmark\n"))
1011 else:
1007 else:
1012 bookmarks.deactivate(repo)
1008 bookmarks.deactivate(repo)
1013 elif action == 'list':
1009 elif action == 'list':
1014 names = pycompat.maplist(repo._bookmarks.expandname, names)
1010 names = pycompat.maplist(repo._bookmarks.expandname, names)
1015 with ui.formatter('bookmarks', opts) as fm:
1011 with ui.formatter('bookmarks', opts) as fm:
1016 bookmarks.printbookmarks(ui, repo, fm, names)
1012 bookmarks.printbookmarks(ui, repo, fm, names)
1017 else:
1013 else:
1018 raise error.ProgrammingError('invalid action: %s' % action)
1014 raise error.ProgrammingError('invalid action: %s' % action)
1019
1015
1020 @command('branch',
1016 @command('branch',
1021 [('f', 'force', None,
1017 [('f', 'force', None,
1022 _('set branch name even if it shadows an existing branch')),
1018 _('set branch name even if it shadows an existing branch')),
1023 ('C', 'clean', None, _('reset branch name to parent branch name')),
1019 ('C', 'clean', None, _('reset branch name to parent branch name')),
1024 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1020 ('r', 'rev', [], _('change branches of the given revs (EXPERIMENTAL)')),
1025 ],
1021 ],
1026 _('[-fC] [NAME]'))
1022 _('[-fC] [NAME]'))
1027 def branch(ui, repo, label=None, **opts):
1023 def branch(ui, repo, label=None, **opts):
1028 """set or show the current branch name
1024 """set or show the current branch name
1029
1025
1030 .. note::
1026 .. note::
1031
1027
1032 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
1033 light-weight bookmark instead. See :hg:`help glossary` for more
1029 light-weight bookmark instead. See :hg:`help glossary` for more
1034 information about named branches and bookmarks.
1030 information about named branches and bookmarks.
1035
1031
1036 With no argument, show the current branch name. With one argument,
1032 With no argument, show the current branch name. With one argument,
1037 set the working directory branch name (the branch will not exist
1033 set the working directory branch name (the branch will not exist
1038 in the repository until the next commit). Standard practice
1034 in the repository until the next commit). Standard practice
1039 recommends that primary development take place on the 'default'
1035 recommends that primary development take place on the 'default'
1040 branch.
1036 branch.
1041
1037
1042 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
1043 branch name that already exists.
1039 branch name that already exists.
1044
1040
1045 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
1046 the parent of the working directory, negating a previous branch
1042 the parent of the working directory, negating a previous branch
1047 change.
1043 change.
1048
1044
1049 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
1050 :hg:`commit --close-branch` to mark this branch head as closed.
1046 :hg:`commit --close-branch` to mark this branch head as closed.
1051 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
1052 considered closed.
1048 considered closed.
1053
1049
1054 Returns 0 on success.
1050 Returns 0 on success.
1055 """
1051 """
1056 opts = pycompat.byteskwargs(opts)
1052 opts = pycompat.byteskwargs(opts)
1057 revs = opts.get('rev')
1053 revs = opts.get('rev')
1058 if label:
1054 if label:
1059 label = label.strip()
1055 label = label.strip()
1060
1056
1061 if not opts.get('clean') and not label:
1057 if not opts.get('clean') and not label:
1062 if revs:
1058 if revs:
1063 raise error.Abort(_("no branch name specified for the revisions"))
1059 raise error.Abort(_("no branch name specified for the revisions"))
1064 ui.write("%s\n" % repo.dirstate.branch())
1060 ui.write("%s\n" % repo.dirstate.branch())
1065 return
1061 return
1066
1062
1067 with repo.wlock():
1063 with repo.wlock():
1068 if opts.get('clean'):
1064 if opts.get('clean'):
1069 label = repo[None].p1().branch()
1065 label = repo[None].p1().branch()
1070 repo.dirstate.setbranch(label)
1066 repo.dirstate.setbranch(label)
1071 ui.status(_('reset working directory to branch %s\n') % label)
1067 ui.status(_('reset working directory to branch %s\n') % label)
1072 elif label:
1068 elif label:
1073
1069
1074 scmutil.checknewlabel(repo, label, 'branch')
1070 scmutil.checknewlabel(repo, label, 'branch')
1075 if revs:
1071 if revs:
1076 return cmdutil.changebranch(ui, repo, revs, label)
1072 return cmdutil.changebranch(ui, repo, revs, label)
1077
1073
1078 if not opts.get('force') and label in repo.branchmap():
1074 if not opts.get('force') and label in repo.branchmap():
1079 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()]:
1080 raise error.Abort(_('a branch of the same name already'
1076 raise error.Abort(_('a branch of the same name already'
1081 ' exists'),
1077 ' exists'),
1082 # i18n: "it" refers to an existing branch
1078 # i18n: "it" refers to an existing branch
1083 hint=_("use 'hg update' to switch to it"))
1079 hint=_("use 'hg update' to switch to it"))
1084
1080
1085 repo.dirstate.setbranch(label)
1081 repo.dirstate.setbranch(label)
1086 ui.status(_('marked working directory as branch %s\n') % label)
1082 ui.status(_('marked working directory as branch %s\n') % label)
1087
1083
1088 # find any open named branches aside from default
1084 # find any open named branches aside from default
1089 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1085 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1090 if n != "default" and not c]
1086 if n != "default" and not c]
1091 if not others:
1087 if not others:
1092 ui.status(_('(branches are permanent and global, '
1088 ui.status(_('(branches are permanent and global, '
1093 'did you want a bookmark?)\n'))
1089 'did you want a bookmark?)\n'))
1094
1090
1095 @command('branches',
1091 @command('branches',
1096 [('a', 'active', False,
1092 [('a', 'active', False,
1097 _('show only branches that have unmerged heads (DEPRECATED)')),
1093 _('show only branches that have unmerged heads (DEPRECATED)')),
1098 ('c', 'closed', False, _('show normal and closed branches')),
1094 ('c', 'closed', False, _('show normal and closed branches')),
1099 ] + formatteropts,
1095 ] + formatteropts,
1100 _('[-c]'),
1096 _('[-c]'),
1101 intents={INTENT_READONLY})
1097 intents={INTENT_READONLY})
1102 def branches(ui, repo, active=False, closed=False, **opts):
1098 def branches(ui, repo, active=False, closed=False, **opts):
1103 """list repository named branches
1099 """list repository named branches
1104
1100
1105 List the repository's named branches, indicating which ones are
1101 List the repository's named branches, indicating which ones are
1106 inactive. If -c/--closed is specified, also list branches which have
1102 inactive. If -c/--closed is specified, also list branches which have
1107 been marked closed (see :hg:`commit --close-branch`).
1103 been marked closed (see :hg:`commit --close-branch`).
1108
1104
1109 Use the command :hg:`update` to switch to an existing branch.
1105 Use the command :hg:`update` to switch to an existing branch.
1110
1106
1111 Returns 0.
1107 Returns 0.
1112 """
1108 """
1113
1109
1114 opts = pycompat.byteskwargs(opts)
1110 opts = pycompat.byteskwargs(opts)
1115 ui.pager('branches')
1111 ui.pager('branches')
1116 fm = ui.formatter('branches', opts)
1112 fm = ui.formatter('branches', opts)
1117 hexfunc = fm.hexfunc
1113 hexfunc = fm.hexfunc
1118
1114
1119 allheads = set(repo.heads())
1115 allheads = set(repo.heads())
1120 branches = []
1116 branches = []
1121 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1117 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1122 isactive = False
1118 isactive = False
1123 if not isclosed:
1119 if not isclosed:
1124 openheads = set(repo.branchmap().iteropen(heads))
1120 openheads = set(repo.branchmap().iteropen(heads))
1125 isactive = bool(openheads & allheads)
1121 isactive = bool(openheads & allheads)
1126 branches.append((tag, repo[tip], isactive, not isclosed))
1122 branches.append((tag, repo[tip], isactive, not isclosed))
1127 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]),
1128 reverse=True)
1124 reverse=True)
1129
1125
1130 for tag, ctx, isactive, isopen in branches:
1126 for tag, ctx, isactive, isopen in branches:
1131 if active and not isactive:
1127 if active and not isactive:
1132 continue
1128 continue
1133 if isactive:
1129 if isactive:
1134 label = 'branches.active'
1130 label = 'branches.active'
1135 notice = ''
1131 notice = ''
1136 elif not isopen:
1132 elif not isopen:
1137 if not closed:
1133 if not closed:
1138 continue
1134 continue
1139 label = 'branches.closed'
1135 label = 'branches.closed'
1140 notice = _(' (closed)')
1136 notice = _(' (closed)')
1141 else:
1137 else:
1142 label = 'branches.inactive'
1138 label = 'branches.inactive'
1143 notice = _(' (inactive)')
1139 notice = _(' (inactive)')
1144 current = (tag == repo.dirstate.branch())
1140 current = (tag == repo.dirstate.branch())
1145 if current:
1141 if current:
1146 label = 'branches.current'
1142 label = 'branches.current'
1147
1143
1148 fm.startitem()
1144 fm.startitem()
1149 fm.write('branch', '%s', tag, label=label)
1145 fm.write('branch', '%s', tag, label=label)
1150 rev = ctx.rev()
1146 rev = ctx.rev()
1151 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1147 padsize = max(31 - len("%d" % rev) - encoding.colwidth(tag), 0)
1152 fmt = ' ' * padsize + ' %d:%s'
1148 fmt = ' ' * padsize + ' %d:%s'
1153 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()),
1154 label='log.changeset changeset.%s' % ctx.phasestr())
1150 label='log.changeset changeset.%s' % ctx.phasestr())
1155 fm.context(ctx=ctx)
1151 fm.context(ctx=ctx)
1156 fm.data(active=isactive, closed=not isopen, current=current)
1152 fm.data(active=isactive, closed=not isopen, current=current)
1157 if not ui.quiet:
1153 if not ui.quiet:
1158 fm.plain(notice)
1154 fm.plain(notice)
1159 fm.plain('\n')
1155 fm.plain('\n')
1160 fm.end()
1156 fm.end()
1161
1157
1162 @command('bundle',
1158 @command('bundle',
1163 [('f', 'force', None, _('run even when the destination is unrelated')),
1159 [('f', 'force', None, _('run even when the destination is unrelated')),
1164 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1160 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1165 _('REV')),
1161 _('REV')),
1166 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1162 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1167 _('BRANCH')),
1163 _('BRANCH')),
1168 ('', 'base', [],
1164 ('', 'base', [],
1169 _('a base changeset assumed to be available at the destination'),
1165 _('a base changeset assumed to be available at the destination'),
1170 _('REV')),
1166 _('REV')),
1171 ('a', 'all', None, _('bundle all changesets in the repository')),
1167 ('a', 'all', None, _('bundle all changesets in the repository')),
1172 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1168 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1173 ] + remoteopts,
1169 ] + remoteopts,
1174 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1170 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1175 def bundle(ui, repo, fname, dest=None, **opts):
1171 def bundle(ui, repo, fname, dest=None, **opts):
1176 """create a bundle file
1172 """create a bundle file
1177
1173
1178 Generate a bundle file containing data to be transferred to another
1174 Generate a bundle file containing data to be transferred to another
1179 repository.
1175 repository.
1180
1176
1181 To create a bundle containing all changesets, use -a/--all
1177 To create a bundle containing all changesets, use -a/--all
1182 (or --base null). Otherwise, hg assumes the destination will have
1178 (or --base null). Otherwise, hg assumes the destination will have
1183 all the nodes you specify with --base parameters. Otherwise, hg
1179 all the nodes you specify with --base parameters. Otherwise, hg
1184 will assume the repository has all the nodes in destination, or
1180 will assume the repository has all the nodes in destination, or
1185 default-push/default if no destination is specified, where destination
1181 default-push/default if no destination is specified, where destination
1186 is the repository you provide through DEST option.
1182 is the repository you provide through DEST option.
1187
1183
1188 You can change bundle format with the -t/--type option. See
1184 You can change bundle format with the -t/--type option. See
1189 :hg:`help bundlespec` for documentation on this format. By default,
1185 :hg:`help bundlespec` for documentation on this format. By default,
1190 the most appropriate format is used and compression defaults to
1186 the most appropriate format is used and compression defaults to
1191 bzip2.
1187 bzip2.
1192
1188
1193 The bundle file can then be transferred using conventional means
1189 The bundle file can then be transferred using conventional means
1194 and applied to another repository with the unbundle or pull
1190 and applied to another repository with the unbundle or pull
1195 command. This is useful when direct push and pull are not
1191 command. This is useful when direct push and pull are not
1196 available or when exporting an entire repository is undesirable.
1192 available or when exporting an entire repository is undesirable.
1197
1193
1198 Applying bundles preserves all changeset contents including
1194 Applying bundles preserves all changeset contents including
1199 permissions, copy/rename information, and revision history.
1195 permissions, copy/rename information, and revision history.
1200
1196
1201 Returns 0 on success, 1 if no changes found.
1197 Returns 0 on success, 1 if no changes found.
1202 """
1198 """
1203 opts = pycompat.byteskwargs(opts)
1199 opts = pycompat.byteskwargs(opts)
1204 revs = None
1200 revs = None
1205 if 'rev' in opts:
1201 if 'rev' in opts:
1206 revstrings = opts['rev']
1202 revstrings = opts['rev']
1207 revs = scmutil.revrange(repo, revstrings)
1203 revs = scmutil.revrange(repo, revstrings)
1208 if revstrings and not revs:
1204 if revstrings and not revs:
1209 raise error.Abort(_('no commits to bundle'))
1205 raise error.Abort(_('no commits to bundle'))
1210
1206
1211 bundletype = opts.get('type', 'bzip2').lower()
1207 bundletype = opts.get('type', 'bzip2').lower()
1212 try:
1208 try:
1213 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1209 bundlespec = exchange.parsebundlespec(repo, bundletype, strict=False)
1214 except error.UnsupportedBundleSpecification as e:
1210 except error.UnsupportedBundleSpecification as e:
1215 raise error.Abort(pycompat.bytestr(e),
1211 raise error.Abort(pycompat.bytestr(e),
1216 hint=_("see 'hg help bundlespec' for supported "
1212 hint=_("see 'hg help bundlespec' for supported "
1217 "values for --type"))
1213 "values for --type"))
1218 cgversion = bundlespec.contentopts["cg.version"]
1214 cgversion = bundlespec.contentopts["cg.version"]
1219
1215
1220 # Packed bundles are a pseudo bundle format for now.
1216 # Packed bundles are a pseudo bundle format for now.
1221 if cgversion == 's1':
1217 if cgversion == 's1':
1222 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1218 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1223 hint=_("use 'hg debugcreatestreamclonebundle'"))
1219 hint=_("use 'hg debugcreatestreamclonebundle'"))
1224
1220
1225 if opts.get('all'):
1221 if opts.get('all'):
1226 if dest:
1222 if dest:
1227 raise error.Abort(_("--all is incompatible with specifying "
1223 raise error.Abort(_("--all is incompatible with specifying "
1228 "a destination"))
1224 "a destination"))
1229 if opts.get('base'):
1225 if opts.get('base'):
1230 ui.warn(_("ignoring --base because --all was specified\n"))
1226 ui.warn(_("ignoring --base because --all was specified\n"))
1231 base = ['null']
1227 base = ['null']
1232 else:
1228 else:
1233 base = scmutil.revrange(repo, opts.get('base'))
1229 base = scmutil.revrange(repo, opts.get('base'))
1234 if cgversion not in changegroup.supportedoutgoingversions(repo):
1230 if cgversion not in changegroup.supportedoutgoingversions(repo):
1235 raise error.Abort(_("repository does not support bundle version %s") %
1231 raise error.Abort(_("repository does not support bundle version %s") %
1236 cgversion)
1232 cgversion)
1237
1233
1238 if base:
1234 if base:
1239 if dest:
1235 if dest:
1240 raise error.Abort(_("--base is incompatible with specifying "
1236 raise error.Abort(_("--base is incompatible with specifying "
1241 "a destination"))
1237 "a destination"))
1242 common = [repo[rev].node() for rev in base]
1238 common = [repo[rev].node() for rev in base]
1243 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
1244 outgoing = discovery.outgoing(repo, common, heads)
1240 outgoing = discovery.outgoing(repo, common, heads)
1245 else:
1241 else:
1246 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1242 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1247 dest, branches = hg.parseurl(dest, opts.get('branch'))
1243 dest, branches = hg.parseurl(dest, opts.get('branch'))
1248 other = hg.peer(repo, opts, dest)
1244 other = hg.peer(repo, opts, dest)
1249 revs = [repo[r].hex() for r in revs]
1245 revs = [repo[r].hex() for r in revs]
1250 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1246 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1251 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1247 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1252 outgoing = discovery.findcommonoutgoing(repo, other,
1248 outgoing = discovery.findcommonoutgoing(repo, other,
1253 onlyheads=heads,
1249 onlyheads=heads,
1254 force=opts.get('force'),
1250 force=opts.get('force'),
1255 portable=True)
1251 portable=True)
1256
1252
1257 if not outgoing.missing:
1253 if not outgoing.missing:
1258 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1254 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1259 return 1
1255 return 1
1260
1256
1261 if cgversion == '01': #bundle1
1257 if cgversion == '01': #bundle1
1262 bversion = 'HG10' + bundlespec.wirecompression
1258 bversion = 'HG10' + bundlespec.wirecompression
1263 bcompression = None
1259 bcompression = None
1264 elif cgversion in ('02', '03'):
1260 elif cgversion in ('02', '03'):
1265 bversion = 'HG20'
1261 bversion = 'HG20'
1266 bcompression = bundlespec.wirecompression
1262 bcompression = bundlespec.wirecompression
1267 else:
1263 else:
1268 raise error.ProgrammingError(
1264 raise error.ProgrammingError(
1269 'bundle: unexpected changegroup version %s' % cgversion)
1265 'bundle: unexpected changegroup version %s' % cgversion)
1270
1266
1271 # TODO compression options should be derived from bundlespec parsing.
1267 # TODO compression options should be derived from bundlespec parsing.
1272 # This is a temporary hack to allow adjusting bundle compression
1268 # This is a temporary hack to allow adjusting bundle compression
1273 # level without a) formalizing the bundlespec changes to declare it
1269 # level without a) formalizing the bundlespec changes to declare it
1274 # b) introducing a command flag.
1270 # b) introducing a command flag.
1275 compopts = {}
1271 compopts = {}
1276 complevel = ui.configint('experimental',
1272 complevel = ui.configint('experimental',
1277 'bundlecomplevel.' + bundlespec.compression)
1273 'bundlecomplevel.' + bundlespec.compression)
1278 if complevel is None:
1274 if complevel is None:
1279 complevel = ui.configint('experimental', 'bundlecomplevel')
1275 complevel = ui.configint('experimental', 'bundlecomplevel')
1280 if complevel is not None:
1276 if complevel is not None:
1281 compopts['level'] = complevel
1277 compopts['level'] = complevel
1282
1278
1283 # Allow overriding the bundling of obsmarker in phases through
1279 # Allow overriding the bundling of obsmarker in phases through
1284 # 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
1285 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1281 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1286 bundlespec.contentopts['obsolescence'] = True
1282 bundlespec.contentopts['obsolescence'] = True
1287 if repo.ui.configbool('experimental', 'bundle-phases'):
1283 if repo.ui.configbool('experimental', 'bundle-phases'):
1288 bundlespec.contentopts['phases'] = True
1284 bundlespec.contentopts['phases'] = True
1289
1285
1290 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1286 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1291 bundlespec.contentopts, compression=bcompression,
1287 bundlespec.contentopts, compression=bcompression,
1292 compopts=compopts)
1288 compopts=compopts)
1293
1289
1294 @command('cat',
1290 @command('cat',
1295 [('o', 'output', '',
1291 [('o', 'output', '',
1296 _('print output to file with formatted name'), _('FORMAT')),
1292 _('print output to file with formatted name'), _('FORMAT')),
1297 ('r', 'rev', '', _('print the given revision'), _('REV')),
1293 ('r', 'rev', '', _('print the given revision'), _('REV')),
1298 ('', 'decode', None, _('apply any matching decode filter')),
1294 ('', 'decode', None, _('apply any matching decode filter')),
1299 ] + walkopts + formatteropts,
1295 ] + walkopts + formatteropts,
1300 _('[OPTION]... FILE...'),
1296 _('[OPTION]... FILE...'),
1301 inferrepo=True,
1297 inferrepo=True,
1302 intents={INTENT_READONLY})
1298 intents={INTENT_READONLY})
1303 def cat(ui, repo, file1, *pats, **opts):
1299 def cat(ui, repo, file1, *pats, **opts):
1304 """output the current or given revision of files
1300 """output the current or given revision of files
1305
1301
1306 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
1307 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.
1308
1304
1309 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
1310 given using a template string. See :hg:`help templates`. In addition
1306 given using a template string. See :hg:`help templates`. In addition
1311 to the common template keywords, the following formatting rules are
1307 to the common template keywords, the following formatting rules are
1312 supported:
1308 supported:
1313
1309
1314 :``%%``: literal "%" character
1310 :``%%``: literal "%" character
1315 :``%s``: basename of file being printed
1311 :``%s``: basename of file being printed
1316 :``%d``: dirname of file being printed, or '.' if in repository root
1312 :``%d``: dirname of file being printed, or '.' if in repository root
1317 :``%p``: root-relative path name of file being printed
1313 :``%p``: root-relative path name of file being printed
1318 :``%H``: changeset hash (40 hexadecimal digits)
1314 :``%H``: changeset hash (40 hexadecimal digits)
1319 :``%R``: changeset revision number
1315 :``%R``: changeset revision number
1320 :``%h``: short-form changeset hash (12 hexadecimal digits)
1316 :``%h``: short-form changeset hash (12 hexadecimal digits)
1321 :``%r``: zero-padded changeset revision number
1317 :``%r``: zero-padded changeset revision number
1322 :``%b``: basename of the exporting repository
1318 :``%b``: basename of the exporting repository
1323 :``\\``: literal "\\" character
1319 :``\\``: literal "\\" character
1324
1320
1325 Returns 0 on success.
1321 Returns 0 on success.
1326 """
1322 """
1327 opts = pycompat.byteskwargs(opts)
1323 opts = pycompat.byteskwargs(opts)
1328 rev = opts.get('rev')
1324 rev = opts.get('rev')
1329 if rev:
1325 if rev:
1330 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1326 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
1331 ctx = scmutil.revsingle(repo, rev)
1327 ctx = scmutil.revsingle(repo, rev)
1332 m = scmutil.match(ctx, (file1,) + pats, opts)
1328 m = scmutil.match(ctx, (file1,) + pats, opts)
1333 fntemplate = opts.pop('output', '')
1329 fntemplate = opts.pop('output', '')
1334 if cmdutil.isstdiofilename(fntemplate):
1330 if cmdutil.isstdiofilename(fntemplate):
1335 fntemplate = ''
1331 fntemplate = ''
1336
1332
1337 if fntemplate:
1333 if fntemplate:
1338 fm = formatter.nullformatter(ui, 'cat', opts)
1334 fm = formatter.nullformatter(ui, 'cat', opts)
1339 else:
1335 else:
1340 ui.pager('cat')
1336 ui.pager('cat')
1341 fm = ui.formatter('cat', opts)
1337 fm = ui.formatter('cat', opts)
1342 with fm:
1338 with fm:
1343 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1339 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '',
1344 **pycompat.strkwargs(opts))
1340 **pycompat.strkwargs(opts))
1345
1341
1346 @command('^clone',
1342 @command('^clone',
1347 [('U', 'noupdate', None, _('the clone will include an empty working '
1343 [('U', 'noupdate', None, _('the clone will include an empty working '
1348 'directory (only a repository)')),
1344 'directory (only a repository)')),
1349 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1345 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1350 _('REV')),
1346 _('REV')),
1351 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1347 ('r', 'rev', [], _('do not clone everything, but include this changeset'
1352 ' and its ancestors'), _('REV')),
1348 ' and its ancestors'), _('REV')),
1353 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1349 ('b', 'branch', [], _('do not clone everything, but include this branch\'s'
1354 ' changesets and their ancestors'), _('BRANCH')),
1350 ' changesets and their ancestors'), _('BRANCH')),
1355 ('', 'pull', None, _('use pull protocol to copy metadata')),
1351 ('', 'pull', None, _('use pull protocol to copy metadata')),
1356 ('', 'uncompressed', None,
1352 ('', 'uncompressed', None,
1357 _('an alias to --stream (DEPRECATED)')),
1353 _('an alias to --stream (DEPRECATED)')),
1358 ('', 'stream', None,
1354 ('', 'stream', None,
1359 _('clone with minimal data processing')),
1355 _('clone with minimal data processing')),
1360 ] + remoteopts,
1356 ] + remoteopts,
1361 _('[OPTION]... SOURCE [DEST]'),
1357 _('[OPTION]... SOURCE [DEST]'),
1362 norepo=True)
1358 norepo=True)
1363 def clone(ui, source, dest=None, **opts):
1359 def clone(ui, source, dest=None, **opts):
1364 """make a copy of an existing repository
1360 """make a copy of an existing repository
1365
1361
1366 Create a copy of an existing repository in a new directory.
1362 Create a copy of an existing repository in a new directory.
1367
1363
1368 If no destination directory name is specified, it defaults to the
1364 If no destination directory name is specified, it defaults to the
1369 basename of the source.
1365 basename of the source.
1370
1366
1371 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
1372 ``.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.
1373
1369
1374 Only local paths and ``ssh://`` URLs are supported as
1370 Only local paths and ``ssh://`` URLs are supported as
1375 destinations. For ``ssh://`` destinations, no working directory or
1371 destinations. For ``ssh://`` destinations, no working directory or
1376 ``.hg/hgrc`` will be created on the remote side.
1372 ``.hg/hgrc`` will be created on the remote side.
1377
1373
1378 If the source repository has a bookmark called '@' set, that
1374 If the source repository has a bookmark called '@' set, that
1379 revision will be checked out in the new repository by default.
1375 revision will be checked out in the new repository by default.
1380
1376
1381 To check out a particular version, use -u/--update, or
1377 To check out a particular version, use -u/--update, or
1382 -U/--noupdate to create a clone with no working directory.
1378 -U/--noupdate to create a clone with no working directory.
1383
1379
1384 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
1385 identifiers with -r/--rev or branches with -b/--branch. The
1381 identifiers with -r/--rev or branches with -b/--branch. The
1386 resulting clone will contain only the specified changesets and
1382 resulting clone will contain only the specified changesets and
1387 their ancestors. These options (or 'clone src#rev dest') imply
1383 their ancestors. These options (or 'clone src#rev dest') imply
1388 --pull, even for local source repositories.
1384 --pull, even for local source repositories.
1389
1385
1390 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
1391 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
1392 storage format. --stream activates a different clone mode that essentially
1388 storage format. --stream activates a different clone mode that essentially
1393 copies repository files from the remote with minimal data processing. This
1389 copies repository files from the remote with minimal data processing. This
1394 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.
1395 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
1396 result in substantially faster clones where I/O throughput is plentiful,
1392 result in substantially faster clones where I/O throughput is plentiful,
1397 especially for larger repositories. A side-effect of --stream clones is
1393 especially for larger repositories. A side-effect of --stream clones is
1398 that storage settings and requirements on the remote are applied locally:
1394 that storage settings and requirements on the remote are applied locally:
1399 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
1400 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
1401 modern Mercurial remote.
1397 modern Mercurial remote.
1402
1398
1403 .. note::
1399 .. note::
1404
1400
1405 Specifying a tag will include the tagged changeset but not the
1401 Specifying a tag will include the tagged changeset but not the
1406 changeset containing the tag.
1402 changeset containing the tag.
1407
1403
1408 .. container:: verbose
1404 .. container:: verbose
1409
1405
1410 For efficiency, hardlinks are used for cloning whenever the
1406 For efficiency, hardlinks are used for cloning whenever the
1411 source and destination are on the same filesystem (note this
1407 source and destination are on the same filesystem (note this
1412 applies only to the repository data, not to the working
1408 applies only to the repository data, not to the working
1413 directory). Some filesystems, such as AFS, implement hardlinking
1409 directory). Some filesystems, such as AFS, implement hardlinking
1414 incorrectly, but do not report errors. In these cases, use the
1410 incorrectly, but do not report errors. In these cases, use the
1415 --pull option to avoid hardlinking.
1411 --pull option to avoid hardlinking.
1416
1412
1417 Mercurial will update the working directory to the first applicable
1413 Mercurial will update the working directory to the first applicable
1418 revision from this list:
1414 revision from this list:
1419
1415
1420 a) null if -U or the source repository has no changesets
1416 a) null if -U or the source repository has no changesets
1421 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
1422 the source repository's working directory
1418 the source repository's working directory
1423 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
1424 latest head of that branch)
1420 latest head of that branch)
1425 d) the changeset specified with -r
1421 d) the changeset specified with -r
1426 e) the tipmost head specified with -b
1422 e) the tipmost head specified with -b
1427 f) the tipmost head specified with the url#branch source syntax
1423 f) the tipmost head specified with the url#branch source syntax
1428 g) the revision marked with the '@' bookmark, if present
1424 g) the revision marked with the '@' bookmark, if present
1429 h) the tipmost head of the default branch
1425 h) the tipmost head of the default branch
1430 i) tip
1426 i) tip
1431
1427
1432 When cloning from servers that support it, Mercurial may fetch
1428 When cloning from servers that support it, Mercurial may fetch
1433 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
1434 same stream. When this is done, hooks operating on incoming changesets
1430 same stream. When this is done, hooks operating on incoming changesets
1435 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
1436 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,
1437 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
1438 clone. This behavior may change in future releases.
1434 clone. This behavior may change in future releases.
1439 See :hg:`help -e clonebundles` for more.
1435 See :hg:`help -e clonebundles` for more.
1440
1436
1441 Examples:
1437 Examples:
1442
1438
1443 - clone a remote repository to a new directory named hg/::
1439 - clone a remote repository to a new directory named hg/::
1444
1440
1445 hg clone https://www.mercurial-scm.org/repo/hg/
1441 hg clone https://www.mercurial-scm.org/repo/hg/
1446
1442
1447 - create a lightweight local clone::
1443 - create a lightweight local clone::
1448
1444
1449 hg clone project/ project-feature/
1445 hg clone project/ project-feature/
1450
1446
1451 - 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)::
1452
1448
1453 hg clone ssh://user@server//home/projects/alpha/
1449 hg clone ssh://user@server//home/projects/alpha/
1454
1450
1455 - do a streaming clone while checking out a specified version::
1451 - do a streaming clone while checking out a specified version::
1456
1452
1457 hg clone --stream http://server/repo -u 1.5
1453 hg clone --stream http://server/repo -u 1.5
1458
1454
1459 - create a repository without changesets after a particular revision::
1455 - create a repository without changesets after a particular revision::
1460
1456
1461 hg clone -r 04e544 experimental/ good/
1457 hg clone -r 04e544 experimental/ good/
1462
1458
1463 - clone (and track) a particular named branch::
1459 - clone (and track) a particular named branch::
1464
1460
1465 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1461 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1466
1462
1467 See :hg:`help urls` for details on specifying URLs.
1463 See :hg:`help urls` for details on specifying URLs.
1468
1464
1469 Returns 0 on success.
1465 Returns 0 on success.
1470 """
1466 """
1471 opts = pycompat.byteskwargs(opts)
1467 opts = pycompat.byteskwargs(opts)
1472 if opts.get('noupdate') and opts.get('updaterev'):
1468 if opts.get('noupdate') and opts.get('updaterev'):
1473 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1469 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1474
1470
1475 # --include/--exclude can come from narrow or sparse.
1471 # --include/--exclude can come from narrow or sparse.
1476 includepats, excludepats = None, None
1472 includepats, excludepats = None, None
1477
1473
1478 # 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
1479 # patterns are sets if narrow is requested without patterns.
1475 # patterns are sets if narrow is requested without patterns.
1480 if opts.get('narrow'):
1476 if opts.get('narrow'):
1481 includepats = set()
1477 includepats = set()
1482 excludepats = set()
1478 excludepats = set()
1483
1479
1484 if opts.get('include'):
1480 if opts.get('include'):
1485 includepats = narrowspec.parsepatterns(opts.get('include'))
1481 includepats = narrowspec.parsepatterns(opts.get('include'))
1486 if opts.get('exclude'):
1482 if opts.get('exclude'):
1487 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1483 excludepats = narrowspec.parsepatterns(opts.get('exclude'))
1488
1484
1489 r = hg.clone(ui, opts, source, dest,
1485 r = hg.clone(ui, opts, source, dest,
1490 pull=opts.get('pull'),
1486 pull=opts.get('pull'),
1491 stream=opts.get('stream') or opts.get('uncompressed'),
1487 stream=opts.get('stream') or opts.get('uncompressed'),
1492 revs=opts.get('rev'),
1488 revs=opts.get('rev'),
1493 update=opts.get('updaterev') or not opts.get('noupdate'),
1489 update=opts.get('updaterev') or not opts.get('noupdate'),
1494 branch=opts.get('branch'),
1490 branch=opts.get('branch'),
1495 shareopts=opts.get('shareopts'),
1491 shareopts=opts.get('shareopts'),
1496 storeincludepats=includepats,
1492 storeincludepats=includepats,
1497 storeexcludepats=excludepats)
1493 storeexcludepats=excludepats)
1498
1494
1499 return r is None
1495 return r is None
1500
1496
1501 @command('^commit|ci',
1497 @command('^commit|ci',
1502 [('A', 'addremove', None,
1498 [('A', 'addremove', None,
1503 _('mark new/missing files as added/removed before committing')),
1499 _('mark new/missing files as added/removed before committing')),
1504 ('', 'close-branch', None,
1500 ('', 'close-branch', None,
1505 _('mark a branch head as closed')),
1501 _('mark a branch head as closed')),
1506 ('', 'amend', None, _('amend the parent of the working directory')),
1502 ('', 'amend', None, _('amend the parent of the working directory')),
1507 ('s', 'secret', None, _('use the secret phase for committing')),
1503 ('s', 'secret', None, _('use the secret phase for committing')),
1508 ('e', 'edit', None, _('invoke editor on commit messages')),
1504 ('e', 'edit', None, _('invoke editor on commit messages')),
1509 ('i', 'interactive', None, _('use interactive mode')),
1505 ('i', 'interactive', None, _('use interactive mode')),
1510 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1506 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1511 _('[OPTION]... [FILE]...'),
1507 _('[OPTION]... [FILE]...'),
1512 inferrepo=True)
1508 inferrepo=True)
1513 def commit(ui, repo, *pats, **opts):
1509 def commit(ui, repo, *pats, **opts):
1514 """commit the specified files or all outstanding changes
1510 """commit the specified files or all outstanding changes
1515
1511
1516 Commit changes to the given files into the repository. Unlike a
1512 Commit changes to the given files into the repository. Unlike a
1517 centralized SCM, this operation is a local operation. See
1513 centralized SCM, this operation is a local operation. See
1518 :hg:`push` for a way to actively distribute your changes.
1514 :hg:`push` for a way to actively distribute your changes.
1519
1515
1520 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`
1521 will be committed.
1517 will be committed.
1522
1518
1523 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
1524 filenames or -I/-X filters.
1520 filenames or -I/-X filters.
1525
1521
1526 If no commit message is specified, Mercurial starts your
1522 If no commit message is specified, Mercurial starts your
1527 configured editor where you can enter a message. In case your
1523 configured editor where you can enter a message. In case your
1528 commit fails, you will find a backup of your message in
1524 commit fails, you will find a backup of your message in
1529 ``.hg/last-message.txt``.
1525 ``.hg/last-message.txt``.
1530
1526
1531 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
1532 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
1533 will be considered closed and no longer listed.
1529 will be considered closed and no longer listed.
1534
1530
1535 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
1536 working directory with a new commit that contains the changes
1532 working directory with a new commit that contains the changes
1537 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`,
1538 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
1539 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1535 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1540 on how to restore it).
1536 on how to restore it).
1541
1537
1542 Message, user and date are taken from the amended commit unless
1538 Message, user and date are taken from the amended commit unless
1543 specified. When a message isn't specified on the command line,
1539 specified. When a message isn't specified on the command line,
1544 the editor will open with the message of the amended commit.
1540 the editor will open with the message of the amended commit.
1545
1541
1546 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`)
1547 or changesets that have children.
1543 or changesets that have children.
1548
1544
1549 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.
1550
1546
1551 Returns 0 on success, 1 if nothing changed.
1547 Returns 0 on success, 1 if nothing changed.
1552
1548
1553 .. container:: verbose
1549 .. container:: verbose
1554
1550
1555 Examples:
1551 Examples:
1556
1552
1557 - commit all files ending in .py::
1553 - commit all files ending in .py::
1558
1554
1559 hg commit --include "set:**.py"
1555 hg commit --include "set:**.py"
1560
1556
1561 - commit all non-binary files::
1557 - commit all non-binary files::
1562
1558
1563 hg commit --exclude "set:binary()"
1559 hg commit --exclude "set:binary()"
1564
1560
1565 - amend the current commit and set the date to now::
1561 - amend the current commit and set the date to now::
1566
1562
1567 hg commit --amend --date now
1563 hg commit --amend --date now
1568 """
1564 """
1569 with repo.wlock(), repo.lock():
1565 with repo.wlock(), repo.lock():
1570 return _docommit(ui, repo, *pats, **opts)
1566 return _docommit(ui, repo, *pats, **opts)
1571
1567
1572 def _docommit(ui, repo, *pats, **opts):
1568 def _docommit(ui, repo, *pats, **opts):
1573 if opts.get(r'interactive'):
1569 if opts.get(r'interactive'):
1574 opts.pop(r'interactive')
1570 opts.pop(r'interactive')
1575 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1571 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1576 cmdutil.recordfilter, *pats,
1572 cmdutil.recordfilter, *pats,
1577 **opts)
1573 **opts)
1578 # 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
1579 # commit(), 1 if nothing changed or None on success.
1575 # commit(), 1 if nothing changed or None on success.
1580 return 1 if ret == 0 else ret
1576 return 1 if ret == 0 else ret
1581
1577
1582 opts = pycompat.byteskwargs(opts)
1578 opts = pycompat.byteskwargs(opts)
1583 if opts.get('subrepos'):
1579 if opts.get('subrepos'):
1584 if opts.get('amend'):
1580 if opts.get('amend'):
1585 raise error.Abort(_('cannot amend with --subrepos'))
1581 raise error.Abort(_('cannot amend with --subrepos'))
1586 # Let --subrepos on the command line override config setting.
1582 # Let --subrepos on the command line override config setting.
1587 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1583 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1588
1584
1589 cmdutil.checkunfinished(repo, commit=True)
1585 cmdutil.checkunfinished(repo, commit=True)
1590
1586
1591 branch = repo[None].branch()
1587 branch = repo[None].branch()
1592 bheads = repo.branchheads(branch)
1588 bheads = repo.branchheads(branch)
1593
1589
1594 extra = {}
1590 extra = {}
1595 if opts.get('close_branch'):
1591 if opts.get('close_branch'):
1596 extra['close'] = '1'
1592 extra['close'] = '1'
1597
1593
1598 if not bheads:
1594 if not bheads:
1599 raise error.Abort(_('can only close branch heads'))
1595 raise error.Abort(_('can only close branch heads'))
1600 elif opts.get('amend'):
1596 elif opts.get('amend'):
1601 if repo[None].parents()[0].p1().branch() != branch and \
1597 if repo[None].parents()[0].p1().branch() != branch and \
1602 repo[None].parents()[0].p2().branch() != branch:
1598 repo[None].parents()[0].p2().branch() != branch:
1603 raise error.Abort(_('can only close branch heads'))
1599 raise error.Abort(_('can only close branch heads'))
1604
1600
1605 if opts.get('amend'):
1601 if opts.get('amend'):
1606 if ui.configbool('ui', 'commitsubrepos'):
1602 if ui.configbool('ui', 'commitsubrepos'):
1607 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1603 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1608
1604
1609 old = repo['.']
1605 old = repo['.']
1610 rewriteutil.precheck(repo, [old.rev()], 'amend')
1606 rewriteutil.precheck(repo, [old.rev()], 'amend')
1611
1607
1612 # Currently histedit gets confused if an amend happens while histedit
1608 # Currently histedit gets confused if an amend happens while histedit
1613 # is in progress. Since we have a checkunfinished command, we are
1609 # is in progress. Since we have a checkunfinished command, we are
1614 # temporarily honoring it.
1610 # temporarily honoring it.
1615 #
1611 #
1616 # Note: eventually this guard will be removed. Please do not expect
1612 # Note: eventually this guard will be removed. Please do not expect
1617 # this behavior to remain.
1613 # this behavior to remain.
1618 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1614 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1619 cmdutil.checkunfinished(repo)
1615 cmdutil.checkunfinished(repo)
1620
1616
1621 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1617 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1622 if node == old.node():
1618 if node == old.node():
1623 ui.status(_("nothing changed\n"))
1619 ui.status(_("nothing changed\n"))
1624 return 1
1620 return 1
1625 else:
1621 else:
1626 def commitfunc(ui, repo, message, match, opts):
1622 def commitfunc(ui, repo, message, match, opts):
1627 overrides = {}
1623 overrides = {}
1628 if opts.get('secret'):
1624 if opts.get('secret'):
1629 overrides[('phases', 'new-commit')] = 'secret'
1625 overrides[('phases', 'new-commit')] = 'secret'
1630
1626
1631 baseui = repo.baseui
1627 baseui = repo.baseui
1632 with baseui.configoverride(overrides, 'commit'):
1628 with baseui.configoverride(overrides, 'commit'):
1633 with ui.configoverride(overrides, 'commit'):
1629 with ui.configoverride(overrides, 'commit'):
1634 editform = cmdutil.mergeeditform(repo[None],
1630 editform = cmdutil.mergeeditform(repo[None],
1635 'commit.normal')
1631 'commit.normal')
1636 editor = cmdutil.getcommiteditor(
1632 editor = cmdutil.getcommiteditor(
1637 editform=editform, **pycompat.strkwargs(opts))
1633 editform=editform, **pycompat.strkwargs(opts))
1638 return repo.commit(message,
1634 return repo.commit(message,
1639 opts.get('user'),
1635 opts.get('user'),
1640 opts.get('date'),
1636 opts.get('date'),
1641 match,
1637 match,
1642 editor=editor,
1638 editor=editor,
1643 extra=extra)
1639 extra=extra)
1644
1640
1645 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1641 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1646
1642
1647 if not node:
1643 if not node:
1648 stat = cmdutil.postcommitstatus(repo, pats, opts)
1644 stat = cmdutil.postcommitstatus(repo, pats, opts)
1649 if stat[3]:
1645 if stat[3]:
1650 ui.status(_("nothing changed (%d missing files, see "
1646 ui.status(_("nothing changed (%d missing files, see "
1651 "'hg status')\n") % len(stat[3]))
1647 "'hg status')\n") % len(stat[3]))
1652 else:
1648 else:
1653 ui.status(_("nothing changed\n"))
1649 ui.status(_("nothing changed\n"))
1654 return 1
1650 return 1
1655
1651
1656 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1652 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1657
1653
1658 @command('config|showconfig|debugconfig',
1654 @command('config|showconfig|debugconfig',
1659 [('u', 'untrusted', None, _('show untrusted configuration options')),
1655 [('u', 'untrusted', None, _('show untrusted configuration options')),
1660 ('e', 'edit', None, _('edit user config')),
1656 ('e', 'edit', None, _('edit user config')),
1661 ('l', 'local', None, _('edit repository config')),
1657 ('l', 'local', None, _('edit repository config')),
1662 ('g', 'global', None, _('edit global config'))] + formatteropts,
1658 ('g', 'global', None, _('edit global config'))] + formatteropts,
1663 _('[-u] [NAME]...'),
1659 _('[-u] [NAME]...'),
1664 optionalrepo=True,
1660 optionalrepo=True,
1665 intents={INTENT_READONLY})
1661 intents={INTENT_READONLY})
1666 def config(ui, repo, *values, **opts):
1662 def config(ui, repo, *values, **opts):
1667 """show combined config settings from all hgrc files
1663 """show combined config settings from all hgrc files
1668
1664
1669 With no arguments, print names and values of all config items.
1665 With no arguments, print names and values of all config items.
1670
1666
1671 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
1672 of that config item.
1668 of that config item.
1673
1669
1674 With multiple arguments, print names and values of all config
1670 With multiple arguments, print names and values of all config
1675 items with matching section names or section.names.
1671 items with matching section names or section.names.
1676
1672
1677 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
1678 --global, edit the system-wide config file. With --local, edit the
1674 --global, edit the system-wide config file. With --local, edit the
1679 repository-level config file.
1675 repository-level config file.
1680
1676
1681 With --debug, the source (filename and line number) is printed
1677 With --debug, the source (filename and line number) is printed
1682 for each config item.
1678 for each config item.
1683
1679
1684 See :hg:`help config` for more information about config files.
1680 See :hg:`help config` for more information about config files.
1685
1681
1686 Returns 0 on success, 1 if NAME does not exist.
1682 Returns 0 on success, 1 if NAME does not exist.
1687
1683
1688 """
1684 """
1689
1685
1690 opts = pycompat.byteskwargs(opts)
1686 opts = pycompat.byteskwargs(opts)
1691 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'):
1692 if opts.get('local') and opts.get('global'):
1688 if opts.get('local') and opts.get('global'):
1693 raise error.Abort(_("can't use --local and --global together"))
1689 raise error.Abort(_("can't use --local and --global together"))
1694
1690
1695 if opts.get('local'):
1691 if opts.get('local'):
1696 if not repo:
1692 if not repo:
1697 raise error.Abort(_("can't use --local outside a repository"))
1693 raise error.Abort(_("can't use --local outside a repository"))
1698 paths = [repo.vfs.join('hgrc')]
1694 paths = [repo.vfs.join('hgrc')]
1699 elif opts.get('global'):
1695 elif opts.get('global'):
1700 paths = rcutil.systemrcpath()
1696 paths = rcutil.systemrcpath()
1701 else:
1697 else:
1702 paths = rcutil.userrcpath()
1698 paths = rcutil.userrcpath()
1703
1699
1704 for f in paths:
1700 for f in paths:
1705 if os.path.exists(f):
1701 if os.path.exists(f):
1706 break
1702 break
1707 else:
1703 else:
1708 if opts.get('global'):
1704 if opts.get('global'):
1709 samplehgrc = uimod.samplehgrcs['global']
1705 samplehgrc = uimod.samplehgrcs['global']
1710 elif opts.get('local'):
1706 elif opts.get('local'):
1711 samplehgrc = uimod.samplehgrcs['local']
1707 samplehgrc = uimod.samplehgrcs['local']
1712 else:
1708 else:
1713 samplehgrc = uimod.samplehgrcs['user']
1709 samplehgrc = uimod.samplehgrcs['user']
1714
1710
1715 f = paths[0]
1711 f = paths[0]
1716 fp = open(f, "wb")
1712 fp = open(f, "wb")
1717 fp.write(util.tonativeeol(samplehgrc))
1713 fp.write(util.tonativeeol(samplehgrc))
1718 fp.close()
1714 fp.close()
1719
1715
1720 editor = ui.geteditor()
1716 editor = ui.geteditor()
1721 ui.system("%s \"%s\"" % (editor, f),
1717 ui.system("%s \"%s\"" % (editor, f),
1722 onerr=error.Abort, errprefix=_("edit failed"),
1718 onerr=error.Abort, errprefix=_("edit failed"),
1723 blockedtag='config_edit')
1719 blockedtag='config_edit')
1724 return
1720 return
1725 ui.pager('config')
1721 ui.pager('config')
1726 fm = ui.formatter('config', opts)
1722 fm = ui.formatter('config', opts)
1727 for t, f in rcutil.rccomponents():
1723 for t, f in rcutil.rccomponents():
1728 if t == 'path':
1724 if t == 'path':
1729 ui.debug('read config from: %s\n' % f)
1725 ui.debug('read config from: %s\n' % f)
1730 elif t == 'items':
1726 elif t == 'items':
1731 for section, name, value, source in f:
1727 for section, name, value, source in f:
1732 ui.debug('set config by: %s\n' % source)
1728 ui.debug('set config by: %s\n' % source)
1733 else:
1729 else:
1734 raise error.ProgrammingError('unknown rctype: %s' % t)
1730 raise error.ProgrammingError('unknown rctype: %s' % t)
1735 untrusted = bool(opts.get('untrusted'))
1731 untrusted = bool(opts.get('untrusted'))
1736
1732
1737 selsections = selentries = []
1733 selsections = selentries = []
1738 if values:
1734 if values:
1739 selsections = [v for v in values if '.' not in v]
1735 selsections = [v for v in values if '.' not in v]
1740 selentries = [v for v in values if '.' in v]
1736 selentries = [v for v in values if '.' in v]
1741 uniquesel = (len(selentries) == 1 and not selsections)
1737 uniquesel = (len(selentries) == 1 and not selsections)
1742 selsections = set(selsections)
1738 selsections = set(selsections)
1743 selentries = set(selentries)
1739 selentries = set(selentries)
1744
1740
1745 matched = False
1741 matched = False
1746 for section, name, value in ui.walkconfig(untrusted=untrusted):
1742 for section, name, value in ui.walkconfig(untrusted=untrusted):
1747 source = ui.configsource(section, name, untrusted)
1743 source = ui.configsource(section, name, untrusted)
1748 value = pycompat.bytestr(value)
1744 value = pycompat.bytestr(value)
1749 if fm.isplain():
1745 if fm.isplain():
1750 source = source or 'none'
1746 source = source or 'none'
1751 value = value.replace('\n', '\\n')
1747 value = value.replace('\n', '\\n')
1752 entryname = section + '.' + name
1748 entryname = section + '.' + name
1753 if values and not (section in selsections or entryname in selentries):
1749 if values and not (section in selsections or entryname in selentries):
1754 continue
1750 continue
1755 fm.startitem()
1751 fm.startitem()
1756 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1752 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1757 if uniquesel:
1753 if uniquesel:
1758 fm.data(name=entryname)
1754 fm.data(name=entryname)
1759 fm.write('value', '%s\n', value)
1755 fm.write('value', '%s\n', value)
1760 else:
1756 else:
1761 fm.write('name value', '%s=%s\n', entryname, value)
1757 fm.write('name value', '%s=%s\n', entryname, value)
1762 matched = True
1758 matched = True
1763 fm.end()
1759 fm.end()
1764 if matched:
1760 if matched:
1765 return 0
1761 return 0
1766 return 1
1762 return 1
1767
1763
1768 @command('copy|cp',
1764 @command('copy|cp',
1769 [('A', 'after', None, _('record a copy that has already occurred')),
1765 [('A', 'after', None, _('record a copy that has already occurred')),
1770 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1766 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1771 ] + walkopts + dryrunopts,
1767 ] + walkopts + dryrunopts,
1772 _('[OPTION]... [SOURCE]... DEST'))
1768 _('[OPTION]... [SOURCE]... DEST'))
1773 def copy(ui, repo, *pats, **opts):
1769 def copy(ui, repo, *pats, **opts):
1774 """mark files as copied for the next commit
1770 """mark files as copied for the next commit
1775
1771
1776 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
1777 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,
1778 the source must be a single file.
1774 the source must be a single file.
1779
1775
1780 By default, this command copies the contents of files as they
1776 By default, this command copies the contents of files as they
1781 exist in the working directory. If invoked with -A/--after, the
1777 exist in the working directory. If invoked with -A/--after, the
1782 operation is recorded, but no copying is performed.
1778 operation is recorded, but no copying is performed.
1783
1779
1784 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
1785 before that, see :hg:`revert`.
1781 before that, see :hg:`revert`.
1786
1782
1787 Returns 0 on success, 1 if errors are encountered.
1783 Returns 0 on success, 1 if errors are encountered.
1788 """
1784 """
1789 opts = pycompat.byteskwargs(opts)
1785 opts = pycompat.byteskwargs(opts)
1790 with repo.wlock(False):
1786 with repo.wlock(False):
1791 return cmdutil.copy(ui, repo, pats, opts)
1787 return cmdutil.copy(ui, repo, pats, opts)
1792
1788
1793 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1789 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1794 def debugcommands(ui, cmd='', *args):
1790 def debugcommands(ui, cmd='', *args):
1795 """list all available commands and options"""
1791 """list all available commands and options"""
1796 for cmd, vals in sorted(table.iteritems()):
1792 for cmd, vals in sorted(table.iteritems()):
1797 cmd = cmd.split('|')[0].strip('^')
1793 cmd = cmd.split('|')[0].strip('^')
1798 opts = ', '.join([i[1] for i in vals[1]])
1794 opts = ', '.join([i[1] for i in vals[1]])
1799 ui.write('%s: %s\n' % (cmd, opts))
1795 ui.write('%s: %s\n' % (cmd, opts))
1800
1796
1801 @command('debugcomplete',
1797 @command('debugcomplete',
1802 [('o', 'options', None, _('show the command options'))],
1798 [('o', 'options', None, _('show the command options'))],
1803 _('[-o] CMD'),
1799 _('[-o] CMD'),
1804 norepo=True)
1800 norepo=True)
1805 def debugcomplete(ui, cmd='', **opts):
1801 def debugcomplete(ui, cmd='', **opts):
1806 """returns the completion list associated with the given command"""
1802 """returns the completion list associated with the given command"""
1807
1803
1808 if opts.get(r'options'):
1804 if opts.get(r'options'):
1809 options = []
1805 options = []
1810 otables = [globalopts]
1806 otables = [globalopts]
1811 if cmd:
1807 if cmd:
1812 aliases, entry = cmdutil.findcmd(cmd, table, False)
1808 aliases, entry = cmdutil.findcmd(cmd, table, False)
1813 otables.append(entry[1])
1809 otables.append(entry[1])
1814 for t in otables:
1810 for t in otables:
1815 for o in t:
1811 for o in t:
1816 if "(DEPRECATED)" in o[3]:
1812 if "(DEPRECATED)" in o[3]:
1817 continue
1813 continue
1818 if o[0]:
1814 if o[0]:
1819 options.append('-%s' % o[0])
1815 options.append('-%s' % o[0])
1820 options.append('--%s' % o[1])
1816 options.append('--%s' % o[1])
1821 ui.write("%s\n" % "\n".join(options))
1817 ui.write("%s\n" % "\n".join(options))
1822 return
1818 return
1823
1819
1824 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1820 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1825 if ui.verbose:
1821 if ui.verbose:
1826 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1822 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1827 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1823 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1828
1824
1829 @command('^diff',
1825 @command('^diff',
1830 [('r', 'rev', [], _('revision'), _('REV')),
1826 [('r', 'rev', [], _('revision'), _('REV')),
1831 ('c', 'change', '', _('change made by revision'), _('REV'))
1827 ('c', 'change', '', _('change made by revision'), _('REV'))
1832 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1828 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1833 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1829 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1834 inferrepo=True,
1830 inferrepo=True,
1835 intents={INTENT_READONLY})
1831 intents={INTENT_READONLY})
1836 def diff(ui, repo, *pats, **opts):
1832 def diff(ui, repo, *pats, **opts):
1837 """diff repository (or selected files)
1833 """diff repository (or selected files)
1838
1834
1839 Show differences between revisions for the specified files.
1835 Show differences between revisions for the specified files.
1840
1836
1841 Differences between files are shown using the unified diff format.
1837 Differences between files are shown using the unified diff format.
1842
1838
1843 .. note::
1839 .. note::
1844
1840
1845 :hg:`diff` may generate unexpected results for merges, as it will
1841 :hg:`diff` may generate unexpected results for merges, as it will
1846 default to comparing against the working directory's first
1842 default to comparing against the working directory's first
1847 parent changeset if no revisions are specified.
1843 parent changeset if no revisions are specified.
1848
1844
1849 When two revision arguments are given, then changes are shown
1845 When two revision arguments are given, then changes are shown
1850 between those revisions. If only one revision is specified then
1846 between those revisions. If only one revision is specified then
1851 that revision is compared to the working directory, and, when no
1847 that revision is compared to the working directory, and, when no
1852 revisions are specified, the working directory files are compared
1848 revisions are specified, the working directory files are compared
1853 to its first parent.
1849 to its first parent.
1854
1850
1855 Alternatively you can specify -c/--change with a revision to see
1851 Alternatively you can specify -c/--change with a revision to see
1856 the changes in that changeset relative to its first parent.
1852 the changes in that changeset relative to its first parent.
1857
1853
1858 Without the -a/--text option, diff will avoid generating diffs of
1854 Without the -a/--text option, diff will avoid generating diffs of
1859 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
1860 anyway, probably with undesirable results.
1856 anyway, probably with undesirable results.
1861
1857
1862 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
1863 format. For more information, read :hg:`help diffs`.
1859 format. For more information, read :hg:`help diffs`.
1864
1860
1865 .. container:: verbose
1861 .. container:: verbose
1866
1862
1867 Examples:
1863 Examples:
1868
1864
1869 - compare a file in the current working directory to its parent::
1865 - compare a file in the current working directory to its parent::
1870
1866
1871 hg diff foo.c
1867 hg diff foo.c
1872
1868
1873 - compare two historical versions of a directory, with rename info::
1869 - compare two historical versions of a directory, with rename info::
1874
1870
1875 hg diff --git -r 1.0:1.2 lib/
1871 hg diff --git -r 1.0:1.2 lib/
1876
1872
1877 - get change stats relative to the last change on some date::
1873 - get change stats relative to the last change on some date::
1878
1874
1879 hg diff --stat -r "date('may 2')"
1875 hg diff --stat -r "date('may 2')"
1880
1876
1881 - diff all newly-added files that contain a keyword::
1877 - diff all newly-added files that contain a keyword::
1882
1878
1883 hg diff "set:added() and grep(GNU)"
1879 hg diff "set:added() and grep(GNU)"
1884
1880
1885 - compare a revision and its parents::
1881 - compare a revision and its parents::
1886
1882
1887 hg diff -c 9353 # compare against first parent
1883 hg diff -c 9353 # compare against first parent
1888 hg diff -r 9353^:9353 # same using revset syntax
1884 hg diff -r 9353^:9353 # same using revset syntax
1889 hg diff -r 9353^2:9353 # compare against the second parent
1885 hg diff -r 9353^2:9353 # compare against the second parent
1890
1886
1891 Returns 0 on success.
1887 Returns 0 on success.
1892 """
1888 """
1893
1889
1894 opts = pycompat.byteskwargs(opts)
1890 opts = pycompat.byteskwargs(opts)
1895 revs = opts.get('rev')
1891 revs = opts.get('rev')
1896 change = opts.get('change')
1892 change = opts.get('change')
1897 stat = opts.get('stat')
1893 stat = opts.get('stat')
1898 reverse = opts.get('reverse')
1894 reverse = opts.get('reverse')
1899
1895
1900 if revs and change:
1896 if revs and change:
1901 msg = _('cannot specify --rev and --change at the same time')
1897 msg = _('cannot specify --rev and --change at the same time')
1902 raise error.Abort(msg)
1898 raise error.Abort(msg)
1903 elif change:
1899 elif change:
1904 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1900 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
1905 ctx2 = scmutil.revsingle(repo, change, None)
1901 ctx2 = scmutil.revsingle(repo, change, None)
1906 ctx1 = ctx2.p1()
1902 ctx1 = ctx2.p1()
1907 else:
1903 else:
1908 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1904 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
1909 ctx1, ctx2 = scmutil.revpair(repo, revs)
1905 ctx1, ctx2 = scmutil.revpair(repo, revs)
1910 node1, node2 = ctx1.node(), ctx2.node()
1906 node1, node2 = ctx1.node(), ctx2.node()
1911
1907
1912 if reverse:
1908 if reverse:
1913 node1, node2 = node2, node1
1909 node1, node2 = node2, node1
1914
1910
1915 diffopts = patch.diffallopts(ui, opts)
1911 diffopts = patch.diffallopts(ui, opts)
1916 m = scmutil.match(ctx2, pats, opts)
1912 m = scmutil.match(ctx2, pats, opts)
1917 m = matchmod.intersectmatchers(m, repo.narrowmatch())
1913 m = matchmod.intersectmatchers(m, repo.narrowmatch())
1918 ui.pager('diff')
1914 ui.pager('diff')
1919 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1915 logcmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1920 listsubrepos=opts.get('subrepos'),
1916 listsubrepos=opts.get('subrepos'),
1921 root=opts.get('root'))
1917 root=opts.get('root'))
1922
1918
1923 @command('^export',
1919 @command('^export',
1924 [('B', 'bookmark', '',
1920 [('B', 'bookmark', '',
1925 _('export changes only reachable by given bookmark')),
1921 _('export changes only reachable by given bookmark')),
1926 ('o', 'output', '',
1922 ('o', 'output', '',
1927 _('print output to file with formatted name'), _('FORMAT')),
1923 _('print output to file with formatted name'), _('FORMAT')),
1928 ('', 'switch-parent', None, _('diff against the second parent')),
1924 ('', 'switch-parent', None, _('diff against the second parent')),
1929 ('r', 'rev', [], _('revisions to export'), _('REV')),
1925 ('r', 'rev', [], _('revisions to export'), _('REV')),
1930 ] + diffopts + formatteropts,
1926 ] + diffopts + formatteropts,
1931 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1927 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
1932 intents={INTENT_READONLY})
1928 intents={INTENT_READONLY})
1933 def export(ui, repo, *changesets, **opts):
1929 def export(ui, repo, *changesets, **opts):
1934 """dump the header and diffs for one or more changesets
1930 """dump the header and diffs for one or more changesets
1935
1931
1936 Print the changeset header and diffs for one or more revisions.
1932 Print the changeset header and diffs for one or more revisions.
1937 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.
1938
1934
1939 The information shown in the changeset header is: author, date,
1935 The information shown in the changeset header is: author, date,
1940 branch name (if non-default), changeset hash, parent(s) and commit
1936 branch name (if non-default), changeset hash, parent(s) and commit
1941 comment.
1937 comment.
1942
1938
1943 .. note::
1939 .. note::
1944
1940
1945 :hg:`export` may generate unexpected diff output for merge
1941 :hg:`export` may generate unexpected diff output for merge
1946 changesets, as it will compare the merge changeset against its
1942 changesets, as it will compare the merge changeset against its
1947 first parent only.
1943 first parent only.
1948
1944
1949 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
1950 given using a template string. See :hg:`help templates`. In addition
1946 given using a template string. See :hg:`help templates`. In addition
1951 to the common template keywords, the following formatting rules are
1947 to the common template keywords, the following formatting rules are
1952 supported:
1948 supported:
1953
1949
1954 :``%%``: literal "%" character
1950 :``%%``: literal "%" character
1955 :``%H``: changeset hash (40 hexadecimal digits)
1951 :``%H``: changeset hash (40 hexadecimal digits)
1956 :``%N``: number of patches being generated
1952 :``%N``: number of patches being generated
1957 :``%R``: changeset revision number
1953 :``%R``: changeset revision number
1958 :``%b``: basename of the exporting repository
1954 :``%b``: basename of the exporting repository
1959 :``%h``: short-form changeset hash (12 hexadecimal digits)
1955 :``%h``: short-form changeset hash (12 hexadecimal digits)
1960 :``%m``: first line of the commit message (only alphanumeric characters)
1956 :``%m``: first line of the commit message (only alphanumeric characters)
1961 :``%n``: zero-padded sequence number, starting at 1
1957 :``%n``: zero-padded sequence number, starting at 1
1962 :``%r``: zero-padded changeset revision number
1958 :``%r``: zero-padded changeset revision number
1963 :``\\``: literal "\\" character
1959 :``\\``: literal "\\" character
1964
1960
1965 Without the -a/--text option, export will avoid generating diffs
1961 Without the -a/--text option, export will avoid generating diffs
1966 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
1967 diff anyway, probably with undesirable results.
1963 diff anyway, probably with undesirable results.
1968
1964
1969 With -B/--bookmark changesets reachable by the given bookmark are
1965 With -B/--bookmark changesets reachable by the given bookmark are
1970 selected.
1966 selected.
1971
1967
1972 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
1973 format. See :hg:`help diffs` for more information.
1969 format. See :hg:`help diffs` for more information.
1974
1970
1975 With the --switch-parent option, the diff will be against the
1971 With the --switch-parent option, the diff will be against the
1976 second parent. It can be useful to review a merge.
1972 second parent. It can be useful to review a merge.
1977
1973
1978 .. container:: verbose
1974 .. container:: verbose
1979
1975
1980 Examples:
1976 Examples:
1981
1977
1982 - use export and import to transplant a bugfix to the current
1978 - use export and import to transplant a bugfix to the current
1983 branch::
1979 branch::
1984
1980
1985 hg export -r 9353 | hg import -
1981 hg export -r 9353 | hg import -
1986
1982
1987 - export all the changesets between two revisions to a file with
1983 - export all the changesets between two revisions to a file with
1988 rename information::
1984 rename information::
1989
1985
1990 hg export --git -r 123:150 > changes.txt
1986 hg export --git -r 123:150 > changes.txt
1991
1987
1992 - split outgoing changes into a series of patches with
1988 - split outgoing changes into a series of patches with
1993 descriptive names::
1989 descriptive names::
1994
1990
1995 hg export -r "outgoing()" -o "%n-%m.patch"
1991 hg export -r "outgoing()" -o "%n-%m.patch"
1996
1992
1997 Returns 0 on success.
1993 Returns 0 on success.
1998 """
1994 """
1999 opts = pycompat.byteskwargs(opts)
1995 opts = pycompat.byteskwargs(opts)
2000 bookmark = opts.get('bookmark')
1996 bookmark = opts.get('bookmark')
2001 changesets += tuple(opts.get('rev', []))
1997 changesets += tuple(opts.get('rev', []))
2002
1998
2003 if bookmark and changesets:
1999 if bookmark and changesets:
2004 raise error.Abort(_("-r and -B are mutually exclusive"))
2000 raise error.Abort(_("-r and -B are mutually exclusive"))
2005
2001
2006 if bookmark:
2002 if bookmark:
2007 if bookmark not in repo._bookmarks:
2003 if bookmark not in repo._bookmarks:
2008 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2004 raise error.Abort(_("bookmark '%s' not found") % bookmark)
2009
2005
2010 revs = scmutil.bookmarkrevs(repo, bookmark)
2006 revs = scmutil.bookmarkrevs(repo, bookmark)
2011 else:
2007 else:
2012 if not changesets:
2008 if not changesets:
2013 changesets = ['.']
2009 changesets = ['.']
2014
2010
2015 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2011 repo = scmutil.unhidehashlikerevs(repo, changesets, 'nowarn')
2016 revs = scmutil.revrange(repo, changesets)
2012 revs = scmutil.revrange(repo, changesets)
2017
2013
2018 if not revs:
2014 if not revs:
2019 raise error.Abort(_("export requires at least one changeset"))
2015 raise error.Abort(_("export requires at least one changeset"))
2020 if len(revs) > 1:
2016 if len(revs) > 1:
2021 ui.note(_('exporting patches:\n'))
2017 ui.note(_('exporting patches:\n'))
2022 else:
2018 else:
2023 ui.note(_('exporting patch:\n'))
2019 ui.note(_('exporting patch:\n'))
2024
2020
2025 fntemplate = opts.get('output')
2021 fntemplate = opts.get('output')
2026 if cmdutil.isstdiofilename(fntemplate):
2022 if cmdutil.isstdiofilename(fntemplate):
2027 fntemplate = ''
2023 fntemplate = ''
2028
2024
2029 if fntemplate:
2025 if fntemplate:
2030 fm = formatter.nullformatter(ui, 'export', opts)
2026 fm = formatter.nullformatter(ui, 'export', opts)
2031 else:
2027 else:
2032 ui.pager('export')
2028 ui.pager('export')
2033 fm = ui.formatter('export', opts)
2029 fm = ui.formatter('export', opts)
2034 with fm:
2030 with fm:
2035 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2031 cmdutil.export(repo, revs, fm, fntemplate=fntemplate,
2036 switch_parent=opts.get('switch_parent'),
2032 switch_parent=opts.get('switch_parent'),
2037 opts=patch.diffallopts(ui, opts))
2033 opts=patch.diffallopts(ui, opts))
2038
2034
2039 @command('files',
2035 @command('files',
2040 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2036 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2041 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2037 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2042 ] + walkopts + formatteropts + subrepoopts,
2038 ] + walkopts + formatteropts + subrepoopts,
2043 _('[OPTION]... [FILE]...'),
2039 _('[OPTION]... [FILE]...'),
2044 intents={INTENT_READONLY})
2040 intents={INTENT_READONLY})
2045 def files(ui, repo, *pats, **opts):
2041 def files(ui, repo, *pats, **opts):
2046 """list tracked files
2042 """list tracked files
2047
2043
2048 Print files under Mercurial control in the working directory or
2044 Print files under Mercurial control in the working directory or
2049 specified revision for given files (excluding removed files).
2045 specified revision for given files (excluding removed files).
2050 Files can be specified as filenames or filesets.
2046 Files can be specified as filenames or filesets.
2051
2047
2052 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
2053 of all files under Mercurial control.
2049 of all files under Mercurial control.
2054
2050
2055 .. container:: verbose
2051 .. container:: verbose
2056
2052
2057 Examples:
2053 Examples:
2058
2054
2059 - list all files under the current directory::
2055 - list all files under the current directory::
2060
2056
2061 hg files .
2057 hg files .
2062
2058
2063 - shows sizes and flags for current revision::
2059 - shows sizes and flags for current revision::
2064
2060
2065 hg files -vr .
2061 hg files -vr .
2066
2062
2067 - list all files named README::
2063 - list all files named README::
2068
2064
2069 hg files -I "**/README"
2065 hg files -I "**/README"
2070
2066
2071 - list all binary files::
2067 - list all binary files::
2072
2068
2073 hg files "set:binary()"
2069 hg files "set:binary()"
2074
2070
2075 - find files containing a regular expression::
2071 - find files containing a regular expression::
2076
2072
2077 hg files "set:grep('bob')"
2073 hg files "set:grep('bob')"
2078
2074
2079 - search tracked file contents with xargs and grep::
2075 - search tracked file contents with xargs and grep::
2080
2076
2081 hg files -0 | xargs -0 grep foo
2077 hg files -0 | xargs -0 grep foo
2082
2078
2083 See :hg:`help patterns` and :hg:`help filesets` for more information
2079 See :hg:`help patterns` and :hg:`help filesets` for more information
2084 on specifying file patterns.
2080 on specifying file patterns.
2085
2081
2086 Returns 0 if a match is found, 1 otherwise.
2082 Returns 0 if a match is found, 1 otherwise.
2087
2083
2088 """
2084 """
2089
2085
2090 opts = pycompat.byteskwargs(opts)
2086 opts = pycompat.byteskwargs(opts)
2091 rev = opts.get('rev')
2087 rev = opts.get('rev')
2092 if rev:
2088 if rev:
2093 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2089 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2094 ctx = scmutil.revsingle(repo, rev, None)
2090 ctx = scmutil.revsingle(repo, rev, None)
2095
2091
2096 end = '\n'
2092 end = '\n'
2097 if opts.get('print0'):
2093 if opts.get('print0'):
2098 end = '\0'
2094 end = '\0'
2099 fmt = '%s' + end
2095 fmt = '%s' + end
2100
2096
2101 m = scmutil.match(ctx, pats, opts)
2097 m = scmutil.match(ctx, pats, opts)
2102 ui.pager('files')
2098 ui.pager('files')
2103 with ui.formatter('files', opts) as fm:
2099 with ui.formatter('files', opts) as fm:
2104 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2100 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2105
2101
2106 @command(
2102 @command(
2107 '^forget',
2103 '^forget',
2108 [('i', 'interactive', None, _('use interactive mode')),
2104 [('i', 'interactive', None, _('use interactive mode')),
2109 ] + walkopts + dryrunopts,
2105 ] + walkopts + dryrunopts,
2110 _('[OPTION]... FILE...'), inferrepo=True)
2106 _('[OPTION]... FILE...'), inferrepo=True)
2111 def forget(ui, repo, *pats, **opts):
2107 def forget(ui, repo, *pats, **opts):
2112 """forget the specified files on the next commit
2108 """forget the specified files on the next commit
2113
2109
2114 Mark the specified files so they will no longer be tracked
2110 Mark the specified files so they will no longer be tracked
2115 after the next commit.
2111 after the next commit.
2116
2112
2117 This only removes files from the current branch, not from the
2113 This only removes files from the current branch, not from the
2118 entire project history, and it does not delete them from the
2114 entire project history, and it does not delete them from the
2119 working directory.
2115 working directory.
2120
2116
2121 To delete the file from the working directory, see :hg:`remove`.
2117 To delete the file from the working directory, see :hg:`remove`.
2122
2118
2123 To undo a forget before the next commit, see :hg:`add`.
2119 To undo a forget before the next commit, see :hg:`add`.
2124
2120
2125 .. container:: verbose
2121 .. container:: verbose
2126
2122
2127 Examples:
2123 Examples:
2128
2124
2129 - forget newly-added binary files::
2125 - forget newly-added binary files::
2130
2126
2131 hg forget "set:added() and binary()"
2127 hg forget "set:added() and binary()"
2132
2128
2133 - forget files that would be excluded by .hgignore::
2129 - forget files that would be excluded by .hgignore::
2134
2130
2135 hg forget "set:hgignore()"
2131 hg forget "set:hgignore()"
2136
2132
2137 Returns 0 on success.
2133 Returns 0 on success.
2138 """
2134 """
2139
2135
2140 opts = pycompat.byteskwargs(opts)
2136 opts = pycompat.byteskwargs(opts)
2141 if not pats:
2137 if not pats:
2142 raise error.Abort(_('no files specified'))
2138 raise error.Abort(_('no files specified'))
2143
2139
2144 m = scmutil.match(repo[None], pats, opts)
2140 m = scmutil.match(repo[None], pats, opts)
2145 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2141 dryrun, interactive = opts.get('dry_run'), opts.get('interactive')
2146 rejected = cmdutil.forget(ui, repo, m, prefix="",
2142 rejected = cmdutil.forget(ui, repo, m, prefix="",
2147 explicitonly=False, dryrun=dryrun,
2143 explicitonly=False, dryrun=dryrun,
2148 interactive=interactive)[0]
2144 interactive=interactive)[0]
2149 return rejected and 1 or 0
2145 return rejected and 1 or 0
2150
2146
2151 @command(
2147 @command(
2152 'graft',
2148 'graft',
2153 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2149 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2154 ('c', 'continue', False, _('resume interrupted graft')),
2150 ('c', 'continue', False, _('resume interrupted graft')),
2155 ('', 'stop', False, _('stop interrupted graft')),
2151 ('', 'stop', False, _('stop interrupted graft')),
2156 ('', 'abort', False, _('abort interrupted graft')),
2152 ('', 'abort', False, _('abort interrupted graft')),
2157 ('e', 'edit', False, _('invoke editor on commit messages')),
2153 ('e', 'edit', False, _('invoke editor on commit messages')),
2158 ('', 'log', None, _('append graft info to log message')),
2154 ('', 'log', None, _('append graft info to log message')),
2159 ('', 'no-commit', None,
2155 ('', 'no-commit', None,
2160 _("don't commit, just apply the changes in working directory")),
2156 _("don't commit, just apply the changes in working directory")),
2161 ('f', 'force', False, _('force graft')),
2157 ('f', 'force', False, _('force graft')),
2162 ('D', 'currentdate', False,
2158 ('D', 'currentdate', False,
2163 _('record the current date as commit date')),
2159 _('record the current date as commit date')),
2164 ('U', 'currentuser', False,
2160 ('U', 'currentuser', False,
2165 _('record the current user as committer'), _('DATE'))]
2161 _('record the current user as committer'), _('DATE'))]
2166 + commitopts2 + mergetoolopts + dryrunopts,
2162 + commitopts2 + mergetoolopts + dryrunopts,
2167 _('[OPTION]... [-r REV]... REV...'))
2163 _('[OPTION]... [-r REV]... REV...'))
2168 def graft(ui, repo, *revs, **opts):
2164 def graft(ui, repo, *revs, **opts):
2169 '''copy changes from other branches onto the current branch
2165 '''copy changes from other branches onto the current branch
2170
2166
2171 This command uses Mercurial's merge logic to copy individual
2167 This command uses Mercurial's merge logic to copy individual
2172 changes from other branches without merging branches in the
2168 changes from other branches without merging branches in the
2173 history graph. This is sometimes known as 'backporting' or
2169 history graph. This is sometimes known as 'backporting' or
2174 'cherry-picking'. By default, graft will copy user, date, and
2170 'cherry-picking'. By default, graft will copy user, date, and
2175 description from the source changesets.
2171 description from the source changesets.
2176
2172
2177 Changesets that are ancestors of the current revision, that have
2173 Changesets that are ancestors of the current revision, that have
2178 already been grafted, or that are merges will be skipped.
2174 already been grafted, or that are merges will be skipped.
2179
2175
2180 If --log is specified, log messages will have a comment appended
2176 If --log is specified, log messages will have a comment appended
2181 of the form::
2177 of the form::
2182
2178
2183 (grafted from CHANGESETHASH)
2179 (grafted from CHANGESETHASH)
2184
2180
2185 If --force is specified, revisions will be grafted even if they
2181 If --force is specified, revisions will be grafted even if they
2186 are already ancestors of, or have been grafted to, the destination.
2182 are already ancestors of, or have been grafted to, the destination.
2187 This is useful when the revisions have since been backed out.
2183 This is useful when the revisions have since been backed out.
2188
2184
2189 If a graft merge results in conflicts, the graft process is
2185 If a graft merge results in conflicts, the graft process is
2190 interrupted so that the current merge can be manually resolved.
2186 interrupted so that the current merge can be manually resolved.
2191 Once all conflicts are addressed, the graft process can be
2187 Once all conflicts are addressed, the graft process can be
2192 continued with the -c/--continue option.
2188 continued with the -c/--continue option.
2193
2189
2194 The -c/--continue option reapplies all the earlier options.
2190 The -c/--continue option reapplies all the earlier options.
2195
2191
2196 .. container:: verbose
2192 .. container:: verbose
2197
2193
2198 Examples:
2194 Examples:
2199
2195
2200 - 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::
2201
2197
2202 hg update stable
2198 hg update stable
2203 hg graft --edit 9393
2199 hg graft --edit 9393
2204
2200
2205 - graft a range of changesets with one exception, updating dates::
2201 - graft a range of changesets with one exception, updating dates::
2206
2202
2207 hg graft -D "2085::2093 and not 2091"
2203 hg graft -D "2085::2093 and not 2091"
2208
2204
2209 - continue a graft after resolving conflicts::
2205 - continue a graft after resolving conflicts::
2210
2206
2211 hg graft -c
2207 hg graft -c
2212
2208
2213 - show the source of a grafted changeset::
2209 - show the source of a grafted changeset::
2214
2210
2215 hg log --debug -r .
2211 hg log --debug -r .
2216
2212
2217 - show revisions sorted by date::
2213 - show revisions sorted by date::
2218
2214
2219 hg log -r "sort(all(), date)"
2215 hg log -r "sort(all(), date)"
2220
2216
2221 See :hg:`help revisions` for more about specifying revisions.
2217 See :hg:`help revisions` for more about specifying revisions.
2222
2218
2223 Returns 0 on successful completion.
2219 Returns 0 on successful completion.
2224 '''
2220 '''
2225 with repo.wlock():
2221 with repo.wlock():
2226 return _dograft(ui, repo, *revs, **opts)
2222 return _dograft(ui, repo, *revs, **opts)
2227
2223
2228 def _dograft(ui, repo, *revs, **opts):
2224 def _dograft(ui, repo, *revs, **opts):
2229 opts = pycompat.byteskwargs(opts)
2225 opts = pycompat.byteskwargs(opts)
2230 if revs and opts.get('rev'):
2226 if revs and opts.get('rev'):
2231 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2227 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2232 'revision ordering!\n'))
2228 'revision ordering!\n'))
2233
2229
2234 revs = list(revs)
2230 revs = list(revs)
2235 revs.extend(opts.get('rev'))
2231 revs.extend(opts.get('rev'))
2236 # a dict of data to be stored in state file
2232 # a dict of data to be stored in state file
2237 statedata = {}
2233 statedata = {}
2238 # list of new nodes created by ongoing graft
2234 # list of new nodes created by ongoing graft
2239 statedata['newnodes'] = []
2235 statedata['newnodes'] = []
2240
2236
2241 if not opts.get('user') and opts.get('currentuser'):
2237 if not opts.get('user') and opts.get('currentuser'):
2242 opts['user'] = ui.username()
2238 opts['user'] = ui.username()
2243 if not opts.get('date') and opts.get('currentdate'):
2239 if not opts.get('date') and opts.get('currentdate'):
2244 opts['date'] = "%d %d" % dateutil.makedate()
2240 opts['date'] = "%d %d" % dateutil.makedate()
2245
2241
2246 editor = cmdutil.getcommiteditor(editform='graft',
2242 editor = cmdutil.getcommiteditor(editform='graft',
2247 **pycompat.strkwargs(opts))
2243 **pycompat.strkwargs(opts))
2248
2244
2249 cont = False
2245 cont = False
2250 if opts.get('no_commit'):
2246 if opts.get('no_commit'):
2251 if opts.get('edit'):
2247 if opts.get('edit'):
2252 raise error.Abort(_("cannot specify --no-commit and "
2248 raise error.Abort(_("cannot specify --no-commit and "
2253 "--edit together"))
2249 "--edit together"))
2254 if opts.get('currentuser'):
2250 if opts.get('currentuser'):
2255 raise error.Abort(_("cannot specify --no-commit and "
2251 raise error.Abort(_("cannot specify --no-commit and "
2256 "--currentuser together"))
2252 "--currentuser together"))
2257 if opts.get('currentdate'):
2253 if opts.get('currentdate'):
2258 raise error.Abort(_("cannot specify --no-commit and "
2254 raise error.Abort(_("cannot specify --no-commit and "
2259 "--currentdate together"))
2255 "--currentdate together"))
2260 if opts.get('log'):
2256 if opts.get('log'):
2261 raise error.Abort(_("cannot specify --no-commit and "
2257 raise error.Abort(_("cannot specify --no-commit and "
2262 "--log together"))
2258 "--log together"))
2263
2259
2264 graftstate = statemod.cmdstate(repo, 'graftstate')
2260 graftstate = statemod.cmdstate(repo, 'graftstate')
2265
2261
2266 if opts.get('stop'):
2262 if opts.get('stop'):
2267 if opts.get('continue'):
2263 if opts.get('continue'):
2268 raise error.Abort(_("cannot use '--continue' and "
2264 raise error.Abort(_("cannot use '--continue' and "
2269 "'--stop' together"))
2265 "'--stop' together"))
2270 if opts.get('abort'):
2266 if opts.get('abort'):
2271 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2267 raise error.Abort(_("cannot use '--abort' and '--stop' together"))
2272
2268
2273 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2269 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2274 opts.get('date'), opts.get('currentdate'),
2270 opts.get('date'), opts.get('currentdate'),
2275 opts.get('currentuser'), opts.get('rev'))):
2271 opts.get('currentuser'), opts.get('rev'))):
2276 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2272 raise error.Abort(_("cannot specify any other flag with '--stop'"))
2277 return _stopgraft(ui, repo, graftstate)
2273 return _stopgraft(ui, repo, graftstate)
2278 elif opts.get('abort'):
2274 elif opts.get('abort'):
2279 if opts.get('continue'):
2275 if opts.get('continue'):
2280 raise error.Abort(_("cannot use '--continue' and "
2276 raise error.Abort(_("cannot use '--continue' and "
2281 "'--abort' together"))
2277 "'--abort' together"))
2282 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2278 if any((opts.get('edit'), opts.get('log'), opts.get('user'),
2283 opts.get('date'), opts.get('currentdate'),
2279 opts.get('date'), opts.get('currentdate'),
2284 opts.get('currentuser'), opts.get('rev'))):
2280 opts.get('currentuser'), opts.get('rev'))):
2285 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2281 raise error.Abort(_("cannot specify any other flag with '--abort'"))
2286
2282
2287 return _abortgraft(ui, repo, graftstate)
2283 return _abortgraft(ui, repo, graftstate)
2288 elif opts.get('continue'):
2284 elif opts.get('continue'):
2289 cont = True
2285 cont = True
2290 if revs:
2286 if revs:
2291 raise error.Abort(_("can't specify --continue and revisions"))
2287 raise error.Abort(_("can't specify --continue and revisions"))
2292 # read in unfinished revisions
2288 # read in unfinished revisions
2293 if graftstate.exists():
2289 if graftstate.exists():
2294 statedata = _readgraftstate(repo, graftstate)
2290 statedata = _readgraftstate(repo, graftstate)
2295 if statedata.get('date'):
2291 if statedata.get('date'):
2296 opts['date'] = statedata['date']
2292 opts['date'] = statedata['date']
2297 if statedata.get('user'):
2293 if statedata.get('user'):
2298 opts['user'] = statedata['user']
2294 opts['user'] = statedata['user']
2299 if statedata.get('log'):
2295 if statedata.get('log'):
2300 opts['log'] = True
2296 opts['log'] = True
2301 if statedata.get('no_commit'):
2297 if statedata.get('no_commit'):
2302 opts['no_commit'] = statedata.get('no_commit')
2298 opts['no_commit'] = statedata.get('no_commit')
2303 nodes = statedata['nodes']
2299 nodes = statedata['nodes']
2304 revs = [repo[node].rev() for node in nodes]
2300 revs = [repo[node].rev() for node in nodes]
2305 else:
2301 else:
2306 cmdutil.wrongtooltocontinue(repo, _('graft'))
2302 cmdutil.wrongtooltocontinue(repo, _('graft'))
2307 else:
2303 else:
2308 if not revs:
2304 if not revs:
2309 raise error.Abort(_('no revisions specified'))
2305 raise error.Abort(_('no revisions specified'))
2310 cmdutil.checkunfinished(repo)
2306 cmdutil.checkunfinished(repo)
2311 cmdutil.bailifchanged(repo)
2307 cmdutil.bailifchanged(repo)
2312 revs = scmutil.revrange(repo, revs)
2308 revs = scmutil.revrange(repo, revs)
2313
2309
2314 skipped = set()
2310 skipped = set()
2315 # check for merges
2311 # check for merges
2316 for rev in repo.revs('%ld and merge()', revs):
2312 for rev in repo.revs('%ld and merge()', revs):
2317 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2313 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2318 skipped.add(rev)
2314 skipped.add(rev)
2319 revs = [r for r in revs if r not in skipped]
2315 revs = [r for r in revs if r not in skipped]
2320 if not revs:
2316 if not revs:
2321 return -1
2317 return -1
2322
2318
2323 # 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
2324 # --continues. That's because without --force, any revisions we decided to
2320 # --continues. That's because without --force, any revisions we decided to
2325 # 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
2326 # 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
2327 # 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
2328 # already, they'd have been in the graftstate.
2324 # already, they'd have been in the graftstate.
2329 if not (cont or opts.get('force')):
2325 if not (cont or opts.get('force')):
2330 # check for ancestors of dest branch
2326 # check for ancestors of dest branch
2331 crev = repo['.'].rev()
2327 crev = repo['.'].rev()
2332 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2328 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2333 # XXX make this lazy in the future
2329 # XXX make this lazy in the future
2334 # don't mutate while iterating, create a copy
2330 # don't mutate while iterating, create a copy
2335 for rev in list(revs):
2331 for rev in list(revs):
2336 if rev in ancestors:
2332 if rev in ancestors:
2337 ui.warn(_('skipping ancestor revision %d:%s\n') %
2333 ui.warn(_('skipping ancestor revision %d:%s\n') %
2338 (rev, repo[rev]))
2334 (rev, repo[rev]))
2339 # XXX remove on list is slow
2335 # XXX remove on list is slow
2340 revs.remove(rev)
2336 revs.remove(rev)
2341 if not revs:
2337 if not revs:
2342 return -1
2338 return -1
2343
2339
2344 # analyze revs for earlier grafts
2340 # analyze revs for earlier grafts
2345 ids = {}
2341 ids = {}
2346 for ctx in repo.set("%ld", revs):
2342 for ctx in repo.set("%ld", revs):
2347 ids[ctx.hex()] = ctx.rev()
2343 ids[ctx.hex()] = ctx.rev()
2348 n = ctx.extra().get('source')
2344 n = ctx.extra().get('source')
2349 if n:
2345 if n:
2350 ids[n] = ctx.rev()
2346 ids[n] = ctx.rev()
2351
2347
2352 # check ancestors for earlier grafts
2348 # check ancestors for earlier grafts
2353 ui.debug('scanning for duplicate grafts\n')
2349 ui.debug('scanning for duplicate grafts\n')
2354
2350
2355 # 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
2356 # revs, are the ones that are common ancestors of *all* revs:
2352 # revs, are the ones that are common ancestors of *all* revs:
2357 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2353 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2358 ctx = repo[rev]
2354 ctx = repo[rev]
2359 n = ctx.extra().get('source')
2355 n = ctx.extra().get('source')
2360 if n in ids:
2356 if n in ids:
2361 try:
2357 try:
2362 r = repo[n].rev()
2358 r = repo[n].rev()
2363 except error.RepoLookupError:
2359 except error.RepoLookupError:
2364 r = None
2360 r = None
2365 if r in revs:
2361 if r in revs:
2366 ui.warn(_('skipping revision %d:%s '
2362 ui.warn(_('skipping revision %d:%s '
2367 '(already grafted to %d:%s)\n')
2363 '(already grafted to %d:%s)\n')
2368 % (r, repo[r], rev, ctx))
2364 % (r, repo[r], rev, ctx))
2369 revs.remove(r)
2365 revs.remove(r)
2370 elif ids[n] in revs:
2366 elif ids[n] in revs:
2371 if r is None:
2367 if r is None:
2372 ui.warn(_('skipping already grafted revision %d:%s '
2368 ui.warn(_('skipping already grafted revision %d:%s '
2373 '(%d:%s also has unknown origin %s)\n')
2369 '(%d:%s also has unknown origin %s)\n')
2374 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2370 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2375 else:
2371 else:
2376 ui.warn(_('skipping already grafted revision %d:%s '
2372 ui.warn(_('skipping already grafted revision %d:%s '
2377 '(%d:%s also has origin %d:%s)\n')
2373 '(%d:%s also has origin %d:%s)\n')
2378 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2374 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2379 revs.remove(ids[n])
2375 revs.remove(ids[n])
2380 elif ctx.hex() in ids:
2376 elif ctx.hex() in ids:
2381 r = ids[ctx.hex()]
2377 r = ids[ctx.hex()]
2382 ui.warn(_('skipping already grafted revision %d:%s '
2378 ui.warn(_('skipping already grafted revision %d:%s '
2383 '(was grafted from %d:%s)\n') %
2379 '(was grafted from %d:%s)\n') %
2384 (r, repo[r], rev, ctx))
2380 (r, repo[r], rev, ctx))
2385 revs.remove(r)
2381 revs.remove(r)
2386 if not revs:
2382 if not revs:
2387 return -1
2383 return -1
2388
2384
2389 if opts.get('no_commit'):
2385 if opts.get('no_commit'):
2390 statedata['no_commit'] = True
2386 statedata['no_commit'] = True
2391 for pos, ctx in enumerate(repo.set("%ld", revs)):
2387 for pos, ctx in enumerate(repo.set("%ld", revs)):
2392 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2388 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2393 ctx.description().split('\n', 1)[0])
2389 ctx.description().split('\n', 1)[0])
2394 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2390 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2395 if names:
2391 if names:
2396 desc += ' (%s)' % ' '.join(names)
2392 desc += ' (%s)' % ' '.join(names)
2397 ui.status(_('grafting %s\n') % desc)
2393 ui.status(_('grafting %s\n') % desc)
2398 if opts.get('dry_run'):
2394 if opts.get('dry_run'):
2399 continue
2395 continue
2400
2396
2401 source = ctx.extra().get('source')
2397 source = ctx.extra().get('source')
2402 extra = {}
2398 extra = {}
2403 if source:
2399 if source:
2404 extra['source'] = source
2400 extra['source'] = source
2405 extra['intermediate-source'] = ctx.hex()
2401 extra['intermediate-source'] = ctx.hex()
2406 else:
2402 else:
2407 extra['source'] = ctx.hex()
2403 extra['source'] = ctx.hex()
2408 user = ctx.user()
2404 user = ctx.user()
2409 if opts.get('user'):
2405 if opts.get('user'):
2410 user = opts['user']
2406 user = opts['user']
2411 statedata['user'] = user
2407 statedata['user'] = user
2412 date = ctx.date()
2408 date = ctx.date()
2413 if opts.get('date'):
2409 if opts.get('date'):
2414 date = opts['date']
2410 date = opts['date']
2415 statedata['date'] = date
2411 statedata['date'] = date
2416 message = ctx.description()
2412 message = ctx.description()
2417 if opts.get('log'):
2413 if opts.get('log'):
2418 message += '\n(grafted from %s)' % ctx.hex()
2414 message += '\n(grafted from %s)' % ctx.hex()
2419 statedata['log'] = True
2415 statedata['log'] = True
2420
2416
2421 # we don't merge the first commit when continuing
2417 # we don't merge the first commit when continuing
2422 if not cont:
2418 if not cont:
2423 # perform the graft merge with p1(rev) as 'ancestor'
2419 # perform the graft merge with p1(rev) as 'ancestor'
2424 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2420 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
2425 with ui.configoverride(overrides, 'graft'):
2421 with ui.configoverride(overrides, 'graft'):
2426 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2422 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'graft'])
2427 # report any conflicts
2423 # report any conflicts
2428 if stats.unresolvedcount > 0:
2424 if stats.unresolvedcount > 0:
2429 # write out state for --continue
2425 # write out state for --continue
2430 nodes = [repo[rev].hex() for rev in revs[pos:]]
2426 nodes = [repo[rev].hex() for rev in revs[pos:]]
2431 statedata['nodes'] = nodes
2427 statedata['nodes'] = nodes
2432 stateversion = 1
2428 stateversion = 1
2433 graftstate.save(stateversion, statedata)
2429 graftstate.save(stateversion, statedata)
2434 hint = _("use 'hg resolve' and 'hg graft --continue'")
2430 hint = _("use 'hg resolve' and 'hg graft --continue'")
2435 raise error.Abort(
2431 raise error.Abort(
2436 _("unresolved conflicts, can't continue"),
2432 _("unresolved conflicts, can't continue"),
2437 hint=hint)
2433 hint=hint)
2438 else:
2434 else:
2439 cont = False
2435 cont = False
2440
2436
2441 # commit if --no-commit is false
2437 # commit if --no-commit is false
2442 if not opts.get('no_commit'):
2438 if not opts.get('no_commit'):
2443 node = repo.commit(text=message, user=user, date=date, extra=extra,
2439 node = repo.commit(text=message, user=user, date=date, extra=extra,
2444 editor=editor)
2440 editor=editor)
2445 if node is None:
2441 if node is None:
2446 ui.warn(
2442 ui.warn(
2447 _('note: graft of %d:%s created no changes to commit\n') %
2443 _('note: graft of %d:%s created no changes to commit\n') %
2448 (ctx.rev(), ctx))
2444 (ctx.rev(), ctx))
2449 # 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
2450 elif statedata.get('newnodes') is not None:
2446 elif statedata.get('newnodes') is not None:
2451 statedata['newnodes'].append(node)
2447 statedata['newnodes'].append(node)
2452
2448
2453 # remove state when we complete successfully
2449 # remove state when we complete successfully
2454 if not opts.get('dry_run'):
2450 if not opts.get('dry_run'):
2455 graftstate.delete()
2451 graftstate.delete()
2456
2452
2457 return 0
2453 return 0
2458
2454
2459 def _abortgraft(ui, repo, graftstate):
2455 def _abortgraft(ui, repo, graftstate):
2460 """abort the interrupted graft and rollbacks to the state before interrupted
2456 """abort the interrupted graft and rollbacks to the state before interrupted
2461 graft"""
2457 graft"""
2462 if not graftstate.exists():
2458 if not graftstate.exists():
2463 raise error.Abort(_("no interrupted graft to abort"))
2459 raise error.Abort(_("no interrupted graft to abort"))
2464 statedata = _readgraftstate(repo, graftstate)
2460 statedata = _readgraftstate(repo, graftstate)
2465 newnodes = statedata.get('newnodes')
2461 newnodes = statedata.get('newnodes')
2466 if newnodes is None:
2462 if newnodes is None:
2467 # 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
2468 # the graft
2464 # the graft
2469 raise error.Abort(_("cannot abort using an old graftstate"))
2465 raise error.Abort(_("cannot abort using an old graftstate"))
2470
2466
2471 # changeset from which graft operation was started
2467 # changeset from which graft operation was started
2472 startctx = None
2468 startctx = None
2473 if len(newnodes) > 0:
2469 if len(newnodes) > 0:
2474 startctx = repo[newnodes[0]].p1()
2470 startctx = repo[newnodes[0]].p1()
2475 else:
2471 else:
2476 startctx = repo['.']
2472 startctx = repo['.']
2477 # whether to strip or not
2473 # whether to strip or not
2478 cleanup = False
2474 cleanup = False
2479 if newnodes:
2475 if newnodes:
2480 newnodes = [repo[r].rev() for r in newnodes]
2476 newnodes = [repo[r].rev() for r in newnodes]
2481 cleanup = True
2477 cleanup = True
2482 # checking that none of the newnodes turned public or is public
2478 # checking that none of the newnodes turned public or is public
2483 immutable = [c for c in newnodes if not repo[c].mutable()]
2479 immutable = [c for c in newnodes if not repo[c].mutable()]
2484 if immutable:
2480 if immutable:
2485 repo.ui.warn(_("cannot clean up public changesets %s\n")
2481 repo.ui.warn(_("cannot clean up public changesets %s\n")
2486 % ', '.join(bytes(repo[r]) for r in immutable),
2482 % ', '.join(bytes(repo[r]) for r in immutable),
2487 hint=_("see 'hg help phases' for details"))
2483 hint=_("see 'hg help phases' for details"))
2488 cleanup = False
2484 cleanup = False
2489
2485
2490 # 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
2491 desc = set(repo.changelog.descendants(newnodes))
2487 desc = set(repo.changelog.descendants(newnodes))
2492 if desc - set(newnodes):
2488 if desc - set(newnodes):
2493 repo.ui.warn(_("new changesets detected on destination "
2489 repo.ui.warn(_("new changesets detected on destination "
2494 "branch, can't strip\n"))
2490 "branch, can't strip\n"))
2495 cleanup = False
2491 cleanup = False
2496
2492
2497 if cleanup:
2493 if cleanup:
2498 with repo.wlock(), repo.lock():
2494 with repo.wlock(), repo.lock():
2499 hg.updaterepo(repo, startctx.node(), overwrite=True)
2495 hg.updaterepo(repo, startctx.node(), overwrite=True)
2500 # stripping the new nodes created
2496 # stripping the new nodes created
2501 strippoints = [c.node() for c in repo.set("roots(%ld)",
2497 strippoints = [c.node() for c in repo.set("roots(%ld)",
2502 newnodes)]
2498 newnodes)]
2503 repair.strip(repo.ui, repo, strippoints, backup=False)
2499 repair.strip(repo.ui, repo, strippoints, backup=False)
2504
2500
2505 if not cleanup:
2501 if not cleanup:
2506 # 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
2507 startctx = repo['.']
2503 startctx = repo['.']
2508 hg.updaterepo(repo, startctx.node(), overwrite=True)
2504 hg.updaterepo(repo, startctx.node(), overwrite=True)
2509
2505
2510 ui.status(_("graft aborted\n"))
2506 ui.status(_("graft aborted\n"))
2511 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])
2512 graftstate.delete()
2508 graftstate.delete()
2513 return 0
2509 return 0
2514
2510
2515 def _readgraftstate(repo, graftstate):
2511 def _readgraftstate(repo, graftstate):
2516 """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"""
2517 try:
2513 try:
2518 return graftstate.read()
2514 return graftstate.read()
2519 except error.CorruptedState:
2515 except error.CorruptedState:
2520 nodes = repo.vfs.read('graftstate').splitlines()
2516 nodes = repo.vfs.read('graftstate').splitlines()
2521 return {'nodes': nodes}
2517 return {'nodes': nodes}
2522
2518
2523 def _stopgraft(ui, repo, graftstate):
2519 def _stopgraft(ui, repo, graftstate):
2524 """stop the interrupted graft"""
2520 """stop the interrupted graft"""
2525 if not graftstate.exists():
2521 if not graftstate.exists():
2526 raise error.Abort(_("no interrupted graft found"))
2522 raise error.Abort(_("no interrupted graft found"))
2527 pctx = repo['.']
2523 pctx = repo['.']
2528 hg.updaterepo(repo, pctx.node(), overwrite=True)
2524 hg.updaterepo(repo, pctx.node(), overwrite=True)
2529 graftstate.delete()
2525 graftstate.delete()
2530 ui.status(_("stopped the interrupted graft\n"))
2526 ui.status(_("stopped the interrupted graft\n"))
2531 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])
2532 return 0
2528 return 0
2533
2529
2534 @command('grep',
2530 @command('grep',
2535 [('0', 'print0', None, _('end fields with NUL')),
2531 [('0', 'print0', None, _('end fields with NUL')),
2536 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2532 ('', 'all', None, _('print all revisions that match (DEPRECATED) ')),
2537 ('', 'diff', None, _('print all revisions when the term was introduced '
2533 ('', 'diff', None, _('print all revisions when the term was introduced '
2538 'or removed')),
2534 'or removed')),
2539 ('a', 'text', None, _('treat all files as text')),
2535 ('a', 'text', None, _('treat all files as text')),
2540 ('f', 'follow', None,
2536 ('f', 'follow', None,
2541 _('follow changeset history,'
2537 _('follow changeset history,'
2542 ' or file history across copies and renames')),
2538 ' or file history across copies and renames')),
2543 ('i', 'ignore-case', None, _('ignore case when matching')),
2539 ('i', 'ignore-case', None, _('ignore case when matching')),
2544 ('l', 'files-with-matches', None,
2540 ('l', 'files-with-matches', None,
2545 _('print only filenames and revisions that match')),
2541 _('print only filenames and revisions that match')),
2546 ('n', 'line-number', None, _('print matching line numbers')),
2542 ('n', 'line-number', None, _('print matching line numbers')),
2547 ('r', 'rev', [],
2543 ('r', 'rev', [],
2548 _('only search files changed within revision range'), _('REV')),
2544 _('only search files changed within revision range'), _('REV')),
2549 ('', 'all-files', None,
2545 ('', 'all-files', None,
2550 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2546 _('include all files in the changeset while grepping (EXPERIMENTAL)')),
2551 ('u', 'user', None, _('list the author (long with -v)')),
2547 ('u', 'user', None, _('list the author (long with -v)')),
2552 ('d', 'date', None, _('list the date (short with -q)')),
2548 ('d', 'date', None, _('list the date (short with -q)')),
2553 ] + formatteropts + walkopts,
2549 ] + formatteropts + walkopts,
2554 _('[OPTION]... PATTERN [FILE]...'),
2550 _('[OPTION]... PATTERN [FILE]...'),
2555 inferrepo=True,
2551 inferrepo=True,
2556 intents={INTENT_READONLY})
2552 intents={INTENT_READONLY})
2557 def grep(ui, repo, pattern, *pats, **opts):
2553 def grep(ui, repo, pattern, *pats, **opts):
2558 """search revision history for a pattern in specified files
2554 """search revision history for a pattern in specified files
2559
2555
2560 Search revision history for a regular expression in the specified
2556 Search revision history for a regular expression in the specified
2561 files or the entire project.
2557 files or the entire project.
2562
2558
2563 By default, grep prints the most recent revision number for each
2559 By default, grep prints the most recent revision number for each
2564 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
2565 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
2566 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
2567 --diff flag.
2563 --diff flag.
2568
2564
2569 PATTERN can be any Python (roughly Perl-compatible) regular
2565 PATTERN can be any Python (roughly Perl-compatible) regular
2570 expression.
2566 expression.
2571
2567
2572 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
2573 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
2574 current branch or have been deleted in a prior changeset.
2570 current branch or have been deleted in a prior changeset.
2575
2571
2576 Returns 0 if a match is found, 1 otherwise.
2572 Returns 0 if a match is found, 1 otherwise.
2577 """
2573 """
2578 opts = pycompat.byteskwargs(opts)
2574 opts = pycompat.byteskwargs(opts)
2579 diff = opts.get('all') or opts.get('diff')
2575 diff = opts.get('all') or opts.get('diff')
2580 all_files = opts.get('all_files')
2576 all_files = opts.get('all_files')
2581 if diff and opts.get('all_files'):
2577 if diff and opts.get('all_files'):
2582 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2578 raise error.Abort(_('--diff and --all-files are mutually exclusive'))
2583 # 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
2584 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:
2585 # experimental config: commands.grep.all-files
2581 # experimental config: commands.grep.all-files
2586 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2582 opts['all_files'] = ui.configbool('commands', 'grep.all-files')
2587 plaingrep = opts.get('all_files') and not opts.get('rev')
2583 plaingrep = opts.get('all_files') and not opts.get('rev')
2588 if plaingrep:
2584 if plaingrep:
2589 opts['rev'] = ['wdir()']
2585 opts['rev'] = ['wdir()']
2590
2586
2591 reflags = re.M
2587 reflags = re.M
2592 if opts.get('ignore_case'):
2588 if opts.get('ignore_case'):
2593 reflags |= re.I
2589 reflags |= re.I
2594 try:
2590 try:
2595 regexp = util.re.compile(pattern, reflags)
2591 regexp = util.re.compile(pattern, reflags)
2596 except re.error as inst:
2592 except re.error as inst:
2597 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2593 ui.warn(_("grep: invalid match pattern: %s\n") % pycompat.bytestr(inst))
2598 return 1
2594 return 1
2599 sep, eol = ':', '\n'
2595 sep, eol = ':', '\n'
2600 if opts.get('print0'):
2596 if opts.get('print0'):
2601 sep = eol = '\0'
2597 sep = eol = '\0'
2602
2598
2603 getfile = util.lrucachefunc(repo.file)
2599 getfile = util.lrucachefunc(repo.file)
2604
2600
2605 def matchlines(body):
2601 def matchlines(body):
2606 begin = 0
2602 begin = 0
2607 linenum = 0
2603 linenum = 0
2608 while begin < len(body):
2604 while begin < len(body):
2609 match = regexp.search(body, begin)
2605 match = regexp.search(body, begin)
2610 if not match:
2606 if not match:
2611 break
2607 break
2612 mstart, mend = match.span()
2608 mstart, mend = match.span()
2613 linenum += body.count('\n', begin, mstart) + 1
2609 linenum += body.count('\n', begin, mstart) + 1
2614 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2610 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2615 begin = body.find('\n', mend) + 1 or len(body) + 1
2611 begin = body.find('\n', mend) + 1 or len(body) + 1
2616 lend = begin - 1
2612 lend = begin - 1
2617 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2613 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2618
2614
2619 class linestate(object):
2615 class linestate(object):
2620 def __init__(self, line, linenum, colstart, colend):
2616 def __init__(self, line, linenum, colstart, colend):
2621 self.line = line
2617 self.line = line
2622 self.linenum = linenum
2618 self.linenum = linenum
2623 self.colstart = colstart
2619 self.colstart = colstart
2624 self.colend = colend
2620 self.colend = colend
2625
2621
2626 def __hash__(self):
2622 def __hash__(self):
2627 return hash((self.linenum, self.line))
2623 return hash((self.linenum, self.line))
2628
2624
2629 def __eq__(self, other):
2625 def __eq__(self, other):
2630 return self.line == other.line
2626 return self.line == other.line
2631
2627
2632 def findpos(self):
2628 def findpos(self):
2633 """Iterate all (start, end) indices of matches"""
2629 """Iterate all (start, end) indices of matches"""
2634 yield self.colstart, self.colend
2630 yield self.colstart, self.colend
2635 p = self.colend
2631 p = self.colend
2636 while p < len(self.line):
2632 while p < len(self.line):
2637 m = regexp.search(self.line, p)
2633 m = regexp.search(self.line, p)
2638 if not m:
2634 if not m:
2639 break
2635 break
2640 yield m.span()
2636 yield m.span()
2641 p = m.end()
2637 p = m.end()
2642
2638
2643 matches = {}
2639 matches = {}
2644 copies = {}
2640 copies = {}
2645 def grepbody(fn, rev, body):
2641 def grepbody(fn, rev, body):
2646 matches[rev].setdefault(fn, [])
2642 matches[rev].setdefault(fn, [])
2647 m = matches[rev][fn]
2643 m = matches[rev][fn]
2648 for lnum, cstart, cend, line in matchlines(body):
2644 for lnum, cstart, cend, line in matchlines(body):
2649 s = linestate(line, lnum, cstart, cend)
2645 s = linestate(line, lnum, cstart, cend)
2650 m.append(s)
2646 m.append(s)
2651
2647
2652 def difflinestates(a, b):
2648 def difflinestates(a, b):
2653 sm = difflib.SequenceMatcher(None, a, b)
2649 sm = difflib.SequenceMatcher(None, a, b)
2654 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2650 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2655 if tag == r'insert':
2651 if tag == r'insert':
2656 for i in pycompat.xrange(blo, bhi):
2652 for i in pycompat.xrange(blo, bhi):
2657 yield ('+', b[i])
2653 yield ('+', b[i])
2658 elif tag == r'delete':
2654 elif tag == r'delete':
2659 for i in pycompat.xrange(alo, ahi):
2655 for i in pycompat.xrange(alo, ahi):
2660 yield ('-', a[i])
2656 yield ('-', a[i])
2661 elif tag == r'replace':
2657 elif tag == r'replace':
2662 for i in pycompat.xrange(alo, ahi):
2658 for i in pycompat.xrange(alo, ahi):
2663 yield ('-', a[i])
2659 yield ('-', a[i])
2664 for i in pycompat.xrange(blo, bhi):
2660 for i in pycompat.xrange(blo, bhi):
2665 yield ('+', b[i])
2661 yield ('+', b[i])
2666
2662
2667 def display(fm, fn, ctx, pstates, states):
2663 def display(fm, fn, ctx, pstates, states):
2668 rev = scmutil.intrev(ctx)
2664 rev = scmutil.intrev(ctx)
2669 if fm.isplain():
2665 if fm.isplain():
2670 formatuser = ui.shortuser
2666 formatuser = ui.shortuser
2671 else:
2667 else:
2672 formatuser = pycompat.bytestr
2668 formatuser = pycompat.bytestr
2673 if ui.quiet:
2669 if ui.quiet:
2674 datefmt = '%Y-%m-%d'
2670 datefmt = '%Y-%m-%d'
2675 else:
2671 else:
2676 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2672 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2677 found = False
2673 found = False
2678 @util.cachefunc
2674 @util.cachefunc
2679 def binary():
2675 def binary():
2680 flog = getfile(fn)
2676 flog = getfile(fn)
2681 try:
2677 try:
2682 return stringutil.binary(flog.read(ctx.filenode(fn)))
2678 return stringutil.binary(flog.read(ctx.filenode(fn)))
2683 except error.WdirUnsupported:
2679 except error.WdirUnsupported:
2684 return ctx[fn].isbinary()
2680 return ctx[fn].isbinary()
2685
2681
2686 fieldnamemap = {'filename': 'path', 'linenumber': 'line_number'}
2682 fieldnamemap = {'filename': 'path', 'linenumber': 'line_number'}
2687 if diff:
2683 if diff:
2688 iter = difflinestates(pstates, states)
2684 iter = difflinestates(pstates, states)
2689 else:
2685 else:
2690 iter = [('', l) for l in states]
2686 iter = [('', l) for l in states]
2691 for change, l in iter:
2687 for change, l in iter:
2692 fm.startitem()
2688 fm.startitem()
2693 fm.context(ctx=ctx)
2689 fm.context(ctx=ctx)
2694 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2690 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)))
2695
2691
2696 cols = [
2692 cols = [
2697 ('filename', '%s', fn, True),
2693 ('filename', '%s', fn, True),
2698 ('rev', '%d', rev, not plaingrep),
2694 ('rev', '%d', rev, not plaingrep),
2699 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2695 ('linenumber', '%d', l.linenum, opts.get('line_number')),
2700 ]
2696 ]
2701 if diff:
2697 if diff:
2702 cols.append(('change', '%s', change, True))
2698 cols.append(('change', '%s', change, True))
2703 cols.extend([
2699 cols.extend([
2704 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2700 ('user', '%s', formatuser(ctx.user()), opts.get('user')),
2705 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2701 ('date', '%s', fm.formatdate(ctx.date(), datefmt),
2706 opts.get('date')),
2702 opts.get('date')),
2707 ])
2703 ])
2708 lastcol = next(
2704 lastcol = next(
2709 name for name, fmt, data, cond in reversed(cols) if cond)
2705 name for name, fmt, data, cond in reversed(cols) if cond)
2710 for name, fmt, data, cond in cols:
2706 for name, fmt, data, cond in cols:
2711 field = fieldnamemap.get(name, name)
2707 field = fieldnamemap.get(name, name)
2712 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2708 fm.condwrite(cond, field, fmt, data, label='grep.%s' % name)
2713 if cond and name != lastcol:
2709 if cond and name != lastcol:
2714 fm.plain(sep, label='grep.sep')
2710 fm.plain(sep, label='grep.sep')
2715 if not opts.get('files_with_matches'):
2711 if not opts.get('files_with_matches'):
2716 fm.plain(sep, label='grep.sep')
2712 fm.plain(sep, label='grep.sep')
2717 if not opts.get('text') and binary():
2713 if not opts.get('text') and binary():
2718 fm.plain(_(" Binary file matches"))
2714 fm.plain(_(" Binary file matches"))
2719 else:
2715 else:
2720 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2716 displaymatches(fm.nested('texts', tmpl='{text}'), l)
2721 fm.plain(eol)
2717 fm.plain(eol)
2722 found = True
2718 found = True
2723 if opts.get('files_with_matches'):
2719 if opts.get('files_with_matches'):
2724 break
2720 break
2725 return found
2721 return found
2726
2722
2727 def displaymatches(fm, l):
2723 def displaymatches(fm, l):
2728 p = 0
2724 p = 0
2729 for s, e in l.findpos():
2725 for s, e in l.findpos():
2730 if p < s:
2726 if p < s:
2731 fm.startitem()
2727 fm.startitem()
2732 fm.write('text', '%s', l.line[p:s])
2728 fm.write('text', '%s', l.line[p:s])
2733 fm.data(matched=False)
2729 fm.data(matched=False)
2734 fm.startitem()
2730 fm.startitem()
2735 fm.write('text', '%s', l.line[s:e], label='grep.match')
2731 fm.write('text', '%s', l.line[s:e], label='grep.match')
2736 fm.data(matched=True)
2732 fm.data(matched=True)
2737 p = e
2733 p = e
2738 if p < len(l.line):
2734 if p < len(l.line):
2739 fm.startitem()
2735 fm.startitem()
2740 fm.write('text', '%s', l.line[p:])
2736 fm.write('text', '%s', l.line[p:])
2741 fm.data(matched=False)
2737 fm.data(matched=False)
2742 fm.end()
2738 fm.end()
2743
2739
2744 skip = {}
2740 skip = {}
2745 revfiles = {}
2741 revfiles = {}
2746 match = scmutil.match(repo[None], pats, opts)
2742 match = scmutil.match(repo[None], pats, opts)
2747 found = False
2743 found = False
2748 follow = opts.get('follow')
2744 follow = opts.get('follow')
2749
2745
2750 def prep(ctx, fns):
2746 def prep(ctx, fns):
2751 rev = ctx.rev()
2747 rev = ctx.rev()
2752 pctx = ctx.p1()
2748 pctx = ctx.p1()
2753 parent = pctx.rev()
2749 parent = pctx.rev()
2754 matches.setdefault(rev, {})
2750 matches.setdefault(rev, {})
2755 matches.setdefault(parent, {})
2751 matches.setdefault(parent, {})
2756 files = revfiles.setdefault(rev, [])
2752 files = revfiles.setdefault(rev, [])
2757 for fn in fns:
2753 for fn in fns:
2758 flog = getfile(fn)
2754 flog = getfile(fn)
2759 try:
2755 try:
2760 fnode = ctx.filenode(fn)
2756 fnode = ctx.filenode(fn)
2761 except error.LookupError:
2757 except error.LookupError:
2762 continue
2758 continue
2763 try:
2759 try:
2764 copied = flog.renamed(fnode)
2760 copied = flog.renamed(fnode)
2765 except error.WdirUnsupported:
2761 except error.WdirUnsupported:
2766 copied = ctx[fn].renamed()
2762 copied = ctx[fn].renamed()
2767 copy = follow and copied and copied[0]
2763 copy = follow and copied and copied[0]
2768 if copy:
2764 if copy:
2769 copies.setdefault(rev, {})[fn] = copy
2765 copies.setdefault(rev, {})[fn] = copy
2770 if fn in skip:
2766 if fn in skip:
2771 if copy:
2767 if copy:
2772 skip[copy] = True
2768 skip[copy] = True
2773 continue
2769 continue
2774 files.append(fn)
2770 files.append(fn)
2775
2771
2776 if fn not in matches[rev]:
2772 if fn not in matches[rev]:
2777 try:
2773 try:
2778 content = flog.read(fnode)
2774 content = flog.read(fnode)
2779 except error.WdirUnsupported:
2775 except error.WdirUnsupported:
2780 content = ctx[fn].data()
2776 content = ctx[fn].data()
2781 grepbody(fn, rev, content)
2777 grepbody(fn, rev, content)
2782
2778
2783 pfn = copy or fn
2779 pfn = copy or fn
2784 if pfn not in matches[parent]:
2780 if pfn not in matches[parent]:
2785 try:
2781 try:
2786 fnode = pctx.filenode(pfn)
2782 fnode = pctx.filenode(pfn)
2787 grepbody(pfn, parent, flog.read(fnode))
2783 grepbody(pfn, parent, flog.read(fnode))
2788 except error.LookupError:
2784 except error.LookupError:
2789 pass
2785 pass
2790
2786
2791 ui.pager('grep')
2787 ui.pager('grep')
2792 fm = ui.formatter('grep', opts)
2788 fm = ui.formatter('grep', opts)
2793 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2789 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2794 rev = ctx.rev()
2790 rev = ctx.rev()
2795 parent = ctx.p1().rev()
2791 parent = ctx.p1().rev()
2796 for fn in sorted(revfiles.get(rev, [])):
2792 for fn in sorted(revfiles.get(rev, [])):
2797 states = matches[rev][fn]
2793 states = matches[rev][fn]
2798 copy = copies.get(rev, {}).get(fn)
2794 copy = copies.get(rev, {}).get(fn)
2799 if fn in skip:
2795 if fn in skip:
2800 if copy:
2796 if copy:
2801 skip[copy] = True
2797 skip[copy] = True
2802 continue
2798 continue
2803 pstates = matches.get(parent, {}).get(copy or fn, [])
2799 pstates = matches.get(parent, {}).get(copy or fn, [])
2804 if pstates or states:
2800 if pstates or states:
2805 r = display(fm, fn, ctx, pstates, states)
2801 r = display(fm, fn, ctx, pstates, states)
2806 found = found or r
2802 found = found or r
2807 if r and not diff and not all_files:
2803 if r and not diff and not all_files:
2808 skip[fn] = True
2804 skip[fn] = True
2809 if copy:
2805 if copy:
2810 skip[copy] = True
2806 skip[copy] = True
2811 del revfiles[rev]
2807 del revfiles[rev]
2812 # 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
2813 # clear the matches dict once the window is over
2809 # clear the matches dict once the window is over
2814 if not revfiles:
2810 if not revfiles:
2815 matches.clear()
2811 matches.clear()
2816 fm.end()
2812 fm.end()
2817
2813
2818 return not found
2814 return not found
2819
2815
2820 @command('heads',
2816 @command('heads',
2821 [('r', 'rev', '',
2817 [('r', 'rev', '',
2822 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2818 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2823 ('t', 'topo', False, _('show topological heads only')),
2819 ('t', 'topo', False, _('show topological heads only')),
2824 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2820 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2825 ('c', 'closed', False, _('show normal and closed branch heads')),
2821 ('c', 'closed', False, _('show normal and closed branch heads')),
2826 ] + templateopts,
2822 ] + templateopts,
2827 _('[-ct] [-r STARTREV] [REV]...'),
2823 _('[-ct] [-r STARTREV] [REV]...'),
2828 intents={INTENT_READONLY})
2824 intents={INTENT_READONLY})
2829 def heads(ui, repo, *branchrevs, **opts):
2825 def heads(ui, repo, *branchrevs, **opts):
2830 """show branch heads
2826 """show branch heads
2831
2827
2832 With no arguments, show all open branch heads in the repository.
2828 With no arguments, show all open branch heads in the repository.
2833 Branch heads are changesets that have no descendants on the
2829 Branch heads are changesets that have no descendants on the
2834 same branch. They are where development generally takes place and
2830 same branch. They are where development generally takes place and
2835 are the usual targets for update and merge operations.
2831 are the usual targets for update and merge operations.
2836
2832
2837 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
2838 branches associated with the specified changesets are shown. This
2834 branches associated with the specified changesets are shown. This
2839 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
2840 currently checked-out branch.
2836 currently checked-out branch.
2841
2837
2842 If -c/--closed is specified, also show branch heads marked closed
2838 If -c/--closed is specified, also show branch heads marked closed
2843 (see :hg:`commit --close-branch`).
2839 (see :hg:`commit --close-branch`).
2844
2840
2845 If STARTREV is specified, only those heads that are descendants of
2841 If STARTREV is specified, only those heads that are descendants of
2846 STARTREV will be displayed.
2842 STARTREV will be displayed.
2847
2843
2848 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
2849 topological heads (changesets with no children) will be shown.
2845 topological heads (changesets with no children) will be shown.
2850
2846
2851 Returns 0 if matching heads are found, 1 if not.
2847 Returns 0 if matching heads are found, 1 if not.
2852 """
2848 """
2853
2849
2854 opts = pycompat.byteskwargs(opts)
2850 opts = pycompat.byteskwargs(opts)
2855 start = None
2851 start = None
2856 rev = opts.get('rev')
2852 rev = opts.get('rev')
2857 if rev:
2853 if rev:
2858 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2854 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
2859 start = scmutil.revsingle(repo, rev, None).node()
2855 start = scmutil.revsingle(repo, rev, None).node()
2860
2856
2861 if opts.get('topo'):
2857 if opts.get('topo'):
2862 heads = [repo[h] for h in repo.heads(start)]
2858 heads = [repo[h] for h in repo.heads(start)]
2863 else:
2859 else:
2864 heads = []
2860 heads = []
2865 for branch in repo.branchmap():
2861 for branch in repo.branchmap():
2866 heads += repo.branchheads(branch, start, opts.get('closed'))
2862 heads += repo.branchheads(branch, start, opts.get('closed'))
2867 heads = [repo[h] for h in heads]
2863 heads = [repo[h] for h in heads]
2868
2864
2869 if branchrevs:
2865 if branchrevs:
2870 branches = set(repo[r].branch()
2866 branches = set(repo[r].branch()
2871 for r in scmutil.revrange(repo, branchrevs))
2867 for r in scmutil.revrange(repo, branchrevs))
2872 heads = [h for h in heads if h.branch() in branches]
2868 heads = [h for h in heads if h.branch() in branches]
2873
2869
2874 if opts.get('active') and branchrevs:
2870 if opts.get('active') and branchrevs:
2875 dagheads = repo.heads(start)
2871 dagheads = repo.heads(start)
2876 heads = [h for h in heads if h.node() in dagheads]
2872 heads = [h for h in heads if h.node() in dagheads]
2877
2873
2878 if branchrevs:
2874 if branchrevs:
2879 haveheads = set(h.branch() for h in heads)
2875 haveheads = set(h.branch() for h in heads)
2880 if branches - haveheads:
2876 if branches - haveheads:
2881 headless = ', '.join(b for b in branches - haveheads)
2877 headless = ', '.join(b for b in branches - haveheads)
2882 msg = _('no open branch heads found on branches %s')
2878 msg = _('no open branch heads found on branches %s')
2883 if opts.get('rev'):
2879 if opts.get('rev'):
2884 msg += _(' (started at %s)') % opts['rev']
2880 msg += _(' (started at %s)') % opts['rev']
2885 ui.warn((msg + '\n') % headless)
2881 ui.warn((msg + '\n') % headless)
2886
2882
2887 if not heads:
2883 if not heads:
2888 return 1
2884 return 1
2889
2885
2890 ui.pager('heads')
2886 ui.pager('heads')
2891 heads = sorted(heads, key=lambda x: -x.rev())
2887 heads = sorted(heads, key=lambda x: -x.rev())
2892 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2888 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
2893 for ctx in heads:
2889 for ctx in heads:
2894 displayer.show(ctx)
2890 displayer.show(ctx)
2895 displayer.close()
2891 displayer.close()
2896
2892
2897 @command('help',
2893 @command('help',
2898 [('e', 'extension', None, _('show only help for extensions')),
2894 [('e', 'extension', None, _('show only help for extensions')),
2899 ('c', 'command', None, _('show only help for commands')),
2895 ('c', 'command', None, _('show only help for commands')),
2900 ('k', 'keyword', None, _('show topics matching keyword')),
2896 ('k', 'keyword', None, _('show topics matching keyword')),
2901 ('s', 'system', [], _('show help for specific platform(s)')),
2897 ('s', 'system', [], _('show help for specific platform(s)')),
2902 ],
2898 ],
2903 _('[-ecks] [TOPIC]'),
2899 _('[-ecks] [TOPIC]'),
2904 norepo=True,
2900 norepo=True,
2905 intents={INTENT_READONLY})
2901 intents={INTENT_READONLY})
2906 def help_(ui, name=None, **opts):
2902 def help_(ui, name=None, **opts):
2907 """show help for a given topic or a help overview
2903 """show help for a given topic or a help overview
2908
2904
2909 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.
2910
2906
2911 Given a topic, extension, or command name, print help for that
2907 Given a topic, extension, or command name, print help for that
2912 topic.
2908 topic.
2913
2909
2914 Returns 0 if successful.
2910 Returns 0 if successful.
2915 """
2911 """
2916
2912
2917 keep = opts.get(r'system') or []
2913 keep = opts.get(r'system') or []
2918 if len(keep) == 0:
2914 if len(keep) == 0:
2919 if pycompat.sysplatform.startswith('win'):
2915 if pycompat.sysplatform.startswith('win'):
2920 keep.append('windows')
2916 keep.append('windows')
2921 elif pycompat.sysplatform == 'OpenVMS':
2917 elif pycompat.sysplatform == 'OpenVMS':
2922 keep.append('vms')
2918 keep.append('vms')
2923 elif pycompat.sysplatform == 'plan9':
2919 elif pycompat.sysplatform == 'plan9':
2924 keep.append('plan9')
2920 keep.append('plan9')
2925 else:
2921 else:
2926 keep.append('unix')
2922 keep.append('unix')
2927 keep.append(pycompat.sysplatform.lower())
2923 keep.append(pycompat.sysplatform.lower())
2928 if ui.verbose:
2924 if ui.verbose:
2929 keep.append('verbose')
2925 keep.append('verbose')
2930
2926
2931 commands = sys.modules[__name__]
2927 commands = sys.modules[__name__]
2932 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2928 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2933 ui.pager('help')
2929 ui.pager('help')
2934 ui.write(formatted)
2930 ui.write(formatted)
2935
2931
2936
2932
2937 @command('identify|id',
2933 @command('identify|id',
2938 [('r', 'rev', '',
2934 [('r', 'rev', '',
2939 _('identify the specified revision'), _('REV')),
2935 _('identify the specified revision'), _('REV')),
2940 ('n', 'num', None, _('show local revision number')),
2936 ('n', 'num', None, _('show local revision number')),
2941 ('i', 'id', None, _('show global revision id')),
2937 ('i', 'id', None, _('show global revision id')),
2942 ('b', 'branch', None, _('show branch')),
2938 ('b', 'branch', None, _('show branch')),
2943 ('t', 'tags', None, _('show tags')),
2939 ('t', 'tags', None, _('show tags')),
2944 ('B', 'bookmarks', None, _('show bookmarks')),
2940 ('B', 'bookmarks', None, _('show bookmarks')),
2945 ] + remoteopts + formatteropts,
2941 ] + remoteopts + formatteropts,
2946 _('[-nibtB] [-r REV] [SOURCE]'),
2942 _('[-nibtB] [-r REV] [SOURCE]'),
2947 optionalrepo=True,
2943 optionalrepo=True,
2948 intents={INTENT_READONLY})
2944 intents={INTENT_READONLY})
2949 def identify(ui, repo, source=None, rev=None,
2945 def identify(ui, repo, source=None, rev=None,
2950 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2946 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2951 """identify the working directory or specified revision
2947 """identify the working directory or specified revision
2952
2948
2953 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
2954 two parent hash identifiers, followed by a "+" if the working
2950 two parent hash identifiers, followed by a "+" if the working
2955 directory has uncommitted changes, the branch name (if not default),
2951 directory has uncommitted changes, the branch name (if not default),
2956 a list of tags, and a list of bookmarks.
2952 a list of tags, and a list of bookmarks.
2957
2953
2958 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
2959 repository including the working directory. Specify -r. to get information
2955 repository including the working directory. Specify -r. to get information
2960 of the working directory parent without scanning uncommitted changes.
2956 of the working directory parent without scanning uncommitted changes.
2961
2957
2962 Specifying a path to a repository root or Mercurial bundle will
2958 Specifying a path to a repository root or Mercurial bundle will
2963 cause lookup to operate on that repository/bundle.
2959 cause lookup to operate on that repository/bundle.
2964
2960
2965 .. container:: verbose
2961 .. container:: verbose
2966
2962
2967 Examples:
2963 Examples:
2968
2964
2969 - generate a build identifier for the working directory::
2965 - generate a build identifier for the working directory::
2970
2966
2971 hg id --id > build-id.dat
2967 hg id --id > build-id.dat
2972
2968
2973 - find the revision corresponding to a tag::
2969 - find the revision corresponding to a tag::
2974
2970
2975 hg id -n -r 1.3
2971 hg id -n -r 1.3
2976
2972
2977 - check the most recent revision of a remote repository::
2973 - check the most recent revision of a remote repository::
2978
2974
2979 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2975 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2980
2976
2981 See :hg:`log` for generating more information about specific revisions,
2977 See :hg:`log` for generating more information about specific revisions,
2982 including full hash identifiers.
2978 including full hash identifiers.
2983
2979
2984 Returns 0 if successful.
2980 Returns 0 if successful.
2985 """
2981 """
2986
2982
2987 opts = pycompat.byteskwargs(opts)
2983 opts = pycompat.byteskwargs(opts)
2988 if not repo and not source:
2984 if not repo and not source:
2989 raise error.Abort(_("there is no Mercurial repository here "
2985 raise error.Abort(_("there is no Mercurial repository here "
2990 "(.hg not found)"))
2986 "(.hg not found)"))
2991
2987
2992 default = not (num or id or branch or tags or bookmarks)
2988 default = not (num or id or branch or tags or bookmarks)
2993 output = []
2989 output = []
2994 revs = []
2990 revs = []
2995
2991
2996 if source:
2992 if source:
2997 source, branches = hg.parseurl(ui.expandpath(source))
2993 source, branches = hg.parseurl(ui.expandpath(source))
2998 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
2999 repo = peer.local()
2995 repo = peer.local()
3000 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2996 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3001
2997
3002 fm = ui.formatter('identify', opts)
2998 fm = ui.formatter('identify', opts)
3003 fm.startitem()
2999 fm.startitem()
3004
3000
3005 if not repo:
3001 if not repo:
3006 if num or branch or tags:
3002 if num or branch or tags:
3007 raise error.Abort(
3003 raise error.Abort(
3008 _("can't query remote revision number, branch, or tags"))
3004 _("can't query remote revision number, branch, or tags"))
3009 if not rev and revs:
3005 if not rev and revs:
3010 rev = revs[0]
3006 rev = revs[0]
3011 if not rev:
3007 if not rev:
3012 rev = "tip"
3008 rev = "tip"
3013
3009
3014 remoterev = peer.lookup(rev)
3010 remoterev = peer.lookup(rev)
3015 hexrev = fm.hexfunc(remoterev)
3011 hexrev = fm.hexfunc(remoterev)
3016 if default or id:
3012 if default or id:
3017 output = [hexrev]
3013 output = [hexrev]
3018 fm.data(id=hexrev)
3014 fm.data(id=hexrev)
3019
3015
3020 def getbms():
3016 def getbms():
3021 bms = []
3017 bms = []
3022
3018
3023 if 'bookmarks' in peer.listkeys('namespaces'):
3019 if 'bookmarks' in peer.listkeys('namespaces'):
3024 hexremoterev = hex(remoterev)
3020 hexremoterev = hex(remoterev)
3025 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3021 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3026 if bmr == hexremoterev]
3022 if bmr == hexremoterev]
3027
3023
3028 return sorted(bms)
3024 return sorted(bms)
3029
3025
3030 bms = getbms()
3026 bms = getbms()
3031 if bookmarks:
3027 if bookmarks:
3032 output.extend(bms)
3028 output.extend(bms)
3033 elif default and not ui.quiet:
3029 elif default and not ui.quiet:
3034 # multiple bookmarks for a single parent separated by '/'
3030 # multiple bookmarks for a single parent separated by '/'
3035 bm = '/'.join(bms)
3031 bm = '/'.join(bms)
3036 if bm:
3032 if bm:
3037 output.append(bm)
3033 output.append(bm)
3038
3034
3039 fm.data(node=hex(remoterev))
3035 fm.data(node=hex(remoterev))
3040 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
3036 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
3041 else:
3037 else:
3042 if rev:
3038 if rev:
3043 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3039 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3044 ctx = scmutil.revsingle(repo, rev, None)
3040 ctx = scmutil.revsingle(repo, rev, None)
3045
3041
3046 if ctx.rev() is None:
3042 if ctx.rev() is None:
3047 ctx = repo[None]
3043 ctx = repo[None]
3048 parents = ctx.parents()
3044 parents = ctx.parents()
3049 taglist = []
3045 taglist = []
3050 for p in parents:
3046 for p in parents:
3051 taglist.extend(p.tags())
3047 taglist.extend(p.tags())
3052
3048
3053 dirty = ""
3049 dirty = ""
3054 if ctx.dirty(missing=True, merge=False, branch=False):
3050 if ctx.dirty(missing=True, merge=False, branch=False):
3055 dirty = '+'
3051 dirty = '+'
3056 fm.data(dirty=dirty)
3052 fm.data(dirty=dirty)
3057
3053
3058 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3054 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3059 if default or id:
3055 if default or id:
3060 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3056 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
3061 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3057 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
3062
3058
3063 if num:
3059 if num:
3064 numoutput = ["%d" % p.rev() for p in parents]
3060 numoutput = ["%d" % p.rev() for p in parents]
3065 output.append("%s%s" % ('+'.join(numoutput), dirty))
3061 output.append("%s%s" % ('+'.join(numoutput), dirty))
3066
3062
3067 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3063 fm.data(parents=fm.formatlist([fm.hexfunc(p.node())
3068 for p in parents], name='node'))
3064 for p in parents], name='node'))
3069 else:
3065 else:
3070 hexoutput = fm.hexfunc(ctx.node())
3066 hexoutput = fm.hexfunc(ctx.node())
3071 if default or id:
3067 if default or id:
3072 output = [hexoutput]
3068 output = [hexoutput]
3073 fm.data(id=hexoutput)
3069 fm.data(id=hexoutput)
3074
3070
3075 if num:
3071 if num:
3076 output.append(pycompat.bytestr(ctx.rev()))
3072 output.append(pycompat.bytestr(ctx.rev()))
3077 taglist = ctx.tags()
3073 taglist = ctx.tags()
3078
3074
3079 if default and not ui.quiet:
3075 if default and not ui.quiet:
3080 b = ctx.branch()
3076 b = ctx.branch()
3081 if b != 'default':
3077 if b != 'default':
3082 output.append("(%s)" % b)
3078 output.append("(%s)" % b)
3083
3079
3084 # multiple tags for a single parent separated by '/'
3080 # multiple tags for a single parent separated by '/'
3085 t = '/'.join(taglist)
3081 t = '/'.join(taglist)
3086 if t:
3082 if t:
3087 output.append(t)
3083 output.append(t)
3088
3084
3089 # multiple bookmarks for a single parent separated by '/'
3085 # multiple bookmarks for a single parent separated by '/'
3090 bm = '/'.join(ctx.bookmarks())
3086 bm = '/'.join(ctx.bookmarks())
3091 if bm:
3087 if bm:
3092 output.append(bm)
3088 output.append(bm)
3093 else:
3089 else:
3094 if branch:
3090 if branch:
3095 output.append(ctx.branch())
3091 output.append(ctx.branch())
3096
3092
3097 if tags:
3093 if tags:
3098 output.extend(taglist)
3094 output.extend(taglist)
3099
3095
3100 if bookmarks:
3096 if bookmarks:
3101 output.extend(ctx.bookmarks())
3097 output.extend(ctx.bookmarks())
3102
3098
3103 fm.data(node=ctx.hex())
3099 fm.data(node=ctx.hex())
3104 fm.data(branch=ctx.branch())
3100 fm.data(branch=ctx.branch())
3105 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3101 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
3106 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3102 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
3107 fm.context(ctx=ctx)
3103 fm.context(ctx=ctx)
3108
3104
3109 fm.plain("%s\n" % ' '.join(output))
3105 fm.plain("%s\n" % ' '.join(output))
3110 fm.end()
3106 fm.end()
3111
3107
3112 @command('import|patch',
3108 @command('import|patch',
3113 [('p', 'strip', 1,
3109 [('p', 'strip', 1,
3114 _('directory strip option for patch. This has the same '
3110 _('directory strip option for patch. This has the same '
3115 'meaning as the corresponding patch option'), _('NUM')),
3111 'meaning as the corresponding patch option'), _('NUM')),
3116 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3112 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3117 ('e', 'edit', False, _('invoke editor on commit messages')),
3113 ('e', 'edit', False, _('invoke editor on commit messages')),
3118 ('f', 'force', None,
3114 ('f', 'force', None,
3119 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3115 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3120 ('', 'no-commit', None,
3116 ('', 'no-commit', None,
3121 _("don't commit, just update the working directory")),
3117 _("don't commit, just update the working directory")),
3122 ('', 'bypass', None,
3118 ('', 'bypass', None,
3123 _("apply patch without touching the working directory")),
3119 _("apply patch without touching the working directory")),
3124 ('', 'partial', None,
3120 ('', 'partial', None,
3125 _('commit even if some hunks fail')),
3121 _('commit even if some hunks fail')),
3126 ('', 'exact', None,
3122 ('', 'exact', None,
3127 _('abort if patch would apply lossily')),
3123 _('abort if patch would apply lossily')),
3128 ('', 'prefix', '',
3124 ('', 'prefix', '',
3129 _('apply patch to subdirectory'), _('DIR')),
3125 _('apply patch to subdirectory'), _('DIR')),
3130 ('', 'import-branch', None,
3126 ('', 'import-branch', None,
3131 _('use any branch information in patch (implied by --exact)'))] +
3127 _('use any branch information in patch (implied by --exact)'))] +
3132 commitopts + commitopts2 + similarityopts,
3128 commitopts + commitopts2 + similarityopts,
3133 _('[OPTION]... PATCH...'))
3129 _('[OPTION]... PATCH...'))
3134 def import_(ui, repo, patch1=None, *patches, **opts):
3130 def import_(ui, repo, patch1=None, *patches, **opts):
3135 """import an ordered set of patches
3131 """import an ordered set of patches
3136
3132
3137 Import a list of patches and commit them individually (unless
3133 Import a list of patches and commit them individually (unless
3138 --no-commit is specified).
3134 --no-commit is specified).
3139
3135
3140 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
3141 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
3142 there.
3138 there.
3143
3139
3144 Import first applies changes to the working directory (unless
3140 Import first applies changes to the working directory (unless
3145 --bypass is specified), import will abort if there are outstanding
3141 --bypass is specified), import will abort if there are outstanding
3146 changes.
3142 changes.
3147
3143
3148 Use --bypass to apply and commit patches directly to the
3144 Use --bypass to apply and commit patches directly to the
3149 repository, without affecting the working directory. Without
3145 repository, without affecting the working directory. Without
3150 --exact, patches will be applied on top of the working directory
3146 --exact, patches will be applied on top of the working directory
3151 parent revision.
3147 parent revision.
3152
3148
3153 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
3154 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
3155 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
3156 message are used as default committer and commit message. All
3152 message are used as default committer and commit message. All
3157 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
3158 message.
3154 message.
3159
3155
3160 If the imported patch was generated by :hg:`export`, user and
3156 If the imported patch was generated by :hg:`export`, user and
3161 description from patch override values from message headers and
3157 description from patch override values from message headers and
3162 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
3163 override these.
3159 override these.
3164
3160
3165 If --exact is specified, import will set the working directory to
3161 If --exact is specified, import will set the working directory to
3166 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
3167 resulting changeset has a different ID than the one recorded in
3163 resulting changeset has a different ID than the one recorded in
3168 the patch. This will guard against various ways that portable
3164 the patch. This will guard against various ways that portable
3169 patch formats and mail systems might fail to transfer Mercurial
3165 patch formats and mail systems might fail to transfer Mercurial
3170 data or metadata. See :hg:`bundle` for lossless transmission.
3166 data or metadata. See :hg:`bundle` for lossless transmission.
3171
3167
3172 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
3173 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
3174 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
3175 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
3176 changeset. This flag exists to let people import patches that
3172 changeset. This flag exists to let people import patches that
3177 partially apply without losing the associated metadata (author,
3173 partially apply without losing the associated metadata (author,
3178 date, description, ...).
3174 date, description, ...).
3179
3175
3180 .. note::
3176 .. note::
3181
3177
3182 When no hunks apply cleanly, :hg:`import --partial` will create
3178 When no hunks apply cleanly, :hg:`import --partial` will create
3183 an empty changeset, importing only the patch metadata.
3179 an empty changeset, importing only the patch metadata.
3184
3180
3185 With -s/--similarity, hg will attempt to discover renames and
3181 With -s/--similarity, hg will attempt to discover renames and
3186 copies in the patch in the same way as :hg:`addremove`.
3182 copies in the patch in the same way as :hg:`addremove`.
3187
3183
3188 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
3189 by setting the ``ui.patch`` configuration option. For the default
3185 by setting the ``ui.patch`` configuration option. For the default
3190 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3186 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3191 See :hg:`help config` for more information about configuration
3187 See :hg:`help config` for more information about configuration
3192 files and how to use these options.
3188 files and how to use these options.
3193
3189
3194 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.
3195
3191
3196 .. container:: verbose
3192 .. container:: verbose
3197
3193
3198 Examples:
3194 Examples:
3199
3195
3200 - import a traditional patch from a website and detect renames::
3196 - import a traditional patch from a website and detect renames::
3201
3197
3202 hg import -s 80 http://example.com/bugfix.patch
3198 hg import -s 80 http://example.com/bugfix.patch
3203
3199
3204 - import a changeset from an hgweb server::
3200 - import a changeset from an hgweb server::
3205
3201
3206 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3202 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3207
3203
3208 - import all the patches in an Unix-style mbox::
3204 - import all the patches in an Unix-style mbox::
3209
3205
3210 hg import incoming-patches.mbox
3206 hg import incoming-patches.mbox
3211
3207
3212 - import patches from stdin::
3208 - import patches from stdin::
3213
3209
3214 hg import -
3210 hg import -
3215
3211
3216 - attempt to exactly restore an exported changeset (not always
3212 - attempt to exactly restore an exported changeset (not always
3217 possible)::
3213 possible)::
3218
3214
3219 hg import --exact proposed-fix.patch
3215 hg import --exact proposed-fix.patch
3220
3216
3221 - 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
3222 the default internal tool.
3218 the default internal tool.
3223
3219
3224 hg import --config ui.patch="patch --merge" fuzzy.patch
3220 hg import --config ui.patch="patch --merge" fuzzy.patch
3225
3221
3226 - change the default fuzzing from 2 to a less strict 7
3222 - change the default fuzzing from 2 to a less strict 7
3227
3223
3228 hg import --config ui.fuzz=7 fuzz.patch
3224 hg import --config ui.fuzz=7 fuzz.patch
3229
3225
3230 Returns 0 on success, 1 on partial success (see --partial).
3226 Returns 0 on success, 1 on partial success (see --partial).
3231 """
3227 """
3232
3228
3233 opts = pycompat.byteskwargs(opts)
3229 opts = pycompat.byteskwargs(opts)
3234 if not patch1:
3230 if not patch1:
3235 raise error.Abort(_('need at least one patch to import'))
3231 raise error.Abort(_('need at least one patch to import'))
3236
3232
3237 patches = (patch1,) + patches
3233 patches = (patch1,) + patches
3238
3234
3239 date = opts.get('date')
3235 date = opts.get('date')
3240 if date:
3236 if date:
3241 opts['date'] = dateutil.parsedate(date)
3237 opts['date'] = dateutil.parsedate(date)
3242
3238
3243 exact = opts.get('exact')
3239 exact = opts.get('exact')
3244 update = not opts.get('bypass')
3240 update = not opts.get('bypass')
3245 if not update and opts.get('no_commit'):
3241 if not update and opts.get('no_commit'):
3246 raise error.Abort(_('cannot use --no-commit with --bypass'))
3242 raise error.Abort(_('cannot use --no-commit with --bypass'))
3247 try:
3243 try:
3248 sim = float(opts.get('similarity') or 0)
3244 sim = float(opts.get('similarity') or 0)
3249 except ValueError:
3245 except ValueError:
3250 raise error.Abort(_('similarity must be a number'))
3246 raise error.Abort(_('similarity must be a number'))
3251 if sim < 0 or sim > 100:
3247 if sim < 0 or sim > 100:
3252 raise error.Abort(_('similarity must be between 0 and 100'))
3248 raise error.Abort(_('similarity must be between 0 and 100'))
3253 if sim and not update:
3249 if sim and not update:
3254 raise error.Abort(_('cannot use --similarity with --bypass'))
3250 raise error.Abort(_('cannot use --similarity with --bypass'))
3255 if exact:
3251 if exact:
3256 if opts.get('edit'):
3252 if opts.get('edit'):
3257 raise error.Abort(_('cannot use --exact with --edit'))
3253 raise error.Abort(_('cannot use --exact with --edit'))
3258 if opts.get('prefix'):
3254 if opts.get('prefix'):
3259 raise error.Abort(_('cannot use --exact with --prefix'))
3255 raise error.Abort(_('cannot use --exact with --prefix'))
3260
3256
3261 base = opts["base"]
3257 base = opts["base"]
3262 msgs = []
3258 msgs = []
3263 ret = 0
3259 ret = 0
3264
3260
3265 with repo.wlock():
3261 with repo.wlock():
3266 if update:
3262 if update:
3267 cmdutil.checkunfinished(repo)
3263 cmdutil.checkunfinished(repo)
3268 if (exact or not opts.get('force')):
3264 if (exact or not opts.get('force')):
3269 cmdutil.bailifchanged(repo)
3265 cmdutil.bailifchanged(repo)
3270
3266
3271 if not opts.get('no_commit'):
3267 if not opts.get('no_commit'):
3272 lock = repo.lock
3268 lock = repo.lock
3273 tr = lambda: repo.transaction('import')
3269 tr = lambda: repo.transaction('import')
3274 dsguard = util.nullcontextmanager
3270 dsguard = util.nullcontextmanager
3275 else:
3271 else:
3276 lock = util.nullcontextmanager
3272 lock = util.nullcontextmanager
3277 tr = util.nullcontextmanager
3273 tr = util.nullcontextmanager
3278 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3274 dsguard = lambda: dirstateguard.dirstateguard(repo, 'import')
3279 with lock(), tr(), dsguard():
3275 with lock(), tr(), dsguard():
3280 parents = repo[None].parents()
3276 parents = repo[None].parents()
3281 for patchurl in patches:
3277 for patchurl in patches:
3282 if patchurl == '-':
3278 if patchurl == '-':
3283 ui.status(_('applying patch from stdin\n'))
3279 ui.status(_('applying patch from stdin\n'))
3284 patchfile = ui.fin
3280 patchfile = ui.fin
3285 patchurl = 'stdin' # for error message
3281 patchurl = 'stdin' # for error message
3286 else:
3282 else:
3287 patchurl = os.path.join(base, patchurl)
3283 patchurl = os.path.join(base, patchurl)
3288 ui.status(_('applying %s\n') % patchurl)
3284 ui.status(_('applying %s\n') % patchurl)
3289 patchfile = hg.openpath(ui, patchurl)
3285 patchfile = hg.openpath(ui, patchurl)
3290
3286
3291 haspatch = False
3287 haspatch = False
3292 for hunk in patch.split(patchfile):
3288 for hunk in patch.split(patchfile):
3293 with patch.extract(ui, hunk) as patchdata:
3289 with patch.extract(ui, hunk) as patchdata:
3294 msg, node, rej = cmdutil.tryimportone(ui, repo,
3290 msg, node, rej = cmdutil.tryimportone(ui, repo,
3295 patchdata,
3291 patchdata,
3296 parents, opts,
3292 parents, opts,
3297 msgs, hg.clean)
3293 msgs, hg.clean)
3298 if msg:
3294 if msg:
3299 haspatch = True
3295 haspatch = True
3300 ui.note(msg + '\n')
3296 ui.note(msg + '\n')
3301 if update or exact:
3297 if update or exact:
3302 parents = repo[None].parents()
3298 parents = repo[None].parents()
3303 else:
3299 else:
3304 parents = [repo[node]]
3300 parents = [repo[node]]
3305 if rej:
3301 if rej:
3306 ui.write_err(_("patch applied partially\n"))
3302 ui.write_err(_("patch applied partially\n"))
3307 ui.write_err(_("(fix the .rej files and run "
3303 ui.write_err(_("(fix the .rej files and run "
3308 "`hg commit --amend`)\n"))
3304 "`hg commit --amend`)\n"))
3309 ret = 1
3305 ret = 1
3310 break
3306 break
3311
3307
3312 if not haspatch:
3308 if not haspatch:
3313 raise error.Abort(_('%s: no diffs found') % patchurl)
3309 raise error.Abort(_('%s: no diffs found') % patchurl)
3314
3310
3315 if msgs:
3311 if msgs:
3316 repo.savecommitmessage('\n* * *\n'.join(msgs))
3312 repo.savecommitmessage('\n* * *\n'.join(msgs))
3317 return ret
3313 return ret
3318
3314
3319 @command('incoming|in',
3315 @command('incoming|in',
3320 [('f', 'force', None,
3316 [('f', 'force', None,
3321 _('run even if remote repository is unrelated')),
3317 _('run even if remote repository is unrelated')),
3322 ('n', 'newest-first', None, _('show newest record first')),
3318 ('n', 'newest-first', None, _('show newest record first')),
3323 ('', 'bundle', '',
3319 ('', 'bundle', '',
3324 _('file to store the bundles into'), _('FILE')),
3320 _('file to store the bundles into'), _('FILE')),
3325 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3321 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3326 ('B', 'bookmarks', False, _("compare bookmarks")),
3322 ('B', 'bookmarks', False, _("compare bookmarks")),
3327 ('b', 'branch', [],
3323 ('b', 'branch', [],
3328 _('a specific branch you would like to pull'), _('BRANCH')),
3324 _('a specific branch you would like to pull'), _('BRANCH')),
3329 ] + logopts + remoteopts + subrepoopts,
3325 ] + logopts + remoteopts + subrepoopts,
3330 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3326 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3331 def incoming(ui, repo, source="default", **opts):
3327 def incoming(ui, repo, source="default", **opts):
3332 """show new changesets found in source
3328 """show new changesets found in source
3333
3329
3334 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
3335 pull location. These are the changesets that would have been pulled
3331 pull location. These are the changesets that would have been pulled
3336 by :hg:`pull` at the time you issued this command.
3332 by :hg:`pull` at the time you issued this command.
3337
3333
3338 See pull for valid source format details.
3334 See pull for valid source format details.
3339
3335
3340 .. container:: verbose
3336 .. container:: verbose
3341
3337
3342 With -B/--bookmarks, the result of bookmark comparison between
3338 With -B/--bookmarks, the result of bookmark comparison between
3343 local and remote repositories is displayed. With -v/--verbose,
3339 local and remote repositories is displayed. With -v/--verbose,
3344 status is also displayed for each bookmark like below::
3340 status is also displayed for each bookmark like below::
3345
3341
3346 BM1 01234567890a added
3342 BM1 01234567890a added
3347 BM2 1234567890ab advanced
3343 BM2 1234567890ab advanced
3348 BM3 234567890abc diverged
3344 BM3 234567890abc diverged
3349 BM4 34567890abcd changed
3345 BM4 34567890abcd changed
3350
3346
3351 The action taken locally when pulling depends on the
3347 The action taken locally when pulling depends on the
3352 status of each bookmark:
3348 status of each bookmark:
3353
3349
3354 :``added``: pull will create it
3350 :``added``: pull will create it
3355 :``advanced``: pull will update it
3351 :``advanced``: pull will update it
3356 :``diverged``: pull will create a divergent bookmark
3352 :``diverged``: pull will create a divergent bookmark
3357 :``changed``: result depends on remote changesets
3353 :``changed``: result depends on remote changesets
3358
3354
3359 From the point of view of pulling behavior, bookmark
3355 From the point of view of pulling behavior, bookmark
3360 existing only in the remote repository are treated as ``added``,
3356 existing only in the remote repository are treated as ``added``,
3361 even if it is in fact locally deleted.
3357 even if it is in fact locally deleted.
3362
3358
3363 .. container:: verbose
3359 .. container:: verbose
3364
3360
3365 For remote repository, using --bundle avoids downloading the
3361 For remote repository, using --bundle avoids downloading the
3366 changesets twice if the incoming is followed by a pull.
3362 changesets twice if the incoming is followed by a pull.
3367
3363
3368 Examples:
3364 Examples:
3369
3365
3370 - show incoming changes with patches and full description::
3366 - show incoming changes with patches and full description::
3371
3367
3372 hg incoming -vp
3368 hg incoming -vp
3373
3369
3374 - show incoming changes excluding merges, store a bundle::
3370 - show incoming changes excluding merges, store a bundle::
3375
3371
3376 hg in -vpM --bundle incoming.hg
3372 hg in -vpM --bundle incoming.hg
3377 hg pull incoming.hg
3373 hg pull incoming.hg
3378
3374
3379 - briefly list changes inside a bundle::
3375 - briefly list changes inside a bundle::
3380
3376
3381 hg in changes.hg -T "{desc|firstline}\\n"
3377 hg in changes.hg -T "{desc|firstline}\\n"
3382
3378
3383 Returns 0 if there are incoming changes, 1 otherwise.
3379 Returns 0 if there are incoming changes, 1 otherwise.
3384 """
3380 """
3385 opts = pycompat.byteskwargs(opts)
3381 opts = pycompat.byteskwargs(opts)
3386 if opts.get('graph'):
3382 if opts.get('graph'):
3387 logcmdutil.checkunsupportedgraphflags([], opts)
3383 logcmdutil.checkunsupportedgraphflags([], opts)
3388 def display(other, chlist, displayer):
3384 def display(other, chlist, displayer):
3389 revdag = logcmdutil.graphrevs(other, chlist, opts)
3385 revdag = logcmdutil.graphrevs(other, chlist, opts)
3390 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3386 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3391 graphmod.asciiedges)
3387 graphmod.asciiedges)
3392
3388
3393 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3389 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3394 return 0
3390 return 0
3395
3391
3396 if opts.get('bundle') and opts.get('subrepos'):
3392 if opts.get('bundle') and opts.get('subrepos'):
3397 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3393 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3398
3394
3399 if opts.get('bookmarks'):
3395 if opts.get('bookmarks'):
3400 source, branches = hg.parseurl(ui.expandpath(source),
3396 source, branches = hg.parseurl(ui.expandpath(source),
3401 opts.get('branch'))
3397 opts.get('branch'))
3402 other = hg.peer(repo, opts, source)
3398 other = hg.peer(repo, opts, source)
3403 if 'bookmarks' not in other.listkeys('namespaces'):
3399 if 'bookmarks' not in other.listkeys('namespaces'):
3404 ui.warn(_("remote doesn't support bookmarks\n"))
3400 ui.warn(_("remote doesn't support bookmarks\n"))
3405 return 0
3401 return 0
3406 ui.pager('incoming')
3402 ui.pager('incoming')
3407 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3403 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3408 return bookmarks.incoming(ui, repo, other)
3404 return bookmarks.incoming(ui, repo, other)
3409
3405
3410 repo._subtoppath = ui.expandpath(source)
3406 repo._subtoppath = ui.expandpath(source)
3411 try:
3407 try:
3412 return hg.incoming(ui, repo, source, opts)
3408 return hg.incoming(ui, repo, source, opts)
3413 finally:
3409 finally:
3414 del repo._subtoppath
3410 del repo._subtoppath
3415
3411
3416
3412
3417 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3413 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3418 norepo=True)
3414 norepo=True)
3419 def init(ui, dest=".", **opts):
3415 def init(ui, dest=".", **opts):
3420 """create a new repository in the given directory
3416 """create a new repository in the given directory
3421
3417
3422 Initialize a new repository in the given directory. If the given
3418 Initialize a new repository in the given directory. If the given
3423 directory does not exist, it will be created.
3419 directory does not exist, it will be created.
3424
3420
3425 If no directory is given, the current directory is used.
3421 If no directory is given, the current directory is used.
3426
3422
3427 It is possible to specify an ``ssh://`` URL as the destination.
3423 It is possible to specify an ``ssh://`` URL as the destination.
3428 See :hg:`help urls` for more information.
3424 See :hg:`help urls` for more information.
3429
3425
3430 Returns 0 on success.
3426 Returns 0 on success.
3431 """
3427 """
3432 opts = pycompat.byteskwargs(opts)
3428 opts = pycompat.byteskwargs(opts)
3433 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3429 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3434
3430
3435 @command('locate',
3431 @command('locate',
3436 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3432 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3437 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3433 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3438 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3434 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3439 ] + walkopts,
3435 ] + walkopts,
3440 _('[OPTION]... [PATTERN]...'))
3436 _('[OPTION]... [PATTERN]...'))
3441 def locate(ui, repo, *pats, **opts):
3437 def locate(ui, repo, *pats, **opts):
3442 """locate files matching specific patterns (DEPRECATED)
3438 """locate files matching specific patterns (DEPRECATED)
3443
3439
3444 Print files under Mercurial control in the working directory whose
3440 Print files under Mercurial control in the working directory whose
3445 names match the given patterns.
3441 names match the given patterns.
3446
3442
3447 By default, this command searches all directories in the working
3443 By default, this command searches all directories in the working
3448 directory. To search just the current directory and its
3444 directory. To search just the current directory and its
3449 subdirectories, use "--include .".
3445 subdirectories, use "--include .".
3450
3446
3451 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
3452 of all files under Mercurial control in the working directory.
3448 of all files under Mercurial control in the working directory.
3453
3449
3454 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"
3455 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
3456 will avoid the problem of "xargs" treating single filenames that
3452 will avoid the problem of "xargs" treating single filenames that
3457 contain whitespace as multiple filenames.
3453 contain whitespace as multiple filenames.
3458
3454
3459 See :hg:`help files` for a more versatile command.
3455 See :hg:`help files` for a more versatile command.
3460
3456
3461 Returns 0 if a match is found, 1 otherwise.
3457 Returns 0 if a match is found, 1 otherwise.
3462 """
3458 """
3463 opts = pycompat.byteskwargs(opts)
3459 opts = pycompat.byteskwargs(opts)
3464 if opts.get('print0'):
3460 if opts.get('print0'):
3465 end = '\0'
3461 end = '\0'
3466 else:
3462 else:
3467 end = '\n'
3463 end = '\n'
3468 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3464 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3469
3465
3470 ret = 1
3466 ret = 1
3471 m = scmutil.match(ctx, pats, opts, default='relglob',
3467 m = scmutil.match(ctx, pats, opts, default='relglob',
3472 badfn=lambda x, y: False)
3468 badfn=lambda x, y: False)
3473
3469
3474 ui.pager('locate')
3470 ui.pager('locate')
3475 if ctx.rev() is None:
3471 if ctx.rev() is None:
3476 # When run on the working copy, "locate" includes removed files, so
3472 # When run on the working copy, "locate" includes removed files, so
3477 # we get the list of files from the dirstate.
3473 # we get the list of files from the dirstate.
3478 filesgen = sorted(repo.dirstate.matches(m))
3474 filesgen = sorted(repo.dirstate.matches(m))
3479 else:
3475 else:
3480 filesgen = ctx.matches(m)
3476 filesgen = ctx.matches(m)
3481 for abs in filesgen:
3477 for abs in filesgen:
3482 if opts.get('fullpath'):
3478 if opts.get('fullpath'):
3483 ui.write(repo.wjoin(abs), end)
3479 ui.write(repo.wjoin(abs), end)
3484 else:
3480 else:
3485 ui.write(((pats and m.rel(abs)) or abs), end)
3481 ui.write(((pats and m.rel(abs)) or abs), end)
3486 ret = 0
3482 ret = 0
3487
3483
3488 return ret
3484 return ret
3489
3485
3490 @command('^log|history',
3486 @command('^log|history',
3491 [('f', 'follow', None,
3487 [('f', 'follow', None,
3492 _('follow changeset history, or file history across copies and renames')),
3488 _('follow changeset history, or file history across copies and renames')),
3493 ('', 'follow-first', None,
3489 ('', 'follow-first', None,
3494 _('only follow the first parent of merge changesets (DEPRECATED)')),
3490 _('only follow the first parent of merge changesets (DEPRECATED)')),
3495 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3491 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3496 ('C', 'copies', None, _('show copied files')),
3492 ('C', 'copies', None, _('show copied files')),
3497 ('k', 'keyword', [],
3493 ('k', 'keyword', [],
3498 _('do case-insensitive search for a given text'), _('TEXT')),
3494 _('do case-insensitive search for a given text'), _('TEXT')),
3499 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3495 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3500 ('L', 'line-range', [],
3496 ('L', 'line-range', [],
3501 _('follow line range of specified file (EXPERIMENTAL)'),
3497 _('follow line range of specified file (EXPERIMENTAL)'),
3502 _('FILE,RANGE')),
3498 _('FILE,RANGE')),
3503 ('', 'removed', None, _('include revisions where files were removed')),
3499 ('', 'removed', None, _('include revisions where files were removed')),
3504 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3500 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3505 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3501 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3506 ('', 'only-branch', [],
3502 ('', 'only-branch', [],
3507 _('show only changesets within the given named branch (DEPRECATED)'),
3503 _('show only changesets within the given named branch (DEPRECATED)'),
3508 _('BRANCH')),
3504 _('BRANCH')),
3509 ('b', 'branch', [],
3505 ('b', 'branch', [],
3510 _('show changesets within the given named branch'), _('BRANCH')),
3506 _('show changesets within the given named branch'), _('BRANCH')),
3511 ('P', 'prune', [],
3507 ('P', 'prune', [],
3512 _('do not display revision or any of its ancestors'), _('REV')),
3508 _('do not display revision or any of its ancestors'), _('REV')),
3513 ] + logopts + walkopts,
3509 ] + logopts + walkopts,
3514 _('[OPTION]... [FILE]'),
3510 _('[OPTION]... [FILE]'),
3515 inferrepo=True,
3511 inferrepo=True,
3516 intents={INTENT_READONLY})
3512 intents={INTENT_READONLY})
3517 def log(ui, repo, *pats, **opts):
3513 def log(ui, repo, *pats, **opts):
3518 """show revision history of entire repository or files
3514 """show revision history of entire repository or files
3519
3515
3520 Print the revision history of the specified files or the entire
3516 Print the revision history of the specified files or the entire
3521 project.
3517 project.
3522
3518
3523 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
3524 --follow is set, in which case the working directory parent is
3520 --follow is set, in which case the working directory parent is
3525 used as the starting revision.
3521 used as the starting revision.
3526
3522
3527 File history is shown without following rename or copy history of
3523 File history is shown without following rename or copy history of
3528 files. Use -f/--follow with a filename to follow history across
3524 files. Use -f/--follow with a filename to follow history across
3529 renames and copies. --follow without a filename will only show
3525 renames and copies. --follow without a filename will only show
3530 ancestors of the starting revision.
3526 ancestors of the starting revision.
3531
3527
3532 By default this command prints revision number and changeset id,
3528 By default this command prints revision number and changeset id,
3533 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
3534 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
3535 changed files and full commit message are shown.
3531 changed files and full commit message are shown.
3536
3532
3537 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
3538 recent changeset at the top.
3534 recent changeset at the top.
3539 '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,
3540 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3536 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
3541 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
3542 line.
3538 line.
3543 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
3544 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.
3545
3541
3546 .. container:: verbose
3542 .. container:: verbose
3547
3543
3548 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
3549 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
3550 specified line range will be shown. This option requires --follow;
3546 specified line range will be shown. This option requires --follow;
3551 it can be specified multiple times. Currently, this option is not
3547 it can be specified multiple times. Currently, this option is not
3552 compatible with --graph. This option is experimental.
3548 compatible with --graph. This option is experimental.
3553
3549
3554 .. note::
3550 .. note::
3555
3551
3556 :hg:`log --patch` may generate unexpected diff output for merge
3552 :hg:`log --patch` may generate unexpected diff output for merge
3557 changesets, as it will only compare the merge changeset against
3553 changesets, as it will only compare the merge changeset against
3558 its first parent. Also, only files different from BOTH parents
3554 its first parent. Also, only files different from BOTH parents
3559 will appear in files:.
3555 will appear in files:.
3560
3556
3561 .. note::
3557 .. note::
3562
3558
3563 For performance reasons, :hg:`log FILE` may omit duplicate changes
3559 For performance reasons, :hg:`log FILE` may omit duplicate changes
3564 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
3565 see all such changes, use the --removed switch.
3561 see all such changes, use the --removed switch.
3566
3562
3567 .. container:: verbose
3563 .. container:: verbose
3568
3564
3569 .. note::
3565 .. note::
3570
3566
3571 The history resulting from -L/--line-range options depends on diff
3567 The history resulting from -L/--line-range options depends on diff
3572 options; for instance if white-spaces are ignored, respective changes
3568 options; for instance if white-spaces are ignored, respective changes
3573 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.
3574
3570
3575 .. container:: verbose
3571 .. container:: verbose
3576
3572
3577 Some examples:
3573 Some examples:
3578
3574
3579 - changesets with full descriptions and file lists::
3575 - changesets with full descriptions and file lists::
3580
3576
3581 hg log -v
3577 hg log -v
3582
3578
3583 - changesets ancestral to the working directory::
3579 - changesets ancestral to the working directory::
3584
3580
3585 hg log -f
3581 hg log -f
3586
3582
3587 - last 10 commits on the current branch::
3583 - last 10 commits on the current branch::
3588
3584
3589 hg log -l 10 -b .
3585 hg log -l 10 -b .
3590
3586
3591 - changesets showing all modifications of a file, including removals::
3587 - changesets showing all modifications of a file, including removals::
3592
3588
3593 hg log --removed file.c
3589 hg log --removed file.c
3594
3590
3595 - all changesets that touch a directory, with diffs, excluding merges::
3591 - all changesets that touch a directory, with diffs, excluding merges::
3596
3592
3597 hg log -Mp lib/
3593 hg log -Mp lib/
3598
3594
3599 - all revision numbers that match a keyword::
3595 - all revision numbers that match a keyword::
3600
3596
3601 hg log -k bug --template "{rev}\\n"
3597 hg log -k bug --template "{rev}\\n"
3602
3598
3603 - the full hash identifier of the working directory parent::
3599 - the full hash identifier of the working directory parent::
3604
3600
3605 hg log -r . --template "{node}\\n"
3601 hg log -r . --template "{node}\\n"
3606
3602
3607 - list available log templates::
3603 - list available log templates::
3608
3604
3609 hg log -T list
3605 hg log -T list
3610
3606
3611 - check if a given changeset is included in a tagged release::
3607 - check if a given changeset is included in a tagged release::
3612
3608
3613 hg log -r "a21ccf and ancestor(1.9)"
3609 hg log -r "a21ccf and ancestor(1.9)"
3614
3610
3615 - find all changesets by some user in a date range::
3611 - find all changesets by some user in a date range::
3616
3612
3617 hg log -k alice -d "may 2008 to jul 2008"
3613 hg log -k alice -d "may 2008 to jul 2008"
3618
3614
3619 - summary of all changesets after the last tag::
3615 - summary of all changesets after the last tag::
3620
3616
3621 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3617 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3622
3618
3623 - changesets touching lines 13 to 23 for file.c::
3619 - changesets touching lines 13 to 23 for file.c::
3624
3620
3625 hg log -L file.c,13:23
3621 hg log -L file.c,13:23
3626
3622
3627 - 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
3628 main.c with patch::
3624 main.c with patch::
3629
3625
3630 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
3631
3627
3632 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.
3633
3629
3634 See :hg:`help revisions` for more about specifying and ordering
3630 See :hg:`help revisions` for more about specifying and ordering
3635 revisions.
3631 revisions.
3636
3632
3637 See :hg:`help templates` for more about pre-packaged styles and
3633 See :hg:`help templates` for more about pre-packaged styles and
3638 specifying custom templates. The default template used by the log
3634 specifying custom templates. The default template used by the log
3639 command can be customized via the ``ui.logtemplate`` configuration
3635 command can be customized via the ``ui.logtemplate`` configuration
3640 setting.
3636 setting.
3641
3637
3642 Returns 0 on success.
3638 Returns 0 on success.
3643
3639
3644 """
3640 """
3645 opts = pycompat.byteskwargs(opts)
3641 opts = pycompat.byteskwargs(opts)
3646 linerange = opts.get('line_range')
3642 linerange = opts.get('line_range')
3647
3643
3648 if linerange and not opts.get('follow'):
3644 if linerange and not opts.get('follow'):
3649 raise error.Abort(_('--line-range requires --follow'))
3645 raise error.Abort(_('--line-range requires --follow'))
3650
3646
3651 if linerange and pats:
3647 if linerange and pats:
3652 # TODO: take pats as patterns with no line-range filter
3648 # TODO: take pats as patterns with no line-range filter
3653 raise error.Abort(
3649 raise error.Abort(
3654 _('FILE arguments are not compatible with --line-range option')
3650 _('FILE arguments are not compatible with --line-range option')
3655 )
3651 )
3656
3652
3657 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3653 repo = scmutil.unhidehashlikerevs(repo, opts.get('rev'), 'nowarn')
3658 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3654 revs, differ = logcmdutil.getrevs(repo, pats, opts)
3659 if linerange:
3655 if linerange:
3660 # TODO: should follow file history from logcmdutil._initialrevs(),
3656 # TODO: should follow file history from logcmdutil._initialrevs(),
3661 # then filter the result by logcmdutil._makerevset() and --limit
3657 # then filter the result by logcmdutil._makerevset() and --limit
3662 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3658 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
3663
3659
3664 getrenamed = None
3660 getrenamed = None
3665 if opts.get('copies'):
3661 if opts.get('copies'):
3666 endrev = None
3662 endrev = None
3667 if revs:
3663 if revs:
3668 endrev = revs.max() + 1
3664 endrev = revs.max() + 1
3669 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3665 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3670
3666
3671 ui.pager('log')
3667 ui.pager('log')
3672 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3668 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, differ,
3673 buffered=True)
3669 buffered=True)
3674 if opts.get('graph'):
3670 if opts.get('graph'):
3675 displayfn = logcmdutil.displaygraphrevs
3671 displayfn = logcmdutil.displaygraphrevs
3676 else:
3672 else:
3677 displayfn = logcmdutil.displayrevs
3673 displayfn = logcmdutil.displayrevs
3678 displayfn(ui, repo, revs, displayer, getrenamed)
3674 displayfn(ui, repo, revs, displayer, getrenamed)
3679
3675
3680 @command('manifest',
3676 @command('manifest',
3681 [('r', 'rev', '', _('revision to display'), _('REV')),
3677 [('r', 'rev', '', _('revision to display'), _('REV')),
3682 ('', 'all', False, _("list files from all revisions"))]
3678 ('', 'all', False, _("list files from all revisions"))]
3683 + formatteropts,
3679 + formatteropts,
3684 _('[-r REV]'),
3680 _('[-r REV]'),
3685 intents={INTENT_READONLY})
3681 intents={INTENT_READONLY})
3686 def manifest(ui, repo, node=None, rev=None, **opts):
3682 def manifest(ui, repo, node=None, rev=None, **opts):
3687 """output the current or given revision of the project manifest
3683 """output the current or given revision of the project manifest
3688
3684
3689 Print a list of version controlled files for the given revision.
3685 Print a list of version controlled files for the given revision.
3690 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
3691 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.
3692
3688
3693 With -v, print file permissions, symlink and executable bits.
3689 With -v, print file permissions, symlink and executable bits.
3694 With --debug, print file revision hashes.
3690 With --debug, print file revision hashes.
3695
3691
3696 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
3697 is printed. This includes deleted and renamed files.
3693 is printed. This includes deleted and renamed files.
3698
3694
3699 Returns 0 on success.
3695 Returns 0 on success.
3700 """
3696 """
3701 opts = pycompat.byteskwargs(opts)
3697 opts = pycompat.byteskwargs(opts)
3702 fm = ui.formatter('manifest', opts)
3698 fm = ui.formatter('manifest', opts)
3703
3699
3704 if opts.get('all'):
3700 if opts.get('all'):
3705 if rev or node:
3701 if rev or node:
3706 raise error.Abort(_("can't specify a revision with --all"))
3702 raise error.Abort(_("can't specify a revision with --all"))
3707
3703
3708 res = set()
3704 res = set()
3709 for rev in repo:
3705 for rev in repo:
3710 ctx = repo[rev]
3706 ctx = repo[rev]
3711 res |= set(ctx.files())
3707 res |= set(ctx.files())
3712
3708
3713 ui.pager('manifest')
3709 ui.pager('manifest')
3714 for f in sorted(res):
3710 for f in sorted(res):
3715 fm.startitem()
3711 fm.startitem()
3716 fm.write("path", '%s\n', f)
3712 fm.write("path", '%s\n', f)
3717 fm.end()
3713 fm.end()
3718 return
3714 return
3719
3715
3720 if rev and node:
3716 if rev and node:
3721 raise error.Abort(_("please specify just one revision"))
3717 raise error.Abort(_("please specify just one revision"))
3722
3718
3723 if not node:
3719 if not node:
3724 node = rev
3720 node = rev
3725
3721
3726 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3722 char = {'l': '@', 'x': '*', '': '', 't': 'd'}
3727 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3723 mode = {'l': '644', 'x': '755', '': '644', 't': '755'}
3728 if node:
3724 if node:
3729 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3725 repo = scmutil.unhidehashlikerevs(repo, [node], 'nowarn')
3730 ctx = scmutil.revsingle(repo, node)
3726 ctx = scmutil.revsingle(repo, node)
3731 mf = ctx.manifest()
3727 mf = ctx.manifest()
3732 ui.pager('manifest')
3728 ui.pager('manifest')
3733 for f in ctx:
3729 for f in ctx:
3734 fm.startitem()
3730 fm.startitem()
3735 fm.context(ctx=ctx)
3731 fm.context(ctx=ctx)
3736 fl = ctx[f].flags()
3732 fl = ctx[f].flags()
3737 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3733 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3738 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])
3739 fm.write('path', '%s\n', f)
3735 fm.write('path', '%s\n', f)
3740 fm.end()
3736 fm.end()
3741
3737
3742 @command('^merge',
3738 @command('^merge',
3743 [('f', 'force', None,
3739 [('f', 'force', None,
3744 _('force a merge including outstanding changes (DEPRECATED)')),
3740 _('force a merge including outstanding changes (DEPRECATED)')),
3745 ('r', 'rev', '', _('revision to merge'), _('REV')),
3741 ('r', 'rev', '', _('revision to merge'), _('REV')),
3746 ('P', 'preview', None,
3742 ('P', 'preview', None,
3747 _('review revisions to merge (no merge is performed)')),
3743 _('review revisions to merge (no merge is performed)')),
3748 ('', 'abort', None, _('abort the ongoing merge')),
3744 ('', 'abort', None, _('abort the ongoing merge')),
3749 ] + mergetoolopts,
3745 ] + mergetoolopts,
3750 _('[-P] [[-r] REV]'))
3746 _('[-P] [[-r] REV]'))
3751 def merge(ui, repo, node=None, **opts):
3747 def merge(ui, repo, node=None, **opts):
3752 """merge another revision into working directory
3748 """merge another revision into working directory
3753
3749
3754 The current working directory is updated with all changes made in
3750 The current working directory is updated with all changes made in
3755 the requested revision since the last common predecessor revision.
3751 the requested revision since the last common predecessor revision.
3756
3752
3757 Files that changed between either parent are marked as changed for
3753 Files that changed between either parent are marked as changed for
3758 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
3759 updates to the repository are allowed. The next commit will have
3755 updates to the repository are allowed. The next commit will have
3760 two parents.
3756 two parents.
3761
3757
3762 ``--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
3763 merges. It overrides the HGMERGE environment variable and your
3759 merges. It overrides the HGMERGE environment variable and your
3764 configuration files. See :hg:`help merge-tools` for options.
3760 configuration files. See :hg:`help merge-tools` for options.
3765
3761
3766 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
3767 head revision, and the current branch contains exactly one other
3763 head revision, and the current branch contains exactly one other
3768 head, the other head is merged with by default. Otherwise, an
3764 head, the other head is merged with by default. Otherwise, an
3769 explicit revision with which to merge with must be provided.
3765 explicit revision with which to merge with must be provided.
3770
3766
3771 See :hg:`help resolve` for information on handling file conflicts.
3767 See :hg:`help resolve` for information on handling file conflicts.
3772
3768
3773 To undo an uncommitted merge, use :hg:`merge --abort` which
3769 To undo an uncommitted merge, use :hg:`merge --abort` which
3774 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
3775 all changes.
3771 all changes.
3776
3772
3777 Returns 0 on success, 1 if there are unresolved files.
3773 Returns 0 on success, 1 if there are unresolved files.
3778 """
3774 """
3779
3775
3780 opts = pycompat.byteskwargs(opts)
3776 opts = pycompat.byteskwargs(opts)
3781 abort = opts.get('abort')
3777 abort = opts.get('abort')
3782 if abort and repo.dirstate.p2() == nullid:
3778 if abort and repo.dirstate.p2() == nullid:
3783 cmdutil.wrongtooltocontinue(repo, _('merge'))
3779 cmdutil.wrongtooltocontinue(repo, _('merge'))
3784 if abort:
3780 if abort:
3785 if node:
3781 if node:
3786 raise error.Abort(_("cannot specify a node with --abort"))
3782 raise error.Abort(_("cannot specify a node with --abort"))
3787 if opts.get('rev'):
3783 if opts.get('rev'):
3788 raise error.Abort(_("cannot specify both --rev and --abort"))
3784 raise error.Abort(_("cannot specify both --rev and --abort"))
3789 if opts.get('preview'):
3785 if opts.get('preview'):
3790 raise error.Abort(_("cannot specify --preview with --abort"))
3786 raise error.Abort(_("cannot specify --preview with --abort"))
3791 if opts.get('rev') and node:
3787 if opts.get('rev') and node:
3792 raise error.Abort(_("please specify just one revision"))
3788 raise error.Abort(_("please specify just one revision"))
3793 if not node:
3789 if not node:
3794 node = opts.get('rev')
3790 node = opts.get('rev')
3795
3791
3796 if node:
3792 if node:
3797 node = scmutil.revsingle(repo, node).node()
3793 node = scmutil.revsingle(repo, node).node()
3798
3794
3799 if not node and not abort:
3795 if not node and not abort:
3800 node = repo[destutil.destmerge(repo)].node()
3796 node = repo[destutil.destmerge(repo)].node()
3801
3797
3802 if opts.get('preview'):
3798 if opts.get('preview'):
3803 # find nodes that are ancestors of p2 but not of p1
3799 # find nodes that are ancestors of p2 but not of p1
3804 p1 = repo.lookup('.')
3800 p1 = repo.lookup('.')
3805 p2 = node
3801 p2 = node
3806 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3802 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3807
3803
3808 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3804 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3809 for node in nodes:
3805 for node in nodes:
3810 displayer.show(repo[node])
3806 displayer.show(repo[node])
3811 displayer.close()
3807 displayer.close()
3812 return 0
3808 return 0
3813
3809
3814 # ui.forcemerge is an internal variable, do not document
3810 # ui.forcemerge is an internal variable, do not document
3815 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3811 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
3816 with ui.configoverride(overrides, 'merge'):
3812 with ui.configoverride(overrides, 'merge'):
3817 force = opts.get('force')
3813 force = opts.get('force')
3818 labels = ['working copy', 'merge rev']
3814 labels = ['working copy', 'merge rev']
3819 return hg.merge(repo, node, force=force, mergeforce=force,
3815 return hg.merge(repo, node, force=force, mergeforce=force,
3820 labels=labels, abort=abort)
3816 labels=labels, abort=abort)
3821
3817
3822 @command('outgoing|out',
3818 @command('outgoing|out',
3823 [('f', 'force', None, _('run even when the destination is unrelated')),
3819 [('f', 'force', None, _('run even when the destination is unrelated')),
3824 ('r', 'rev', [],
3820 ('r', 'rev', [],
3825 _('a changeset intended to be included in the destination'), _('REV')),
3821 _('a changeset intended to be included in the destination'), _('REV')),
3826 ('n', 'newest-first', None, _('show newest record first')),
3822 ('n', 'newest-first', None, _('show newest record first')),
3827 ('B', 'bookmarks', False, _('compare bookmarks')),
3823 ('B', 'bookmarks', False, _('compare bookmarks')),
3828 ('b', 'branch', [], _('a specific branch you would like to push'),
3824 ('b', 'branch', [], _('a specific branch you would like to push'),
3829 _('BRANCH')),
3825 _('BRANCH')),
3830 ] + logopts + remoteopts + subrepoopts,
3826 ] + logopts + remoteopts + subrepoopts,
3831 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3827 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3832 def outgoing(ui, repo, dest=None, **opts):
3828 def outgoing(ui, repo, dest=None, **opts):
3833 """show changesets not found in the destination
3829 """show changesets not found in the destination
3834
3830
3835 Show changesets not found in the specified destination repository
3831 Show changesets not found in the specified destination repository
3836 or the default push location. These are the changesets that would
3832 or the default push location. These are the changesets that would
3837 be pushed if a push was requested.
3833 be pushed if a push was requested.
3838
3834
3839 See pull for details of valid destination formats.
3835 See pull for details of valid destination formats.
3840
3836
3841 .. container:: verbose
3837 .. container:: verbose
3842
3838
3843 With -B/--bookmarks, the result of bookmark comparison between
3839 With -B/--bookmarks, the result of bookmark comparison between
3844 local and remote repositories is displayed. With -v/--verbose,
3840 local and remote repositories is displayed. With -v/--verbose,
3845 status is also displayed for each bookmark like below::
3841 status is also displayed for each bookmark like below::
3846
3842
3847 BM1 01234567890a added
3843 BM1 01234567890a added
3848 BM2 deleted
3844 BM2 deleted
3849 BM3 234567890abc advanced
3845 BM3 234567890abc advanced
3850 BM4 34567890abcd diverged
3846 BM4 34567890abcd diverged
3851 BM5 4567890abcde changed
3847 BM5 4567890abcde changed
3852
3848
3853 The action taken when pushing depends on the
3849 The action taken when pushing depends on the
3854 status of each bookmark:
3850 status of each bookmark:
3855
3851
3856 :``added``: push with ``-B`` will create it
3852 :``added``: push with ``-B`` will create it
3857 :``deleted``: push with ``-B`` will delete it
3853 :``deleted``: push with ``-B`` will delete it
3858 :``advanced``: push will update it
3854 :``advanced``: push will update it
3859 :``diverged``: push with ``-B`` will update it
3855 :``diverged``: push with ``-B`` will update it
3860 :``changed``: push with ``-B`` will update it
3856 :``changed``: push with ``-B`` will update it
3861
3857
3862 From the point of view of pushing behavior, bookmarks
3858 From the point of view of pushing behavior, bookmarks
3863 existing only in the remote repository are treated as
3859 existing only in the remote repository are treated as
3864 ``deleted``, even if it is in fact added remotely.
3860 ``deleted``, even if it is in fact added remotely.
3865
3861
3866 Returns 0 if there are outgoing changes, 1 otherwise.
3862 Returns 0 if there are outgoing changes, 1 otherwise.
3867 """
3863 """
3868 # 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
3869 # style URLs, so don't overwrite dest.
3865 # style URLs, so don't overwrite dest.
3870 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3866 path = ui.paths.getpath(dest, default=('default-push', 'default'))
3871 if not path:
3867 if not path:
3872 raise error.Abort(_('default repository not configured!'),
3868 raise error.Abort(_('default repository not configured!'),
3873 hint=_("see 'hg help config.paths'"))
3869 hint=_("see 'hg help config.paths'"))
3874
3870
3875 opts = pycompat.byteskwargs(opts)
3871 opts = pycompat.byteskwargs(opts)
3876 if opts.get('graph'):
3872 if opts.get('graph'):
3877 logcmdutil.checkunsupportedgraphflags([], opts)
3873 logcmdutil.checkunsupportedgraphflags([], opts)
3878 o, other = hg._outgoing(ui, repo, dest, opts)
3874 o, other = hg._outgoing(ui, repo, dest, opts)
3879 if not o:
3875 if not o:
3880 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3876 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3881 return
3877 return
3882
3878
3883 revdag = logcmdutil.graphrevs(repo, o, opts)
3879 revdag = logcmdutil.graphrevs(repo, o, opts)
3884 ui.pager('outgoing')
3880 ui.pager('outgoing')
3885 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3881 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
3886 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3882 logcmdutil.displaygraph(ui, repo, revdag, displayer,
3887 graphmod.asciiedges)
3883 graphmod.asciiedges)
3888 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3884 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3889 return 0
3885 return 0
3890
3886
3891 if opts.get('bookmarks'):
3887 if opts.get('bookmarks'):
3892 dest = path.pushloc or path.loc
3888 dest = path.pushloc or path.loc
3893 other = hg.peer(repo, opts, dest)
3889 other = hg.peer(repo, opts, dest)
3894 if 'bookmarks' not in other.listkeys('namespaces'):
3890 if 'bookmarks' not in other.listkeys('namespaces'):
3895 ui.warn(_("remote doesn't support bookmarks\n"))
3891 ui.warn(_("remote doesn't support bookmarks\n"))
3896 return 0
3892 return 0
3897 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3893 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3898 ui.pager('outgoing')
3894 ui.pager('outgoing')
3899 return bookmarks.outgoing(ui, repo, other)
3895 return bookmarks.outgoing(ui, repo, other)
3900
3896
3901 repo._subtoppath = path.pushloc or path.loc
3897 repo._subtoppath = path.pushloc or path.loc
3902 try:
3898 try:
3903 return hg.outgoing(ui, repo, dest, opts)
3899 return hg.outgoing(ui, repo, dest, opts)
3904 finally:
3900 finally:
3905 del repo._subtoppath
3901 del repo._subtoppath
3906
3902
3907 @command('parents',
3903 @command('parents',
3908 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3904 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3909 ] + templateopts,
3905 ] + templateopts,
3910 _('[-r REV] [FILE]'),
3906 _('[-r REV] [FILE]'),
3911 inferrepo=True)
3907 inferrepo=True)
3912 def parents(ui, repo, file_=None, **opts):
3908 def parents(ui, repo, file_=None, **opts):
3913 """show the parents of the working directory or revision (DEPRECATED)
3909 """show the parents of the working directory or revision (DEPRECATED)
3914
3910
3915 Print the working directory's parent revisions. If a revision is
3911 Print the working directory's parent revisions. If a revision is
3916 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.
3917 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
3918 last changed (before the working directory revision or the
3914 last changed (before the working directory revision or the
3919 argument to --rev if given) is printed.
3915 argument to --rev if given) is printed.
3920
3916
3921 This command is equivalent to::
3917 This command is equivalent to::
3922
3918
3923 hg log -r "p1()+p2()" or
3919 hg log -r "p1()+p2()" or
3924 hg log -r "p1(REV)+p2(REV)" or
3920 hg log -r "p1(REV)+p2(REV)" or
3925 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
3926 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))"
3927
3923
3928 See :hg:`summary` and :hg:`help revsets` for related information.
3924 See :hg:`summary` and :hg:`help revsets` for related information.
3929
3925
3930 Returns 0 on success.
3926 Returns 0 on success.
3931 """
3927 """
3932
3928
3933 opts = pycompat.byteskwargs(opts)
3929 opts = pycompat.byteskwargs(opts)
3934 rev = opts.get('rev')
3930 rev = opts.get('rev')
3935 if rev:
3931 if rev:
3936 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3932 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
3937 ctx = scmutil.revsingle(repo, rev, None)
3933 ctx = scmutil.revsingle(repo, rev, None)
3938
3934
3939 if file_:
3935 if file_:
3940 m = scmutil.match(ctx, (file_,), opts)
3936 m = scmutil.match(ctx, (file_,), opts)
3941 if m.anypats() or len(m.files()) != 1:
3937 if m.anypats() or len(m.files()) != 1:
3942 raise error.Abort(_('can only specify an explicit filename'))
3938 raise error.Abort(_('can only specify an explicit filename'))
3943 file_ = m.files()[0]
3939 file_ = m.files()[0]
3944 filenodes = []
3940 filenodes = []
3945 for cp in ctx.parents():
3941 for cp in ctx.parents():
3946 if not cp:
3942 if not cp:
3947 continue
3943 continue
3948 try:
3944 try:
3949 filenodes.append(cp.filenode(file_))
3945 filenodes.append(cp.filenode(file_))
3950 except error.LookupError:
3946 except error.LookupError:
3951 pass
3947 pass
3952 if not filenodes:
3948 if not filenodes:
3953 raise error.Abort(_("'%s' not found in manifest!") % file_)
3949 raise error.Abort(_("'%s' not found in manifest!") % file_)
3954 p = []
3950 p = []
3955 for fn in filenodes:
3951 for fn in filenodes:
3956 fctx = repo.filectx(file_, fileid=fn)
3952 fctx = repo.filectx(file_, fileid=fn)
3957 p.append(fctx.node())
3953 p.append(fctx.node())
3958 else:
3954 else:
3959 p = [cp.node() for cp in ctx.parents()]
3955 p = [cp.node() for cp in ctx.parents()]
3960
3956
3961 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3957 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3962 for n in p:
3958 for n in p:
3963 if n != nullid:
3959 if n != nullid:
3964 displayer.show(repo[n])
3960 displayer.show(repo[n])
3965 displayer.close()
3961 displayer.close()
3966
3962
3967 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3963 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3968 intents={INTENT_READONLY})
3964 intents={INTENT_READONLY})
3969 def paths(ui, repo, search=None, **opts):
3965 def paths(ui, repo, search=None, **opts):
3970 """show aliases for remote repositories
3966 """show aliases for remote repositories
3971
3967
3972 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,
3973 show definition of all available names.
3969 show definition of all available names.
3974
3970
3975 Option -q/--quiet suppresses all output when searching for NAME
3971 Option -q/--quiet suppresses all output when searching for NAME
3976 and shows only the path names when listing all definitions.
3972 and shows only the path names when listing all definitions.
3977
3973
3978 Path names are defined in the [paths] section of your
3974 Path names are defined in the [paths] section of your
3979 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3975 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3980 repository, ``.hg/hgrc`` is used, too.
3976 repository, ``.hg/hgrc`` is used, too.
3981
3977
3982 The path names ``default`` and ``default-push`` have a special
3978 The path names ``default`` and ``default-push`` have a special
3983 meaning. When performing a push or pull operation, they are used
3979 meaning. When performing a push or pull operation, they are used
3984 as fallbacks if no location is specified on the command-line.
3980 as fallbacks if no location is specified on the command-line.
3985 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
3986 ``default`` will be used for pull; otherwise ``default`` is used
3982 ``default`` will be used for pull; otherwise ``default`` is used
3987 as the fallback for both. When cloning a repository, the clone
3983 as the fallback for both. When cloning a repository, the clone
3988 source is written as ``default`` in ``.hg/hgrc``.
3984 source is written as ``default`` in ``.hg/hgrc``.
3989
3985
3990 .. note::
3986 .. note::
3991
3987
3992 ``default`` and ``default-push`` apply to all inbound (e.g.
3988 ``default`` and ``default-push`` apply to all inbound (e.g.
3993 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3989 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3994 and :hg:`bundle`) operations.
3990 and :hg:`bundle`) operations.
3995
3991
3996 See :hg:`help urls` for more information.
3992 See :hg:`help urls` for more information.
3997
3993
3998 Returns 0 on success.
3994 Returns 0 on success.
3999 """
3995 """
4000
3996
4001 opts = pycompat.byteskwargs(opts)
3997 opts = pycompat.byteskwargs(opts)
4002 ui.pager('paths')
3998 ui.pager('paths')
4003 if search:
3999 if search:
4004 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4000 pathitems = [(name, path) for name, path in ui.paths.iteritems()
4005 if name == search]
4001 if name == search]
4006 else:
4002 else:
4007 pathitems = sorted(ui.paths.iteritems())
4003 pathitems = sorted(ui.paths.iteritems())
4008
4004
4009 fm = ui.formatter('paths', opts)
4005 fm = ui.formatter('paths', opts)
4010 if fm.isplain():
4006 if fm.isplain():
4011 hidepassword = util.hidepassword
4007 hidepassword = util.hidepassword
4012 else:
4008 else:
4013 hidepassword = bytes
4009 hidepassword = bytes
4014 if ui.quiet:
4010 if ui.quiet:
4015 namefmt = '%s\n'
4011 namefmt = '%s\n'
4016 else:
4012 else:
4017 namefmt = '%s = '
4013 namefmt = '%s = '
4018 showsubopts = not search and not ui.quiet
4014 showsubopts = not search and not ui.quiet
4019
4015
4020 for name, path in pathitems:
4016 for name, path in pathitems:
4021 fm.startitem()
4017 fm.startitem()
4022 fm.condwrite(not search, 'name', namefmt, name)
4018 fm.condwrite(not search, 'name', namefmt, name)
4023 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4019 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
4024 for subopt, value in sorted(path.suboptions.items()):
4020 for subopt, value in sorted(path.suboptions.items()):
4025 assert subopt not in ('name', 'url')
4021 assert subopt not in ('name', 'url')
4026 if showsubopts:
4022 if showsubopts:
4027 fm.plain('%s:%s = ' % (name, subopt))
4023 fm.plain('%s:%s = ' % (name, subopt))
4028 fm.condwrite(showsubopts, subopt, '%s\n', value)
4024 fm.condwrite(showsubopts, subopt, '%s\n', value)
4029
4025
4030 fm.end()
4026 fm.end()
4031
4027
4032 if search and not pathitems:
4028 if search and not pathitems:
4033 if not ui.quiet:
4029 if not ui.quiet:
4034 ui.warn(_("not found!\n"))
4030 ui.warn(_("not found!\n"))
4035 return 1
4031 return 1
4036 else:
4032 else:
4037 return 0
4033 return 0
4038
4034
4039 @command('phase',
4035 @command('phase',
4040 [('p', 'public', False, _('set changeset phase to public')),
4036 [('p', 'public', False, _('set changeset phase to public')),
4041 ('d', 'draft', False, _('set changeset phase to draft')),
4037 ('d', 'draft', False, _('set changeset phase to draft')),
4042 ('s', 'secret', False, _('set changeset phase to secret')),
4038 ('s', 'secret', False, _('set changeset phase to secret')),
4043 ('f', 'force', False, _('allow to move boundary backward')),
4039 ('f', 'force', False, _('allow to move boundary backward')),
4044 ('r', 'rev', [], _('target revision'), _('REV')),
4040 ('r', 'rev', [], _('target revision'), _('REV')),
4045 ],
4041 ],
4046 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4042 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4047 def phase(ui, repo, *revs, **opts):
4043 def phase(ui, repo, *revs, **opts):
4048 """set or show the current phase name
4044 """set or show the current phase name
4049
4045
4050 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).
4051
4047
4052 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
4053 phase value of the specified revisions.
4049 phase value of the specified revisions.
4054
4050
4055 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
4056 lower phase to a higher phase. Phases are ordered as follows::
4052 lower phase to a higher phase. Phases are ordered as follows::
4057
4053
4058 public < draft < secret
4054 public < draft < secret
4059
4055
4060 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.
4061
4057
4062 (For more information about the phases concept, see :hg:`help phases`.)
4058 (For more information about the phases concept, see :hg:`help phases`.)
4063 """
4059 """
4064 opts = pycompat.byteskwargs(opts)
4060 opts = pycompat.byteskwargs(opts)
4065 # search for a unique phase argument
4061 # search for a unique phase argument
4066 targetphase = None
4062 targetphase = None
4067 for idx, name in enumerate(phases.phasenames):
4063 for idx, name in enumerate(phases.phasenames):
4068 if opts.get(name, False):
4064 if opts.get(name, False):
4069 if targetphase is not None:
4065 if targetphase is not None:
4070 raise error.Abort(_('only one phase can be specified'))
4066 raise error.Abort(_('only one phase can be specified'))
4071 targetphase = idx
4067 targetphase = idx
4072
4068
4073 # look for specified revision
4069 # look for specified revision
4074 revs = list(revs)
4070 revs = list(revs)
4075 revs.extend(opts['rev'])
4071 revs.extend(opts['rev'])
4076 if not revs:
4072 if not revs:
4077 # display both parents as the second parent phase can influence
4073 # display both parents as the second parent phase can influence
4078 # the phase of a merge commit
4074 # the phase of a merge commit
4079 revs = [c.rev() for c in repo[None].parents()]
4075 revs = [c.rev() for c in repo[None].parents()]
4080
4076
4081 revs = scmutil.revrange(repo, revs)
4077 revs = scmutil.revrange(repo, revs)
4082
4078
4083 ret = 0
4079 ret = 0
4084 if targetphase is None:
4080 if targetphase is None:
4085 # display
4081 # display
4086 for r in revs:
4082 for r in revs:
4087 ctx = repo[r]
4083 ctx = repo[r]
4088 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4084 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4089 else:
4085 else:
4090 with repo.lock(), repo.transaction("phase") as tr:
4086 with repo.lock(), repo.transaction("phase") as tr:
4091 # set phase
4087 # set phase
4092 if not revs:
4088 if not revs:
4093 raise error.Abort(_('empty revision set'))
4089 raise error.Abort(_('empty revision set'))
4094 nodes = [repo[r].node() for r in revs]
4090 nodes = [repo[r].node() for r in revs]
4095 # moving revision from public to draft may hide them
4091 # moving revision from public to draft may hide them
4096 # We have to check result on an unfiltered repository
4092 # We have to check result on an unfiltered repository
4097 unfi = repo.unfiltered()
4093 unfi = repo.unfiltered()
4098 getphase = unfi._phasecache.phase
4094 getphase = unfi._phasecache.phase
4099 olddata = [getphase(unfi, r) for r in unfi]
4095 olddata = [getphase(unfi, r) for r in unfi]
4100 phases.advanceboundary(repo, tr, targetphase, nodes)
4096 phases.advanceboundary(repo, tr, targetphase, nodes)
4101 if opts['force']:
4097 if opts['force']:
4102 phases.retractboundary(repo, tr, targetphase, nodes)
4098 phases.retractboundary(repo, tr, targetphase, nodes)
4103 getphase = unfi._phasecache.phase
4099 getphase = unfi._phasecache.phase
4104 newdata = [getphase(unfi, r) for r in unfi]
4100 newdata = [getphase(unfi, r) for r in unfi]
4105 changes = sum(newdata[r] != olddata[r] for r in unfi)
4101 changes = sum(newdata[r] != olddata[r] for r in unfi)
4106 cl = unfi.changelog
4102 cl = unfi.changelog
4107 rejected = [n for n in nodes
4103 rejected = [n for n in nodes
4108 if newdata[cl.rev(n)] < targetphase]
4104 if newdata[cl.rev(n)] < targetphase]
4109 if rejected:
4105 if rejected:
4110 ui.warn(_('cannot move %i changesets to a higher '
4106 ui.warn(_('cannot move %i changesets to a higher '
4111 'phase, use --force\n') % len(rejected))
4107 'phase, use --force\n') % len(rejected))
4112 ret = 1
4108 ret = 1
4113 if changes:
4109 if changes:
4114 msg = _('phase changed for %i changesets\n') % changes
4110 msg = _('phase changed for %i changesets\n') % changes
4115 if ret:
4111 if ret:
4116 ui.status(msg)
4112 ui.status(msg)
4117 else:
4113 else:
4118 ui.note(msg)
4114 ui.note(msg)
4119 else:
4115 else:
4120 ui.warn(_('no phases changed\n'))
4116 ui.warn(_('no phases changed\n'))
4121 return ret
4117 return ret
4122
4118
4123 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4119 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4124 """Run after a changegroup has been added via pull/unbundle
4120 """Run after a changegroup has been added via pull/unbundle
4125
4121
4126 This takes arguments below:
4122 This takes arguments below:
4127
4123
4128 :modheads: change of heads by pull/unbundle
4124 :modheads: change of heads by pull/unbundle
4129 :optupdate: updating working directory is needed or not
4125 :optupdate: updating working directory is needed or not
4130 :checkout: update destination revision (or None to default destination)
4126 :checkout: update destination revision (or None to default destination)
4131 :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
4132 """
4128 """
4133 if modheads == 0:
4129 if modheads == 0:
4134 return
4130 return
4135 if optupdate:
4131 if optupdate:
4136 try:
4132 try:
4137 return hg.updatetotally(ui, repo, checkout, brev)
4133 return hg.updatetotally(ui, repo, checkout, brev)
4138 except error.UpdateAbort as inst:
4134 except error.UpdateAbort as inst:
4139 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4135 msg = _("not updating: %s") % stringutil.forcebytestr(inst)
4140 hint = inst.hint
4136 hint = inst.hint
4141 raise error.UpdateAbort(msg, hint=hint)
4137 raise error.UpdateAbort(msg, hint=hint)
4142 if modheads > 1:
4138 if modheads > 1:
4143 currentbranchheads = len(repo.branchheads())
4139 currentbranchheads = len(repo.branchheads())
4144 if currentbranchheads == modheads:
4140 if currentbranchheads == modheads:
4145 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"))
4146 elif currentbranchheads > 1:
4142 elif currentbranchheads > 1:
4147 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4143 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4148 "merge)\n"))
4144 "merge)\n"))
4149 else:
4145 else:
4150 ui.status(_("(run 'hg heads' to see heads)\n"))
4146 ui.status(_("(run 'hg heads' to see heads)\n"))
4151 elif not ui.configbool('commands', 'update.requiredest'):
4147 elif not ui.configbool('commands', 'update.requiredest'):
4152 ui.status(_("(run 'hg update' to get a working copy)\n"))
4148 ui.status(_("(run 'hg update' to get a working copy)\n"))
4153
4149
4154 @command('^pull',
4150 @command('^pull',
4155 [('u', 'update', None,
4151 [('u', 'update', None,
4156 _('update to new branch head if new descendants were pulled')),
4152 _('update to new branch head if new descendants were pulled')),
4157 ('f', 'force', None, _('run even when remote repository is unrelated')),
4153 ('f', 'force', None, _('run even when remote repository is unrelated')),
4158 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4154 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4159 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4155 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4160 ('b', 'branch', [], _('a specific branch you would like to pull'),
4156 ('b', 'branch', [], _('a specific branch you would like to pull'),
4161 _('BRANCH')),
4157 _('BRANCH')),
4162 ] + remoteopts,
4158 ] + remoteopts,
4163 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4159 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4164 def pull(ui, repo, source="default", **opts):
4160 def pull(ui, repo, source="default", **opts):
4165 """pull changes from the specified source
4161 """pull changes from the specified source
4166
4162
4167 Pull changes from a remote repository to a local one.
4163 Pull changes from a remote repository to a local one.
4168
4164
4169 This finds all changes from the repository at the specified path
4165 This finds all changes from the repository at the specified path
4170 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
4171 -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
4172 project in the working directory.
4168 project in the working directory.
4173
4169
4174 When cloning from servers that support it, Mercurial may fetch
4170 When cloning from servers that support it, Mercurial may fetch
4175 pre-generated data. When this is done, hooks operating on incoming
4171 pre-generated data. When this is done, hooks operating on incoming
4176 changesets and changegroups may fire more than once, once for each
4172 changesets and changegroups may fire more than once, once for each
4177 pre-generated bundle and as well as for any additional remaining
4173 pre-generated bundle and as well as for any additional remaining
4178 data. See :hg:`help -e clonebundles` for more.
4174 data. See :hg:`help -e clonebundles` for more.
4179
4175
4180 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
4181 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
4182 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
4183 -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`.
4184
4180
4185 If SOURCE is omitted, the 'default' path will be used.
4181 If SOURCE is omitted, the 'default' path will be used.
4186 See :hg:`help urls` for more information.
4182 See :hg:`help urls` for more information.
4187
4183
4188 Specifying bookmark as ``.`` is equivalent to specifying the active
4184 Specifying bookmark as ``.`` is equivalent to specifying the active
4189 bookmark's name.
4185 bookmark's name.
4190
4186
4191 Returns 0 on success, 1 if an update had unresolved files.
4187 Returns 0 on success, 1 if an update had unresolved files.
4192 """
4188 """
4193
4189
4194 opts = pycompat.byteskwargs(opts)
4190 opts = pycompat.byteskwargs(opts)
4195 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4191 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
4196 msg = _('update destination required by configuration')
4192 msg = _('update destination required by configuration')
4197 hint = _('use hg pull followed by hg update DEST')
4193 hint = _('use hg pull followed by hg update DEST')
4198 raise error.Abort(msg, hint=hint)
4194 raise error.Abort(msg, hint=hint)
4199
4195
4200 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4196 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4201 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4197 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4202 other = hg.peer(repo, opts, source)
4198 other = hg.peer(repo, opts, source)
4203 try:
4199 try:
4204 revs, checkout = hg.addbranchrevs(repo, other, branches,
4200 revs, checkout = hg.addbranchrevs(repo, other, branches,
4205 opts.get('rev'))
4201 opts.get('rev'))
4206
4202
4207
4203
4208 pullopargs = {}
4204 pullopargs = {}
4209 if opts.get('bookmark'):
4205 if opts.get('bookmark'):
4210 if not revs:
4206 if not revs:
4211 revs = []
4207 revs = []
4212 # 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
4213 # update the bookmark name. This can result in the revision pulled
4209 # update the bookmark name. This can result in the revision pulled
4214 # 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
4215 # condition on the server. (See issue 4689 for details)
4211 # condition on the server. (See issue 4689 for details)
4216 remotebookmarks = other.listkeys('bookmarks')
4212 remotebookmarks = other.listkeys('bookmarks')
4217 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4213 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
4218 pullopargs['remotebookmarks'] = remotebookmarks
4214 pullopargs['remotebookmarks'] = remotebookmarks
4219 for b in opts['bookmark']:
4215 for b in opts['bookmark']:
4220 b = repo._bookmarks.expandname(b)
4216 b = repo._bookmarks.expandname(b)
4221 if b not in remotebookmarks:
4217 if b not in remotebookmarks:
4222 raise error.Abort(_('remote bookmark %s not found!') % b)
4218 raise error.Abort(_('remote bookmark %s not found!') % b)
4223 revs.append(hex(remotebookmarks[b]))
4219 revs.append(hex(remotebookmarks[b]))
4224
4220
4225 if revs:
4221 if revs:
4226 try:
4222 try:
4227 # When 'rev' is a bookmark name, we cannot guarantee that it
4223 # When 'rev' is a bookmark name, we cannot guarantee that it
4228 # will be updated with that name because of a race condition
4224 # will be updated with that name because of a race condition
4229 # server side. (See issue 4689 for details)
4225 # server side. (See issue 4689 for details)
4230 oldrevs = revs
4226 oldrevs = revs
4231 revs = [] # actually, nodes
4227 revs = [] # actually, nodes
4232 for r in oldrevs:
4228 for r in oldrevs:
4233 with other.commandexecutor() as e:
4229 with other.commandexecutor() as e:
4234 node = e.callcommand('lookup', {'key': r}).result()
4230 node = e.callcommand('lookup', {'key': r}).result()
4235
4231
4236 revs.append(node)
4232 revs.append(node)
4237 if r == checkout:
4233 if r == checkout:
4238 checkout = node
4234 checkout = node
4239 except error.CapabilityError:
4235 except error.CapabilityError:
4240 err = _("other repository doesn't support revision lookup, "
4236 err = _("other repository doesn't support revision lookup, "
4241 "so a rev cannot be specified.")
4237 "so a rev cannot be specified.")
4242 raise error.Abort(err)
4238 raise error.Abort(err)
4243
4239
4244 wlock = util.nullcontextmanager()
4240 wlock = util.nullcontextmanager()
4245 if opts.get('update'):
4241 if opts.get('update'):
4246 wlock = repo.wlock()
4242 wlock = repo.wlock()
4247 with wlock:
4243 with wlock:
4248 pullopargs.update(opts.get('opargs', {}))
4244 pullopargs.update(opts.get('opargs', {}))
4249 modheads = exchange.pull(repo, other, heads=revs,
4245 modheads = exchange.pull(repo, other, heads=revs,
4250 force=opts.get('force'),
4246 force=opts.get('force'),
4251 bookmarks=opts.get('bookmark', ()),
4247 bookmarks=opts.get('bookmark', ()),
4252 opargs=pullopargs).cgresult
4248 opargs=pullopargs).cgresult
4253
4249
4254 # 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
4255 # 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
4256 # destination of the update
4252 # destination of the update
4257 brev = None
4253 brev = None
4258
4254
4259 if checkout:
4255 if checkout:
4260 checkout = repo.changelog.rev(checkout)
4256 checkout = repo.changelog.rev(checkout)
4261
4257
4262 # order below depends on implementation of
4258 # order below depends on implementation of
4263 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4259 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4264 # because 'checkout' is determined without it.
4260 # because 'checkout' is determined without it.
4265 if opts.get('rev'):
4261 if opts.get('rev'):
4266 brev = opts['rev'][0]
4262 brev = opts['rev'][0]
4267 elif opts.get('branch'):
4263 elif opts.get('branch'):
4268 brev = opts['branch'][0]
4264 brev = opts['branch'][0]
4269 else:
4265 else:
4270 brev = branches[0]
4266 brev = branches[0]
4271 repo._subtoppath = source
4267 repo._subtoppath = source
4272 try:
4268 try:
4273 ret = postincoming(ui, repo, modheads, opts.get('update'),
4269 ret = postincoming(ui, repo, modheads, opts.get('update'),
4274 checkout, brev)
4270 checkout, brev)
4275
4271
4276 finally:
4272 finally:
4277 del repo._subtoppath
4273 del repo._subtoppath
4278
4274
4279 finally:
4275 finally:
4280 other.close()
4276 other.close()
4281 return ret
4277 return ret
4282
4278
4283 @command('^push',
4279 @command('^push',
4284 [('f', 'force', None, _('force push')),
4280 [('f', 'force', None, _('force push')),
4285 ('r', 'rev', [],
4281 ('r', 'rev', [],
4286 _('a changeset intended to be included in the destination'),
4282 _('a changeset intended to be included in the destination'),
4287 _('REV')),
4283 _('REV')),
4288 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4284 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4289 ('b', 'branch', [],
4285 ('b', 'branch', [],
4290 _('a specific branch you would like to push'), _('BRANCH')),
4286 _('a specific branch you would like to push'), _('BRANCH')),
4291 ('', 'new-branch', False, _('allow pushing a new branch')),
4287 ('', 'new-branch', False, _('allow pushing a new branch')),
4292 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4288 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4293 ] + remoteopts,
4289 ] + remoteopts,
4294 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4290 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4295 def push(ui, repo, dest=None, **opts):
4291 def push(ui, repo, dest=None, **opts):
4296 """push changes to the specified destination
4292 """push changes to the specified destination
4297
4293
4298 Push changesets from the local repository to the specified
4294 Push changesets from the local repository to the specified
4299 destination.
4295 destination.
4300
4296
4301 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
4302 in the destination repository from the current one.
4298 in the destination repository from the current one.
4303
4299
4304 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
4305 destination, since multiple heads would make it unclear which head
4301 destination, since multiple heads would make it unclear which head
4306 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
4307 before pushing.
4303 before pushing.
4308
4304
4309 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
4310 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
4311 only create a new branch without forcing other changes.
4307 only create a new branch without forcing other changes.
4312
4308
4313 .. note::
4309 .. note::
4314
4310
4315 Extra care should be taken with the -f/--force option,
4311 Extra care should be taken with the -f/--force option,
4316 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
4317 almost always cause confusion for collaborators.
4313 almost always cause confusion for collaborators.
4318
4314
4319 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
4320 will be pushed to the remote repository.
4316 will be pushed to the remote repository.
4321
4317
4322 If -B/--bookmark is used, the specified bookmarked revision, its
4318 If -B/--bookmark is used, the specified bookmarked revision, its
4323 ancestors, and the bookmark will be pushed to the remote
4319 ancestors, and the bookmark will be pushed to the remote
4324 repository. Specifying ``.`` is equivalent to specifying the active
4320 repository. Specifying ``.`` is equivalent to specifying the active
4325 bookmark's name.
4321 bookmark's name.
4326
4322
4327 Please see :hg:`help urls` for important details about ``ssh://``
4323 Please see :hg:`help urls` for important details about ``ssh://``
4328 URLs. If DESTINATION is omitted, a default path will be used.
4324 URLs. If DESTINATION is omitted, a default path will be used.
4329
4325
4330 .. container:: verbose
4326 .. container:: verbose
4331
4327
4332 The --pushvars option sends strings to the server that become
4328 The --pushvars option sends strings to the server that become
4333 environment variables prepended with ``HG_USERVAR_``. For example,
4329 environment variables prepended with ``HG_USERVAR_``. For example,
4334 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4330 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4335 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4331 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4336
4332
4337 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
4338 levels. One example is having a hook that blocks commits containing
4334 levels. One example is having a hook that blocks commits containing
4339 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
4340 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
4341 strings that look like conflict markers.
4337 strings that look like conflict markers.
4342
4338
4343 By default, servers will ignore `--pushvars`. To enable it add the
4339 By default, servers will ignore `--pushvars`. To enable it add the
4344 following to your configuration file::
4340 following to your configuration file::
4345
4341
4346 [push]
4342 [push]
4347 pushvars.server = true
4343 pushvars.server = true
4348
4344
4349 Returns 0 if push was successful, 1 if nothing to push.
4345 Returns 0 if push was successful, 1 if nothing to push.
4350 """
4346 """
4351
4347
4352 opts = pycompat.byteskwargs(opts)
4348 opts = pycompat.byteskwargs(opts)
4353 if opts.get('bookmark'):
4349 if opts.get('bookmark'):
4354 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4350 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4355 for b in opts['bookmark']:
4351 for b in opts['bookmark']:
4356 # translate -B options to -r so changesets get pushed
4352 # translate -B options to -r so changesets get pushed
4357 b = repo._bookmarks.expandname(b)
4353 b = repo._bookmarks.expandname(b)
4358 if b in repo._bookmarks:
4354 if b in repo._bookmarks:
4359 opts.setdefault('rev', []).append(b)
4355 opts.setdefault('rev', []).append(b)
4360 else:
4356 else:
4361 # 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
4362 # this lets simultaneous -r, -b options continue working
4358 # this lets simultaneous -r, -b options continue working
4363 opts.setdefault('rev', []).append("null")
4359 opts.setdefault('rev', []).append("null")
4364
4360
4365 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4361 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4366 if not path:
4362 if not path:
4367 raise error.Abort(_('default repository not configured!'),
4363 raise error.Abort(_('default repository not configured!'),
4368 hint=_("see 'hg help config.paths'"))
4364 hint=_("see 'hg help config.paths'"))
4369 dest = path.pushloc or path.loc
4365 dest = path.pushloc or path.loc
4370 branches = (path.branch, opts.get('branch') or [])
4366 branches = (path.branch, opts.get('branch') or [])
4371 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4367 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4372 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4368 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4373 other = hg.peer(repo, opts, dest)
4369 other = hg.peer(repo, opts, dest)
4374
4370
4375 if revs:
4371 if revs:
4376 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4372 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
4377 if not revs:
4373 if not revs:
4378 raise error.Abort(_("specified revisions evaluate to an empty set"),
4374 raise error.Abort(_("specified revisions evaluate to an empty set"),
4379 hint=_("use different revision arguments"))
4375 hint=_("use different revision arguments"))
4380 elif path.pushrev:
4376 elif path.pushrev:
4381 # 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
4382 # to DAG heads to make discovery simpler.
4378 # to DAG heads to make discovery simpler.
4383 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4379 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4384 revs = scmutil.revrange(repo, [expr])
4380 revs = scmutil.revrange(repo, [expr])
4385 revs = [repo[rev].node() for rev in revs]
4381 revs = [repo[rev].node() for rev in revs]
4386 if not revs:
4382 if not revs:
4387 raise error.Abort(_('default push revset for path evaluates to an '
4383 raise error.Abort(_('default push revset for path evaluates to an '
4388 'empty set'))
4384 'empty set'))
4389
4385
4390 repo._subtoppath = dest
4386 repo._subtoppath = dest
4391 try:
4387 try:
4392 # push subrepos depth-first for coherent ordering
4388 # push subrepos depth-first for coherent ordering
4393 c = repo['.']
4389 c = repo['.']
4394 subs = c.substate # only repos that are committed
4390 subs = c.substate # only repos that are committed
4395 for s in sorted(subs):
4391 for s in sorted(subs):
4396 result = c.sub(s).push(opts)
4392 result = c.sub(s).push(opts)
4397 if result == 0:
4393 if result == 0:
4398 return not result
4394 return not result
4399 finally:
4395 finally:
4400 del repo._subtoppath
4396 del repo._subtoppath
4401
4397
4402 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
4403 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4399 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4404
4400
4405 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4401 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4406 newbranch=opts.get('new_branch'),
4402 newbranch=opts.get('new_branch'),
4407 bookmarks=opts.get('bookmark', ()),
4403 bookmarks=opts.get('bookmark', ()),
4408 opargs=opargs)
4404 opargs=opargs)
4409
4405
4410 result = not pushop.cgresult
4406 result = not pushop.cgresult
4411
4407
4412 if pushop.bkresult is not None:
4408 if pushop.bkresult is not None:
4413 if pushop.bkresult == 2:
4409 if pushop.bkresult == 2:
4414 result = 2
4410 result = 2
4415 elif not result and pushop.bkresult:
4411 elif not result and pushop.bkresult:
4416 result = 2
4412 result = 2
4417
4413
4418 return result
4414 return result
4419
4415
4420 @command('recover', [])
4416 @command('recover', [])
4421 def recover(ui, repo):
4417 def recover(ui, repo):
4422 """roll back an interrupted transaction
4418 """roll back an interrupted transaction
4423
4419
4424 Recover from an interrupted commit or pull.
4420 Recover from an interrupted commit or pull.
4425
4421
4426 This command tries to fix the repository status after an
4422 This command tries to fix the repository status after an
4427 interrupted operation. It should only be necessary when Mercurial
4423 interrupted operation. It should only be necessary when Mercurial
4428 suggests it.
4424 suggests it.
4429
4425
4430 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.
4431 """
4427 """
4432 if repo.recover():
4428 if repo.recover():
4433 return hg.verify(repo)
4429 return hg.verify(repo)
4434 return 1
4430 return 1
4435
4431
4436 @command('^remove|rm',
4432 @command('^remove|rm',
4437 [('A', 'after', None, _('record delete for missing files')),
4433 [('A', 'after', None, _('record delete for missing files')),
4438 ('f', 'force', None,
4434 ('f', 'force', None,
4439 _('forget added files, delete modified files')),
4435 _('forget added files, delete modified files')),
4440 ] + subrepoopts + walkopts + dryrunopts,
4436 ] + subrepoopts + walkopts + dryrunopts,
4441 _('[OPTION]... FILE...'),
4437 _('[OPTION]... FILE...'),
4442 inferrepo=True)
4438 inferrepo=True)
4443 def remove(ui, repo, *pats, **opts):
4439 def remove(ui, repo, *pats, **opts):
4444 """remove the specified files on the next commit
4440 """remove the specified files on the next commit
4445
4441
4446 Schedule the indicated files for removal from the current branch.
4442 Schedule the indicated files for removal from the current branch.
4447
4443
4448 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.
4449 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
4450 files, see :hg:`forget`.
4446 files, see :hg:`forget`.
4451
4447
4452 .. container:: verbose
4448 .. container:: verbose
4453
4449
4454 -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
4455 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
4456 can be used to remove files from the next revision without
4452 can be used to remove files from the next revision without
4457 deleting them from the working directory.
4453 deleting them from the working directory.
4458
4454
4459 The following table details the behavior of remove for different
4455 The following table details the behavior of remove for different
4460 file states (columns) and option combinations (rows). The file
4456 file states (columns) and option combinations (rows). The file
4461 states are Added [A], Clean [C], Modified [M] and Missing [!]
4457 states are Added [A], Clean [C], Modified [M] and Missing [!]
4462 (as reported by :hg:`status`). The actions are Warn, Remove
4458 (as reported by :hg:`status`). The actions are Warn, Remove
4463 (from branch) and Delete (from disk):
4459 (from branch) and Delete (from disk):
4464
4460
4465 ========= == == == ==
4461 ========= == == == ==
4466 opt/state A C M !
4462 opt/state A C M !
4467 ========= == == == ==
4463 ========= == == == ==
4468 none W RD W R
4464 none W RD W R
4469 -f R RD RD R
4465 -f R RD RD R
4470 -A W W W R
4466 -A W W W R
4471 -Af R R R R
4467 -Af R R R R
4472 ========= == == == ==
4468 ========= == == == ==
4473
4469
4474 .. note::
4470 .. note::
4475
4471
4476 :hg:`remove` never deletes files in Added [A] state from the
4472 :hg:`remove` never deletes files in Added [A] state from the
4477 working directory, not even if ``--force`` is specified.
4473 working directory, not even if ``--force`` is specified.
4478
4474
4479 Returns 0 on success, 1 if any warnings encountered.
4475 Returns 0 on success, 1 if any warnings encountered.
4480 """
4476 """
4481
4477
4482 opts = pycompat.byteskwargs(opts)
4478 opts = pycompat.byteskwargs(opts)
4483 after, force = opts.get('after'), opts.get('force')
4479 after, force = opts.get('after'), opts.get('force')
4484 dryrun = opts.get('dry_run')
4480 dryrun = opts.get('dry_run')
4485 if not pats and not after:
4481 if not pats and not after:
4486 raise error.Abort(_('no files specified'))
4482 raise error.Abort(_('no files specified'))
4487
4483
4488 m = scmutil.match(repo[None], pats, opts)
4484 m = scmutil.match(repo[None], pats, opts)
4489 subrepos = opts.get('subrepos')
4485 subrepos = opts.get('subrepos')
4490 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4486 return cmdutil.remove(ui, repo, m, "", after, force, subrepos,
4491 dryrun=dryrun)
4487 dryrun=dryrun)
4492
4488
4493 @command('rename|move|mv',
4489 @command('rename|move|mv',
4494 [('A', 'after', None, _('record a rename that has already occurred')),
4490 [('A', 'after', None, _('record a rename that has already occurred')),
4495 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4491 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4496 ] + walkopts + dryrunopts,
4492 ] + walkopts + dryrunopts,
4497 _('[OPTION]... SOURCE... DEST'))
4493 _('[OPTION]... SOURCE... DEST'))
4498 def rename(ui, repo, *pats, **opts):
4494 def rename(ui, repo, *pats, **opts):
4499 """rename files; equivalent of copy + remove
4495 """rename files; equivalent of copy + remove
4500
4496
4501 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
4502 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
4503 file, there can only be one source.
4499 file, there can only be one source.
4504
4500
4505 By default, this command copies the contents of files as they
4501 By default, this command copies the contents of files as they
4506 exist in the working directory. If invoked with -A/--after, the
4502 exist in the working directory. If invoked with -A/--after, the
4507 operation is recorded, but no copying is performed.
4503 operation is recorded, but no copying is performed.
4508
4504
4509 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
4510 before that, see :hg:`revert`.
4506 before that, see :hg:`revert`.
4511
4507
4512 Returns 0 on success, 1 if errors are encountered.
4508 Returns 0 on success, 1 if errors are encountered.
4513 """
4509 """
4514 opts = pycompat.byteskwargs(opts)
4510 opts = pycompat.byteskwargs(opts)
4515 with repo.wlock(False):
4511 with repo.wlock(False):
4516 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4512 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4517
4513
4518 @command('resolve',
4514 @command('resolve',
4519 [('a', 'all', None, _('select all unresolved files')),
4515 [('a', 'all', None, _('select all unresolved files')),
4520 ('l', 'list', None, _('list state of files needing merge')),
4516 ('l', 'list', None, _('list state of files needing merge')),
4521 ('m', 'mark', None, _('mark files as resolved')),
4517 ('m', 'mark', None, _('mark files as resolved')),
4522 ('u', 'unmark', None, _('mark files as unresolved')),
4518 ('u', 'unmark', None, _('mark files as unresolved')),
4523 ('n', 'no-status', None, _('hide status prefix')),
4519 ('n', 'no-status', None, _('hide status prefix')),
4524 ('', 're-merge', None, _('re-merge files'))]
4520 ('', 're-merge', None, _('re-merge files'))]
4525 + mergetoolopts + walkopts + formatteropts,
4521 + mergetoolopts + walkopts + formatteropts,
4526 _('[OPTION]... [FILE]...'),
4522 _('[OPTION]... [FILE]...'),
4527 inferrepo=True)
4523 inferrepo=True)
4528 def resolve(ui, repo, *pats, **opts):
4524 def resolve(ui, repo, *pats, **opts):
4529 """redo merges or set/view the merge status of files
4525 """redo merges or set/view the merge status of files
4530
4526
4531 Merges with unresolved conflicts are often the result of
4527 Merges with unresolved conflicts are often the result of
4532 non-interactive merging using the ``internal:merge`` configuration
4528 non-interactive merging using the ``internal:merge`` configuration
4533 setting, or a command-line merge tool like ``diff3``. The resolve
4529 setting, or a command-line merge tool like ``diff3``. The resolve
4534 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
4535 :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
4536 working directory must have two parents). See :hg:`help
4532 working directory must have two parents). See :hg:`help
4537 merge-tools` for information on configuring merge tools.
4533 merge-tools` for information on configuring merge tools.
4538
4534
4539 The resolve command can be used in the following ways:
4535 The resolve command can be used in the following ways:
4540
4536
4541 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4537 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
4542 the specified files, discarding any previous merge attempts. Re-merging
4538 the specified files, discarding any previous merge attempts. Re-merging
4543 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``
4544 to select all unresolved files. ``--tool`` can be used to specify
4540 to select all unresolved files. ``--tool`` can be used to specify
4545 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
4546 environment variable and your configuration files. Previous file
4542 environment variable and your configuration files. Previous file
4547 contents are saved with a ``.orig`` suffix.
4543 contents are saved with a ``.orig`` suffix.
4548
4544
4549 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4545 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4550 (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
4551 to mark all unresolved files.
4547 to mark all unresolved files.
4552
4548
4553 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4549 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4554 default is to mark all resolved files.
4550 default is to mark all resolved files.
4555
4551
4556 - :hg:`resolve -l`: list files which had or still have conflicts.
4552 - :hg:`resolve -l`: list files which had or still have conflicts.
4557 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4553 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4558 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4554 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4559 the list. See :hg:`help filesets` for details.
4555 the list. See :hg:`help filesets` for details.
4560
4556
4561 .. note::
4557 .. note::
4562
4558
4563 Mercurial will not let you commit files with unresolved merge
4559 Mercurial will not let you commit files with unresolved merge
4564 conflicts. You must use :hg:`resolve -m ...` before you can
4560 conflicts. You must use :hg:`resolve -m ...` before you can
4565 commit after a conflicting merge.
4561 commit after a conflicting merge.
4566
4562
4567 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.
4568 """
4564 """
4569
4565
4570 opts = pycompat.byteskwargs(opts)
4566 opts = pycompat.byteskwargs(opts)
4571 confirm = ui.configbool('commands', 'resolve.confirm')
4567 confirm = ui.configbool('commands', 'resolve.confirm')
4572 flaglist = 'all mark unmark list no_status re_merge'.split()
4568 flaglist = 'all mark unmark list no_status re_merge'.split()
4573 all, mark, unmark, show, nostatus, remerge = \
4569 all, mark, unmark, show, nostatus, remerge = \
4574 [opts.get(o) for o in flaglist]
4570 [opts.get(o) for o in flaglist]
4575
4571
4576 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4572 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
4577 if actioncount > 1:
4573 if actioncount > 1:
4578 raise error.Abort(_("too many actions specified"))
4574 raise error.Abort(_("too many actions specified"))
4579 elif (actioncount == 0
4575 elif (actioncount == 0
4580 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4576 and ui.configbool('commands', 'resolve.explicit-re-merge')):
4581 hint = _('use --mark, --unmark, --list or --re-merge')
4577 hint = _('use --mark, --unmark, --list or --re-merge')
4582 raise error.Abort(_('no action specified'), hint=hint)
4578 raise error.Abort(_('no action specified'), hint=hint)
4583 if pats and all:
4579 if pats and all:
4584 raise error.Abort(_("can't specify --all and patterns"))
4580 raise error.Abort(_("can't specify --all and patterns"))
4585 if not (all or pats or show or mark or unmark):
4581 if not (all or pats or show or mark or unmark):
4586 raise error.Abort(_('no files or directories specified'),
4582 raise error.Abort(_('no files or directories specified'),
4587 hint=('use --all to re-merge all unresolved files'))
4583 hint=('use --all to re-merge all unresolved files'))
4588
4584
4589 if confirm:
4585 if confirm:
4590 if all:
4586 if all:
4591 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4587 if ui.promptchoice(_(b're-merge all unresolved files (yn)?'
4592 b'$$ &Yes $$ &No')):
4588 b'$$ &Yes $$ &No')):
4593 raise error.Abort(_('user quit'))
4589 raise error.Abort(_('user quit'))
4594 if mark and not pats:
4590 if mark and not pats:
4595 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4591 if ui.promptchoice(_(b'mark all unresolved files as resolved (yn)?'
4596 b'$$ &Yes $$ &No')):
4592 b'$$ &Yes $$ &No')):
4597 raise error.Abort(_('user quit'))
4593 raise error.Abort(_('user quit'))
4598 if unmark and not pats:
4594 if unmark and not pats:
4599 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4595 if ui.promptchoice(_(b'mark all resolved files as unresolved (yn)?'
4600 b'$$ &Yes $$ &No')):
4596 b'$$ &Yes $$ &No')):
4601 raise error.Abort(_('user quit'))
4597 raise error.Abort(_('user quit'))
4602
4598
4603 if show:
4599 if show:
4604 ui.pager('resolve')
4600 ui.pager('resolve')
4605 fm = ui.formatter('resolve', opts)
4601 fm = ui.formatter('resolve', opts)
4606 ms = mergemod.mergestate.read(repo)
4602 ms = mergemod.mergestate.read(repo)
4607 wctx = repo[None]
4603 wctx = repo[None]
4608 m = scmutil.match(wctx, pats, opts)
4604 m = scmutil.match(wctx, pats, opts)
4609
4605
4610 # Labels and keys based on merge state. Unresolved path conflicts show
4606 # Labels and keys based on merge state. Unresolved path conflicts show
4611 # 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
4612 # resolved conflicts.
4608 # resolved conflicts.
4613 mergestateinfo = {
4609 mergestateinfo = {
4614 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4610 mergemod.MERGE_RECORD_UNRESOLVED: ('resolve.unresolved', 'U'),
4615 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4611 mergemod.MERGE_RECORD_RESOLVED: ('resolve.resolved', 'R'),
4616 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4612 mergemod.MERGE_RECORD_UNRESOLVED_PATH: ('resolve.unresolved', 'P'),
4617 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4613 mergemod.MERGE_RECORD_RESOLVED_PATH: ('resolve.resolved', 'R'),
4618 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4614 mergemod.MERGE_RECORD_DRIVER_RESOLVED: ('resolve.driverresolved',
4619 'D'),
4615 'D'),
4620 }
4616 }
4621
4617
4622 for f in ms:
4618 for f in ms:
4623 if not m(f):
4619 if not m(f):
4624 continue
4620 continue
4625
4621
4626 label, key = mergestateinfo[ms[f]]
4622 label, key = mergestateinfo[ms[f]]
4627 fm.startitem()
4623 fm.startitem()
4628 fm.context(ctx=wctx)
4624 fm.context(ctx=wctx)
4629 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4625 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4630 fm.write('path', '%s\n', f, label=label)
4626 fm.write('path', '%s\n', f, label=label)
4631 fm.end()
4627 fm.end()
4632 return 0
4628 return 0
4633
4629
4634 with repo.wlock():
4630 with repo.wlock():
4635 ms = mergemod.mergestate.read(repo)
4631 ms = mergemod.mergestate.read(repo)
4636
4632
4637 if not (ms.active() or repo.dirstate.p2() != nullid):
4633 if not (ms.active() or repo.dirstate.p2() != nullid):
4638 raise error.Abort(
4634 raise error.Abort(
4639 _('resolve command not applicable when not merging'))
4635 _('resolve command not applicable when not merging'))
4640
4636
4641 wctx = repo[None]
4637 wctx = repo[None]
4642
4638
4643 if (ms.mergedriver
4639 if (ms.mergedriver
4644 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4640 and ms.mdstate() == mergemod.MERGE_DRIVER_STATE_UNMARKED):
4645 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4641 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4646 ms.commit()
4642 ms.commit()
4647 # allow mark and unmark to go through
4643 # allow mark and unmark to go through
4648 if not mark and not unmark and not proceed:
4644 if not mark and not unmark and not proceed:
4649 return 1
4645 return 1
4650
4646
4651 m = scmutil.match(wctx, pats, opts)
4647 m = scmutil.match(wctx, pats, opts)
4652 ret = 0
4648 ret = 0
4653 didwork = False
4649 didwork = False
4654 runconclude = False
4650 runconclude = False
4655
4651
4656 tocomplete = []
4652 tocomplete = []
4657 hasconflictmarkers = []
4653 hasconflictmarkers = []
4658 if mark:
4654 if mark:
4659 markcheck = ui.config('commands', 'resolve.mark-check')
4655 markcheck = ui.config('commands', 'resolve.mark-check')
4660 if markcheck not in ['warn', 'abort']:
4656 if markcheck not in ['warn', 'abort']:
4661 # Treat all invalid / unrecognized values as 'none'.
4657 # Treat all invalid / unrecognized values as 'none'.
4662 markcheck = False
4658 markcheck = False
4663 for f in ms:
4659 for f in ms:
4664 if not m(f):
4660 if not m(f):
4665 continue
4661 continue
4666
4662
4667 didwork = True
4663 didwork = True
4668
4664
4669 # 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
4670 # step if asked to resolve
4666 # step if asked to resolve
4671 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4667 if ms[f] == mergemod.MERGE_RECORD_DRIVER_RESOLVED:
4672 exact = m.exact(f)
4668 exact = m.exact(f)
4673 if mark:
4669 if mark:
4674 if exact:
4670 if exact:
4675 ui.warn(_('not marking %s as it is driver-resolved\n')
4671 ui.warn(_('not marking %s as it is driver-resolved\n')
4676 % f)
4672 % f)
4677 elif unmark:
4673 elif unmark:
4678 if exact:
4674 if exact:
4679 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4675 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4680 % f)
4676 % f)
4681 else:
4677 else:
4682 runconclude = True
4678 runconclude = True
4683 continue
4679 continue
4684
4680
4685 # path conflicts must be resolved manually
4681 # path conflicts must be resolved manually
4686 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4682 if ms[f] in (mergemod.MERGE_RECORD_UNRESOLVED_PATH,
4687 mergemod.MERGE_RECORD_RESOLVED_PATH):
4683 mergemod.MERGE_RECORD_RESOLVED_PATH):
4688 if mark:
4684 if mark:
4689 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4685 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED_PATH)
4690 elif unmark:
4686 elif unmark:
4691 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4687 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED_PATH)
4692 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4688 elif ms[f] == mergemod.MERGE_RECORD_UNRESOLVED_PATH:
4693 ui.warn(_('%s: path conflict must be resolved manually\n')
4689 ui.warn(_('%s: path conflict must be resolved manually\n')
4694 % f)
4690 % f)
4695 continue
4691 continue
4696
4692
4697 if mark:
4693 if mark:
4698 if markcheck:
4694 if markcheck:
4699 with repo.wvfs(f) as fobj:
4695 with repo.wvfs(f) as fobj:
4700 fdata = fobj.read()
4696 fdata = fobj.read()
4701 if filemerge.hasconflictmarkers(fdata) and \
4697 if filemerge.hasconflictmarkers(fdata) and \
4702 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4698 ms[f] != mergemod.MERGE_RECORD_RESOLVED:
4703 hasconflictmarkers.append(f)
4699 hasconflictmarkers.append(f)
4704 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4700 ms.mark(f, mergemod.MERGE_RECORD_RESOLVED)
4705 elif unmark:
4701 elif unmark:
4706 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4702 ms.mark(f, mergemod.MERGE_RECORD_UNRESOLVED)
4707 else:
4703 else:
4708 # backup pre-resolve (merge uses .orig for its own purposes)
4704 # backup pre-resolve (merge uses .orig for its own purposes)
4709 a = repo.wjoin(f)
4705 a = repo.wjoin(f)
4710 try:
4706 try:
4711 util.copyfile(a, a + ".resolve")
4707 util.copyfile(a, a + ".resolve")
4712 except (IOError, OSError) as inst:
4708 except (IOError, OSError) as inst:
4713 if inst.errno != errno.ENOENT:
4709 if inst.errno != errno.ENOENT:
4714 raise
4710 raise
4715
4711
4716 try:
4712 try:
4717 # preresolve file
4713 # preresolve file
4718 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4714 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4719 with ui.configoverride(overrides, 'resolve'):
4715 with ui.configoverride(overrides, 'resolve'):
4720 complete, r = ms.preresolve(f, wctx)
4716 complete, r = ms.preresolve(f, wctx)
4721 if not complete:
4717 if not complete:
4722 tocomplete.append(f)
4718 tocomplete.append(f)
4723 elif r:
4719 elif r:
4724 ret = 1
4720 ret = 1
4725 finally:
4721 finally:
4726 ms.commit()
4722 ms.commit()
4727
4723
4728 # replace filemerge's .orig file with our resolve file, but only
4724 # replace filemerge's .orig file with our resolve file, but only
4729 # for merges that are complete
4725 # for merges that are complete
4730 if complete:
4726 if complete:
4731 try:
4727 try:
4732 util.rename(a + ".resolve",
4728 util.rename(a + ".resolve",
4733 scmutil.origpath(ui, repo, a))
4729 scmutil.origpath(ui, repo, a))
4734 except OSError as inst:
4730 except OSError as inst:
4735 if inst.errno != errno.ENOENT:
4731 if inst.errno != errno.ENOENT:
4736 raise
4732 raise
4737
4733
4738 if hasconflictmarkers:
4734 if hasconflictmarkers:
4739 ui.warn(_('warning: the following files still have conflict '
4735 ui.warn(_('warning: the following files still have conflict '
4740 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4736 'markers:\n ') + '\n '.join(hasconflictmarkers) + '\n')
4741 if markcheck == 'abort' and not all:
4737 if markcheck == 'abort' and not all:
4742 raise error.Abort(_('conflict markers detected'),
4738 raise error.Abort(_('conflict markers detected'),
4743 hint=_('use --all to mark anyway'))
4739 hint=_('use --all to mark anyway'))
4744
4740
4745 for f in tocomplete:
4741 for f in tocomplete:
4746 try:
4742 try:
4747 # resolve file
4743 # resolve file
4748 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4744 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
4749 with ui.configoverride(overrides, 'resolve'):
4745 with ui.configoverride(overrides, 'resolve'):
4750 r = ms.resolve(f, wctx)
4746 r = ms.resolve(f, wctx)
4751 if r:
4747 if r:
4752 ret = 1
4748 ret = 1
4753 finally:
4749 finally:
4754 ms.commit()
4750 ms.commit()
4755
4751
4756 # replace filemerge's .orig file with our resolve file
4752 # replace filemerge's .orig file with our resolve file
4757 a = repo.wjoin(f)
4753 a = repo.wjoin(f)
4758 try:
4754 try:
4759 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4755 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4760 except OSError as inst:
4756 except OSError as inst:
4761 if inst.errno != errno.ENOENT:
4757 if inst.errno != errno.ENOENT:
4762 raise
4758 raise
4763
4759
4764 ms.commit()
4760 ms.commit()
4765 ms.recordactions()
4761 ms.recordactions()
4766
4762
4767 if not didwork and pats:
4763 if not didwork and pats:
4768 hint = None
4764 hint = None
4769 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]):
4770 pats = ['path:%s' % p for p in pats]
4766 pats = ['path:%s' % p for p in pats]
4771 m = scmutil.match(wctx, pats, opts)
4767 m = scmutil.match(wctx, pats, opts)
4772 for f in ms:
4768 for f in ms:
4773 if not m(f):
4769 if not m(f):
4774 continue
4770 continue
4775 def flag(o):
4771 def flag(o):
4776 if o == 're_merge':
4772 if o == 're_merge':
4777 return '--re-merge '
4773 return '--re-merge '
4778 return '-%s ' % o[0:1]
4774 return '-%s ' % o[0:1]
4779 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)])
4780 hint = _("(try: hg resolve %s%s)\n") % (
4776 hint = _("(try: hg resolve %s%s)\n") % (
4781 flags,
4777 flags,
4782 ' '.join(pats))
4778 ' '.join(pats))
4783 break
4779 break
4784 ui.warn(_("arguments do not match paths that need resolving\n"))
4780 ui.warn(_("arguments do not match paths that need resolving\n"))
4785 if hint:
4781 if hint:
4786 ui.warn(hint)
4782 ui.warn(hint)
4787 elif ms.mergedriver and ms.mdstate() != 's':
4783 elif ms.mergedriver and ms.mdstate() != 's':
4788 # run conclude step when either a driver-resolved file is requested
4784 # run conclude step when either a driver-resolved file is requested
4789 # or there are no driver-resolved files
4785 # or there are no driver-resolved files
4790 # 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
4791 # because we might not have tried to resolve some
4787 # because we might not have tried to resolve some
4792 if ((runconclude or not list(ms.driverresolved()))
4788 if ((runconclude or not list(ms.driverresolved()))
4793 and not list(ms.unresolved())):
4789 and not list(ms.unresolved())):
4794 proceed = mergemod.driverconclude(repo, ms, wctx)
4790 proceed = mergemod.driverconclude(repo, ms, wctx)
4795 ms.commit()
4791 ms.commit()
4796 if not proceed:
4792 if not proceed:
4797 return 1
4793 return 1
4798
4794
4799 # Nudge users into finishing an unfinished operation
4795 # Nudge users into finishing an unfinished operation
4800 unresolvedf = list(ms.unresolved())
4796 unresolvedf = list(ms.unresolved())
4801 driverresolvedf = list(ms.driverresolved())
4797 driverresolvedf = list(ms.driverresolved())
4802 if not unresolvedf and not driverresolvedf:
4798 if not unresolvedf and not driverresolvedf:
4803 ui.status(_('(no more unresolved files)\n'))
4799 ui.status(_('(no more unresolved files)\n'))
4804 cmdutil.checkafterresolved(repo)
4800 cmdutil.checkafterresolved(repo)
4805 elif not unresolvedf:
4801 elif not unresolvedf:
4806 ui.status(_('(no more unresolved files -- '
4802 ui.status(_('(no more unresolved files -- '
4807 'run "hg resolve --all" to conclude)\n'))
4803 'run "hg resolve --all" to conclude)\n'))
4808
4804
4809 return ret
4805 return ret
4810
4806
4811 @command('revert',
4807 @command('revert',
4812 [('a', 'all', None, _('revert all changes when no arguments given')),
4808 [('a', 'all', None, _('revert all changes when no arguments given')),
4813 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4809 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4814 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4810 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4815 ('C', 'no-backup', None, _('do not save backup copies of files')),
4811 ('C', 'no-backup', None, _('do not save backup copies of files')),
4816 ('i', 'interactive', None, _('interactively select the changes')),
4812 ('i', 'interactive', None, _('interactively select the changes')),
4817 ] + walkopts + dryrunopts,
4813 ] + walkopts + dryrunopts,
4818 _('[OPTION]... [-r REV] [NAME]...'))
4814 _('[OPTION]... [-r REV] [NAME]...'))
4819 def revert(ui, repo, *pats, **opts):
4815 def revert(ui, repo, *pats, **opts):
4820 """restore files to their checkout state
4816 """restore files to their checkout state
4821
4817
4822 .. note::
4818 .. note::
4823
4819
4824 To check out earlier revisions, you should use :hg:`update REV`.
4820 To check out earlier revisions, you should use :hg:`update REV`.
4825 To cancel an uncommitted merge (and lose your changes),
4821 To cancel an uncommitted merge (and lose your changes),
4826 use :hg:`merge --abort`.
4822 use :hg:`merge --abort`.
4827
4823
4828 With no revision specified, revert the specified files or directories
4824 With no revision specified, revert the specified files or directories
4829 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.
4830 This restores the contents of files to an unmodified
4826 This restores the contents of files to an unmodified
4831 state and unschedules adds, removes, copies, and renames. If the
4827 state and unschedules adds, removes, copies, and renames. If the
4832 working directory has two parents, you must explicitly specify a
4828 working directory has two parents, you must explicitly specify a
4833 revision.
4829 revision.
4834
4830
4835 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
4836 directories to their states as of a specific revision. Because
4832 directories to their states as of a specific revision. Because
4837 revert does not change the working directory parents, this will
4833 revert does not change the working directory parents, this will
4838 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
4839 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
4840 related method.
4836 related method.
4841
4837
4842 Modified files are saved with a .orig suffix before reverting.
4838 Modified files are saved with a .orig suffix before reverting.
4843 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
4844 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
4845 repository by setting the ``ui.origbackuppath`` configuration
4841 repository by setting the ``ui.origbackuppath`` configuration
4846 option.
4842 option.
4847
4843
4848 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.
4849
4845
4850 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
4851 earlier changeset.
4847 earlier changeset.
4852
4848
4853 Returns 0 on success.
4849 Returns 0 on success.
4854 """
4850 """
4855
4851
4856 opts = pycompat.byteskwargs(opts)
4852 opts = pycompat.byteskwargs(opts)
4857 if opts.get("date"):
4853 if opts.get("date"):
4858 if opts.get("rev"):
4854 if opts.get("rev"):
4859 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"))
4860 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4856 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4861
4857
4862 parent, p2 = repo.dirstate.parents()
4858 parent, p2 = repo.dirstate.parents()
4863 if not opts.get('rev') and p2 != nullid:
4859 if not opts.get('rev') and p2 != nullid:
4864 # revert after merge is a trap for new users (issue2915)
4860 # revert after merge is a trap for new users (issue2915)
4865 raise error.Abort(_('uncommitted merge with no revision specified'),
4861 raise error.Abort(_('uncommitted merge with no revision specified'),
4866 hint=_("use 'hg update' or see 'hg help revert'"))
4862 hint=_("use 'hg update' or see 'hg help revert'"))
4867
4863
4868 rev = opts.get('rev')
4864 rev = opts.get('rev')
4869 if rev:
4865 if rev:
4870 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4866 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
4871 ctx = scmutil.revsingle(repo, rev)
4867 ctx = scmutil.revsingle(repo, rev)
4872
4868
4873 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
4874 opts.get('all') or opts.get('interactive'))):
4870 opts.get('all') or opts.get('interactive'))):
4875 msg = _("no files or directories specified")
4871 msg = _("no files or directories specified")
4876 if p2 != nullid:
4872 if p2 != nullid:
4877 hint = _("uncommitted merge, use --all to discard all changes,"
4873 hint = _("uncommitted merge, use --all to discard all changes,"
4878 " or 'hg update -C .' to abort the merge")
4874 " or 'hg update -C .' to abort the merge")
4879 raise error.Abort(msg, hint=hint)
4875 raise error.Abort(msg, hint=hint)
4880 dirty = any(repo.status())
4876 dirty = any(repo.status())
4881 node = ctx.node()
4877 node = ctx.node()
4882 if node != parent:
4878 if node != parent:
4883 if dirty:
4879 if dirty:
4884 hint = _("uncommitted changes, use --all to discard all"
4880 hint = _("uncommitted changes, use --all to discard all"
4885 " changes, or 'hg update %d' to update") % ctx.rev()
4881 " changes, or 'hg update %d' to update") % ctx.rev()
4886 else:
4882 else:
4887 hint = _("use --all to revert all files,"
4883 hint = _("use --all to revert all files,"
4888 " or 'hg update %d' to update") % ctx.rev()
4884 " or 'hg update %d' to update") % ctx.rev()
4889 elif dirty:
4885 elif dirty:
4890 hint = _("uncommitted changes, use --all to discard all changes")
4886 hint = _("uncommitted changes, use --all to discard all changes")
4891 else:
4887 else:
4892 hint = _("use --all to revert all files")
4888 hint = _("use --all to revert all files")
4893 raise error.Abort(msg, hint=hint)
4889 raise error.Abort(msg, hint=hint)
4894
4890
4895 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4891 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4896 **pycompat.strkwargs(opts))
4892 **pycompat.strkwargs(opts))
4897
4893
4898 @command('rollback', dryrunopts +
4894 @command('rollback', dryrunopts +
4899 [('f', 'force', False, _('ignore safety measures'))])
4895 [('f', 'force', False, _('ignore safety measures'))])
4900 def rollback(ui, repo, **opts):
4896 def rollback(ui, repo, **opts):
4901 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4897 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4902
4898
4903 Please use :hg:`commit --amend` instead of rollback to correct
4899 Please use :hg:`commit --amend` instead of rollback to correct
4904 mistakes in the last commit.
4900 mistakes in the last commit.
4905
4901
4906 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
4907 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
4908 restore the dirstate at the time of the last transaction, losing
4904 restore the dirstate at the time of the last transaction, losing
4909 any dirstate changes since that time. This command does not alter
4905 any dirstate changes since that time. This command does not alter
4910 the working directory.
4906 the working directory.
4911
4907
4912 Transactions are used to encapsulate the effects of all commands
4908 Transactions are used to encapsulate the effects of all commands
4913 that create new changesets or propagate existing changesets into a
4909 that create new changesets or propagate existing changesets into a
4914 repository.
4910 repository.
4915
4911
4916 .. container:: verbose
4912 .. container:: verbose
4917
4913
4918 For example, the following commands are transactional, and their
4914 For example, the following commands are transactional, and their
4919 effects can be rolled back:
4915 effects can be rolled back:
4920
4916
4921 - commit
4917 - commit
4922 - import
4918 - import
4923 - pull
4919 - pull
4924 - push (with this repository as the destination)
4920 - push (with this repository as the destination)
4925 - unbundle
4921 - unbundle
4926
4922
4927 To avoid permanent data loss, rollback will refuse to rollback a
4923 To avoid permanent data loss, rollback will refuse to rollback a
4928 commit transaction if it isn't checked out. Use --force to
4924 commit transaction if it isn't checked out. Use --force to
4929 override this protection.
4925 override this protection.
4930
4926
4931 The rollback command can be entirely disabled by setting the
4927 The rollback command can be entirely disabled by setting the
4932 ``ui.rollback`` configuration setting to false. If you're here
4928 ``ui.rollback`` configuration setting to false. If you're here
4933 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
4934 re-enable the command by setting ``ui.rollback`` to true.
4930 re-enable the command by setting ``ui.rollback`` to true.
4935
4931
4936 This command is not intended for use on public repositories. Once
4932 This command is not intended for use on public repositories. Once
4937 changes are visible for pull by other users, rolling a transaction
4933 changes are visible for pull by other users, rolling a transaction
4938 back locally is ineffective (someone else may already have pulled
4934 back locally is ineffective (someone else may already have pulled
4939 the changes). Furthermore, a race is possible with readers of the
4935 the changes). Furthermore, a race is possible with readers of the
4940 repository; for example an in-progress pull from the repository
4936 repository; for example an in-progress pull from the repository
4941 may fail if a rollback is performed.
4937 may fail if a rollback is performed.
4942
4938
4943 Returns 0 on success, 1 if no rollback data is available.
4939 Returns 0 on success, 1 if no rollback data is available.
4944 """
4940 """
4945 if not ui.configbool('ui', 'rollback'):
4941 if not ui.configbool('ui', 'rollback'):
4946 raise error.Abort(_('rollback is disabled because it is unsafe'),
4942 raise error.Abort(_('rollback is disabled because it is unsafe'),
4947 hint=('see `hg help -v rollback` for information'))
4943 hint=('see `hg help -v rollback` for information'))
4948 return repo.rollback(dryrun=opts.get(r'dry_run'),
4944 return repo.rollback(dryrun=opts.get(r'dry_run'),
4949 force=opts.get(r'force'))
4945 force=opts.get(r'force'))
4950
4946
4951 @command('root', [], intents={INTENT_READONLY})
4947 @command('root', [], intents={INTENT_READONLY})
4952 def root(ui, repo):
4948 def root(ui, repo):
4953 """print the root (top) of the current working directory
4949 """print the root (top) of the current working directory
4954
4950
4955 Print the root directory of the current repository.
4951 Print the root directory of the current repository.
4956
4952
4957 Returns 0 on success.
4953 Returns 0 on success.
4958 """
4954 """
4959 ui.write(repo.root + "\n")
4955 ui.write(repo.root + "\n")
4960
4956
4961 @command('^serve',
4957 @command('^serve',
4962 [('A', 'accesslog', '', _('name of access log file to write to'),
4958 [('A', 'accesslog', '', _('name of access log file to write to'),
4963 _('FILE')),
4959 _('FILE')),
4964 ('d', 'daemon', None, _('run server in background')),
4960 ('d', 'daemon', None, _('run server in background')),
4965 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4961 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4966 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4962 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4967 # use string type, then we can check if something was passed
4963 # use string type, then we can check if something was passed
4968 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4964 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4969 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4965 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4970 _('ADDR')),
4966 _('ADDR')),
4971 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4967 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4972 _('PREFIX')),
4968 _('PREFIX')),
4973 ('n', 'name', '',
4969 ('n', 'name', '',
4974 _('name to show in web pages (default: working directory)'), _('NAME')),
4970 _('name to show in web pages (default: working directory)'), _('NAME')),
4975 ('', 'web-conf', '',
4971 ('', 'web-conf', '',
4976 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4972 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4977 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4973 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4978 _('FILE')),
4974 _('FILE')),
4979 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4975 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4980 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4976 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4981 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4977 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4982 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4978 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4983 ('', 'style', '', _('template style to use'), _('STYLE')),
4979 ('', 'style', '', _('template style to use'), _('STYLE')),
4984 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4980 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4985 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
4981 ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
4986 ('', 'print-url', None, _('start and print only the URL'))]
4982 ('', 'print-url', None, _('start and print only the URL'))]
4987 + subrepoopts,
4983 + subrepoopts,
4988 _('[OPTION]...'),
4984 _('[OPTION]...'),
4989 optionalrepo=True)
4985 optionalrepo=True)
4990 def serve(ui, repo, **opts):
4986 def serve(ui, repo, **opts):
4991 """start stand-alone webserver
4987 """start stand-alone webserver
4992
4988
4993 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
4994 this for ad-hoc sharing and browsing of repositories. It is
4990 this for ad-hoc sharing and browsing of repositories. It is
4995 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
4996 longer periods of time.
4992 longer periods of time.
4997
4993
4998 Please note that the server does not implement access control.
4994 Please note that the server does not implement access control.
4999 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
5000 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``
5001 option to ``*`` to allow everybody to push to the server. You
4997 option to ``*`` to allow everybody to push to the server. You
5002 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.
5003
4999
5004 By default, the server logs accesses to stdout and errors to
5000 By default, the server logs accesses to stdout and errors to
5005 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
5006 files.
5002 files.
5007
5003
5008 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
5009 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
5010 number it uses.
5006 number it uses.
5011
5007
5012 Returns 0 on success.
5008 Returns 0 on success.
5013 """
5009 """
5014
5010
5015 opts = pycompat.byteskwargs(opts)
5011 opts = pycompat.byteskwargs(opts)
5016 if opts["stdio"] and opts["cmdserver"]:
5012 if opts["stdio"] and opts["cmdserver"]:
5017 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5013 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5018 if opts["print_url"] and ui.verbose:
5014 if opts["print_url"] and ui.verbose:
5019 raise error.Abort(_("cannot use --print-url with --verbose"))
5015 raise error.Abort(_("cannot use --print-url with --verbose"))
5020
5016
5021 if opts["stdio"]:
5017 if opts["stdio"]:
5022 if repo is None:
5018 if repo is None:
5023 raise error.RepoError(_("there is no Mercurial repository here"
5019 raise error.RepoError(_("there is no Mercurial repository here"
5024 " (.hg not found)"))
5020 " (.hg not found)"))
5025 s = wireprotoserver.sshserver(ui, repo)
5021 s = wireprotoserver.sshserver(ui, repo)
5026 s.serve_forever()
5022 s.serve_forever()
5027
5023
5028 service = server.createservice(ui, repo, opts)
5024 service = server.createservice(ui, repo, opts)
5029 return server.runservice(opts, initfn=service.init, runfn=service.run)
5025 return server.runservice(opts, initfn=service.init, runfn=service.run)
5030
5026
5031 _NOTTERSE = 'nothing'
5027 _NOTTERSE = 'nothing'
5032
5028
5033 @command('^status|st',
5029 @command('^status|st',
5034 [('A', 'all', None, _('show status of all files')),
5030 [('A', 'all', None, _('show status of all files')),
5035 ('m', 'modified', None, _('show only modified files')),
5031 ('m', 'modified', None, _('show only modified files')),
5036 ('a', 'added', None, _('show only added files')),
5032 ('a', 'added', None, _('show only added files')),
5037 ('r', 'removed', None, _('show only removed files')),
5033 ('r', 'removed', None, _('show only removed files')),
5038 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5034 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5039 ('c', 'clean', None, _('show only files without changes')),
5035 ('c', 'clean', None, _('show only files without changes')),
5040 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5036 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5041 ('i', 'ignored', None, _('show only ignored files')),
5037 ('i', 'ignored', None, _('show only ignored files')),
5042 ('n', 'no-status', None, _('hide status prefix')),
5038 ('n', 'no-status', None, _('hide status prefix')),
5043 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5039 ('t', 'terse', _NOTTERSE, _('show the terse output (EXPERIMENTAL)')),
5044 ('C', 'copies', None, _('show source of copied files')),
5040 ('C', 'copies', None, _('show source of copied files')),
5045 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5041 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5046 ('', 'rev', [], _('show difference from revision'), _('REV')),
5042 ('', 'rev', [], _('show difference from revision'), _('REV')),
5047 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5043 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5048 ] + walkopts + subrepoopts + formatteropts,
5044 ] + walkopts + subrepoopts + formatteropts,
5049 _('[OPTION]... [FILE]...'),
5045 _('[OPTION]... [FILE]...'),
5050 inferrepo=True,
5046 inferrepo=True,
5051 intents={INTENT_READONLY})
5047 intents={INTENT_READONLY})
5052 def status(ui, repo, *pats, **opts):
5048 def status(ui, repo, *pats, **opts):
5053 """show changed files in the working directory
5049 """show changed files in the working directory
5054
5050
5055 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
5056 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
5057 the source of a copy/move operation, are not listed unless
5053 the source of a copy/move operation, are not listed unless
5058 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5054 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5059 Unless options described with "show only ..." are given, the
5055 Unless options described with "show only ..." are given, the
5060 options -mardu are used.
5056 options -mardu are used.
5061
5057
5062 Option -q/--quiet hides untracked (unknown and ignored) files
5058 Option -q/--quiet hides untracked (unknown and ignored) files
5063 unless explicitly requested with -u/--unknown or -i/--ignored.
5059 unless explicitly requested with -u/--unknown or -i/--ignored.
5064
5060
5065 .. note::
5061 .. note::
5066
5062
5067 :hg:`status` may appear to disagree with diff if permissions have
5063 :hg:`status` may appear to disagree with diff if permissions have
5068 changed or a merge has occurred. The standard diff format does
5064 changed or a merge has occurred. The standard diff format does
5069 not report permission changes and diff only reports changes
5065 not report permission changes and diff only reports changes
5070 relative to one merge parent.
5066 relative to one merge parent.
5071
5067
5072 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.
5073 If two revisions are given, the differences between them are
5069 If two revisions are given, the differences between them are
5074 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
5075 the changed files of a revision from its first parent.
5071 the changed files of a revision from its first parent.
5076
5072
5077 The codes used to show the status of files are::
5073 The codes used to show the status of files are::
5078
5074
5079 M = modified
5075 M = modified
5080 A = added
5076 A = added
5081 R = removed
5077 R = removed
5082 C = clean
5078 C = clean
5083 ! = missing (deleted by non-hg command, but still tracked)
5079 ! = missing (deleted by non-hg command, but still tracked)
5084 ? = not tracked
5080 ? = not tracked
5085 I = ignored
5081 I = ignored
5086 = origin of the previous file (with --copies)
5082 = origin of the previous file (with --copies)
5087
5083
5088 .. container:: verbose
5084 .. container:: verbose
5089
5085
5090 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
5091 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
5092 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5088 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
5093 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'
5094 for 'ignored' and 'c' for clean.
5090 for 'ignored' and 'c' for clean.
5095
5091
5096 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
5097 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
5098 and -i/--ignored options are also used.
5094 and -i/--ignored options are also used.
5099
5095
5100 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
5101 unfinished merge, shelve, rebase state etc. You can have this behavior
5097 unfinished merge, shelve, rebase state etc. You can have this behavior
5102 turned on by default by enabling the ``commands.status.verbose`` option.
5098 turned on by default by enabling the ``commands.status.verbose`` option.
5103
5099
5104 You can skip displaying some of these states by setting
5100 You can skip displaying some of these states by setting
5105 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5101 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
5106 'histedit', 'merge', 'rebase', or 'unshelve'.
5102 'histedit', 'merge', 'rebase', or 'unshelve'.
5107
5103
5108 Examples:
5104 Examples:
5109
5105
5110 - show changes in the working directory relative to a
5106 - show changes in the working directory relative to a
5111 changeset::
5107 changeset::
5112
5108
5113 hg status --rev 9353
5109 hg status --rev 9353
5114
5110
5115 - show changes in the working directory relative to the
5111 - show changes in the working directory relative to the
5116 current directory (see :hg:`help patterns` for more information)::
5112 current directory (see :hg:`help patterns` for more information)::
5117
5113
5118 hg status re:
5114 hg status re:
5119
5115
5120 - show all changes including copies in an existing changeset::
5116 - show all changes including copies in an existing changeset::
5121
5117
5122 hg status --copies --change 9353
5118 hg status --copies --change 9353
5123
5119
5124 - get a NUL separated list of added files, suitable for xargs::
5120 - get a NUL separated list of added files, suitable for xargs::
5125
5121
5126 hg status -an0
5122 hg status -an0
5127
5123
5128 - show more information about the repository status, abbreviating
5124 - show more information about the repository status, abbreviating
5129 added, removed, modified, deleted, and untracked paths::
5125 added, removed, modified, deleted, and untracked paths::
5130
5126
5131 hg status -v -t mardu
5127 hg status -v -t mardu
5132
5128
5133 Returns 0 on success.
5129 Returns 0 on success.
5134
5130
5135 """
5131 """
5136
5132
5137 opts = pycompat.byteskwargs(opts)
5133 opts = pycompat.byteskwargs(opts)
5138 revs = opts.get('rev')
5134 revs = opts.get('rev')
5139 change = opts.get('change')
5135 change = opts.get('change')
5140 terse = opts.get('terse')
5136 terse = opts.get('terse')
5141 if terse is _NOTTERSE:
5137 if terse is _NOTTERSE:
5142 if revs:
5138 if revs:
5143 terse = ''
5139 terse = ''
5144 else:
5140 else:
5145 terse = ui.config('commands', 'status.terse')
5141 terse = ui.config('commands', 'status.terse')
5146
5142
5147 if revs and change:
5143 if revs and change:
5148 msg = _('cannot specify --rev and --change at the same time')
5144 msg = _('cannot specify --rev and --change at the same time')
5149 raise error.Abort(msg)
5145 raise error.Abort(msg)
5150 elif revs and terse:
5146 elif revs and terse:
5151 msg = _('cannot use --terse with --rev')
5147 msg = _('cannot use --terse with --rev')
5152 raise error.Abort(msg)
5148 raise error.Abort(msg)
5153 elif change:
5149 elif change:
5154 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5150 repo = scmutil.unhidehashlikerevs(repo, [change], 'nowarn')
5155 ctx2 = scmutil.revsingle(repo, change, None)
5151 ctx2 = scmutil.revsingle(repo, change, None)
5156 ctx1 = ctx2.p1()
5152 ctx1 = ctx2.p1()
5157 else:
5153 else:
5158 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5154 repo = scmutil.unhidehashlikerevs(repo, revs, 'nowarn')
5159 ctx1, ctx2 = scmutil.revpair(repo, revs)
5155 ctx1, ctx2 = scmutil.revpair(repo, revs)
5160
5156
5161 if pats or ui.configbool('commands', 'status.relative'):
5157 if pats or ui.configbool('commands', 'status.relative'):
5162 cwd = repo.getcwd()
5158 cwd = repo.getcwd()
5163 else:
5159 else:
5164 cwd = ''
5160 cwd = ''
5165
5161
5166 if opts.get('print0'):
5162 if opts.get('print0'):
5167 end = '\0'
5163 end = '\0'
5168 else:
5164 else:
5169 end = '\n'
5165 end = '\n'
5170 copy = {}
5166 copy = {}
5171 states = 'modified added removed deleted unknown ignored clean'.split()
5167 states = 'modified added removed deleted unknown ignored clean'.split()
5172 show = [k for k in states if opts.get(k)]
5168 show = [k for k in states if opts.get(k)]
5173 if opts.get('all'):
5169 if opts.get('all'):
5174 show += ui.quiet and (states[:4] + ['clean']) or states
5170 show += ui.quiet and (states[:4] + ['clean']) or states
5175
5171
5176 if not show:
5172 if not show:
5177 if ui.quiet:
5173 if ui.quiet:
5178 show = states[:4]
5174 show = states[:4]
5179 else:
5175 else:
5180 show = states[:5]
5176 show = states[:5]
5181
5177
5182 m = scmutil.match(ctx2, pats, opts)
5178 m = scmutil.match(ctx2, pats, opts)
5183 if terse:
5179 if terse:
5184 # we need to compute clean and unknown to terse
5180 # we need to compute clean and unknown to terse
5185 stat = repo.status(ctx1.node(), ctx2.node(), m,
5181 stat = repo.status(ctx1.node(), ctx2.node(), m,
5186 'ignored' in show or 'i' in terse,
5182 'ignored' in show or 'i' in terse,
5187 clean=True, unknown=True,
5183 clean=True, unknown=True,
5188 listsubrepos=opts.get('subrepos'))
5184 listsubrepos=opts.get('subrepos'))
5189
5185
5190 stat = cmdutil.tersedir(stat, terse)
5186 stat = cmdutil.tersedir(stat, terse)
5191 else:
5187 else:
5192 stat = repo.status(ctx1.node(), ctx2.node(), m,
5188 stat = repo.status(ctx1.node(), ctx2.node(), m,
5193 'ignored' in show, 'clean' in show,
5189 'ignored' in show, 'clean' in show,
5194 'unknown' in show, opts.get('subrepos'))
5190 'unknown' in show, opts.get('subrepos'))
5195
5191
5196 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5192 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
5197
5193
5198 if (opts.get('all') or opts.get('copies')
5194 if (opts.get('all') or opts.get('copies')
5199 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5195 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5200 copy = copies.pathcopies(ctx1, ctx2, m)
5196 copy = copies.pathcopies(ctx1, ctx2, m)
5201
5197
5202 ui.pager('status')
5198 ui.pager('status')
5203 fm = ui.formatter('status', opts)
5199 fm = ui.formatter('status', opts)
5204 fmt = '%s' + end
5200 fmt = '%s' + end
5205 showchar = not opts.get('no_status')
5201 showchar = not opts.get('no_status')
5206
5202
5207 for state, char, files in changestates:
5203 for state, char, files in changestates:
5208 if state in show:
5204 if state in show:
5209 label = 'status.' + state
5205 label = 'status.' + state
5210 for f in files:
5206 for f in files:
5211 fm.startitem()
5207 fm.startitem()
5212 fm.context(ctx=ctx2)
5208 fm.context(ctx=ctx2)
5213 fm.data(path=f)
5209 fm.data(path=f)
5214 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5210 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5215 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5211 fm.plain(fmt % repo.pathto(f, cwd), label=label)
5216 if f in copy:
5212 if f in copy:
5217 fm.data(source=copy[f])
5213 fm.data(source=copy[f])
5218 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5214 fm.plain((' %s' + end) % repo.pathto(copy[f], cwd),
5219 label='status.copied')
5215 label='status.copied')
5220
5216
5221 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5217 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
5222 and not ui.plain()):
5218 and not ui.plain()):
5223 cmdutil.morestatus(repo, fm)
5219 cmdutil.morestatus(repo, fm)
5224 fm.end()
5220 fm.end()
5225
5221
5226 @command('^summary|sum',
5222 @command('^summary|sum',
5227 [('', 'remote', None, _('check for push and pull'))],
5223 [('', 'remote', None, _('check for push and pull'))],
5228 '[--remote]',
5224 '[--remote]',
5229 intents={INTENT_READONLY})
5225 intents={INTENT_READONLY})
5230 def summary(ui, repo, **opts):
5226 def summary(ui, repo, **opts):
5231 """summarize working directory state
5227 """summarize working directory state
5232
5228
5233 This generates a brief summary of the working directory state,
5229 This generates a brief summary of the working directory state,
5234 including parents, branch, commit status, phase and available updates.
5230 including parents, branch, commit status, phase and available updates.
5235
5231
5236 With the --remote option, this will check the default paths for
5232 With the --remote option, this will check the default paths for
5237 incoming and outgoing changes. This can be time-consuming.
5233 incoming and outgoing changes. This can be time-consuming.
5238
5234
5239 Returns 0 on success.
5235 Returns 0 on success.
5240 """
5236 """
5241
5237
5242 opts = pycompat.byteskwargs(opts)
5238 opts = pycompat.byteskwargs(opts)
5243 ui.pager('summary')
5239 ui.pager('summary')
5244 ctx = repo[None]
5240 ctx = repo[None]
5245 parents = ctx.parents()
5241 parents = ctx.parents()
5246 pnode = parents[0].node()
5242 pnode = parents[0].node()
5247 marks = []
5243 marks = []
5248
5244
5249 ms = None
5245 ms = None
5250 try:
5246 try:
5251 ms = mergemod.mergestate.read(repo)
5247 ms = mergemod.mergestate.read(repo)
5252 except error.UnsupportedMergeRecords as e:
5248 except error.UnsupportedMergeRecords as e:
5253 s = ' '.join(e.recordtypes)
5249 s = ' '.join(e.recordtypes)
5254 ui.warn(
5250 ui.warn(
5255 _('warning: merge state has unsupported record types: %s\n') % s)
5251 _('warning: merge state has unsupported record types: %s\n') % s)
5256 unresolved = []
5252 unresolved = []
5257 else:
5253 else:
5258 unresolved = list(ms.unresolved())
5254 unresolved = list(ms.unresolved())
5259
5255
5260 for p in parents:
5256 for p in parents:
5261 # label with log.changeset (instead of log.parent) since this
5257 # label with log.changeset (instead of log.parent) since this
5262 # shows a working directory parent *changeset*:
5258 # shows a working directory parent *changeset*:
5263 # i18n: column positioning for "hg summary"
5259 # i18n: column positioning for "hg summary"
5264 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5260 ui.write(_('parent: %d:%s ') % (p.rev(), p),
5265 label=logcmdutil.changesetlabels(p))
5261 label=logcmdutil.changesetlabels(p))
5266 ui.write(' '.join(p.tags()), label='log.tag')
5262 ui.write(' '.join(p.tags()), label='log.tag')
5267 if p.bookmarks():
5263 if p.bookmarks():
5268 marks.extend(p.bookmarks())
5264 marks.extend(p.bookmarks())
5269 if p.rev() == -1:
5265 if p.rev() == -1:
5270 if not len(repo):
5266 if not len(repo):
5271 ui.write(_(' (empty repository)'))
5267 ui.write(_(' (empty repository)'))
5272 else:
5268 else:
5273 ui.write(_(' (no revision checked out)'))
5269 ui.write(_(' (no revision checked out)'))
5274 if p.obsolete():
5270 if p.obsolete():
5275 ui.write(_(' (obsolete)'))
5271 ui.write(_(' (obsolete)'))
5276 if p.isunstable():
5272 if p.isunstable():
5277 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5273 instabilities = (ui.label(instability, 'trouble.%s' % instability)
5278 for instability in p.instabilities())
5274 for instability in p.instabilities())
5279 ui.write(' ('
5275 ui.write(' ('
5280 + ', '.join(instabilities)
5276 + ', '.join(instabilities)
5281 + ')')
5277 + ')')
5282 ui.write('\n')
5278 ui.write('\n')
5283 if p.description():
5279 if p.description():
5284 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5280 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5285 label='log.summary')
5281 label='log.summary')
5286
5282
5287 branch = ctx.branch()
5283 branch = ctx.branch()
5288 bheads = repo.branchheads(branch)
5284 bheads = repo.branchheads(branch)
5289 # i18n: column positioning for "hg summary"
5285 # i18n: column positioning for "hg summary"
5290 m = _('branch: %s\n') % branch
5286 m = _('branch: %s\n') % branch
5291 if branch != 'default':
5287 if branch != 'default':
5292 ui.write(m, label='log.branch')
5288 ui.write(m, label='log.branch')
5293 else:
5289 else:
5294 ui.status(m, label='log.branch')
5290 ui.status(m, label='log.branch')
5295
5291
5296 if marks:
5292 if marks:
5297 active = repo._activebookmark
5293 active = repo._activebookmark
5298 # i18n: column positioning for "hg summary"
5294 # i18n: column positioning for "hg summary"
5299 ui.write(_('bookmarks:'), label='log.bookmark')
5295 ui.write(_('bookmarks:'), label='log.bookmark')
5300 if active is not None:
5296 if active is not None:
5301 if active in marks:
5297 if active in marks:
5302 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5298 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
5303 marks.remove(active)
5299 marks.remove(active)
5304 else:
5300 else:
5305 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5301 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
5306 for m in marks:
5302 for m in marks:
5307 ui.write(' ' + m, label='log.bookmark')
5303 ui.write(' ' + m, label='log.bookmark')
5308 ui.write('\n', label='log.bookmark')
5304 ui.write('\n', label='log.bookmark')
5309
5305
5310 status = repo.status(unknown=True)
5306 status = repo.status(unknown=True)
5311
5307
5312 c = repo.dirstate.copies()
5308 c = repo.dirstate.copies()
5313 copied, renamed = [], []
5309 copied, renamed = [], []
5314 for d, s in c.iteritems():
5310 for d, s in c.iteritems():
5315 if s in status.removed:
5311 if s in status.removed:
5316 status.removed.remove(s)
5312 status.removed.remove(s)
5317 renamed.append(d)
5313 renamed.append(d)
5318 else:
5314 else:
5319 copied.append(d)
5315 copied.append(d)
5320 if d in status.added:
5316 if d in status.added:
5321 status.added.remove(d)
5317 status.added.remove(d)
5322
5318
5323 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()]
5324
5320
5325 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5321 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5326 (ui.label(_('%d added'), 'status.added'), status.added),
5322 (ui.label(_('%d added'), 'status.added'), status.added),
5327 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5323 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5328 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5324 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5329 (ui.label(_('%d copied'), 'status.copied'), copied),
5325 (ui.label(_('%d copied'), 'status.copied'), copied),
5330 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5326 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5331 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5327 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5332 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5328 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5333 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5329 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5334 t = []
5330 t = []
5335 for l, s in labels:
5331 for l, s in labels:
5336 if s:
5332 if s:
5337 t.append(l % len(s))
5333 t.append(l % len(s))
5338
5334
5339 t = ', '.join(t)
5335 t = ', '.join(t)
5340 cleanworkdir = False
5336 cleanworkdir = False
5341
5337
5342 if repo.vfs.exists('graftstate'):
5338 if repo.vfs.exists('graftstate'):
5343 t += _(' (graft in progress)')
5339 t += _(' (graft in progress)')
5344 if repo.vfs.exists('updatestate'):
5340 if repo.vfs.exists('updatestate'):
5345 t += _(' (interrupted update)')
5341 t += _(' (interrupted update)')
5346 elif len(parents) > 1:
5342 elif len(parents) > 1:
5347 t += _(' (merge)')
5343 t += _(' (merge)')
5348 elif branch != parents[0].branch():
5344 elif branch != parents[0].branch():
5349 t += _(' (new branch)')
5345 t += _(' (new branch)')
5350 elif (parents[0].closesbranch() and
5346 elif (parents[0].closesbranch() and
5351 pnode in repo.branchheads(branch, closed=True)):
5347 pnode in repo.branchheads(branch, closed=True)):
5352 t += _(' (head closed)')
5348 t += _(' (head closed)')
5353 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
5354 copied or subs):
5350 copied or subs):
5355 t += _(' (clean)')
5351 t += _(' (clean)')
5356 cleanworkdir = True
5352 cleanworkdir = True
5357 elif pnode not in bheads:
5353 elif pnode not in bheads:
5358 t += _(' (new branch head)')
5354 t += _(' (new branch head)')
5359
5355
5360 if parents:
5356 if parents:
5361 pendingphase = max(p.phase() for p in parents)
5357 pendingphase = max(p.phase() for p in parents)
5362 else:
5358 else:
5363 pendingphase = phases.public
5359 pendingphase = phases.public
5364
5360
5365 if pendingphase > phases.newcommitphase(ui):
5361 if pendingphase > phases.newcommitphase(ui):
5366 t += ' (%s)' % phases.phasenames[pendingphase]
5362 t += ' (%s)' % phases.phasenames[pendingphase]
5367
5363
5368 if cleanworkdir:
5364 if cleanworkdir:
5369 # i18n: column positioning for "hg summary"
5365 # i18n: column positioning for "hg summary"
5370 ui.status(_('commit: %s\n') % t.strip())
5366 ui.status(_('commit: %s\n') % t.strip())
5371 else:
5367 else:
5372 # i18n: column positioning for "hg summary"
5368 # i18n: column positioning for "hg summary"
5373 ui.write(_('commit: %s\n') % t.strip())
5369 ui.write(_('commit: %s\n') % t.strip())
5374
5370
5375 # all ancestors of branch heads - all ancestors of parent = new csets
5371 # all ancestors of branch heads - all ancestors of parent = new csets
5376 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5372 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5377 bheads))
5373 bheads))
5378
5374
5379 if new == 0:
5375 if new == 0:
5380 # i18n: column positioning for "hg summary"
5376 # i18n: column positioning for "hg summary"
5381 ui.status(_('update: (current)\n'))
5377 ui.status(_('update: (current)\n'))
5382 elif pnode not in bheads:
5378 elif pnode not in bheads:
5383 # i18n: column positioning for "hg summary"
5379 # i18n: column positioning for "hg summary"
5384 ui.write(_('update: %d new changesets (update)\n') % new)
5380 ui.write(_('update: %d new changesets (update)\n') % new)
5385 else:
5381 else:
5386 # i18n: column positioning for "hg summary"
5382 # i18n: column positioning for "hg summary"
5387 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5383 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5388 (new, len(bheads)))
5384 (new, len(bheads)))
5389
5385
5390 t = []
5386 t = []
5391 draft = len(repo.revs('draft()'))
5387 draft = len(repo.revs('draft()'))
5392 if draft:
5388 if draft:
5393 t.append(_('%d draft') % draft)
5389 t.append(_('%d draft') % draft)
5394 secret = len(repo.revs('secret()'))
5390 secret = len(repo.revs('secret()'))
5395 if secret:
5391 if secret:
5396 t.append(_('%d secret') % secret)
5392 t.append(_('%d secret') % secret)
5397
5393
5398 if draft or secret:
5394 if draft or secret:
5399 ui.status(_('phases: %s\n') % ', '.join(t))
5395 ui.status(_('phases: %s\n') % ', '.join(t))
5400
5396
5401 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5397 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5402 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5398 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5403 numtrouble = len(repo.revs(trouble + "()"))
5399 numtrouble = len(repo.revs(trouble + "()"))
5404 # We write all the possibilities to ease translation
5400 # We write all the possibilities to ease translation
5405 troublemsg = {
5401 troublemsg = {
5406 "orphan": _("orphan: %d changesets"),
5402 "orphan": _("orphan: %d changesets"),
5407 "contentdivergent": _("content-divergent: %d changesets"),
5403 "contentdivergent": _("content-divergent: %d changesets"),
5408 "phasedivergent": _("phase-divergent: %d changesets"),
5404 "phasedivergent": _("phase-divergent: %d changesets"),
5409 }
5405 }
5410 if numtrouble > 0:
5406 if numtrouble > 0:
5411 ui.status(troublemsg[trouble] % numtrouble + "\n")
5407 ui.status(troublemsg[trouble] % numtrouble + "\n")
5412
5408
5413 cmdutil.summaryhooks(ui, repo)
5409 cmdutil.summaryhooks(ui, repo)
5414
5410
5415 if opts.get('remote'):
5411 if opts.get('remote'):
5416 needsincoming, needsoutgoing = True, True
5412 needsincoming, needsoutgoing = True, True
5417 else:
5413 else:
5418 needsincoming, needsoutgoing = False, False
5414 needsincoming, needsoutgoing = False, False
5419 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5415 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5420 if i:
5416 if i:
5421 needsincoming = True
5417 needsincoming = True
5422 if o:
5418 if o:
5423 needsoutgoing = True
5419 needsoutgoing = True
5424 if not needsincoming and not needsoutgoing:
5420 if not needsincoming and not needsoutgoing:
5425 return
5421 return
5426
5422
5427 def getincoming():
5423 def getincoming():
5428 source, branches = hg.parseurl(ui.expandpath('default'))
5424 source, branches = hg.parseurl(ui.expandpath('default'))
5429 sbranch = branches[0]
5425 sbranch = branches[0]
5430 try:
5426 try:
5431 other = hg.peer(repo, {}, source)
5427 other = hg.peer(repo, {}, source)
5432 except error.RepoError:
5428 except error.RepoError:
5433 if opts.get('remote'):
5429 if opts.get('remote'):
5434 raise
5430 raise
5435 return source, sbranch, None, None, None
5431 return source, sbranch, None, None, None
5436 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5432 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5437 if revs:
5433 if revs:
5438 revs = [other.lookup(rev) for rev in revs]
5434 revs = [other.lookup(rev) for rev in revs]
5439 ui.debug('comparing with %s\n' % util.hidepassword(source))
5435 ui.debug('comparing with %s\n' % util.hidepassword(source))
5440 repo.ui.pushbuffer()
5436 repo.ui.pushbuffer()
5441 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5437 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5442 repo.ui.popbuffer()
5438 repo.ui.popbuffer()
5443 return source, sbranch, other, commoninc, commoninc[1]
5439 return source, sbranch, other, commoninc, commoninc[1]
5444
5440
5445 if needsincoming:
5441 if needsincoming:
5446 source, sbranch, sother, commoninc, incoming = getincoming()
5442 source, sbranch, sother, commoninc, incoming = getincoming()
5447 else:
5443 else:
5448 source = sbranch = sother = commoninc = incoming = None
5444 source = sbranch = sother = commoninc = incoming = None
5449
5445
5450 def getoutgoing():
5446 def getoutgoing():
5451 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5447 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5452 dbranch = branches[0]
5448 dbranch = branches[0]
5453 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5449 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5454 if source != dest:
5450 if source != dest:
5455 try:
5451 try:
5456 dother = hg.peer(repo, {}, dest)
5452 dother = hg.peer(repo, {}, dest)
5457 except error.RepoError:
5453 except error.RepoError:
5458 if opts.get('remote'):
5454 if opts.get('remote'):
5459 raise
5455 raise
5460 return dest, dbranch, None, None
5456 return dest, dbranch, None, None
5461 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5457 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5462 elif sother is None:
5458 elif sother is None:
5463 # there is no explicit destination peer, but source one is invalid
5459 # there is no explicit destination peer, but source one is invalid
5464 return dest, dbranch, None, None
5460 return dest, dbranch, None, None
5465 else:
5461 else:
5466 dother = sother
5462 dother = sother
5467 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5463 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5468 common = None
5464 common = None
5469 else:
5465 else:
5470 common = commoninc
5466 common = commoninc
5471 if revs:
5467 if revs:
5472 revs = [repo.lookup(rev) for rev in revs]
5468 revs = [repo.lookup(rev) for rev in revs]
5473 repo.ui.pushbuffer()
5469 repo.ui.pushbuffer()
5474 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5470 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5475 commoninc=common)
5471 commoninc=common)
5476 repo.ui.popbuffer()
5472 repo.ui.popbuffer()
5477 return dest, dbranch, dother, outgoing
5473 return dest, dbranch, dother, outgoing
5478
5474
5479 if needsoutgoing:
5475 if needsoutgoing:
5480 dest, dbranch, dother, outgoing = getoutgoing()
5476 dest, dbranch, dother, outgoing = getoutgoing()
5481 else:
5477 else:
5482 dest = dbranch = dother = outgoing = None
5478 dest = dbranch = dother = outgoing = None
5483
5479
5484 if opts.get('remote'):
5480 if opts.get('remote'):
5485 t = []
5481 t = []
5486 if incoming:
5482 if incoming:
5487 t.append(_('1 or more incoming'))
5483 t.append(_('1 or more incoming'))
5488 o = outgoing.missing
5484 o = outgoing.missing
5489 if o:
5485 if o:
5490 t.append(_('%d outgoing') % len(o))
5486 t.append(_('%d outgoing') % len(o))
5491 other = dother or sother
5487 other = dother or sother
5492 if 'bookmarks' in other.listkeys('namespaces'):
5488 if 'bookmarks' in other.listkeys('namespaces'):
5493 counts = bookmarks.summary(repo, other)
5489 counts = bookmarks.summary(repo, other)
5494 if counts[0] > 0:
5490 if counts[0] > 0:
5495 t.append(_('%d incoming bookmarks') % counts[0])
5491 t.append(_('%d incoming bookmarks') % counts[0])
5496 if counts[1] > 0:
5492 if counts[1] > 0:
5497 t.append(_('%d outgoing bookmarks') % counts[1])
5493 t.append(_('%d outgoing bookmarks') % counts[1])
5498
5494
5499 if t:
5495 if t:
5500 # i18n: column positioning for "hg summary"
5496 # i18n: column positioning for "hg summary"
5501 ui.write(_('remote: %s\n') % (', '.join(t)))
5497 ui.write(_('remote: %s\n') % (', '.join(t)))
5502 else:
5498 else:
5503 # i18n: column positioning for "hg summary"
5499 # i18n: column positioning for "hg summary"
5504 ui.status(_('remote: (synced)\n'))
5500 ui.status(_('remote: (synced)\n'))
5505
5501
5506 cmdutil.summaryremotehooks(ui, repo, opts,
5502 cmdutil.summaryremotehooks(ui, repo, opts,
5507 ((source, sbranch, sother, commoninc),
5503 ((source, sbranch, sother, commoninc),
5508 (dest, dbranch, dother, outgoing)))
5504 (dest, dbranch, dother, outgoing)))
5509
5505
5510 @command('tag',
5506 @command('tag',
5511 [('f', 'force', None, _('force tag')),
5507 [('f', 'force', None, _('force tag')),
5512 ('l', 'local', None, _('make the tag local')),
5508 ('l', 'local', None, _('make the tag local')),
5513 ('r', 'rev', '', _('revision to tag'), _('REV')),
5509 ('r', 'rev', '', _('revision to tag'), _('REV')),
5514 ('', 'remove', None, _('remove a tag')),
5510 ('', 'remove', None, _('remove a tag')),
5515 # -l/--local is already there, commitopts cannot be used
5511 # -l/--local is already there, commitopts cannot be used
5516 ('e', 'edit', None, _('invoke editor on commit messages')),
5512 ('e', 'edit', None, _('invoke editor on commit messages')),
5517 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5513 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5518 ] + commitopts2,
5514 ] + commitopts2,
5519 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5515 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5520 def tag(ui, repo, name1, *names, **opts):
5516 def tag(ui, repo, name1, *names, **opts):
5521 """add one or more tags for the current or given revision
5517 """add one or more tags for the current or given revision
5522
5518
5523 Name a particular revision using <name>.
5519 Name a particular revision using <name>.
5524
5520
5525 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
5526 very useful to compare different revisions, to go back to significant
5522 very useful to compare different revisions, to go back to significant
5527 earlier versions or to mark branch points as releases, etc. Changing
5523 earlier versions or to mark branch points as releases, etc. Changing
5528 an existing tag is normally disallowed; use -f/--force to override.
5524 an existing tag is normally disallowed; use -f/--force to override.
5529
5525
5530 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
5531 used.
5527 used.
5532
5528
5533 To facilitate version control, distribution, and merging of tags,
5529 To facilitate version control, distribution, and merging of tags,
5534 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
5535 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
5536 also means that tagging creates a new commit. The file
5532 also means that tagging creates a new commit. The file
5537 ".hg/localtags" is used for local tags (not shared among
5533 ".hg/localtags" is used for local tags (not shared among
5538 repositories).
5534 repositories).
5539
5535
5540 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
5541 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
5542 -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
5543 changeset.
5539 changeset.
5544
5540
5545 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.
5546
5542
5547 Since tag names have priority over branch names during revision
5543 Since tag names have priority over branch names during revision
5548 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.
5549
5545
5550 Returns 0 on success.
5546 Returns 0 on success.
5551 """
5547 """
5552 opts = pycompat.byteskwargs(opts)
5548 opts = pycompat.byteskwargs(opts)
5553 with repo.wlock(), repo.lock():
5549 with repo.wlock(), repo.lock():
5554 rev_ = "."
5550 rev_ = "."
5555 names = [t.strip() for t in (name1,) + names]
5551 names = [t.strip() for t in (name1,) + names]
5556 if len(names) != len(set(names)):
5552 if len(names) != len(set(names)):
5557 raise error.Abort(_('tag names must be unique'))
5553 raise error.Abort(_('tag names must be unique'))
5558 for n in names:
5554 for n in names:
5559 scmutil.checknewlabel(repo, n, 'tag')
5555 scmutil.checknewlabel(repo, n, 'tag')
5560 if not n:
5556 if not n:
5561 raise error.Abort(_('tag names cannot consist entirely of '
5557 raise error.Abort(_('tag names cannot consist entirely of '
5562 'whitespace'))
5558 'whitespace'))
5563 if opts.get('rev') and opts.get('remove'):
5559 if opts.get('rev') and opts.get('remove'):
5564 raise error.Abort(_("--rev and --remove are incompatible"))
5560 raise error.Abort(_("--rev and --remove are incompatible"))
5565 if opts.get('rev'):
5561 if opts.get('rev'):
5566 rev_ = opts['rev']
5562 rev_ = opts['rev']
5567 message = opts.get('message')
5563 message = opts.get('message')
5568 if opts.get('remove'):
5564 if opts.get('remove'):
5569 if opts.get('local'):
5565 if opts.get('local'):
5570 expectedtype = 'local'
5566 expectedtype = 'local'
5571 else:
5567 else:
5572 expectedtype = 'global'
5568 expectedtype = 'global'
5573
5569
5574 for n in names:
5570 for n in names:
5575 if not repo.tagtype(n):
5571 if not repo.tagtype(n):
5576 raise error.Abort(_("tag '%s' does not exist") % n)
5572 raise error.Abort(_("tag '%s' does not exist") % n)
5577 if repo.tagtype(n) != expectedtype:
5573 if repo.tagtype(n) != expectedtype:
5578 if expectedtype == 'global':
5574 if expectedtype == 'global':
5579 raise error.Abort(_("tag '%s' is not a global tag") % n)
5575 raise error.Abort(_("tag '%s' is not a global tag") % n)
5580 else:
5576 else:
5581 raise error.Abort(_("tag '%s' is not a local tag") % n)
5577 raise error.Abort(_("tag '%s' is not a local tag") % n)
5582 rev_ = 'null'
5578 rev_ = 'null'
5583 if not message:
5579 if not message:
5584 # we don't translate commit messages
5580 # we don't translate commit messages
5585 message = 'Removed tag %s' % ', '.join(names)
5581 message = 'Removed tag %s' % ', '.join(names)
5586 elif not opts.get('force'):
5582 elif not opts.get('force'):
5587 for n in names:
5583 for n in names:
5588 if n in repo.tags():
5584 if n in repo.tags():
5589 raise error.Abort(_("tag '%s' already exists "
5585 raise error.Abort(_("tag '%s' already exists "
5590 "(use -f to force)") % n)
5586 "(use -f to force)") % n)
5591 if not opts.get('local'):
5587 if not opts.get('local'):
5592 p1, p2 = repo.dirstate.parents()
5588 p1, p2 = repo.dirstate.parents()
5593 if p2 != nullid:
5589 if p2 != nullid:
5594 raise error.Abort(_('uncommitted merge'))
5590 raise error.Abort(_('uncommitted merge'))
5595 bheads = repo.branchheads()
5591 bheads = repo.branchheads()
5596 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:
5597 raise error.Abort(_('working directory is not at a branch head '
5593 raise error.Abort(_('working directory is not at a branch head '
5598 '(use -f to force)'))
5594 '(use -f to force)'))
5599 node = scmutil.revsingle(repo, rev_).node()
5595 node = scmutil.revsingle(repo, rev_).node()
5600
5596
5601 if not message:
5597 if not message:
5602 # we don't translate commit messages
5598 # we don't translate commit messages
5603 message = ('Added tag %s for changeset %s' %
5599 message = ('Added tag %s for changeset %s' %
5604 (', '.join(names), short(node)))
5600 (', '.join(names), short(node)))
5605
5601
5606 date = opts.get('date')
5602 date = opts.get('date')
5607 if date:
5603 if date:
5608 date = dateutil.parsedate(date)
5604 date = dateutil.parsedate(date)
5609
5605
5610 if opts.get('remove'):
5606 if opts.get('remove'):
5611 editform = 'tag.remove'
5607 editform = 'tag.remove'
5612 else:
5608 else:
5613 editform = 'tag.add'
5609 editform = 'tag.add'
5614 editor = cmdutil.getcommiteditor(editform=editform,
5610 editor = cmdutil.getcommiteditor(editform=editform,
5615 **pycompat.strkwargs(opts))
5611 **pycompat.strkwargs(opts))
5616
5612
5617 # don't allow tagging the null rev
5613 # don't allow tagging the null rev
5618 if (not opts.get('remove') and
5614 if (not opts.get('remove') and
5619 scmutil.revsingle(repo, rev_).rev() == nullrev):
5615 scmutil.revsingle(repo, rev_).rev() == nullrev):
5620 raise error.Abort(_("cannot tag null revision"))
5616 raise error.Abort(_("cannot tag null revision"))
5621
5617
5622 tagsmod.tag(repo, names, node, message, opts.get('local'),
5618 tagsmod.tag(repo, names, node, message, opts.get('local'),
5623 opts.get('user'), date, editor=editor)
5619 opts.get('user'), date, editor=editor)
5624
5620
5625 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5621 @command('tags', formatteropts, '', intents={INTENT_READONLY})
5626 def tags(ui, repo, **opts):
5622 def tags(ui, repo, **opts):
5627 """list repository tags
5623 """list repository tags
5628
5624
5629 This lists both regular and local tags. When the -v/--verbose
5625 This lists both regular and local tags. When the -v/--verbose
5630 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.
5631 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.
5632
5628
5633 Returns 0 on success.
5629 Returns 0 on success.
5634 """
5630 """
5635
5631
5636 opts = pycompat.byteskwargs(opts)
5632 opts = pycompat.byteskwargs(opts)
5637 ui.pager('tags')
5633 ui.pager('tags')
5638 fm = ui.formatter('tags', opts)
5634 fm = ui.formatter('tags', opts)
5639 hexfunc = fm.hexfunc
5635 hexfunc = fm.hexfunc
5640 tagtype = ""
5636 tagtype = ""
5641
5637
5642 for t, n in reversed(repo.tagslist()):
5638 for t, n in reversed(repo.tagslist()):
5643 hn = hexfunc(n)
5639 hn = hexfunc(n)
5644 label = 'tags.normal'
5640 label = 'tags.normal'
5645 tagtype = ''
5641 tagtype = ''
5646 if repo.tagtype(t) == 'local':
5642 if repo.tagtype(t) == 'local':
5647 label = 'tags.local'
5643 label = 'tags.local'
5648 tagtype = 'local'
5644 tagtype = 'local'
5649
5645
5650 fm.startitem()
5646 fm.startitem()
5651 fm.context(repo=repo)
5647 fm.context(repo=repo)
5652 fm.write('tag', '%s', t, label=label)
5648 fm.write('tag', '%s', t, label=label)
5653 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5649 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5654 fm.condwrite(not ui.quiet, 'rev node', fmt,
5650 fm.condwrite(not ui.quiet, 'rev node', fmt,
5655 repo.changelog.rev(n), hn, label=label)
5651 repo.changelog.rev(n), hn, label=label)
5656 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5652 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5657 tagtype, label=label)
5653 tagtype, label=label)
5658 fm.plain('\n')
5654 fm.plain('\n')
5659 fm.end()
5655 fm.end()
5660
5656
5661 @command('tip',
5657 @command('tip',
5662 [('p', 'patch', None, _('show patch')),
5658 [('p', 'patch', None, _('show patch')),
5663 ('g', 'git', None, _('use git extended diff format')),
5659 ('g', 'git', None, _('use git extended diff format')),
5664 ] + templateopts,
5660 ] + templateopts,
5665 _('[-p] [-g]'))
5661 _('[-p] [-g]'))
5666 def tip(ui, repo, **opts):
5662 def tip(ui, repo, **opts):
5667 """show the tip revision (DEPRECATED)
5663 """show the tip revision (DEPRECATED)
5668
5664
5669 The tip revision (usually just called the tip) is the changeset
5665 The tip revision (usually just called the tip) is the changeset
5670 most recently added to the repository (and therefore the most
5666 most recently added to the repository (and therefore the most
5671 recently changed head).
5667 recently changed head).
5672
5668
5673 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
5674 you have just pulled changes from another repository, the tip of
5670 you have just pulled changes from another repository, the tip of
5675 that repository becomes the current tip. The "tip" tag is special
5671 that repository becomes the current tip. The "tip" tag is special
5676 and cannot be renamed or assigned to a different changeset.
5672 and cannot be renamed or assigned to a different changeset.
5677
5673
5678 This command is deprecated, please use :hg:`heads` instead.
5674 This command is deprecated, please use :hg:`heads` instead.
5679
5675
5680 Returns 0 on success.
5676 Returns 0 on success.
5681 """
5677 """
5682 opts = pycompat.byteskwargs(opts)
5678 opts = pycompat.byteskwargs(opts)
5683 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5679 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5684 displayer.show(repo['tip'])
5680 displayer.show(repo['tip'])
5685 displayer.close()
5681 displayer.close()
5686
5682
5687 @command('unbundle',
5683 @command('unbundle',
5688 [('u', 'update', None,
5684 [('u', 'update', None,
5689 _('update to new branch head if changesets were unbundled'))],
5685 _('update to new branch head if changesets were unbundled'))],
5690 _('[-u] FILE...'))
5686 _('[-u] FILE...'))
5691 def unbundle(ui, repo, fname1, *fnames, **opts):
5687 def unbundle(ui, repo, fname1, *fnames, **opts):
5692 """apply one or more bundle files
5688 """apply one or more bundle files
5693
5689
5694 Apply one or more bundle files generated by :hg:`bundle`.
5690 Apply one or more bundle files generated by :hg:`bundle`.
5695
5691
5696 Returns 0 on success, 1 if an update has unresolved files.
5692 Returns 0 on success, 1 if an update has unresolved files.
5697 """
5693 """
5698 fnames = (fname1,) + fnames
5694 fnames = (fname1,) + fnames
5699
5695
5700 with repo.lock():
5696 with repo.lock():
5701 for fname in fnames:
5697 for fname in fnames:
5702 f = hg.openpath(ui, fname)
5698 f = hg.openpath(ui, fname)
5703 gen = exchange.readbundle(ui, f, fname)
5699 gen = exchange.readbundle(ui, f, fname)
5704 if isinstance(gen, streamclone.streamcloneapplier):
5700 if isinstance(gen, streamclone.streamcloneapplier):
5705 raise error.Abort(
5701 raise error.Abort(
5706 _('packed bundles cannot be applied with '
5702 _('packed bundles cannot be applied with '
5707 '"hg unbundle"'),
5703 '"hg unbundle"'),
5708 hint=_('use "hg debugapplystreamclonebundle"'))
5704 hint=_('use "hg debugapplystreamclonebundle"'))
5709 url = 'bundle:' + fname
5705 url = 'bundle:' + fname
5710 try:
5706 try:
5711 txnname = 'unbundle'
5707 txnname = 'unbundle'
5712 if not isinstance(gen, bundle2.unbundle20):
5708 if not isinstance(gen, bundle2.unbundle20):
5713 txnname = 'unbundle\n%s' % util.hidepassword(url)
5709 txnname = 'unbundle\n%s' % util.hidepassword(url)
5714 with repo.transaction(txnname) as tr:
5710 with repo.transaction(txnname) as tr:
5715 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5711 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5716 url=url)
5712 url=url)
5717 except error.BundleUnknownFeatureError as exc:
5713 except error.BundleUnknownFeatureError as exc:
5718 raise error.Abort(
5714 raise error.Abort(
5719 _('%s: unknown bundle feature, %s') % (fname, exc),
5715 _('%s: unknown bundle feature, %s') % (fname, exc),
5720 hint=_("see https://mercurial-scm.org/"
5716 hint=_("see https://mercurial-scm.org/"
5721 "wiki/BundleFeature for more "
5717 "wiki/BundleFeature for more "
5722 "information"))
5718 "information"))
5723 modheads = bundle2.combinechangegroupresults(op)
5719 modheads = bundle2.combinechangegroupresults(op)
5724
5720
5725 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5721 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5726
5722
5727 @command('^update|up|checkout|co',
5723 @command('^update|up|checkout|co',
5728 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5724 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5729 ('c', 'check', None, _('require clean working directory')),
5725 ('c', 'check', None, _('require clean working directory')),
5730 ('m', 'merge', None, _('merge uncommitted changes')),
5726 ('m', 'merge', None, _('merge uncommitted changes')),
5731 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5727 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5732 ('r', 'rev', '', _('revision'), _('REV'))
5728 ('r', 'rev', '', _('revision'), _('REV'))
5733 ] + mergetoolopts,
5729 ] + mergetoolopts,
5734 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5730 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5735 def update(ui, repo, node=None, **opts):
5731 def update(ui, repo, node=None, **opts):
5736 """update working directory (or switch revisions)
5732 """update working directory (or switch revisions)
5737
5733
5738 Update the repository's working directory to the specified
5734 Update the repository's working directory to the specified
5739 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
5740 current named branch and move the active bookmark (see :hg:`help
5736 current named branch and move the active bookmark (see :hg:`help
5741 bookmarks`).
5737 bookmarks`).
5742
5738
5743 Update sets the working directory's parent revision to the specified
5739 Update sets the working directory's parent revision to the specified
5744 changeset (see :hg:`help parents`).
5740 changeset (see :hg:`help parents`).
5745
5741
5746 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
5747 directory's parent and there are uncommitted changes, the update is
5743 directory's parent and there are uncommitted changes, the update is
5748 aborted. With the -c/--check option, the working directory is checked
5744 aborted. With the -c/--check option, the working directory is checked
5749 for uncommitted changes; if none are found, the working directory is
5745 for uncommitted changes; if none are found, the working directory is
5750 updated to the specified changeset.
5746 updated to the specified changeset.
5751
5747
5752 .. container:: verbose
5748 .. container:: verbose
5753
5749
5754 The -C/--clean, -c/--check, and -m/--merge options control what
5750 The -C/--clean, -c/--check, and -m/--merge options control what
5755 happens if the working directory contains uncommitted changes.
5751 happens if the working directory contains uncommitted changes.
5756 At most of one of them can be specified.
5752 At most of one of them can be specified.
5757
5753
5758 1. If no option is specified, and if
5754 1. If no option is specified, and if
5759 the requested changeset is an ancestor or descendant of
5755 the requested changeset is an ancestor or descendant of
5760 the working directory's parent, the uncommitted changes
5756 the working directory's parent, the uncommitted changes
5761 are merged into the requested changeset and the merged
5757 are merged into the requested changeset and the merged
5762 result is left uncommitted. If the requested changeset is
5758 result is left uncommitted. If the requested changeset is
5763 not an ancestor or descendant (that is, it is on another
5759 not an ancestor or descendant (that is, it is on another
5764 branch), the update is aborted and the uncommitted changes
5760 branch), the update is aborted and the uncommitted changes
5765 are preserved.
5761 are preserved.
5766
5762
5767 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
5768 requested changeset is not an ancestor or descendant of
5764 requested changeset is not an ancestor or descendant of
5769 the working directory's parent.
5765 the working directory's parent.
5770
5766
5771 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
5772 uncommitted changes are preserved.
5768 uncommitted changes are preserved.
5773
5769
5774 4. With the -C/--clean option, uncommitted changes are discarded and
5770 4. With the -C/--clean option, uncommitted changes are discarded and
5775 the working directory is updated to the requested changeset.
5771 the working directory is updated to the requested changeset.
5776
5772
5777 To cancel an uncommitted merge (and lose your changes), use
5773 To cancel an uncommitted merge (and lose your changes), use
5778 :hg:`merge --abort`.
5774 :hg:`merge --abort`.
5779
5775
5780 Use null as the changeset to remove the working directory (like
5776 Use null as the changeset to remove the working directory (like
5781 :hg:`clone -U`).
5777 :hg:`clone -U`).
5782
5778
5783 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
5784 :hg:`revert [-r REV] NAME`.
5780 :hg:`revert [-r REV] NAME`.
5785
5781
5786 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.
5787
5783
5788 Returns 0 on success, 1 if there are unresolved files.
5784 Returns 0 on success, 1 if there are unresolved files.
5789 """
5785 """
5790 rev = opts.get(r'rev')
5786 rev = opts.get(r'rev')
5791 date = opts.get(r'date')
5787 date = opts.get(r'date')
5792 clean = opts.get(r'clean')
5788 clean = opts.get(r'clean')
5793 check = opts.get(r'check')
5789 check = opts.get(r'check')
5794 merge = opts.get(r'merge')
5790 merge = opts.get(r'merge')
5795 if rev and node:
5791 if rev and node:
5796 raise error.Abort(_("please specify just one revision"))
5792 raise error.Abort(_("please specify just one revision"))
5797
5793
5798 if ui.configbool('commands', 'update.requiredest'):
5794 if ui.configbool('commands', 'update.requiredest'):
5799 if not node and not rev and not date:
5795 if not node and not rev and not date:
5800 raise error.Abort(_('you must specify a destination'),
5796 raise error.Abort(_('you must specify a destination'),
5801 hint=_('for example: hg update ".::"'))
5797 hint=_('for example: hg update ".::"'))
5802
5798
5803 if rev is None or rev == '':
5799 if rev is None or rev == '':
5804 rev = node
5800 rev = node
5805
5801
5806 if date and rev is not None:
5802 if date and rev is not None:
5807 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"))
5808
5804
5809 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:
5810 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, "
5811 "or -m/--merge"))
5807 "or -m/--merge"))
5812
5808
5813 updatecheck = None
5809 updatecheck = None
5814 if check:
5810 if check:
5815 updatecheck = 'abort'
5811 updatecheck = 'abort'
5816 elif merge:
5812 elif merge:
5817 updatecheck = 'none'
5813 updatecheck = 'none'
5818
5814
5819 with repo.wlock():
5815 with repo.wlock():
5820 cmdutil.clearunfinished(repo)
5816 cmdutil.clearunfinished(repo)
5821
5817
5822 if date:
5818 if date:
5823 rev = cmdutil.finddate(ui, repo, date)
5819 rev = cmdutil.finddate(ui, repo, date)
5824
5820
5825 # 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
5826 brev = rev
5822 brev = rev
5827 if rev:
5823 if rev:
5828 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5824 repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn')
5829 ctx = scmutil.revsingle(repo, rev, rev)
5825 ctx = scmutil.revsingle(repo, rev, rev)
5830 rev = ctx.rev()
5826 rev = ctx.rev()
5831 hidden = ctx.hidden()
5827 hidden = ctx.hidden()
5832 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
5828 overrides = {('ui', 'forcemerge'): opts.get(r'tool', '')}
5833 with ui.configoverride(overrides, 'update'):
5829 with ui.configoverride(overrides, 'update'):
5834 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
5830 ret = hg.updatetotally(ui, repo, rev, brev, clean=clean,
5835 updatecheck=updatecheck)
5831 updatecheck=updatecheck)
5836 if hidden:
5832 if hidden:
5837 ctxstr = ctx.hex()[:12]
5833 ctxstr = ctx.hex()[:12]
5838 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
5834 ui.warn(_("updated to hidden changeset %s\n") % ctxstr)
5839
5835
5840 if ctx.obsolete():
5836 if ctx.obsolete():
5841 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5837 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
5842 ui.warn("(%s)\n" % obsfatemsg)
5838 ui.warn("(%s)\n" % obsfatemsg)
5843 return ret
5839 return ret
5844
5840
5845 @command('verify', [])
5841 @command('verify', [])
5846 def verify(ui, repo):
5842 def verify(ui, repo):
5847 """verify the integrity of the repository
5843 """verify the integrity of the repository
5848
5844
5849 Verify the integrity of the current repository.
5845 Verify the integrity of the current repository.
5850
5846
5851 This will perform an extensive check of the repository's
5847 This will perform an extensive check of the repository's
5852 integrity, validating the hashes and checksums of each entry in
5848 integrity, validating the hashes and checksums of each entry in
5853 the changelog, manifest, and tracked files, as well as the
5849 the changelog, manifest, and tracked files, as well as the
5854 integrity of their crosslinks and indices.
5850 integrity of their crosslinks and indices.
5855
5851
5856 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5852 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5857 for more information about recovery from corruption of the
5853 for more information about recovery from corruption of the
5858 repository.
5854 repository.
5859
5855
5860 Returns 0 on success, 1 if errors are encountered.
5856 Returns 0 on success, 1 if errors are encountered.
5861 """
5857 """
5862 return hg.verify(repo)
5858 return hg.verify(repo)
5863
5859
5864 @command('version', [] + formatteropts, norepo=True,
5860 @command('version', [] + formatteropts, norepo=True,
5865 intents={INTENT_READONLY})
5861 intents={INTENT_READONLY})
5866 def version_(ui, **opts):
5862 def version_(ui, **opts):
5867 """output version and copyright information"""
5863 """output version and copyright information"""
5868 opts = pycompat.byteskwargs(opts)
5864 opts = pycompat.byteskwargs(opts)
5869 if ui.verbose:
5865 if ui.verbose:
5870 ui.pager('version')
5866 ui.pager('version')
5871 fm = ui.formatter("version", opts)
5867 fm = ui.formatter("version", opts)
5872 fm.startitem()
5868 fm.startitem()
5873 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5869 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5874 util.version())
5870 util.version())
5875 license = _(
5871 license = _(
5876 "(see https://mercurial-scm.org for more information)\n"
5872 "(see https://mercurial-scm.org for more information)\n"
5877 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5873 "\nCopyright (C) 2005-2018 Matt Mackall and others\n"
5878 "This is free software; see the source for copying conditions. "
5874 "This is free software; see the source for copying conditions. "
5879 "There is NO\nwarranty; "
5875 "There is NO\nwarranty; "
5880 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5876 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5881 )
5877 )
5882 if not ui.quiet:
5878 if not ui.quiet:
5883 fm.plain(license)
5879 fm.plain(license)
5884
5880
5885 if ui.verbose:
5881 if ui.verbose:
5886 fm.plain(_("\nEnabled extensions:\n\n"))
5882 fm.plain(_("\nEnabled extensions:\n\n"))
5887 # format names and versions into columns
5883 # format names and versions into columns
5888 names = []
5884 names = []
5889 vers = []
5885 vers = []
5890 isinternals = []
5886 isinternals = []
5891 for name, module in extensions.extensions():
5887 for name, module in extensions.extensions():
5892 names.append(name)
5888 names.append(name)
5893 vers.append(extensions.moduleversion(module) or None)
5889 vers.append(extensions.moduleversion(module) or None)
5894 isinternals.append(extensions.ismoduleinternal(module))
5890 isinternals.append(extensions.ismoduleinternal(module))
5895 fn = fm.nested("extensions", tmpl='{name}\n')
5891 fn = fm.nested("extensions", tmpl='{name}\n')
5896 if names:
5892 if names:
5897 namefmt = " %%-%ds " % max(len(n) for n in names)
5893 namefmt = " %%-%ds " % max(len(n) for n in names)
5898 places = [_("external"), _("internal")]
5894 places = [_("external"), _("internal")]
5899 for n, v, p in zip(names, vers, isinternals):
5895 for n, v, p in zip(names, vers, isinternals):
5900 fn.startitem()
5896 fn.startitem()
5901 fn.condwrite(ui.verbose, "name", namefmt, n)
5897 fn.condwrite(ui.verbose, "name", namefmt, n)
5902 if ui.verbose:
5898 if ui.verbose:
5903 fn.plain("%s " % places[p])
5899 fn.plain("%s " % places[p])
5904 fn.data(bundled=p)
5900 fn.data(bundled=p)
5905 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5901 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5906 if ui.verbose:
5902 if ui.verbose:
5907 fn.plain("\n")
5903 fn.plain("\n")
5908 fn.end()
5904 fn.end()
5909 fm.end()
5905 fm.end()
5910
5906
5911 def loadcmdtable(ui, name, cmdtable):
5907 def loadcmdtable(ui, name, cmdtable):
5912 """Load command functions from specified cmdtable
5908 """Load command functions from specified cmdtable
5913 """
5909 """
5914 overrides = [cmd for cmd in cmdtable if cmd in table]
5910 overrides = [cmd for cmd in cmdtable if cmd in table]
5915 if overrides:
5911 if overrides:
5916 ui.warn(_("extension '%s' overrides commands: %s\n")
5912 ui.warn(_("extension '%s' overrides commands: %s\n")
5917 % (name, " ".join(overrides)))
5913 % (name, " ".join(overrides)))
5918 table.update(cmdtable)
5914 table.update(cmdtable)
@@ -1,1071 +1,1071 b''
1 $ HGMERGE=true; export HGMERGE
1 $ HGMERGE=true; export HGMERGE
2
2
3 init
3 init
4
4
5 $ hg init repo
5 $ hg init repo
6 $ cd repo
6 $ cd repo
7
7
8 commit
8 commit
9
9
10 $ echo 'a' > a
10 $ echo 'a' > a
11 $ hg ci -A -m test -u nobody -d '1 0'
11 $ hg ci -A -m test -u nobody -d '1 0'
12 adding a
12 adding a
13
13
14 annotate -c
14 annotate -c
15
15
16 $ hg annotate -c a
16 $ hg annotate -c a
17 8435f90966e4: a
17 8435f90966e4: a
18
18
19 annotate -cl
19 annotate -cl
20
20
21 $ hg annotate -cl a
21 $ hg annotate -cl a
22 8435f90966e4:1: a
22 8435f90966e4:1: a
23
23
24 annotate -d
24 annotate -d
25
25
26 $ hg annotate -d a
26 $ hg annotate -d a
27 Thu Jan 01 00:00:01 1970 +0000: a
27 Thu Jan 01 00:00:01 1970 +0000: a
28
28
29 annotate -n
29 annotate -n
30
30
31 $ hg annotate -n a
31 $ hg annotate -n a
32 0: a
32 0: a
33
33
34 annotate -nl
34 annotate -nl
35
35
36 $ hg annotate -nl a
36 $ hg annotate -nl a
37 0:1: a
37 0:1: a
38
38
39 annotate -u
39 annotate -u
40
40
41 $ hg annotate -u a
41 $ hg annotate -u a
42 nobody: a
42 nobody: a
43
43
44 annotate -cdnu
44 annotate -cdnu
45
45
46 $ hg annotate -cdnu a
46 $ hg annotate -cdnu a
47 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
47 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
48
48
49 annotate -cdnul
49 annotate -cdnul
50
50
51 $ hg annotate -cdnul a
51 $ hg annotate -cdnul a
52 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000:1: a
52 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000:1: a
53
53
54 annotate (JSON)
54 annotate (JSON)
55
55
56 $ hg annotate -Tjson a
56 $ hg annotate -Tjson a
57 [
57 [
58 {
58 {
59 "lines": [{"line": "a\n", "rev": 0}],
59 "lines": [{"line": "a\n", "rev": 0}],
60 "path": "a"
60 "path": "a"
61 }
61 }
62 ]
62 ]
63
63
64 $ hg annotate -Tjson -cdfnul a
64 $ hg annotate -Tjson -cdfnul a
65 [
65 [
66 {
66 {
67 "lines": [{"date": [1.0, 0], "line": "a\n", "line_number": 1, "node": "8435f90966e442695d2ded29fdade2bac5ad8065", "path": "a", "rev": 0, "user": "nobody"}],
67 "lines": [{"date": [1.0, 0], "line": "a\n", "line_number": 1, "node": "8435f90966e442695d2ded29fdade2bac5ad8065", "path": "a", "rev": 0, "user": "nobody"}],
68 "path": "a"
68 "path": "a"
69 }
69 }
70 ]
70 ]
71
71
72 log-like templating
72 log-like templating
73
73
74 $ hg annotate -T'{lines % "{rev} {node|shortest}: {line}"}' a
74 $ hg annotate -T'{lines % "{rev} {node|shortest}: {line}"}' a
75 0 8435: a
75 0 8435: a
76
76
77 '{line_number}' field should be populated as necessary
77 '{line_number}' field should be populated as necessary
78
78
79 $ hg annotate -T'{lines % "{rev}:{line_number}: {line}"}' a
79 $ hg annotate -T'{lines % "{rev}:{line_number}: {line}"}' a
80 0:1: a
80 0:1: a
81 $ hg annotate -Ta a \
81 $ hg annotate -Ta a \
82 > --config templates.a='"{lines % "{rev}:{line_number}: {line}"}"'
82 > --config templates.a='"{lines % "{rev}:{line_number}: {line}"}"'
83 0:1: a
83 0:1: a
84
84
85 $ cat <<EOF >>a
85 $ cat <<EOF >>a
86 > a
86 > a
87 > a
87 > a
88 > EOF
88 > EOF
89 $ hg ci -ma1 -d '1 0'
89 $ hg ci -ma1 -d '1 0'
90 $ hg cp a b
90 $ hg cp a b
91 $ hg ci -mb -d '1 0'
91 $ hg ci -mb -d '1 0'
92 $ cat <<EOF >> b
92 $ cat <<EOF >> b
93 > b4
93 > b4
94 > b5
94 > b5
95 > b6
95 > b6
96 > EOF
96 > EOF
97 $ hg ci -mb2 -d '2 0'
97 $ hg ci -mb2 -d '2 0'
98
98
99 default output of '{lines}' should be readable
99 default output of '{lines}' should be readable
100
100
101 $ hg annotate -T'{lines}' a
101 $ hg annotate -T'{lines}' a
102 0: a
102 0: a
103 1: a
103 1: a
104 1: a
104 1: a
105 $ hg annotate -T'{join(lines, "\n")}' a
105 $ hg annotate -T'{join(lines, "\n")}' a
106 0: a
106 0: a
107
107
108 1: a
108 1: a
109
109
110 1: a
110 1: a
111
111
112 several filters can be applied to '{lines}'
112 several filters can be applied to '{lines}'
113
113
114 $ hg annotate -T'{lines|json}\n' a
114 $ hg annotate -T'{lines|json}\n' a
115 [{"line": "a\n", "rev": 0}, {"line": "a\n", "rev": 1}, {"line": "a\n", "rev": 1}]
115 [{"line": "a\n", "rev": 0}, {"line": "a\n", "rev": 1}, {"line": "a\n", "rev": 1}]
116 $ hg annotate -T'{lines|stringify}' a
116 $ hg annotate -T'{lines|stringify}' a
117 0: a
117 0: a
118 1: a
118 1: a
119 1: a
119 1: a
120 $ hg annotate -T'{lines|count}\n' a
120 $ hg annotate -T'{lines|count}\n' a
121 3
121 3
122
122
123 annotate multiple files (JSON)
123 annotate multiple files (JSON)
124
124
125 $ hg annotate -Tjson a b
125 $ hg annotate -Tjson a b
126 [
126 [
127 {
127 {
128 "lines": [{"line": "a\n", "rev": 0}, {"line": "a\n", "rev": 1}, {"line": "a\n", "rev": 1}],
128 "lines": [{"line": "a\n", "rev": 0}, {"line": "a\n", "rev": 1}, {"line": "a\n", "rev": 1}],
129 "path": "a"
129 "path": "a"
130 },
130 },
131 {
131 {
132 "lines": [{"line": "a\n", "rev": 0}, {"line": "a\n", "rev": 1}, {"line": "a\n", "rev": 1}, {"line": "b4\n", "rev": 3}, {"line": "b5\n", "rev": 3}, {"line": "b6\n", "rev": 3}],
132 "lines": [{"line": "a\n", "rev": 0}, {"line": "a\n", "rev": 1}, {"line": "a\n", "rev": 1}, {"line": "b4\n", "rev": 3}, {"line": "b5\n", "rev": 3}, {"line": "b6\n", "rev": 3}],
133 "path": "b"
133 "path": "b"
134 }
134 }
135 ]
135 ]
136
136
137 annotate multiple files (template)
137 annotate multiple files (template)
138
138
139 $ hg annotate -T'== {path} ==\n{lines % "{rev}: {line}"}' a b
139 $ hg annotate -T'== {path} ==\n{lines % "{rev}: {line}"}' a b
140 == a ==
140 == a ==
141 0: a
141 0: a
142 1: a
142 1: a
143 1: a
143 1: a
144 == b ==
144 == b ==
145 0: a
145 0: a
146 1: a
146 1: a
147 1: a
147 1: a
148 3: b4
148 3: b4
149 3: b5
149 3: b5
150 3: b6
150 3: b6
151
151
152 annotate -n b
152 annotate -n b
153
153
154 $ hg annotate -n b
154 $ hg annotate -n b
155 0: a
155 0: a
156 1: a
156 1: a
157 1: a
157 1: a
158 3: b4
158 3: b4
159 3: b5
159 3: b5
160 3: b6
160 3: b6
161
161
162 annotate --no-follow b
162 annotate --no-follow b
163
163
164 $ hg annotate --no-follow b
164 $ hg annotate --no-follow b
165 2: a
165 2: a
166 2: a
166 2: a
167 2: a
167 2: a
168 3: b4
168 3: b4
169 3: b5
169 3: b5
170 3: b6
170 3: b6
171
171
172 annotate -nl b
172 annotate -nl b
173
173
174 $ hg annotate -nl b
174 $ hg annotate -nl b
175 0:1: a
175 0:1: a
176 1:2: a
176 1:2: a
177 1:3: a
177 1:3: a
178 3:4: b4
178 3:4: b4
179 3:5: b5
179 3:5: b5
180 3:6: b6
180 3:6: b6
181
181
182 annotate -nf b
182 annotate -nf b
183
183
184 $ hg annotate -nf b
184 $ hg annotate -nf b
185 0 a: a
185 0 a: a
186 1 a: a
186 1 a: a
187 1 a: a
187 1 a: a
188 3 b: b4
188 3 b: b4
189 3 b: b5
189 3 b: b5
190 3 b: b6
190 3 b: b6
191
191
192 annotate -nlf b
192 annotate -nlf b
193
193
194 $ hg annotate -nlf b
194 $ hg annotate -nlf b
195 0 a:1: a
195 0 a:1: a
196 1 a:2: a
196 1 a:2: a
197 1 a:3: a
197 1 a:3: a
198 3 b:4: b4
198 3 b:4: b4
199 3 b:5: b5
199 3 b:5: b5
200 3 b:6: b6
200 3 b:6: b6
201
201
202 $ hg up -C 2
202 $ hg up -C 2
203 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
203 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
204 $ cat <<EOF >> b
204 $ cat <<EOF >> b
205 > b4
205 > b4
206 > c
206 > c
207 > b5
207 > b5
208 > EOF
208 > EOF
209 $ hg ci -mb2.1 -d '2 0'
209 $ hg ci -mb2.1 -d '2 0'
210 created new head
210 created new head
211 $ hg merge
211 $ hg merge
212 merging b
212 merging b
213 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
213 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
214 (branch merge, don't forget to commit)
214 (branch merge, don't forget to commit)
215 $ hg ci -mmergeb -d '3 0'
215 $ hg ci -mmergeb -d '3 0'
216
216
217 annotate after merge
217 annotate after merge
218
218
219 $ hg annotate -nf b
219 $ hg annotate -nf b
220 0 a: a
220 0 a: a
221 1 a: a
221 1 a: a
222 1 a: a
222 1 a: a
223 3 b: b4
223 3 b: b4
224 4 b: c
224 4 b: c
225 3 b: b5
225 3 b: b5
226
226
227 annotate after merge with -l
227 annotate after merge with -l
228
228
229 $ hg annotate -nlf b
229 $ hg annotate -nlf b
230 0 a:1: a
230 0 a:1: a
231 1 a:2: a
231 1 a:2: a
232 1 a:3: a
232 1 a:3: a
233 3 b:4: b4
233 3 b:4: b4
234 4 b:5: c
234 4 b:5: c
235 3 b:5: b5
235 3 b:5: b5
236
236
237 $ hg up -C 1
237 $ hg up -C 1
238 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
238 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
239 $ hg cp a b
239 $ hg cp a b
240 $ cat <<EOF > b
240 $ cat <<EOF > b
241 > a
241 > a
242 > z
242 > z
243 > a
243 > a
244 > EOF
244 > EOF
245 $ hg ci -mc -d '3 0'
245 $ hg ci -mc -d '3 0'
246 created new head
246 created new head
247 $ hg merge
247 $ hg merge
248 merging b
248 merging b
249 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
249 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
250 (branch merge, don't forget to commit)
250 (branch merge, don't forget to commit)
251 $ cat <<EOF >> b
251 $ cat <<EOF >> b
252 > b4
252 > b4
253 > c
253 > c
254 > b5
254 > b5
255 > EOF
255 > EOF
256 $ echo d >> b
256 $ echo d >> b
257 $ hg ci -mmerge2 -d '4 0'
257 $ hg ci -mmerge2 -d '4 0'
258
258
259 annotate after rename merge
259 annotate after rename merge
260
260
261 $ hg annotate -nf b
261 $ hg annotate -nf b
262 0 a: a
262 0 a: a
263 6 b: z
263 6 b: z
264 1 a: a
264 1 a: a
265 3 b: b4
265 3 b: b4
266 4 b: c
266 4 b: c
267 3 b: b5
267 3 b: b5
268 7 b: d
268 7 b: d
269
269
270 annotate after rename merge with -l
270 annotate after rename merge with -l
271
271
272 $ hg annotate -nlf b
272 $ hg annotate -nlf b
273 0 a:1: a
273 0 a:1: a
274 6 b:2: z
274 6 b:2: z
275 1 a:3: a
275 1 a:3: a
276 3 b:4: b4
276 3 b:4: b4
277 4 b:5: c
277 4 b:5: c
278 3 b:5: b5
278 3 b:5: b5
279 7 b:7: d
279 7 b:7: d
280
280
281 --skip nothing (should be the same as no --skip at all)
281 --skip nothing (should be the same as no --skip at all)
282
282
283 $ hg annotate -nlf b --skip '1::0'
283 $ hg annotate -nlf b --skip '1::0'
284 0 a:1: a
284 0 a:1: a
285 6 b:2: z
285 6 b:2: z
286 1 a:3: a
286 1 a:3: a
287 3 b:4: b4
287 3 b:4: b4
288 4 b:5: c
288 4 b:5: c
289 3 b:5: b5
289 3 b:5: b5
290 7 b:7: d
290 7 b:7: d
291
291
292 --skip a modified line. Note a slight behavior difference in pure - this is
292 --skip a modified line. Note a slight behavior difference in pure - this is
293 because the pure code comes up with slightly different deltas internally.
293 because the pure code comes up with slightly different deltas internally.
294
294
295 $ hg annotate -nlf b --skip 6
295 $ hg annotate -nlf b --skip 6
296 0 a:1: a
296 0 a:1: a
297 1 a:2* z (no-pure !)
297 1 a:2* z (no-pure !)
298 0 a:1* z (pure !)
298 0 a:1* z (pure !)
299 1 a:3: a
299 1 a:3: a
300 3 b:4: b4
300 3 b:4: b4
301 4 b:5: c
301 4 b:5: c
302 3 b:5: b5
302 3 b:5: b5
303 7 b:7: d
303 7 b:7: d
304
304
305 --skip added lines (and test multiple skip)
305 --skip added lines (and test multiple skip)
306
306
307 $ hg annotate -nlf b --skip 3
307 $ hg annotate -nlf b --skip 3
308 0 a:1: a
308 0 a:1: a
309 6 b:2: z
309 6 b:2: z
310 1 a:3: a
310 1 a:3: a
311 1 a:3* b4
311 1 a:3* b4
312 4 b:5: c
312 4 b:5: c
313 1 a:3* b5
313 1 a:3* b5
314 7 b:7: d
314 7 b:7: d
315
315
316 $ hg annotate -nlf b --skip 4
316 $ hg annotate -nlf b --skip 4
317 0 a:1: a
317 0 a:1: a
318 6 b:2: z
318 6 b:2: z
319 1 a:3: a
319 1 a:3: a
320 3 b:4: b4
320 3 b:4: b4
321 1 a:3* c
321 1 a:3* c
322 3 b:5: b5
322 3 b:5: b5
323 7 b:7: d
323 7 b:7: d
324
324
325 $ hg annotate -nlf b --skip 3 --skip 4
325 $ hg annotate -nlf b --skip 3 --skip 4
326 0 a:1: a
326 0 a:1: a
327 6 b:2: z
327 6 b:2: z
328 1 a:3: a
328 1 a:3: a
329 1 a:3* b4
329 1 a:3* b4
330 1 a:3* c
330 1 a:3* c
331 1 a:3* b5
331 1 a:3* b5
332 7 b:7: d
332 7 b:7: d
333
333
334 $ hg annotate -nlf b --skip 'merge()'
334 $ hg annotate -nlf b --skip 'merge()'
335 0 a:1: a
335 0 a:1: a
336 6 b:2: z
336 6 b:2: z
337 1 a:3: a
337 1 a:3: a
338 3 b:4: b4
338 3 b:4: b4
339 4 b:5: c
339 4 b:5: c
340 3 b:5: b5
340 3 b:5: b5
341 3 b:5* d
341 3 b:5* d
342
342
343 --skip everything -- use the revision the file was introduced in
343 --skip everything -- use the revision the file was introduced in
344
344
345 $ hg annotate -nlf b --skip 'all()'
345 $ hg annotate -nlf b --skip 'all()'
346 0 a:1: a
346 0 a:1: a
347 0 a:1* z
347 0 a:1* z
348 0 a:1* a
348 0 a:1* a
349 0 a:1* b4
349 0 a:1* b4
350 0 a:1* c
350 0 a:1* c
351 0 a:1* b5
351 0 a:1* b5
352 0 a:1* d
352 0 a:1* d
353
353
354 Issue2807: alignment of line numbers with -l
354 Issue2807: alignment of line numbers with -l
355
355
356 $ echo more >> b
356 $ echo more >> b
357 $ hg ci -mmore -d '5 0'
357 $ hg ci -mmore -d '5 0'
358 $ echo more >> b
358 $ echo more >> b
359 $ hg ci -mmore -d '6 0'
359 $ hg ci -mmore -d '6 0'
360 $ echo more >> b
360 $ echo more >> b
361 $ hg ci -mmore -d '7 0'
361 $ hg ci -mmore -d '7 0'
362 $ hg annotate -nlf b
362 $ hg annotate -nlf b
363 0 a: 1: a
363 0 a: 1: a
364 6 b: 2: z
364 6 b: 2: z
365 1 a: 3: a
365 1 a: 3: a
366 3 b: 4: b4
366 3 b: 4: b4
367 4 b: 5: c
367 4 b: 5: c
368 3 b: 5: b5
368 3 b: 5: b5
369 7 b: 7: d
369 7 b: 7: d
370 8 b: 8: more
370 8 b: 8: more
371 9 b: 9: more
371 9 b: 9: more
372 10 b:10: more
372 10 b:10: more
373
373
374 linkrev vs rev
374 linkrev vs rev
375
375
376 $ hg annotate -r tip -n a
376 $ hg annotate -r tip -n a
377 0: a
377 0: a
378 1: a
378 1: a
379 1: a
379 1: a
380
380
381 linkrev vs rev with -l
381 linkrev vs rev with -l
382
382
383 $ hg annotate -r tip -nl a
383 $ hg annotate -r tip -nl a
384 0:1: a
384 0:1: a
385 1:2: a
385 1:2: a
386 1:3: a
386 1:3: a
387
387
388 Issue589: "undelete" sequence leads to crash
388 Issue589: "undelete" sequence leads to crash
389
389
390 annotate was crashing when trying to --follow something
390 annotate was crashing when trying to --follow something
391
391
392 like A -> B -> A
392 like A -> B -> A
393
393
394 generate ABA rename configuration
394 generate ABA rename configuration
395
395
396 $ echo foo > foo
396 $ echo foo > foo
397 $ hg add foo
397 $ hg add foo
398 $ hg ci -m addfoo
398 $ hg ci -m addfoo
399 $ hg rename foo bar
399 $ hg rename foo bar
400 $ hg ci -m renamefoo
400 $ hg ci -m renamefoo
401 $ hg rename bar foo
401 $ hg rename bar foo
402 $ hg ci -m renamebar
402 $ hg ci -m renamebar
403
403
404 annotate after ABA with follow
404 annotate after ABA with follow
405
405
406 $ hg annotate --follow foo
406 $ hg annotate --follow foo
407 foo: foo
407 foo: foo
408
408
409 missing file
409 missing file
410
410
411 $ hg ann nosuchfile
411 $ hg ann nosuchfile
412 abort: nosuchfile: no such file in rev e9e6b4fa872f
412 abort: nosuchfile: no such file in rev e9e6b4fa872f
413 [255]
413 [255]
414
414
415 annotate file without '\n' on last line
415 annotate file without '\n' on last line
416
416
417 $ printf "" > c
417 $ printf "" > c
418 $ hg ci -A -m test -u nobody -d '1 0'
418 $ hg ci -A -m test -u nobody -d '1 0'
419 adding c
419 adding c
420 $ hg annotate c
420 $ hg annotate c
421 $ printf "a\nb" > c
421 $ printf "a\nb" > c
422 $ hg ci -m test
422 $ hg ci -m test
423 $ hg annotate c
423 $ hg annotate c
424 [0-9]+: a (re)
424 [0-9]+: a (re)
425 [0-9]+: b (re)
425 [0-9]+: b (re)
426
426
427 Issue3841: check annotation of the file of which filelog includes
427 Issue3841: check annotation of the file of which filelog includes
428 merging between the revision and its ancestor
428 merging between the revision and its ancestor
429
429
430 to reproduce the situation with recent Mercurial, this script uses (1)
430 to reproduce the situation with recent Mercurial, this script uses (1)
431 "hg debugsetparents" to merge without ancestor check by "hg merge",
431 "hg debugsetparents" to merge without ancestor check by "hg merge",
432 and (2) the extension to allow filelog merging between the revision
432 and (2) the extension to allow filelog merging between the revision
433 and its ancestor by overriding "repo._filecommit".
433 and its ancestor by overriding "repo._filecommit".
434
434
435 $ cat > ../legacyrepo.py <<EOF
435 $ cat > ../legacyrepo.py <<EOF
436 > from __future__ import absolute_import
436 > from __future__ import absolute_import
437 > from mercurial import error, node
437 > from mercurial import error, node
438 > def reposetup(ui, repo):
438 > def reposetup(ui, repo):
439 > class legacyrepo(repo.__class__):
439 > class legacyrepo(repo.__class__):
440 > def _filecommit(self, fctx, manifest1, manifest2,
440 > def _filecommit(self, fctx, manifest1, manifest2,
441 > linkrev, tr, changelist):
441 > linkrev, tr, changelist):
442 > fname = fctx.path()
442 > fname = fctx.path()
443 > text = fctx.data()
443 > text = fctx.data()
444 > flog = self.file(fname)
444 > flog = self.file(fname)
445 > fparent1 = manifest1.get(fname, node.nullid)
445 > fparent1 = manifest1.get(fname, node.nullid)
446 > fparent2 = manifest2.get(fname, node.nullid)
446 > fparent2 = manifest2.get(fname, node.nullid)
447 > meta = {}
447 > meta = {}
448 > copy = fctx.renamed()
448 > copy = fctx.renamed()
449 > if copy and copy[0] != fname:
449 > if copy and copy[0] != fname:
450 > raise error.Abort('copying is not supported')
450 > raise error.Abort('copying is not supported')
451 > if fparent2 != node.nullid:
451 > if fparent2 != node.nullid:
452 > changelist.append(fname)
452 > changelist.append(fname)
453 > return flog.add(text, meta, tr, linkrev,
453 > return flog.add(text, meta, tr, linkrev,
454 > fparent1, fparent2)
454 > fparent1, fparent2)
455 > raise error.Abort('only merging is supported')
455 > raise error.Abort('only merging is supported')
456 > repo.__class__ = legacyrepo
456 > repo.__class__ = legacyrepo
457 > EOF
457 > EOF
458
458
459 $ cat > baz <<EOF
459 $ cat > baz <<EOF
460 > 1
460 > 1
461 > 2
461 > 2
462 > 3
462 > 3
463 > 4
463 > 4
464 > 5
464 > 5
465 > EOF
465 > EOF
466 $ hg add baz
466 $ hg add baz
467 $ hg commit -m "baz:0"
467 $ hg commit -m "baz:0"
468
468
469 $ cat > baz <<EOF
469 $ cat > baz <<EOF
470 > 1 baz:1
470 > 1 baz:1
471 > 2
471 > 2
472 > 3
472 > 3
473 > 4
473 > 4
474 > 5
474 > 5
475 > EOF
475 > EOF
476 $ hg commit -m "baz:1"
476 $ hg commit -m "baz:1"
477
477
478 $ cat > baz <<EOF
478 $ cat > baz <<EOF
479 > 1 baz:1
479 > 1 baz:1
480 > 2 baz:2
480 > 2 baz:2
481 > 3
481 > 3
482 > 4
482 > 4
483 > 5
483 > 5
484 > EOF
484 > EOF
485 $ hg debugsetparents 17 17
485 $ hg debugsetparents 17 17
486 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:2"
486 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:2"
487 $ hg debugindexdot baz
487 $ hg debugindexdot baz
488 digraph G {
488 digraph G {
489 -1 -> 0
489 -1 -> 0
490 0 -> 1
490 0 -> 1
491 1 -> 2
491 1 -> 2
492 1 -> 2
492 1 -> 2
493 }
493 }
494 $ hg annotate baz
494 $ hg annotate baz
495 17: 1 baz:1
495 17: 1 baz:1
496 18: 2 baz:2
496 18: 2 baz:2
497 16: 3
497 16: 3
498 16: 4
498 16: 4
499 16: 5
499 16: 5
500
500
501 $ cat > baz <<EOF
501 $ cat > baz <<EOF
502 > 1 baz:1
502 > 1 baz:1
503 > 2 baz:2
503 > 2 baz:2
504 > 3 baz:3
504 > 3 baz:3
505 > 4
505 > 4
506 > 5
506 > 5
507 > EOF
507 > EOF
508 $ hg commit -m "baz:3"
508 $ hg commit -m "baz:3"
509
509
510 $ cat > baz <<EOF
510 $ cat > baz <<EOF
511 > 1 baz:1
511 > 1 baz:1
512 > 2 baz:2
512 > 2 baz:2
513 > 3 baz:3
513 > 3 baz:3
514 > 4 baz:4
514 > 4 baz:4
515 > 5
515 > 5
516 > EOF
516 > EOF
517 $ hg debugsetparents 19 18
517 $ hg debugsetparents 19 18
518 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:4"
518 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:4"
519 $ hg debugindexdot baz
519 $ hg debugindexdot baz
520 digraph G {
520 digraph G {
521 -1 -> 0
521 -1 -> 0
522 0 -> 1
522 0 -> 1
523 1 -> 2
523 1 -> 2
524 1 -> 2
524 1 -> 2
525 2 -> 3
525 2 -> 3
526 3 -> 4
526 3 -> 4
527 2 -> 4
527 2 -> 4
528 }
528 }
529 $ hg annotate baz
529 $ hg annotate baz
530 17: 1 baz:1
530 17: 1 baz:1
531 18: 2 baz:2
531 18: 2 baz:2
532 19: 3 baz:3
532 19: 3 baz:3
533 20: 4 baz:4
533 20: 4 baz:4
534 16: 5
534 16: 5
535
535
536 annotate clean file
536 annotate clean file
537
537
538 $ hg annotate -ncr "wdir()" foo
538 $ hg annotate -ncr "wdir()" foo
539 11 472b18db256d : foo
539 11 472b18db256d : foo
540
540
541 annotate modified file
541 annotate modified file
542
542
543 $ echo foofoo >> foo
543 $ echo foofoo >> foo
544 $ hg annotate -r "wdir()" foo
544 $ hg annotate -r "wdir()" foo
545 11 : foo
545 11 : foo
546 20+: foofoo
546 20+: foofoo
547
547
548 $ hg annotate -cr "wdir()" foo
548 $ hg annotate -cr "wdir()" foo
549 472b18db256d : foo
549 472b18db256d : foo
550 b6bedd5477e7+: foofoo
550 b6bedd5477e7+: foofoo
551
551
552 $ hg annotate -ncr "wdir()" foo
552 $ hg annotate -ncr "wdir()" foo
553 11 472b18db256d : foo
553 11 472b18db256d : foo
554 20 b6bedd5477e7+: foofoo
554 20 b6bedd5477e7+: foofoo
555
555
556 $ hg annotate --debug -ncr "wdir()" foo
556 $ hg annotate --debug -ncr "wdir()" foo
557 11 472b18db256d1e8282064eab4bfdaf48cbfe83cd : foo
557 11 472b18db256d1e8282064eab4bfdaf48cbfe83cd : foo
558 20 b6bedd5477e797f25e568a6402d4697f3f895a72+: foofoo
558 20 b6bedd5477e797f25e568a6402d4697f3f895a72+: foofoo
559
559
560 $ hg annotate -udr "wdir()" foo
560 $ hg annotate -udr "wdir()" foo
561 test Thu Jan 01 00:00:00 1970 +0000: foo
561 test Thu Jan 01 00:00:00 1970 +0000: foo
562 test [A-Za-z0-9:+ ]+: foofoo (re)
562 test [A-Za-z0-9:+ ]+: foofoo (re)
563
563
564 $ hg annotate -ncr "wdir()" -Tjson foo
564 $ hg annotate -ncr "wdir()" -Tjson foo
565 [
565 [
566 {
566 {
567 "lines": [{"line": "foo\n", "node": "472b18db256d1e8282064eab4bfdaf48cbfe83cd", "rev": 11}, {"line": "foofoo\n", "node": null, "rev": null}],
567 "lines": [{"line": "foo\n", "node": "472b18db256d1e8282064eab4bfdaf48cbfe83cd", "rev": 11}, {"line": "foofoo\n", "node": "ffffffffffffffffffffffffffffffffffffffff", "rev": 2147483647}],
568 "path": "foo"
568 "path": "foo"
569 }
569 }
570 ]
570 ]
571
571
572 annotate added file
572 annotate added file
573
573
574 $ echo bar > bar
574 $ echo bar > bar
575 $ hg add bar
575 $ hg add bar
576 $ hg annotate -ncr "wdir()" bar
576 $ hg annotate -ncr "wdir()" bar
577 20 b6bedd5477e7+: bar
577 20 b6bedd5477e7+: bar
578
578
579 annotate renamed file
579 annotate renamed file
580
580
581 $ hg rename foo renamefoo2
581 $ hg rename foo renamefoo2
582 $ hg annotate -ncr "wdir()" renamefoo2
582 $ hg annotate -ncr "wdir()" renamefoo2
583 11 472b18db256d : foo
583 11 472b18db256d : foo
584 20 b6bedd5477e7+: foofoo
584 20 b6bedd5477e7+: foofoo
585
585
586 annotate missing file
586 annotate missing file
587
587
588 $ rm baz
588 $ rm baz
589
589
590 $ hg annotate -ncr "wdir()" baz
590 $ hg annotate -ncr "wdir()" baz
591 abort: $TESTTMP\repo\baz: $ENOENT$ (windows !)
591 abort: $TESTTMP\repo\baz: $ENOENT$ (windows !)
592 abort: $ENOENT$: $TESTTMP/repo/baz (no-windows !)
592 abort: $ENOENT$: $TESTTMP/repo/baz (no-windows !)
593 [255]
593 [255]
594
594
595 annotate removed file
595 annotate removed file
596
596
597 $ hg rm baz
597 $ hg rm baz
598
598
599 $ hg annotate -ncr "wdir()" baz
599 $ hg annotate -ncr "wdir()" baz
600 abort: $TESTTMP\repo\baz: $ENOENT$ (windows !)
600 abort: $TESTTMP\repo\baz: $ENOENT$ (windows !)
601 abort: $ENOENT$: $TESTTMP/repo/baz (no-windows !)
601 abort: $ENOENT$: $TESTTMP/repo/baz (no-windows !)
602 [255]
602 [255]
603
603
604 $ hg revert --all --no-backup --quiet
604 $ hg revert --all --no-backup --quiet
605 $ hg id -n
605 $ hg id -n
606 20
606 20
607
607
608 Test followlines() revset; we usually check both followlines(pat, range) and
608 Test followlines() revset; we usually check both followlines(pat, range) and
609 followlines(pat, range, descend=True) to make sure both give the same result
609 followlines(pat, range, descend=True) to make sure both give the same result
610 when they should.
610 when they should.
611
611
612 $ echo a >> foo
612 $ echo a >> foo
613 $ hg ci -m 'foo: add a'
613 $ hg ci -m 'foo: add a'
614 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5)'
614 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5)'
615 16: baz:0
615 16: baz:0
616 19: baz:3
616 19: baz:3
617 20: baz:4
617 20: baz:4
618 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=20)'
618 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=20)'
619 16: baz:0
619 16: baz:0
620 19: baz:3
620 19: baz:3
621 20: baz:4
621 20: baz:4
622 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=19)'
622 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=19)'
623 16: baz:0
623 16: baz:0
624 19: baz:3
624 19: baz:3
625 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=19, descend=True)'
625 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=19, descend=True)'
626 19: baz:3
626 19: baz:3
627 20: baz:4
627 20: baz:4
628 $ printf "0\n0\n" | cat - baz > baz1
628 $ printf "0\n0\n" | cat - baz > baz1
629 $ mv baz1 baz
629 $ mv baz1 baz
630 $ hg ci -m 'added two lines with 0'
630 $ hg ci -m 'added two lines with 0'
631 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7)'
631 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7)'
632 16: baz:0
632 16: baz:0
633 19: baz:3
633 19: baz:3
634 20: baz:4
634 20: baz:4
635 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, descend=true, startrev=19)'
635 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, descend=true, startrev=19)'
636 19: baz:3
636 19: baz:3
637 20: baz:4
637 20: baz:4
638 $ echo 6 >> baz
638 $ echo 6 >> baz
639 $ hg ci -m 'added line 8'
639 $ hg ci -m 'added line 8'
640 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7)'
640 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7)'
641 16: baz:0
641 16: baz:0
642 19: baz:3
642 19: baz:3
643 20: baz:4
643 20: baz:4
644 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=19, descend=1)'
644 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=19, descend=1)'
645 19: baz:3
645 19: baz:3
646 20: baz:4
646 20: baz:4
647 $ sed 's/3/3+/' baz > baz.new
647 $ sed 's/3/3+/' baz > baz.new
648 $ mv baz.new baz
648 $ mv baz.new baz
649 $ hg ci -m 'baz:3->3+'
649 $ hg ci -m 'baz:3->3+'
650 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7, descend=0)'
650 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7, descend=0)'
651 16: baz:0
651 16: baz:0
652 19: baz:3
652 19: baz:3
653 20: baz:4
653 20: baz:4
654 24: baz:3->3+
654 24: baz:3->3+
655 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=17, descend=True)'
655 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:5, startrev=17, descend=True)'
656 19: baz:3
656 19: baz:3
657 20: baz:4
657 20: baz:4
658 24: baz:3->3+
658 24: baz:3->3+
659 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 1:2, descend=false)'
659 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 1:2, descend=false)'
660 22: added two lines with 0
660 22: added two lines with 0
661
661
662 file patterns are okay
662 file patterns are okay
663 $ hg log -T '{rev}: {desc}\n' -r 'followlines("path:baz", 1:2)'
663 $ hg log -T '{rev}: {desc}\n' -r 'followlines("path:baz", 1:2)'
664 22: added two lines with 0
664 22: added two lines with 0
665
665
666 renames are followed
666 renames are followed
667 $ hg mv baz qux
667 $ hg mv baz qux
668 $ sed 's/4/4+/' qux > qux.new
668 $ sed 's/4/4+/' qux > qux.new
669 $ mv qux.new qux
669 $ mv qux.new qux
670 $ hg ci -m 'qux:4->4+'
670 $ hg ci -m 'qux:4->4+'
671 $ hg log -T '{rev}: {desc}\n' -r 'followlines(qux, 5:7)'
671 $ hg log -T '{rev}: {desc}\n' -r 'followlines(qux, 5:7)'
672 16: baz:0
672 16: baz:0
673 19: baz:3
673 19: baz:3
674 20: baz:4
674 20: baz:4
675 24: baz:3->3+
675 24: baz:3->3+
676 25: qux:4->4+
676 25: qux:4->4+
677
677
678 but are missed when following children
678 but are missed when following children
679 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7, startrev=22, descend=True)'
679 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7, startrev=22, descend=True)'
680 24: baz:3->3+
680 24: baz:3->3+
681
681
682 merge
682 merge
683 $ hg up 24 --quiet
683 $ hg up 24 --quiet
684 $ echo 7 >> baz
684 $ echo 7 >> baz
685 $ hg ci -m 'one more line, out of line range'
685 $ hg ci -m 'one more line, out of line range'
686 created new head
686 created new head
687 $ sed 's/3+/3-/' baz > baz.new
687 $ sed 's/3+/3-/' baz > baz.new
688 $ mv baz.new baz
688 $ mv baz.new baz
689 $ hg ci -m 'baz:3+->3-'
689 $ hg ci -m 'baz:3+->3-'
690 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7)'
690 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7)'
691 16: baz:0
691 16: baz:0
692 19: baz:3
692 19: baz:3
693 20: baz:4
693 20: baz:4
694 24: baz:3->3+
694 24: baz:3->3+
695 27: baz:3+->3-
695 27: baz:3+->3-
696 $ hg merge 25
696 $ hg merge 25
697 merging baz and qux to qux
697 merging baz and qux to qux
698 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
698 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
699 (branch merge, don't forget to commit)
699 (branch merge, don't forget to commit)
700 $ hg ci -m merge
700 $ hg ci -m merge
701 $ hg log -T '{rev}: {desc}\n' -r 'followlines(qux, 5:7)'
701 $ hg log -T '{rev}: {desc}\n' -r 'followlines(qux, 5:7)'
702 16: baz:0
702 16: baz:0
703 19: baz:3
703 19: baz:3
704 20: baz:4
704 20: baz:4
705 24: baz:3->3+
705 24: baz:3->3+
706 25: qux:4->4+
706 25: qux:4->4+
707 27: baz:3+->3-
707 27: baz:3+->3-
708 28: merge
708 28: merge
709 $ hg up 25 --quiet
709 $ hg up 25 --quiet
710 $ hg merge 27
710 $ hg merge 27
711 merging qux and baz to qux
711 merging qux and baz to qux
712 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
712 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
713 (branch merge, don't forget to commit)
713 (branch merge, don't forget to commit)
714 $ hg ci -m 'merge from other side'
714 $ hg ci -m 'merge from other side'
715 created new head
715 created new head
716 $ hg log -T '{rev}: {desc}\n' -r 'followlines(qux, 5:7)'
716 $ hg log -T '{rev}: {desc}\n' -r 'followlines(qux, 5:7)'
717 16: baz:0
717 16: baz:0
718 19: baz:3
718 19: baz:3
719 20: baz:4
719 20: baz:4
720 24: baz:3->3+
720 24: baz:3->3+
721 25: qux:4->4+
721 25: qux:4->4+
722 27: baz:3+->3-
722 27: baz:3+->3-
723 29: merge from other side
723 29: merge from other side
724 $ hg up 24 --quiet
724 $ hg up 24 --quiet
725
725
726 we are missing the branch with rename when following children
726 we are missing the branch with rename when following children
727 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7, startrev=26, descend=True)'
727 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 5:7, startrev=26, descend=True)'
728 27: baz:3+->3-
728 27: baz:3+->3-
729
729
730 we follow all branches in descending direction
730 we follow all branches in descending direction
731 $ hg up 23 --quiet
731 $ hg up 23 --quiet
732 $ sed 's/3/+3/' baz > baz.new
732 $ sed 's/3/+3/' baz > baz.new
733 $ mv baz.new baz
733 $ mv baz.new baz
734 $ hg ci -m 'baz:3->+3'
734 $ hg ci -m 'baz:3->+3'
735 created new head
735 created new head
736 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 2:5, startrev=16, descend=True)' --graph
736 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 2:5, startrev=16, descend=True)' --graph
737 @ 30: baz:3->+3
737 @ 30: baz:3->+3
738 :
738 :
739 : o 27: baz:3+->3-
739 : o 27: baz:3+->3-
740 : :
740 : :
741 : o 24: baz:3->3+
741 : o 24: baz:3->3+
742 :/
742 :/
743 o 20: baz:4
743 o 20: baz:4
744 |\
744 |\
745 | o 19: baz:3
745 | o 19: baz:3
746 |/
746 |/
747 o 18: baz:2
747 o 18: baz:2
748 :
748 :
749 o 16: baz:0
749 o 16: baz:0
750 |
750 |
751 ~
751 ~
752
752
753 Issue5595: on a merge changeset with different line ranges depending on
753 Issue5595: on a merge changeset with different line ranges depending on
754 parent, be conservative and use the surrounding interval to avoid loosing
754 parent, be conservative and use the surrounding interval to avoid loosing
755 track of possible further descendants in specified range.
755 track of possible further descendants in specified range.
756
756
757 $ hg up 23 --quiet
757 $ hg up 23 --quiet
758 $ hg cat baz -r 24
758 $ hg cat baz -r 24
759 0
759 0
760 0
760 0
761 1 baz:1
761 1 baz:1
762 2 baz:2
762 2 baz:2
763 3+ baz:3
763 3+ baz:3
764 4 baz:4
764 4 baz:4
765 5
765 5
766 6
766 6
767 $ cat > baz << EOF
767 $ cat > baz << EOF
768 > 0
768 > 0
769 > 0
769 > 0
770 > a
770 > a
771 > b
771 > b
772 > 3+ baz:3
772 > 3+ baz:3
773 > 4 baz:4
773 > 4 baz:4
774 > y
774 > y
775 > z
775 > z
776 > EOF
776 > EOF
777 $ hg ci -m 'baz: mostly rewrite with some content from 24'
777 $ hg ci -m 'baz: mostly rewrite with some content from 24'
778 created new head
778 created new head
779 $ hg merge --tool :merge-other 24
779 $ hg merge --tool :merge-other 24
780 merging baz
780 merging baz
781 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
781 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
782 (branch merge, don't forget to commit)
782 (branch merge, don't forget to commit)
783 $ hg ci -m 'merge forgetting about baz rewrite'
783 $ hg ci -m 'merge forgetting about baz rewrite'
784 $ cat > baz << EOF
784 $ cat > baz << EOF
785 > 0
785 > 0
786 > 0
786 > 0
787 > 1 baz:1
787 > 1 baz:1
788 > 2+ baz:2
788 > 2+ baz:2
789 > 3+ baz:3
789 > 3+ baz:3
790 > 4 baz:4
790 > 4 baz:4
791 > 5
791 > 5
792 > 6
792 > 6
793 > EOF
793 > EOF
794 $ hg ci -m 'baz: narrow change (2->2+)'
794 $ hg ci -m 'baz: narrow change (2->2+)'
795 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:4, startrev=20, descend=True)' --graph
795 $ hg log -T '{rev}: {desc}\n' -r 'followlines(baz, 3:4, startrev=20, descend=True)' --graph
796 @ 33: baz: narrow change (2->2+)
796 @ 33: baz: narrow change (2->2+)
797 |
797 |
798 o 32: merge forgetting about baz rewrite
798 o 32: merge forgetting about baz rewrite
799 |\
799 |\
800 | o 31: baz: mostly rewrite with some content from 24
800 | o 31: baz: mostly rewrite with some content from 24
801 | :
801 | :
802 | : o 30: baz:3->+3
802 | : o 30: baz:3->+3
803 | :/
803 | :/
804 +---o 27: baz:3+->3-
804 +---o 27: baz:3+->3-
805 | :
805 | :
806 o : 24: baz:3->3+
806 o : 24: baz:3->3+
807 :/
807 :/
808 o 20: baz:4
808 o 20: baz:4
809 |\
809 |\
810 ~ ~
810 ~ ~
811
811
812 check error cases
812 check error cases
813 $ hg up 24 --quiet
813 $ hg up 24 --quiet
814 $ hg log -r 'followlines()'
814 $ hg log -r 'followlines()'
815 hg: parse error: followlines takes at least 1 positional arguments
815 hg: parse error: followlines takes at least 1 positional arguments
816 [255]
816 [255]
817 $ hg log -r 'followlines(baz)'
817 $ hg log -r 'followlines(baz)'
818 hg: parse error: followlines requires a line range
818 hg: parse error: followlines requires a line range
819 [255]
819 [255]
820 $ hg log -r 'followlines(baz, 1)'
820 $ hg log -r 'followlines(baz, 1)'
821 hg: parse error: followlines expects a line range
821 hg: parse error: followlines expects a line range
822 [255]
822 [255]
823 $ hg log -r 'followlines(baz, 1:2, startrev=desc("b"))'
823 $ hg log -r 'followlines(baz, 1:2, startrev=desc("b"))'
824 hg: parse error: followlines expects exactly one revision
824 hg: parse error: followlines expects exactly one revision
825 [255]
825 [255]
826 $ hg log -r 'followlines("glob:*", 1:2)'
826 $ hg log -r 'followlines("glob:*", 1:2)'
827 hg: parse error: followlines expects exactly one file
827 hg: parse error: followlines expects exactly one file
828 [255]
828 [255]
829 $ hg log -r 'followlines(baz, 1:)'
829 $ hg log -r 'followlines(baz, 1:)'
830 hg: parse error: line range bounds must be integers
830 hg: parse error: line range bounds must be integers
831 [255]
831 [255]
832 $ hg log -r 'followlines(baz, :1)'
832 $ hg log -r 'followlines(baz, :1)'
833 hg: parse error: line range bounds must be integers
833 hg: parse error: line range bounds must be integers
834 [255]
834 [255]
835 $ hg log -r 'followlines(baz, x:4)'
835 $ hg log -r 'followlines(baz, x:4)'
836 hg: parse error: line range bounds must be integers
836 hg: parse error: line range bounds must be integers
837 [255]
837 [255]
838 $ hg log -r 'followlines(baz, 5:4)'
838 $ hg log -r 'followlines(baz, 5:4)'
839 hg: parse error: line range must be positive
839 hg: parse error: line range must be positive
840 [255]
840 [255]
841 $ hg log -r 'followlines(baz, 0:4)'
841 $ hg log -r 'followlines(baz, 0:4)'
842 hg: parse error: fromline must be strictly positive
842 hg: parse error: fromline must be strictly positive
843 [255]
843 [255]
844 $ hg log -r 'followlines(baz, 2:40)'
844 $ hg log -r 'followlines(baz, 2:40)'
845 abort: line range exceeds file size
845 abort: line range exceeds file size
846 [255]
846 [255]
847 $ hg log -r 'followlines(baz, 2:4, startrev=20, descend=[1])'
847 $ hg log -r 'followlines(baz, 2:4, startrev=20, descend=[1])'
848 hg: parse error at 43: not a prefix: [
848 hg: parse error at 43: not a prefix: [
849 (followlines(baz, 2:4, startrev=20, descend=[1])
849 (followlines(baz, 2:4, startrev=20, descend=[1])
850 ^ here)
850 ^ here)
851 [255]
851 [255]
852 $ hg log -r 'followlines(baz, 2:4, startrev=20, descend=a)'
852 $ hg log -r 'followlines(baz, 2:4, startrev=20, descend=a)'
853 hg: parse error: descend argument must be a boolean
853 hg: parse error: descend argument must be a boolean
854 [255]
854 [255]
855
855
856 Test empty annotate output
856 Test empty annotate output
857
857
858 $ printf '\0' > binary
858 $ printf '\0' > binary
859 $ touch empty
859 $ touch empty
860 $ hg ci -qAm 'add binary and empty files'
860 $ hg ci -qAm 'add binary and empty files'
861
861
862 $ hg annotate binary empty
862 $ hg annotate binary empty
863 binary: binary file
863 binary: binary file
864
864
865 $ hg annotate -Tjson binary empty
865 $ hg annotate -Tjson binary empty
866 [
866 [
867 {
867 {
868 "path": "binary"
868 "path": "binary"
869 },
869 },
870 {
870 {
871 "lines": [],
871 "lines": [],
872 "path": "empty"
872 "path": "empty"
873 }
873 }
874 ]
874 ]
875
875
876 Test annotate with whitespace options
876 Test annotate with whitespace options
877
877
878 $ cd ..
878 $ cd ..
879 $ hg init repo-ws
879 $ hg init repo-ws
880 $ cd repo-ws
880 $ cd repo-ws
881 $ cat > a <<EOF
881 $ cat > a <<EOF
882 > aa
882 > aa
883 >
883 >
884 > b b
884 > b b
885 > EOF
885 > EOF
886 $ hg ci -Am "adda"
886 $ hg ci -Am "adda"
887 adding a
887 adding a
888 $ sed 's/EOL$//g' > a <<EOF
888 $ sed 's/EOL$//g' > a <<EOF
889 > a a
889 > a a
890 >
890 >
891 > EOL
891 > EOL
892 > b b
892 > b b
893 > EOF
893 > EOF
894 $ hg ci -m "changea"
894 $ hg ci -m "changea"
895
895
896 Annotate with no option
896 Annotate with no option
897
897
898 $ hg annotate a
898 $ hg annotate a
899 1: a a
899 1: a a
900 0:
900 0:
901 1:
901 1:
902 1: b b
902 1: b b
903
903
904 Annotate with --ignore-space-change
904 Annotate with --ignore-space-change
905
905
906 $ hg annotate --ignore-space-change a
906 $ hg annotate --ignore-space-change a
907 1: a a
907 1: a a
908 1:
908 1:
909 0:
909 0:
910 0: b b
910 0: b b
911
911
912 Annotate with --ignore-all-space
912 Annotate with --ignore-all-space
913
913
914 $ hg annotate --ignore-all-space a
914 $ hg annotate --ignore-all-space a
915 0: a a
915 0: a a
916 0:
916 0:
917 1:
917 1:
918 0: b b
918 0: b b
919
919
920 Annotate with --ignore-blank-lines (similar to no options case)
920 Annotate with --ignore-blank-lines (similar to no options case)
921
921
922 $ hg annotate --ignore-blank-lines a
922 $ hg annotate --ignore-blank-lines a
923 1: a a
923 1: a a
924 0:
924 0:
925 1:
925 1:
926 1: b b
926 1: b b
927
927
928 $ cd ..
928 $ cd ..
929
929
930 Annotate with orphaned CR (issue5798)
930 Annotate with orphaned CR (issue5798)
931 -------------------------------------
931 -------------------------------------
932
932
933 $ hg init repo-cr
933 $ hg init repo-cr
934 $ cd repo-cr
934 $ cd repo-cr
935
935
936 $ cat <<'EOF' >> "$TESTTMP/substcr.py"
936 $ cat <<'EOF' >> "$TESTTMP/substcr.py"
937 > import sys
937 > import sys
938 > from mercurial.utils import procutil
938 > from mercurial.utils import procutil
939 > procutil.setbinary(sys.stdin)
939 > procutil.setbinary(sys.stdin)
940 > procutil.setbinary(sys.stdout)
940 > procutil.setbinary(sys.stdout)
941 > stdin = getattr(sys.stdin, 'buffer', sys.stdin)
941 > stdin = getattr(sys.stdin, 'buffer', sys.stdin)
942 > stdout = getattr(sys.stdout, 'buffer', sys.stdout)
942 > stdout = getattr(sys.stdout, 'buffer', sys.stdout)
943 > stdout.write(stdin.read().replace(b'\r', b'[CR]'))
943 > stdout.write(stdin.read().replace(b'\r', b'[CR]'))
944 > EOF
944 > EOF
945
945
946 >>> with open('a', 'wb') as f:
946 >>> with open('a', 'wb') as f:
947 ... f.write(b'0a\r0b\r\n0c\r0d\r\n0e\n0f\n0g') and None
947 ... f.write(b'0a\r0b\r\n0c\r0d\r\n0e\n0f\n0g') and None
948 $ hg ci -qAm0
948 $ hg ci -qAm0
949 >>> with open('a', 'wb') as f:
949 >>> with open('a', 'wb') as f:
950 ... f.write(b'0a\r0b\r\n1c\r1d\r\n0e\n1f\n0g') and None
950 ... f.write(b'0a\r0b\r\n1c\r1d\r\n0e\n1f\n0g') and None
951 $ hg ci -m1
951 $ hg ci -m1
952
952
953 $ hg annotate -r0 a | "$PYTHON" "$TESTTMP/substcr.py"
953 $ hg annotate -r0 a | "$PYTHON" "$TESTTMP/substcr.py"
954 0: 0a[CR]0b[CR]
954 0: 0a[CR]0b[CR]
955 0: 0c[CR]0d[CR]
955 0: 0c[CR]0d[CR]
956 0: 0e
956 0: 0e
957 0: 0f
957 0: 0f
958 0: 0g
958 0: 0g
959 $ hg annotate -r1 a | "$PYTHON" "$TESTTMP/substcr.py"
959 $ hg annotate -r1 a | "$PYTHON" "$TESTTMP/substcr.py"
960 0: 0a[CR]0b[CR]
960 0: 0a[CR]0b[CR]
961 1: 1c[CR]1d[CR]
961 1: 1c[CR]1d[CR]
962 0: 0e
962 0: 0e
963 1: 1f
963 1: 1f
964 0: 0g
964 0: 0g
965
965
966 $ cd ..
966 $ cd ..
967
967
968 Annotate with linkrev pointing to another branch
968 Annotate with linkrev pointing to another branch
969 ------------------------------------------------
969 ------------------------------------------------
970
970
971 create history with a filerev whose linkrev points to another branch
971 create history with a filerev whose linkrev points to another branch
972
972
973 $ hg init branchedlinkrev
973 $ hg init branchedlinkrev
974 $ cd branchedlinkrev
974 $ cd branchedlinkrev
975 $ echo A > a
975 $ echo A > a
976 $ hg commit -Am 'contentA'
976 $ hg commit -Am 'contentA'
977 adding a
977 adding a
978 $ echo B >> a
978 $ echo B >> a
979 $ hg commit -m 'contentB'
979 $ hg commit -m 'contentB'
980 $ hg up --rev 'desc(contentA)'
980 $ hg up --rev 'desc(contentA)'
981 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
981 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
982 $ echo unrelated > unrelated
982 $ echo unrelated > unrelated
983 $ hg commit -Am 'unrelated'
983 $ hg commit -Am 'unrelated'
984 adding unrelated
984 adding unrelated
985 created new head
985 created new head
986 $ hg graft -r 'desc(contentB)'
986 $ hg graft -r 'desc(contentB)'
987 grafting 1:fd27c222e3e6 "contentB"
987 grafting 1:fd27c222e3e6 "contentB"
988 $ echo C >> a
988 $ echo C >> a
989 $ hg commit -m 'contentC'
989 $ hg commit -m 'contentC'
990 $ echo W >> a
990 $ echo W >> a
991 $ hg log -G
991 $ hg log -G
992 @ changeset: 4:072f1e8df249
992 @ changeset: 4:072f1e8df249
993 | tag: tip
993 | tag: tip
994 | user: test
994 | user: test
995 | date: Thu Jan 01 00:00:00 1970 +0000
995 | date: Thu Jan 01 00:00:00 1970 +0000
996 | summary: contentC
996 | summary: contentC
997 |
997 |
998 o changeset: 3:ff38df03cc4b
998 o changeset: 3:ff38df03cc4b
999 | user: test
999 | user: test
1000 | date: Thu Jan 01 00:00:00 1970 +0000
1000 | date: Thu Jan 01 00:00:00 1970 +0000
1001 | summary: contentB
1001 | summary: contentB
1002 |
1002 |
1003 o changeset: 2:62aaf3f6fc06
1003 o changeset: 2:62aaf3f6fc06
1004 | parent: 0:f0932f74827e
1004 | parent: 0:f0932f74827e
1005 | user: test
1005 | user: test
1006 | date: Thu Jan 01 00:00:00 1970 +0000
1006 | date: Thu Jan 01 00:00:00 1970 +0000
1007 | summary: unrelated
1007 | summary: unrelated
1008 |
1008 |
1009 | o changeset: 1:fd27c222e3e6
1009 | o changeset: 1:fd27c222e3e6
1010 |/ user: test
1010 |/ user: test
1011 | date: Thu Jan 01 00:00:00 1970 +0000
1011 | date: Thu Jan 01 00:00:00 1970 +0000
1012 | summary: contentB
1012 | summary: contentB
1013 |
1013 |
1014 o changeset: 0:f0932f74827e
1014 o changeset: 0:f0932f74827e
1015 user: test
1015 user: test
1016 date: Thu Jan 01 00:00:00 1970 +0000
1016 date: Thu Jan 01 00:00:00 1970 +0000
1017 summary: contentA
1017 summary: contentA
1018
1018
1019
1019
1020 Annotate should list ancestor of starting revision only
1020 Annotate should list ancestor of starting revision only
1021
1021
1022 $ hg annotate a
1022 $ hg annotate a
1023 0: A
1023 0: A
1024 3: B
1024 3: B
1025 4: C
1025 4: C
1026
1026
1027 $ hg annotate a -r 'wdir()'
1027 $ hg annotate a -r 'wdir()'
1028 0 : A
1028 0 : A
1029 3 : B
1029 3 : B
1030 4 : C
1030 4 : C
1031 4+: W
1031 4+: W
1032
1032
1033 Even when the starting revision is the linkrev-shadowed one:
1033 Even when the starting revision is the linkrev-shadowed one:
1034
1034
1035 $ hg annotate a -r 3
1035 $ hg annotate a -r 3
1036 0: A
1036 0: A
1037 3: B
1037 3: B
1038
1038
1039 $ cd ..
1039 $ cd ..
1040
1040
1041 Issue5360: Deleted chunk in p1 of a merge changeset
1041 Issue5360: Deleted chunk in p1 of a merge changeset
1042
1042
1043 $ hg init repo-5360
1043 $ hg init repo-5360
1044 $ cd repo-5360
1044 $ cd repo-5360
1045 $ echo 1 > a
1045 $ echo 1 > a
1046 $ hg commit -A a -m 1
1046 $ hg commit -A a -m 1
1047 $ echo 2 >> a
1047 $ echo 2 >> a
1048 $ hg commit -m 2
1048 $ hg commit -m 2
1049 $ echo a > a
1049 $ echo a > a
1050 $ hg commit -m a
1050 $ hg commit -m a
1051 $ hg update '.^' -q
1051 $ hg update '.^' -q
1052 $ echo 3 >> a
1052 $ echo 3 >> a
1053 $ hg commit -m 3 -q
1053 $ hg commit -m 3 -q
1054 $ hg merge 2 -q
1054 $ hg merge 2 -q
1055 $ cat > a << EOF
1055 $ cat > a << EOF
1056 > b
1056 > b
1057 > 1
1057 > 1
1058 > 2
1058 > 2
1059 > 3
1059 > 3
1060 > a
1060 > a
1061 > EOF
1061 > EOF
1062 $ hg resolve --mark -q
1062 $ hg resolve --mark -q
1063 $ hg commit -m m
1063 $ hg commit -m m
1064 $ hg annotate a
1064 $ hg annotate a
1065 4: b
1065 4: b
1066 0: 1
1066 0: 1
1067 1: 2
1067 1: 2
1068 3: 3
1068 3: 3
1069 2: a
1069 2: a
1070
1070
1071 $ cd ..
1071 $ cd ..
@@ -1,764 +1,764 b''
1 (this file is backported from core hg tests/test-annotate.t)
1 (this file is backported from core hg tests/test-annotate.t)
2
2
3 $ cat >> $HGRCPATH << EOF
3 $ cat >> $HGRCPATH << EOF
4 > [diff]
4 > [diff]
5 > git=1
5 > git=1
6 > [extensions]
6 > [extensions]
7 > fastannotate=
7 > fastannotate=
8 > [fastannotate]
8 > [fastannotate]
9 > modes=fctx
9 > modes=fctx
10 > forcefollow=False
10 > forcefollow=False
11 > mainbranch=.
11 > mainbranch=.
12 > EOF
12 > EOF
13
13
14 $ HGMERGE=true; export HGMERGE
14 $ HGMERGE=true; export HGMERGE
15
15
16 init
16 init
17
17
18 $ hg init repo
18 $ hg init repo
19 $ cd repo
19 $ cd repo
20
20
21 commit
21 commit
22
22
23 $ echo 'a' > a
23 $ echo 'a' > a
24 $ hg ci -A -m test -u nobody -d '1 0'
24 $ hg ci -A -m test -u nobody -d '1 0'
25 adding a
25 adding a
26
26
27 annotate -c
27 annotate -c
28
28
29 $ hg annotate -c a
29 $ hg annotate -c a
30 8435f90966e4: a
30 8435f90966e4: a
31
31
32 annotate -cl
32 annotate -cl
33
33
34 $ hg annotate -cl a
34 $ hg annotate -cl a
35 8435f90966e4:1: a
35 8435f90966e4:1: a
36
36
37 annotate -d
37 annotate -d
38
38
39 $ hg annotate -d a
39 $ hg annotate -d a
40 Thu Jan 01 00:00:01 1970 +0000: a
40 Thu Jan 01 00:00:01 1970 +0000: a
41
41
42 annotate -n
42 annotate -n
43
43
44 $ hg annotate -n a
44 $ hg annotate -n a
45 0: a
45 0: a
46
46
47 annotate -nl
47 annotate -nl
48
48
49 $ hg annotate -nl a
49 $ hg annotate -nl a
50 0:1: a
50 0:1: a
51
51
52 annotate -u
52 annotate -u
53
53
54 $ hg annotate -u a
54 $ hg annotate -u a
55 nobody: a
55 nobody: a
56
56
57 annotate -cdnu
57 annotate -cdnu
58
58
59 $ hg annotate -cdnu a
59 $ hg annotate -cdnu a
60 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
60 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
61
61
62 annotate -cdnul
62 annotate -cdnul
63
63
64 $ hg annotate -cdnul a
64 $ hg annotate -cdnul a
65 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000:1: a
65 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000:1: a
66
66
67 annotate (JSON)
67 annotate (JSON)
68
68
69 $ hg annotate -Tjson a
69 $ hg annotate -Tjson a
70 [
70 [
71 {
71 {
72 "lines": [{"line": "a\n", "rev": 0}],
72 "lines": [{"line": "a\n", "rev": 0}],
73 "path": "a"
73 "path": "a"
74 }
74 }
75 ]
75 ]
76
76
77 $ hg annotate -Tjson -cdfnul a
77 $ hg annotate -Tjson -cdfnul a
78 [
78 [
79 {
79 {
80 "lines": [{"date": [1.0, 0], "line": "a\n", "line_number": 1, "node": "8435f90966e442695d2ded29fdade2bac5ad8065", "path": "a", "rev": 0, "user": "nobody"}],
80 "lines": [{"date": [1.0, 0], "line": "a\n", "line_number": 1, "node": "8435f90966e442695d2ded29fdade2bac5ad8065", "path": "a", "rev": 0, "user": "nobody"}],
81 "path": "a"
81 "path": "a"
82 }
82 }
83 ]
83 ]
84
84
85 $ cat <<EOF >>a
85 $ cat <<EOF >>a
86 > a
86 > a
87 > a
87 > a
88 > EOF
88 > EOF
89 $ hg ci -ma1 -d '1 0'
89 $ hg ci -ma1 -d '1 0'
90 $ hg cp a b
90 $ hg cp a b
91 $ hg ci -mb -d '1 0'
91 $ hg ci -mb -d '1 0'
92 $ cat <<EOF >> b
92 $ cat <<EOF >> b
93 > b4
93 > b4
94 > b5
94 > b5
95 > b6
95 > b6
96 > EOF
96 > EOF
97 $ hg ci -mb2 -d '2 0'
97 $ hg ci -mb2 -d '2 0'
98
98
99 annotate -n b
99 annotate -n b
100
100
101 $ hg annotate -n b
101 $ hg annotate -n b
102 0: a
102 0: a
103 1: a
103 1: a
104 1: a
104 1: a
105 3: b4
105 3: b4
106 3: b5
106 3: b5
107 3: b6
107 3: b6
108
108
109 annotate --no-follow b
109 annotate --no-follow b
110
110
111 $ hg annotate --no-follow b
111 $ hg annotate --no-follow b
112 2: a
112 2: a
113 2: a
113 2: a
114 2: a
114 2: a
115 3: b4
115 3: b4
116 3: b5
116 3: b5
117 3: b6
117 3: b6
118
118
119 annotate -nl b
119 annotate -nl b
120
120
121 $ hg annotate -nl b
121 $ hg annotate -nl b
122 0:1: a
122 0:1: a
123 1:2: a
123 1:2: a
124 1:3: a
124 1:3: a
125 3:4: b4
125 3:4: b4
126 3:5: b5
126 3:5: b5
127 3:6: b6
127 3:6: b6
128
128
129 annotate -nf b
129 annotate -nf b
130
130
131 $ hg annotate -nf b
131 $ hg annotate -nf b
132 0 a: a
132 0 a: a
133 1 a: a
133 1 a: a
134 1 a: a
134 1 a: a
135 3 b: b4
135 3 b: b4
136 3 b: b5
136 3 b: b5
137 3 b: b6
137 3 b: b6
138
138
139 annotate -nlf b
139 annotate -nlf b
140
140
141 $ hg annotate -nlf b
141 $ hg annotate -nlf b
142 0 a:1: a
142 0 a:1: a
143 1 a:2: a
143 1 a:2: a
144 1 a:3: a
144 1 a:3: a
145 3 b:4: b4
145 3 b:4: b4
146 3 b:5: b5
146 3 b:5: b5
147 3 b:6: b6
147 3 b:6: b6
148
148
149 $ hg up -C 2
149 $ hg up -C 2
150 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
151 $ cat <<EOF >> b
151 $ cat <<EOF >> b
152 > b4
152 > b4
153 > c
153 > c
154 > b5
154 > b5
155 > EOF
155 > EOF
156 $ hg ci -mb2.1 -d '2 0'
156 $ hg ci -mb2.1 -d '2 0'
157 created new head
157 created new head
158 $ hg merge
158 $ hg merge
159 merging b
159 merging b
160 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
160 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
161 (branch merge, don't forget to commit)
161 (branch merge, don't forget to commit)
162 $ hg ci -mmergeb -d '3 0'
162 $ hg ci -mmergeb -d '3 0'
163
163
164 annotate after merge
164 annotate after merge
165 (note: the first one falls back to the vanilla annotate which does not use linelog)
165 (note: the first one falls back to the vanilla annotate which does not use linelog)
166
166
167 $ hg annotate -nf b --debug
167 $ hg annotate -nf b --debug
168 fastannotate: b: rebuilding broken cache
168 fastannotate: b: rebuilding broken cache
169 fastannotate: b: 5 new changesets in the main branch
169 fastannotate: b: 5 new changesets in the main branch
170 0 a: a
170 0 a: a
171 1 a: a
171 1 a: a
172 1 a: a
172 1 a: a
173 3 b: b4
173 3 b: b4
174 4 b: c
174 4 b: c
175 3 b: b5
175 3 b: b5
176
176
177 (difference explained below)
177 (difference explained below)
178
178
179 $ hg annotate -nf b --debug
179 $ hg annotate -nf b --debug
180 fastannotate: b: using fast path (resolved fctx: False)
180 fastannotate: b: using fast path (resolved fctx: False)
181 0 a: a
181 0 a: a
182 1 a: a
182 1 a: a
183 1 a: a
183 1 a: a
184 4 b: b4
184 4 b: b4
185 4 b: c
185 4 b: c
186 4 b: b5
186 4 b: b5
187
187
188 annotate after merge with -l
188 annotate after merge with -l
189 (fastannotate differs from annotate)
189 (fastannotate differs from annotate)
190
190
191 $ hg log -Gp -T '{rev}:{node}' -r '2..5'
191 $ hg log -Gp -T '{rev}:{node}' -r '2..5'
192 @ 5:64afcdf8e29e063c635be123d8d2fb160af00f7e
192 @ 5:64afcdf8e29e063c635be123d8d2fb160af00f7e
193 |\
193 |\
194 | o 4:5fbdc1152d97597717021ad9e063061b200f146bdiff --git a/b b/b
194 | o 4:5fbdc1152d97597717021ad9e063061b200f146bdiff --git a/b b/b
195 | | --- a/b
195 | | --- a/b
196 | | +++ b/b
196 | | +++ b/b
197 | | @@ -1,3 +1,6 @@
197 | | @@ -1,3 +1,6 @@
198 | | a
198 | | a
199 | | a
199 | | a
200 | | a
200 | | a
201 | | +b4
201 | | +b4
202 | | +c
202 | | +c
203 | | +b5
203 | | +b5
204 | |
204 | |
205 o | 3:37ec9f5c3d1f99572d7075971cb4876e2139b52fdiff --git a/b b/b
205 o | 3:37ec9f5c3d1f99572d7075971cb4876e2139b52fdiff --git a/b b/b
206 |/ --- a/b
206 |/ --- a/b
207 | +++ b/b
207 | +++ b/b
208 | @@ -1,3 +1,6 @@
208 | @@ -1,3 +1,6 @@
209 | a
209 | a
210 | a
210 | a
211 | a
211 | a
212 | +b4
212 | +b4
213 | +b5
213 | +b5
214 | +b6
214 | +b6
215 |
215 |
216 o 2:3086dbafde1ce745abfc8d2d367847280aabae9ddiff --git a/a b/b
216 o 2:3086dbafde1ce745abfc8d2d367847280aabae9ddiff --git a/a b/b
217 | copy from a
217 | copy from a
218 ~ copy to b
218 ~ copy to b
219
219
220
220
221 (in this case, "b4", "b5" could be considered introduced by either rev 3, or rev 4.
221 (in this case, "b4", "b5" could be considered introduced by either rev 3, or rev 4.
222 and that causes the rev number difference)
222 and that causes the rev number difference)
223
223
224 $ hg annotate -nlf b --config fastannotate.modes=
224 $ hg annotate -nlf b --config fastannotate.modes=
225 0 a:1: a
225 0 a:1: a
226 1 a:2: a
226 1 a:2: a
227 1 a:3: a
227 1 a:3: a
228 3 b:4: b4
228 3 b:4: b4
229 4 b:5: c
229 4 b:5: c
230 3 b:5: b5
230 3 b:5: b5
231
231
232 $ hg annotate -nlf b
232 $ hg annotate -nlf b
233 0 a:1: a
233 0 a:1: a
234 1 a:2: a
234 1 a:2: a
235 1 a:3: a
235 1 a:3: a
236 4 b:4: b4
236 4 b:4: b4
237 4 b:5: c
237 4 b:5: c
238 4 b:6: b5
238 4 b:6: b5
239
239
240 $ hg up -C 1
240 $ hg up -C 1
241 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
241 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
242 $ hg cp a b
242 $ hg cp a b
243 $ cat <<EOF > b
243 $ cat <<EOF > b
244 > a
244 > a
245 > z
245 > z
246 > a
246 > a
247 > EOF
247 > EOF
248 $ hg ci -mc -d '3 0'
248 $ hg ci -mc -d '3 0'
249 created new head
249 created new head
250 $ hg merge
250 $ hg merge
251 merging b
251 merging b
252 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
252 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
253 (branch merge, don't forget to commit)
253 (branch merge, don't forget to commit)
254 $ cat <<EOF >> b
254 $ cat <<EOF >> b
255 > b4
255 > b4
256 > c
256 > c
257 > b5
257 > b5
258 > EOF
258 > EOF
259 $ echo d >> b
259 $ echo d >> b
260 $ hg ci -mmerge2 -d '4 0'
260 $ hg ci -mmerge2 -d '4 0'
261
261
262 annotate after rename merge
262 annotate after rename merge
263
263
264 $ hg annotate -nf b
264 $ hg annotate -nf b
265 0 a: a
265 0 a: a
266 6 b: z
266 6 b: z
267 1 a: a
267 1 a: a
268 3 b: b4
268 3 b: b4
269 4 b: c
269 4 b: c
270 3 b: b5
270 3 b: b5
271 7 b: d
271 7 b: d
272
272
273 annotate after rename merge with -l
273 annotate after rename merge with -l
274 (fastannotate differs from annotate)
274 (fastannotate differs from annotate)
275
275
276 $ hg log -Gp -T '{rev}:{node}' -r '0+1+6+7'
276 $ hg log -Gp -T '{rev}:{node}' -r '0+1+6+7'
277 @ 7:6284bb6c38fef984a929862a53bbc71ce9eafa81diff --git a/b b/b
277 @ 7:6284bb6c38fef984a929862a53bbc71ce9eafa81diff --git a/b b/b
278 |\ --- a/b
278 |\ --- a/b
279 | : +++ b/b
279 | : +++ b/b
280 | : @@ -1,3 +1,7 @@
280 | : @@ -1,3 +1,7 @@
281 | : a
281 | : a
282 | : z
282 | : z
283 | : a
283 | : a
284 | : +b4
284 | : +b4
285 | : +c
285 | : +c
286 | : +b5
286 | : +b5
287 | : +d
287 | : +d
288 | :
288 | :
289 o : 6:b80e3e32f75a6a67cd4ac85496a11511e9112816diff --git a/a b/b
289 o : 6:b80e3e32f75a6a67cd4ac85496a11511e9112816diff --git a/a b/b
290 :/ copy from a
290 :/ copy from a
291 : copy to b
291 : copy to b
292 : --- a/a
292 : --- a/a
293 : +++ b/b
293 : +++ b/b
294 : @@ -1,3 +1,3 @@
294 : @@ -1,3 +1,3 @@
295 : -a (?)
295 : -a (?)
296 : a
296 : a
297 : +z
297 : +z
298 : a
298 : a
299 : -a (?)
299 : -a (?)
300 :
300 :
301 o 1:762f04898e6684ff713415f7b8a8d53d33f96c92diff --git a/a b/a
301 o 1:762f04898e6684ff713415f7b8a8d53d33f96c92diff --git a/a b/a
302 | --- a/a
302 | --- a/a
303 | +++ b/a
303 | +++ b/a
304 | @@ -1,1 +1,3 @@
304 | @@ -1,1 +1,3 @@
305 | a
305 | a
306 | +a
306 | +a
307 | +a
307 | +a
308 |
308 |
309 o 0:8435f90966e442695d2ded29fdade2bac5ad8065diff --git a/a b/a
309 o 0:8435f90966e442695d2ded29fdade2bac5ad8065diff --git a/a b/a
310 new file mode 100644
310 new file mode 100644
311 --- /dev/null
311 --- /dev/null
312 +++ b/a
312 +++ b/a
313 @@ -0,0 +1,1 @@
313 @@ -0,0 +1,1 @@
314 +a
314 +a
315
315
316
316
317 (note on question marks:
317 (note on question marks:
318 the upstream bdiff change (96f2f50d923f+3633403888ae+8c0c75aa3ff4+5c4e2636c1a9
318 the upstream bdiff change (96f2f50d923f+3633403888ae+8c0c75aa3ff4+5c4e2636c1a9
319 +38ed54888617) alters the output so deletion is not always at the end of the
319 +38ed54888617) alters the output so deletion is not always at the end of the
320 output. for example:
320 output. for example:
321 | a | b | old | new | # old: e1d6aa0e4c3a, new: 8836f13e3c5b
321 | a | b | old | new | # old: e1d6aa0e4c3a, new: 8836f13e3c5b
322 |-------------------|
322 |-------------------|
323 | a | a | a | -a |
323 | a | a | a | -a |
324 | a | z | +z | a |
324 | a | z | +z | a |
325 | a | a | a | +z |
325 | a | a | a | +z |
326 | | | -a | a |
326 | | | -a | a |
327 |-------------------|
327 |-------------------|
328 | a | a | a |
328 | a | a | a |
329 | a | a | a |
329 | a | a | a |
330 | a | | -a |
330 | a | | -a |
331 this leads to more question marks below)
331 this leads to more question marks below)
332
332
333 (rev 1 adds two "a"s and rev 6 deletes one "a".
333 (rev 1 adds two "a"s and rev 6 deletes one "a".
334 the "a" that rev 6 deletes could be either the first or the second "a" of those two "a"s added by rev 1.
334 the "a" that rev 6 deletes could be either the first or the second "a" of those two "a"s added by rev 1.
335 and that causes the line number difference)
335 and that causes the line number difference)
336
336
337 $ hg annotate -nlf b --config fastannotate.modes=
337 $ hg annotate -nlf b --config fastannotate.modes=
338 0 a:1: a
338 0 a:1: a
339 6 b:2: z
339 6 b:2: z
340 1 a:3: a
340 1 a:3: a
341 3 b:4: b4
341 3 b:4: b4
342 4 b:5: c
342 4 b:5: c
343 3 b:5: b5
343 3 b:5: b5
344 7 b:7: d
344 7 b:7: d
345
345
346 $ hg annotate -nlf b
346 $ hg annotate -nlf b
347 0 a:1: a (?)
347 0 a:1: a (?)
348 1 a:2: a (?)
348 1 a:2: a (?)
349 6 b:2: z
349 6 b:2: z
350 1 a:2: a (?)
350 1 a:2: a (?)
351 1 a:3: a (?)
351 1 a:3: a (?)
352 3 b:4: b4
352 3 b:4: b4
353 4 b:5: c
353 4 b:5: c
354 3 b:5: b5
354 3 b:5: b5
355 7 b:7: d
355 7 b:7: d
356
356
357 Issue2807: alignment of line numbers with -l
357 Issue2807: alignment of line numbers with -l
358 (fastannotate differs from annotate, same reason as above)
358 (fastannotate differs from annotate, same reason as above)
359
359
360 $ echo more >> b
360 $ echo more >> b
361 $ hg ci -mmore -d '5 0'
361 $ hg ci -mmore -d '5 0'
362 $ echo more >> b
362 $ echo more >> b
363 $ hg ci -mmore -d '6 0'
363 $ hg ci -mmore -d '6 0'
364 $ echo more >> b
364 $ echo more >> b
365 $ hg ci -mmore -d '7 0'
365 $ hg ci -mmore -d '7 0'
366 $ hg annotate -nlf b
366 $ hg annotate -nlf b
367 0 a: 1: a (?)
367 0 a: 1: a (?)
368 1 a: 2: a (?)
368 1 a: 2: a (?)
369 6 b: 2: z
369 6 b: 2: z
370 1 a: 2: a (?)
370 1 a: 2: a (?)
371 1 a: 3: a (?)
371 1 a: 3: a (?)
372 3 b: 4: b4
372 3 b: 4: b4
373 4 b: 5: c
373 4 b: 5: c
374 3 b: 5: b5
374 3 b: 5: b5
375 7 b: 7: d
375 7 b: 7: d
376 8 b: 8: more
376 8 b: 8: more
377 9 b: 9: more
377 9 b: 9: more
378 10 b:10: more
378 10 b:10: more
379
379
380 linkrev vs rev
380 linkrev vs rev
381
381
382 $ hg annotate -r tip -n a
382 $ hg annotate -r tip -n a
383 0: a
383 0: a
384 1: a
384 1: a
385 1: a
385 1: a
386
386
387 linkrev vs rev with -l
387 linkrev vs rev with -l
388
388
389 $ hg annotate -r tip -nl a
389 $ hg annotate -r tip -nl a
390 0:1: a
390 0:1: a
391 1:2: a
391 1:2: a
392 1:3: a
392 1:3: a
393
393
394 Issue589: "undelete" sequence leads to crash
394 Issue589: "undelete" sequence leads to crash
395
395
396 annotate was crashing when trying to --follow something
396 annotate was crashing when trying to --follow something
397
397
398 like A -> B -> A
398 like A -> B -> A
399
399
400 generate ABA rename configuration
400 generate ABA rename configuration
401
401
402 $ echo foo > foo
402 $ echo foo > foo
403 $ hg add foo
403 $ hg add foo
404 $ hg ci -m addfoo
404 $ hg ci -m addfoo
405 $ hg rename foo bar
405 $ hg rename foo bar
406 $ hg ci -m renamefoo
406 $ hg ci -m renamefoo
407 $ hg rename bar foo
407 $ hg rename bar foo
408 $ hg ci -m renamebar
408 $ hg ci -m renamebar
409
409
410 annotate after ABA with follow
410 annotate after ABA with follow
411
411
412 $ hg annotate --follow foo
412 $ hg annotate --follow foo
413 foo: foo
413 foo: foo
414
414
415 missing file
415 missing file
416
416
417 $ hg ann nosuchfile
417 $ hg ann nosuchfile
418 abort: nosuchfile: no such file in rev e9e6b4fa872f
418 abort: nosuchfile: no such file in rev e9e6b4fa872f
419 [255]
419 [255]
420
420
421 annotate file without '\n' on last line
421 annotate file without '\n' on last line
422
422
423 $ printf "" > c
423 $ printf "" > c
424 $ hg ci -A -m test -u nobody -d '1 0'
424 $ hg ci -A -m test -u nobody -d '1 0'
425 adding c
425 adding c
426 $ hg annotate c
426 $ hg annotate c
427 $ printf "a\nb" > c
427 $ printf "a\nb" > c
428 $ hg ci -m test
428 $ hg ci -m test
429 $ hg annotate c
429 $ hg annotate c
430 [0-9]+: a (re)
430 [0-9]+: a (re)
431 [0-9]+: b (re)
431 [0-9]+: b (re)
432
432
433 Issue3841: check annotation of the file of which filelog includes
433 Issue3841: check annotation of the file of which filelog includes
434 merging between the revision and its ancestor
434 merging between the revision and its ancestor
435
435
436 to reproduce the situation with recent Mercurial, this script uses (1)
436 to reproduce the situation with recent Mercurial, this script uses (1)
437 "hg debugsetparents" to merge without ancestor check by "hg merge",
437 "hg debugsetparents" to merge without ancestor check by "hg merge",
438 and (2) the extension to allow filelog merging between the revision
438 and (2) the extension to allow filelog merging between the revision
439 and its ancestor by overriding "repo._filecommit".
439 and its ancestor by overriding "repo._filecommit".
440
440
441 $ cat > ../legacyrepo.py <<EOF
441 $ cat > ../legacyrepo.py <<EOF
442 > from mercurial import error, node
442 > from mercurial import error, node
443 > def reposetup(ui, repo):
443 > def reposetup(ui, repo):
444 > class legacyrepo(repo.__class__):
444 > class legacyrepo(repo.__class__):
445 > def _filecommit(self, fctx, manifest1, manifest2,
445 > def _filecommit(self, fctx, manifest1, manifest2,
446 > linkrev, tr, changelist):
446 > linkrev, tr, changelist):
447 > fname = fctx.path()
447 > fname = fctx.path()
448 > text = fctx.data()
448 > text = fctx.data()
449 > flog = self.file(fname)
449 > flog = self.file(fname)
450 > fparent1 = manifest1.get(fname, node.nullid)
450 > fparent1 = manifest1.get(fname, node.nullid)
451 > fparent2 = manifest2.get(fname, node.nullid)
451 > fparent2 = manifest2.get(fname, node.nullid)
452 > meta = {}
452 > meta = {}
453 > copy = fctx.renamed()
453 > copy = fctx.renamed()
454 > if copy and copy[0] != fname:
454 > if copy and copy[0] != fname:
455 > raise error.Abort('copying is not supported')
455 > raise error.Abort('copying is not supported')
456 > if fparent2 != node.nullid:
456 > if fparent2 != node.nullid:
457 > changelist.append(fname)
457 > changelist.append(fname)
458 > return flog.add(text, meta, tr, linkrev,
458 > return flog.add(text, meta, tr, linkrev,
459 > fparent1, fparent2)
459 > fparent1, fparent2)
460 > raise error.Abort('only merging is supported')
460 > raise error.Abort('only merging is supported')
461 > repo.__class__ = legacyrepo
461 > repo.__class__ = legacyrepo
462 > EOF
462 > EOF
463
463
464 $ cat > baz <<EOF
464 $ cat > baz <<EOF
465 > 1
465 > 1
466 > 2
466 > 2
467 > 3
467 > 3
468 > 4
468 > 4
469 > 5
469 > 5
470 > EOF
470 > EOF
471 $ hg add baz
471 $ hg add baz
472 $ hg commit -m "baz:0"
472 $ hg commit -m "baz:0"
473
473
474 $ cat > baz <<EOF
474 $ cat > baz <<EOF
475 > 1 baz:1
475 > 1 baz:1
476 > 2
476 > 2
477 > 3
477 > 3
478 > 4
478 > 4
479 > 5
479 > 5
480 > EOF
480 > EOF
481 $ hg commit -m "baz:1"
481 $ hg commit -m "baz:1"
482
482
483 $ cat > baz <<EOF
483 $ cat > baz <<EOF
484 > 1 baz:1
484 > 1 baz:1
485 > 2 baz:2
485 > 2 baz:2
486 > 3
486 > 3
487 > 4
487 > 4
488 > 5
488 > 5
489 > EOF
489 > EOF
490 $ hg debugsetparents 17 17
490 $ hg debugsetparents 17 17
491 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:2"
491 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:2"
492 $ hg debugindexdot baz
492 $ hg debugindexdot baz
493 digraph G {
493 digraph G {
494 -1 -> 0
494 -1 -> 0
495 0 -> 1
495 0 -> 1
496 1 -> 2
496 1 -> 2
497 1 -> 2
497 1 -> 2
498 }
498 }
499 $ hg annotate baz
499 $ hg annotate baz
500 17: 1 baz:1
500 17: 1 baz:1
501 18: 2 baz:2
501 18: 2 baz:2
502 16: 3
502 16: 3
503 16: 4
503 16: 4
504 16: 5
504 16: 5
505
505
506 $ cat > baz <<EOF
506 $ cat > baz <<EOF
507 > 1 baz:1
507 > 1 baz:1
508 > 2 baz:2
508 > 2 baz:2
509 > 3 baz:3
509 > 3 baz:3
510 > 4
510 > 4
511 > 5
511 > 5
512 > EOF
512 > EOF
513 $ hg commit -m "baz:3"
513 $ hg commit -m "baz:3"
514
514
515 $ cat > baz <<EOF
515 $ cat > baz <<EOF
516 > 1 baz:1
516 > 1 baz:1
517 > 2 baz:2
517 > 2 baz:2
518 > 3 baz:3
518 > 3 baz:3
519 > 4 baz:4
519 > 4 baz:4
520 > 5
520 > 5
521 > EOF
521 > EOF
522 $ hg debugsetparents 19 18
522 $ hg debugsetparents 19 18
523 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:4"
523 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:4"
524 $ hg debugindexdot baz
524 $ hg debugindexdot baz
525 digraph G {
525 digraph G {
526 -1 -> 0
526 -1 -> 0
527 0 -> 1
527 0 -> 1
528 1 -> 2
528 1 -> 2
529 1 -> 2
529 1 -> 2
530 2 -> 3
530 2 -> 3
531 3 -> 4
531 3 -> 4
532 2 -> 4
532 2 -> 4
533 }
533 }
534 $ hg annotate baz
534 $ hg annotate baz
535 17: 1 baz:1
535 17: 1 baz:1
536 18: 2 baz:2
536 18: 2 baz:2
537 19: 3 baz:3
537 19: 3 baz:3
538 20: 4 baz:4
538 20: 4 baz:4
539 16: 5
539 16: 5
540
540
541 annotate clean file
541 annotate clean file
542
542
543 $ hg annotate -ncr "wdir()" foo
543 $ hg annotate -ncr "wdir()" foo
544 11 472b18db256d : foo
544 11 472b18db256d : foo
545
545
546 annotate modified file
546 annotate modified file
547
547
548 $ echo foofoo >> foo
548 $ echo foofoo >> foo
549 $ hg annotate -r "wdir()" foo
549 $ hg annotate -r "wdir()" foo
550 11 : foo
550 11 : foo
551 20+: foofoo
551 20+: foofoo
552
552
553 $ hg annotate -cr "wdir()" foo
553 $ hg annotate -cr "wdir()" foo
554 472b18db256d : foo
554 472b18db256d : foo
555 b6bedd5477e7+: foofoo
555 b6bedd5477e7+: foofoo
556
556
557 $ hg annotate -ncr "wdir()" foo
557 $ hg annotate -ncr "wdir()" foo
558 11 472b18db256d : foo
558 11 472b18db256d : foo
559 20 b6bedd5477e7+: foofoo
559 20 b6bedd5477e7+: foofoo
560
560
561 $ hg annotate --debug -ncr "wdir()" foo
561 $ hg annotate --debug -ncr "wdir()" foo
562 11 472b18db256d1e8282064eab4bfdaf48cbfe83cd : foo
562 11 472b18db256d1e8282064eab4bfdaf48cbfe83cd : foo
563 20 b6bedd5477e797f25e568a6402d4697f3f895a72+: foofoo
563 20 b6bedd5477e797f25e568a6402d4697f3f895a72+: foofoo
564
564
565 $ hg annotate -udr "wdir()" foo
565 $ hg annotate -udr "wdir()" foo
566 test Thu Jan 01 00:00:00 1970 +0000: foo
566 test Thu Jan 01 00:00:00 1970 +0000: foo
567 test [A-Za-z0-9:+ ]+: foofoo (re)
567 test [A-Za-z0-9:+ ]+: foofoo (re)
568
568
569 $ hg annotate -ncr "wdir()" -Tjson foo
569 $ hg annotate -ncr "wdir()" -Tjson foo
570 [
570 [
571 {
571 {
572 "lines": [{"line": "foo\n", "node": "472b18db256d1e8282064eab4bfdaf48cbfe83cd", "rev": 11}, {"line": "foofoo\n", "node": null, "rev": null}],
572 "lines": [{"line": "foo\n", "node": "472b18db256d1e8282064eab4bfdaf48cbfe83cd", "rev": 11}, {"line": "foofoo\n", "node": "ffffffffffffffffffffffffffffffffffffffff", "rev": 2147483647}],
573 "path": "foo"
573 "path": "foo"
574 }
574 }
575 ]
575 ]
576
576
577 annotate added file
577 annotate added file
578
578
579 $ echo bar > bar
579 $ echo bar > bar
580 $ hg add bar
580 $ hg add bar
581 $ hg annotate -ncr "wdir()" bar
581 $ hg annotate -ncr "wdir()" bar
582 20 b6bedd5477e7+: bar
582 20 b6bedd5477e7+: bar
583
583
584 annotate renamed file
584 annotate renamed file
585
585
586 $ hg rename foo renamefoo2
586 $ hg rename foo renamefoo2
587 $ hg annotate -ncr "wdir()" renamefoo2
587 $ hg annotate -ncr "wdir()" renamefoo2
588 11 472b18db256d : foo
588 11 472b18db256d : foo
589 20 b6bedd5477e7+: foofoo
589 20 b6bedd5477e7+: foofoo
590
590
591 annotate missing file
591 annotate missing file
592
592
593 $ rm baz
593 $ rm baz
594 $ hg annotate -ncr "wdir()" baz
594 $ hg annotate -ncr "wdir()" baz
595 abort: $TESTTMP/repo/baz: $ENOENT$ (windows !)
595 abort: $TESTTMP/repo/baz: $ENOENT$ (windows !)
596 abort: $ENOENT$: $TESTTMP/repo/baz (no-windows !)
596 abort: $ENOENT$: $TESTTMP/repo/baz (no-windows !)
597 [255]
597 [255]
598
598
599 annotate removed file
599 annotate removed file
600
600
601 $ hg rm baz
601 $ hg rm baz
602 $ hg annotate -ncr "wdir()" baz
602 $ hg annotate -ncr "wdir()" baz
603 abort: $TESTTMP/repo/baz: $ENOENT$ (windows !)
603 abort: $TESTTMP/repo/baz: $ENOENT$ (windows !)
604 abort: $ENOENT$: $TESTTMP/repo/baz (no-windows !)
604 abort: $ENOENT$: $TESTTMP/repo/baz (no-windows !)
605 [255]
605 [255]
606
606
607 Test annotate with whitespace options
607 Test annotate with whitespace options
608
608
609 $ cd ..
609 $ cd ..
610 $ hg init repo-ws
610 $ hg init repo-ws
611 $ cd repo-ws
611 $ cd repo-ws
612 $ cat > a <<EOF
612 $ cat > a <<EOF
613 > aa
613 > aa
614 >
614 >
615 > b b
615 > b b
616 > EOF
616 > EOF
617 $ hg ci -Am "adda"
617 $ hg ci -Am "adda"
618 adding a
618 adding a
619 $ sed 's/EOL$//g' > a <<EOF
619 $ sed 's/EOL$//g' > a <<EOF
620 > a a
620 > a a
621 >
621 >
622 > EOL
622 > EOL
623 > b b
623 > b b
624 > EOF
624 > EOF
625 $ hg ci -m "changea"
625 $ hg ci -m "changea"
626
626
627 Annotate with no option
627 Annotate with no option
628
628
629 $ hg annotate a
629 $ hg annotate a
630 1: a a
630 1: a a
631 0:
631 0:
632 1:
632 1:
633 1: b b
633 1: b b
634
634
635 Annotate with --ignore-space-change
635 Annotate with --ignore-space-change
636
636
637 $ hg annotate --ignore-space-change a
637 $ hg annotate --ignore-space-change a
638 1: a a
638 1: a a
639 1:
639 1:
640 0:
640 0:
641 0: b b
641 0: b b
642
642
643 Annotate with --ignore-all-space
643 Annotate with --ignore-all-space
644
644
645 $ hg annotate --ignore-all-space a
645 $ hg annotate --ignore-all-space a
646 0: a a
646 0: a a
647 0:
647 0:
648 1:
648 1:
649 0: b b
649 0: b b
650
650
651 Annotate with --ignore-blank-lines (similar to no options case)
651 Annotate with --ignore-blank-lines (similar to no options case)
652
652
653 $ hg annotate --ignore-blank-lines a
653 $ hg annotate --ignore-blank-lines a
654 1: a a
654 1: a a
655 0:
655 0:
656 1:
656 1:
657 1: b b
657 1: b b
658
658
659 $ cd ..
659 $ cd ..
660
660
661 Annotate with linkrev pointing to another branch
661 Annotate with linkrev pointing to another branch
662 ------------------------------------------------
662 ------------------------------------------------
663
663
664 create history with a filerev whose linkrev points to another branch
664 create history with a filerev whose linkrev points to another branch
665
665
666 $ hg init branchedlinkrev
666 $ hg init branchedlinkrev
667 $ cd branchedlinkrev
667 $ cd branchedlinkrev
668 $ echo A > a
668 $ echo A > a
669 $ hg commit -Am 'contentA'
669 $ hg commit -Am 'contentA'
670 adding a
670 adding a
671 $ echo B >> a
671 $ echo B >> a
672 $ hg commit -m 'contentB'
672 $ hg commit -m 'contentB'
673 $ hg up --rev 'desc(contentA)'
673 $ hg up --rev 'desc(contentA)'
674 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
674 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
675 $ echo unrelated > unrelated
675 $ echo unrelated > unrelated
676 $ hg commit -Am 'unrelated'
676 $ hg commit -Am 'unrelated'
677 adding unrelated
677 adding unrelated
678 created new head
678 created new head
679 $ hg graft -r 'desc(contentB)'
679 $ hg graft -r 'desc(contentB)'
680 grafting 1:fd27c222e3e6 "contentB"
680 grafting 1:fd27c222e3e6 "contentB"
681 $ echo C >> a
681 $ echo C >> a
682 $ hg commit -m 'contentC'
682 $ hg commit -m 'contentC'
683 $ echo W >> a
683 $ echo W >> a
684 $ hg log -G
684 $ hg log -G
685 @ changeset: 4:072f1e8df249
685 @ changeset: 4:072f1e8df249
686 | tag: tip
686 | tag: tip
687 | user: test
687 | user: test
688 | date: Thu Jan 01 00:00:00 1970 +0000
688 | date: Thu Jan 01 00:00:00 1970 +0000
689 | summary: contentC
689 | summary: contentC
690 |
690 |
691 o changeset: 3:ff38df03cc4b
691 o changeset: 3:ff38df03cc4b
692 | user: test
692 | user: test
693 | date: Thu Jan 01 00:00:00 1970 +0000
693 | date: Thu Jan 01 00:00:00 1970 +0000
694 | summary: contentB
694 | summary: contentB
695 |
695 |
696 o changeset: 2:62aaf3f6fc06
696 o changeset: 2:62aaf3f6fc06
697 | parent: 0:f0932f74827e
697 | parent: 0:f0932f74827e
698 | user: test
698 | user: test
699 | date: Thu Jan 01 00:00:00 1970 +0000
699 | date: Thu Jan 01 00:00:00 1970 +0000
700 | summary: unrelated
700 | summary: unrelated
701 |
701 |
702 | o changeset: 1:fd27c222e3e6
702 | o changeset: 1:fd27c222e3e6
703 |/ user: test
703 |/ user: test
704 | date: Thu Jan 01 00:00:00 1970 +0000
704 | date: Thu Jan 01 00:00:00 1970 +0000
705 | summary: contentB
705 | summary: contentB
706 |
706 |
707 o changeset: 0:f0932f74827e
707 o changeset: 0:f0932f74827e
708 user: test
708 user: test
709 date: Thu Jan 01 00:00:00 1970 +0000
709 date: Thu Jan 01 00:00:00 1970 +0000
710 summary: contentA
710 summary: contentA
711
711
712
712
713 Annotate should list ancestor of starting revision only
713 Annotate should list ancestor of starting revision only
714
714
715 $ hg annotate a
715 $ hg annotate a
716 0: A
716 0: A
717 3: B
717 3: B
718 4: C
718 4: C
719
719
720 $ hg annotate a -r 'wdir()'
720 $ hg annotate a -r 'wdir()'
721 0 : A
721 0 : A
722 3 : B
722 3 : B
723 4 : C
723 4 : C
724 4+: W
724 4+: W
725
725
726 Even when the starting revision is the linkrev-shadowed one:
726 Even when the starting revision is the linkrev-shadowed one:
727
727
728 $ hg annotate a -r 3
728 $ hg annotate a -r 3
729 0: A
729 0: A
730 3: B
730 3: B
731
731
732 $ cd ..
732 $ cd ..
733
733
734 Issue5360: Deleted chunk in p1 of a merge changeset
734 Issue5360: Deleted chunk in p1 of a merge changeset
735
735
736 $ hg init repo-5360
736 $ hg init repo-5360
737 $ cd repo-5360
737 $ cd repo-5360
738 $ echo 1 > a
738 $ echo 1 > a
739 $ hg commit -A a -m 1
739 $ hg commit -A a -m 1
740 $ echo 2 >> a
740 $ echo 2 >> a
741 $ hg commit -m 2
741 $ hg commit -m 2
742 $ echo a > a
742 $ echo a > a
743 $ hg commit -m a
743 $ hg commit -m a
744 $ hg update '.^' -q
744 $ hg update '.^' -q
745 $ echo 3 >> a
745 $ echo 3 >> a
746 $ hg commit -m 3 -q
746 $ hg commit -m 3 -q
747 $ hg merge 2 -q
747 $ hg merge 2 -q
748 $ cat > a << EOF
748 $ cat > a << EOF
749 > b
749 > b
750 > 1
750 > 1
751 > 2
751 > 2
752 > 3
752 > 3
753 > a
753 > a
754 > EOF
754 > EOF
755 $ hg resolve --mark -q
755 $ hg resolve --mark -q
756 $ hg commit -m m
756 $ hg commit -m m
757 $ hg annotate a
757 $ hg annotate a
758 4: b
758 4: b
759 0: 1
759 0: 1
760 1: 2
760 1: 2
761 3: 3
761 3: 3
762 2: a
762 2: a
763
763
764 $ cd ..
764 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now