##// END OF EJS Templates
templater: add parsing and expansion rules to process "templatealias" section...
Yuya Nishihara -
r28912:867d6ba2 default
parent child Browse files
Show More
@@ -1,7244 +1,7248
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 operator
12 import operator
13 import os
13 import os
14 import random
14 import random
15 import re
15 import re
16 import shlex
16 import shlex
17 import socket
17 import socket
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 import time
20 import time
21
21
22 from .i18n import _
22 from .i18n import _
23 from .node import (
23 from .node import (
24 bin,
24 bin,
25 hex,
25 hex,
26 nullhex,
26 nullhex,
27 nullid,
27 nullid,
28 nullrev,
28 nullrev,
29 short,
29 short,
30 )
30 )
31 from . import (
31 from . import (
32 archival,
32 archival,
33 bookmarks,
33 bookmarks,
34 bundle2,
34 bundle2,
35 changegroup,
35 changegroup,
36 cmdutil,
36 cmdutil,
37 commandserver,
37 commandserver,
38 context,
38 context,
39 copies,
39 copies,
40 dagparser,
40 dagparser,
41 dagutil,
41 dagutil,
42 destutil,
42 destutil,
43 discovery,
43 discovery,
44 encoding,
44 encoding,
45 error,
45 error,
46 exchange,
46 exchange,
47 extensions,
47 extensions,
48 fileset,
48 fileset,
49 graphmod,
49 graphmod,
50 hbisect,
50 hbisect,
51 help,
51 help,
52 hg,
52 hg,
53 hgweb,
53 hgweb,
54 localrepo,
54 localrepo,
55 lock as lockmod,
55 lock as lockmod,
56 merge as mergemod,
56 merge as mergemod,
57 minirst,
57 minirst,
58 obsolete,
58 obsolete,
59 patch,
59 patch,
60 phases,
60 phases,
61 pvec,
61 pvec,
62 repair,
62 repair,
63 revlog,
63 revlog,
64 revset,
64 revset,
65 scmutil,
65 scmutil,
66 setdiscovery,
66 setdiscovery,
67 simplemerge,
67 simplemerge,
68 sshserver,
68 sshserver,
69 streamclone,
69 streamclone,
70 templatekw,
70 templatekw,
71 templater,
71 templater,
72 treediscovery,
72 treediscovery,
73 ui as uimod,
73 ui as uimod,
74 util,
74 util,
75 )
75 )
76
76
77 release = lockmod.release
77 release = lockmod.release
78
78
79 table = {}
79 table = {}
80
80
81 command = cmdutil.command(table)
81 command = cmdutil.command(table)
82
82
83 # label constants
83 # label constants
84 # until 3.5, bookmarks.current was the advertised name, not
84 # until 3.5, bookmarks.current was the advertised name, not
85 # bookmarks.active, so we must use both to avoid breaking old
85 # bookmarks.active, so we must use both to avoid breaking old
86 # custom styles
86 # custom styles
87 activebookmarklabel = 'bookmarks.active bookmarks.current'
87 activebookmarklabel = 'bookmarks.active bookmarks.current'
88
88
89 # common command options
89 # common command options
90
90
91 globalopts = [
91 globalopts = [
92 ('R', 'repository', '',
92 ('R', 'repository', '',
93 _('repository root directory or name of overlay bundle file'),
93 _('repository root directory or name of overlay bundle file'),
94 _('REPO')),
94 _('REPO')),
95 ('', 'cwd', '',
95 ('', 'cwd', '',
96 _('change working directory'), _('DIR')),
96 _('change working directory'), _('DIR')),
97 ('y', 'noninteractive', None,
97 ('y', 'noninteractive', None,
98 _('do not prompt, automatically pick the first choice for all prompts')),
98 _('do not prompt, automatically pick the first choice for all prompts')),
99 ('q', 'quiet', None, _('suppress output')),
99 ('q', 'quiet', None, _('suppress output')),
100 ('v', 'verbose', None, _('enable additional output')),
100 ('v', 'verbose', None, _('enable additional output')),
101 ('', 'config', [],
101 ('', 'config', [],
102 _('set/override config option (use \'section.name=value\')'),
102 _('set/override config option (use \'section.name=value\')'),
103 _('CONFIG')),
103 _('CONFIG')),
104 ('', 'debug', None, _('enable debugging output')),
104 ('', 'debug', None, _('enable debugging output')),
105 ('', 'debugger', None, _('start debugger')),
105 ('', 'debugger', None, _('start debugger')),
106 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
106 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
107 _('ENCODE')),
107 _('ENCODE')),
108 ('', 'encodingmode', encoding.encodingmode,
108 ('', 'encodingmode', encoding.encodingmode,
109 _('set the charset encoding mode'), _('MODE')),
109 _('set the charset encoding mode'), _('MODE')),
110 ('', 'traceback', None, _('always print a traceback on exception')),
110 ('', 'traceback', None, _('always print a traceback on exception')),
111 ('', 'time', None, _('time how long the command takes')),
111 ('', 'time', None, _('time how long the command takes')),
112 ('', 'profile', None, _('print command execution profile')),
112 ('', 'profile', None, _('print command execution profile')),
113 ('', 'version', None, _('output version information and exit')),
113 ('', 'version', None, _('output version information and exit')),
114 ('h', 'help', None, _('display help and exit')),
114 ('h', 'help', None, _('display help and exit')),
115 ('', 'hidden', False, _('consider hidden changesets')),
115 ('', 'hidden', False, _('consider hidden changesets')),
116 ]
116 ]
117
117
118 dryrunopts = [('n', 'dry-run', None,
118 dryrunopts = [('n', 'dry-run', None,
119 _('do not perform actions, just print output'))]
119 _('do not perform actions, just print output'))]
120
120
121 remoteopts = [
121 remoteopts = [
122 ('e', 'ssh', '',
122 ('e', 'ssh', '',
123 _('specify ssh command to use'), _('CMD')),
123 _('specify ssh command to use'), _('CMD')),
124 ('', 'remotecmd', '',
124 ('', 'remotecmd', '',
125 _('specify hg command to run on the remote side'), _('CMD')),
125 _('specify hg command to run on the remote side'), _('CMD')),
126 ('', 'insecure', None,
126 ('', 'insecure', None,
127 _('do not verify server certificate (ignoring web.cacerts config)')),
127 _('do not verify server certificate (ignoring web.cacerts config)')),
128 ]
128 ]
129
129
130 walkopts = [
130 walkopts = [
131 ('I', 'include', [],
131 ('I', 'include', [],
132 _('include names matching the given patterns'), _('PATTERN')),
132 _('include names matching the given patterns'), _('PATTERN')),
133 ('X', 'exclude', [],
133 ('X', 'exclude', [],
134 _('exclude names matching the given patterns'), _('PATTERN')),
134 _('exclude names matching the given patterns'), _('PATTERN')),
135 ]
135 ]
136
136
137 commitopts = [
137 commitopts = [
138 ('m', 'message', '',
138 ('m', 'message', '',
139 _('use text as commit message'), _('TEXT')),
139 _('use text as commit message'), _('TEXT')),
140 ('l', 'logfile', '',
140 ('l', 'logfile', '',
141 _('read commit message from file'), _('FILE')),
141 _('read commit message from file'), _('FILE')),
142 ]
142 ]
143
143
144 commitopts2 = [
144 commitopts2 = [
145 ('d', 'date', '',
145 ('d', 'date', '',
146 _('record the specified date as commit date'), _('DATE')),
146 _('record the specified date as commit date'), _('DATE')),
147 ('u', 'user', '',
147 ('u', 'user', '',
148 _('record the specified user as committer'), _('USER')),
148 _('record the specified user as committer'), _('USER')),
149 ]
149 ]
150
150
151 # hidden for now
151 # hidden for now
152 formatteropts = [
152 formatteropts = [
153 ('T', 'template', '',
153 ('T', 'template', '',
154 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
154 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
155 ]
155 ]
156
156
157 templateopts = [
157 templateopts = [
158 ('', 'style', '',
158 ('', 'style', '',
159 _('display using template map file (DEPRECATED)'), _('STYLE')),
159 _('display using template map file (DEPRECATED)'), _('STYLE')),
160 ('T', 'template', '',
160 ('T', 'template', '',
161 _('display with template'), _('TEMPLATE')),
161 _('display with template'), _('TEMPLATE')),
162 ]
162 ]
163
163
164 logopts = [
164 logopts = [
165 ('p', 'patch', None, _('show patch')),
165 ('p', 'patch', None, _('show patch')),
166 ('g', 'git', None, _('use git extended diff format')),
166 ('g', 'git', None, _('use git extended diff format')),
167 ('l', 'limit', '',
167 ('l', 'limit', '',
168 _('limit number of changes displayed'), _('NUM')),
168 _('limit number of changes displayed'), _('NUM')),
169 ('M', 'no-merges', None, _('do not show merges')),
169 ('M', 'no-merges', None, _('do not show merges')),
170 ('', 'stat', None, _('output diffstat-style summary of changes')),
170 ('', 'stat', None, _('output diffstat-style summary of changes')),
171 ('G', 'graph', None, _("show the revision DAG")),
171 ('G', 'graph', None, _("show the revision DAG")),
172 ] + templateopts
172 ] + templateopts
173
173
174 diffopts = [
174 diffopts = [
175 ('a', 'text', None, _('treat all files as text')),
175 ('a', 'text', None, _('treat all files as text')),
176 ('g', 'git', None, _('use git extended diff format')),
176 ('g', 'git', None, _('use git extended diff format')),
177 ('', 'nodates', None, _('omit dates from diff headers'))
177 ('', 'nodates', None, _('omit dates from diff headers'))
178 ]
178 ]
179
179
180 diffwsopts = [
180 diffwsopts = [
181 ('w', 'ignore-all-space', None,
181 ('w', 'ignore-all-space', None,
182 _('ignore white space when comparing lines')),
182 _('ignore white space when comparing lines')),
183 ('b', 'ignore-space-change', None,
183 ('b', 'ignore-space-change', None,
184 _('ignore changes in the amount of white space')),
184 _('ignore changes in the amount of white space')),
185 ('B', 'ignore-blank-lines', None,
185 ('B', 'ignore-blank-lines', None,
186 _('ignore changes whose lines are all blank')),
186 _('ignore changes whose lines are all blank')),
187 ]
187 ]
188
188
189 diffopts2 = [
189 diffopts2 = [
190 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
190 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
191 ('p', 'show-function', None, _('show which function each change is in')),
191 ('p', 'show-function', None, _('show which function each change is in')),
192 ('', 'reverse', None, _('produce a diff that undoes the changes')),
192 ('', 'reverse', None, _('produce a diff that undoes the changes')),
193 ] + diffwsopts + [
193 ] + diffwsopts + [
194 ('U', 'unified', '',
194 ('U', 'unified', '',
195 _('number of lines of context to show'), _('NUM')),
195 _('number of lines of context to show'), _('NUM')),
196 ('', 'stat', None, _('output diffstat-style summary of changes')),
196 ('', 'stat', None, _('output diffstat-style summary of changes')),
197 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
197 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
198 ]
198 ]
199
199
200 mergetoolopts = [
200 mergetoolopts = [
201 ('t', 'tool', '', _('specify merge tool')),
201 ('t', 'tool', '', _('specify merge tool')),
202 ]
202 ]
203
203
204 similarityopts = [
204 similarityopts = [
205 ('s', 'similarity', '',
205 ('s', 'similarity', '',
206 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
206 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
207 ]
207 ]
208
208
209 subrepoopts = [
209 subrepoopts = [
210 ('S', 'subrepos', None,
210 ('S', 'subrepos', None,
211 _('recurse into subrepositories'))
211 _('recurse into subrepositories'))
212 ]
212 ]
213
213
214 debugrevlogopts = [
214 debugrevlogopts = [
215 ('c', 'changelog', False, _('open changelog')),
215 ('c', 'changelog', False, _('open changelog')),
216 ('m', 'manifest', False, _('open manifest')),
216 ('m', 'manifest', False, _('open manifest')),
217 ('', 'dir', False, _('open directory manifest')),
217 ('', 'dir', False, _('open directory manifest')),
218 ]
218 ]
219
219
220 # Commands start here, listed alphabetically
220 # Commands start here, listed alphabetically
221
221
222 @command('^add',
222 @command('^add',
223 walkopts + subrepoopts + dryrunopts,
223 walkopts + subrepoopts + dryrunopts,
224 _('[OPTION]... [FILE]...'),
224 _('[OPTION]... [FILE]...'),
225 inferrepo=True)
225 inferrepo=True)
226 def add(ui, repo, *pats, **opts):
226 def add(ui, repo, *pats, **opts):
227 """add the specified files on the next commit
227 """add the specified files on the next commit
228
228
229 Schedule files to be version controlled and added to the
229 Schedule files to be version controlled and added to the
230 repository.
230 repository.
231
231
232 The files will be added to the repository at the next commit. To
232 The files will be added to the repository at the next commit. To
233 undo an add before that, see :hg:`forget`.
233 undo an add before that, see :hg:`forget`.
234
234
235 If no names are given, add all files to the repository (except
235 If no names are given, add all files to the repository (except
236 files matching ``.hgignore``).
236 files matching ``.hgignore``).
237
237
238 .. container:: verbose
238 .. container:: verbose
239
239
240 Examples:
240 Examples:
241
241
242 - New (unknown) files are added
242 - New (unknown) files are added
243 automatically by :hg:`add`::
243 automatically by :hg:`add`::
244
244
245 $ ls
245 $ ls
246 foo.c
246 foo.c
247 $ hg status
247 $ hg status
248 ? foo.c
248 ? foo.c
249 $ hg add
249 $ hg add
250 adding foo.c
250 adding foo.c
251 $ hg status
251 $ hg status
252 A foo.c
252 A foo.c
253
253
254 - Specific files to be added can be specified::
254 - Specific files to be added can be specified::
255
255
256 $ ls
256 $ ls
257 bar.c foo.c
257 bar.c foo.c
258 $ hg status
258 $ hg status
259 ? bar.c
259 ? bar.c
260 ? foo.c
260 ? foo.c
261 $ hg add bar.c
261 $ hg add bar.c
262 $ hg status
262 $ hg status
263 A bar.c
263 A bar.c
264 ? foo.c
264 ? foo.c
265
265
266 Returns 0 if all files are successfully added.
266 Returns 0 if all files are successfully added.
267 """
267 """
268
268
269 m = scmutil.match(repo[None], pats, opts)
269 m = scmutil.match(repo[None], pats, opts)
270 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
270 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
271 return rejected and 1 or 0
271 return rejected and 1 or 0
272
272
273 @command('addremove',
273 @command('addremove',
274 similarityopts + subrepoopts + walkopts + dryrunopts,
274 similarityopts + subrepoopts + walkopts + dryrunopts,
275 _('[OPTION]... [FILE]...'),
275 _('[OPTION]... [FILE]...'),
276 inferrepo=True)
276 inferrepo=True)
277 def addremove(ui, repo, *pats, **opts):
277 def addremove(ui, repo, *pats, **opts):
278 """add all new files, delete all missing files
278 """add all new files, delete all missing files
279
279
280 Add all new files and remove all missing files from the
280 Add all new files and remove all missing files from the
281 repository.
281 repository.
282
282
283 Unless names are given, new files are ignored if they match any of
283 Unless names are given, new files are ignored if they match any of
284 the patterns in ``.hgignore``. As with add, these changes take
284 the patterns in ``.hgignore``. As with add, these changes take
285 effect at the next commit.
285 effect at the next commit.
286
286
287 Use the -s/--similarity option to detect renamed files. This
287 Use the -s/--similarity option to detect renamed files. This
288 option takes a percentage between 0 (disabled) and 100 (files must
288 option takes a percentage between 0 (disabled) and 100 (files must
289 be identical) as its parameter. With a parameter greater than 0,
289 be identical) as its parameter. With a parameter greater than 0,
290 this compares every removed file with every added file and records
290 this compares every removed file with every added file and records
291 those similar enough as renames. Detecting renamed files this way
291 those similar enough as renames. Detecting renamed files this way
292 can be expensive. After using this option, :hg:`status -C` can be
292 can be expensive. After using this option, :hg:`status -C` can be
293 used to check which files were identified as moved or renamed. If
293 used to check which files were identified as moved or renamed. If
294 not specified, -s/--similarity defaults to 100 and only renames of
294 not specified, -s/--similarity defaults to 100 and only renames of
295 identical files are detected.
295 identical files are detected.
296
296
297 .. container:: verbose
297 .. container:: verbose
298
298
299 Examples:
299 Examples:
300
300
301 - A number of files (bar.c and foo.c) are new,
301 - A number of files (bar.c and foo.c) are new,
302 while foobar.c has been removed (without using :hg:`remove`)
302 while foobar.c has been removed (without using :hg:`remove`)
303 from the repository::
303 from the repository::
304
304
305 $ ls
305 $ ls
306 bar.c foo.c
306 bar.c foo.c
307 $ hg status
307 $ hg status
308 ! foobar.c
308 ! foobar.c
309 ? bar.c
309 ? bar.c
310 ? foo.c
310 ? foo.c
311 $ hg addremove
311 $ hg addremove
312 adding bar.c
312 adding bar.c
313 adding foo.c
313 adding foo.c
314 removing foobar.c
314 removing foobar.c
315 $ hg status
315 $ hg status
316 A bar.c
316 A bar.c
317 A foo.c
317 A foo.c
318 R foobar.c
318 R foobar.c
319
319
320 - A file foobar.c was moved to foo.c without using :hg:`rename`.
320 - A file foobar.c was moved to foo.c without using :hg:`rename`.
321 Afterwards, it was edited slightly::
321 Afterwards, it was edited slightly::
322
322
323 $ ls
323 $ ls
324 foo.c
324 foo.c
325 $ hg status
325 $ hg status
326 ! foobar.c
326 ! foobar.c
327 ? foo.c
327 ? foo.c
328 $ hg addremove --similarity 90
328 $ hg addremove --similarity 90
329 removing foobar.c
329 removing foobar.c
330 adding foo.c
330 adding foo.c
331 recording removal of foobar.c as rename to foo.c (94% similar)
331 recording removal of foobar.c as rename to foo.c (94% similar)
332 $ hg status -C
332 $ hg status -C
333 A foo.c
333 A foo.c
334 foobar.c
334 foobar.c
335 R foobar.c
335 R foobar.c
336
336
337 Returns 0 if all files are successfully added.
337 Returns 0 if all files are successfully added.
338 """
338 """
339 try:
339 try:
340 sim = float(opts.get('similarity') or 100)
340 sim = float(opts.get('similarity') or 100)
341 except ValueError:
341 except ValueError:
342 raise error.Abort(_('similarity must be a number'))
342 raise error.Abort(_('similarity must be a number'))
343 if sim < 0 or sim > 100:
343 if sim < 0 or sim > 100:
344 raise error.Abort(_('similarity must be between 0 and 100'))
344 raise error.Abort(_('similarity must be between 0 and 100'))
345 matcher = scmutil.match(repo[None], pats, opts)
345 matcher = scmutil.match(repo[None], pats, opts)
346 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
346 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
347
347
348 @command('^annotate|blame',
348 @command('^annotate|blame',
349 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
349 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
350 ('', 'follow', None,
350 ('', 'follow', None,
351 _('follow copies/renames and list the filename (DEPRECATED)')),
351 _('follow copies/renames and list the filename (DEPRECATED)')),
352 ('', 'no-follow', None, _("don't follow copies and renames")),
352 ('', 'no-follow', None, _("don't follow copies and renames")),
353 ('a', 'text', None, _('treat all files as text')),
353 ('a', 'text', None, _('treat all files as text')),
354 ('u', 'user', None, _('list the author (long with -v)')),
354 ('u', 'user', None, _('list the author (long with -v)')),
355 ('f', 'file', None, _('list the filename')),
355 ('f', 'file', None, _('list the filename')),
356 ('d', 'date', None, _('list the date (short with -q)')),
356 ('d', 'date', None, _('list the date (short with -q)')),
357 ('n', 'number', None, _('list the revision number (default)')),
357 ('n', 'number', None, _('list the revision number (default)')),
358 ('c', 'changeset', None, _('list the changeset')),
358 ('c', 'changeset', None, _('list the changeset')),
359 ('l', 'line-number', None, _('show line number at the first appearance'))
359 ('l', 'line-number', None, _('show line number at the first appearance'))
360 ] + diffwsopts + walkopts + formatteropts,
360 ] + diffwsopts + walkopts + formatteropts,
361 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
361 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
362 inferrepo=True)
362 inferrepo=True)
363 def annotate(ui, repo, *pats, **opts):
363 def annotate(ui, repo, *pats, **opts):
364 """show changeset information by line for each file
364 """show changeset information by line for each file
365
365
366 List changes in files, showing the revision id responsible for
366 List changes in files, showing the revision id responsible for
367 each line.
367 each line.
368
368
369 This command is useful for discovering when a change was made and
369 This command is useful for discovering when a change was made and
370 by whom.
370 by whom.
371
371
372 If you include --file, --user, or --date, the revision number is
372 If you include --file, --user, or --date, the revision number is
373 suppressed unless you also include --number.
373 suppressed unless you also include --number.
374
374
375 Without the -a/--text option, annotate will avoid processing files
375 Without the -a/--text option, annotate will avoid processing files
376 it detects as binary. With -a, annotate will annotate the file
376 it detects as binary. With -a, annotate will annotate the file
377 anyway, although the results will probably be neither useful
377 anyway, although the results will probably be neither useful
378 nor desirable.
378 nor desirable.
379
379
380 Returns 0 on success.
380 Returns 0 on success.
381 """
381 """
382 if not pats:
382 if not pats:
383 raise error.Abort(_('at least one filename or pattern is required'))
383 raise error.Abort(_('at least one filename or pattern is required'))
384
384
385 if opts.get('follow'):
385 if opts.get('follow'):
386 # --follow is deprecated and now just an alias for -f/--file
386 # --follow is deprecated and now just an alias for -f/--file
387 # to mimic the behavior of Mercurial before version 1.5
387 # to mimic the behavior of Mercurial before version 1.5
388 opts['file'] = True
388 opts['file'] = True
389
389
390 ctx = scmutil.revsingle(repo, opts.get('rev'))
390 ctx = scmutil.revsingle(repo, opts.get('rev'))
391
391
392 fm = ui.formatter('annotate', opts)
392 fm = ui.formatter('annotate', opts)
393 if ui.quiet:
393 if ui.quiet:
394 datefunc = util.shortdate
394 datefunc = util.shortdate
395 else:
395 else:
396 datefunc = util.datestr
396 datefunc = util.datestr
397 if ctx.rev() is None:
397 if ctx.rev() is None:
398 def hexfn(node):
398 def hexfn(node):
399 if node is None:
399 if node is None:
400 return None
400 return None
401 else:
401 else:
402 return fm.hexfunc(node)
402 return fm.hexfunc(node)
403 if opts.get('changeset'):
403 if opts.get('changeset'):
404 # omit "+" suffix which is appended to node hex
404 # omit "+" suffix which is appended to node hex
405 def formatrev(rev):
405 def formatrev(rev):
406 if rev is None:
406 if rev is None:
407 return '%d' % ctx.p1().rev()
407 return '%d' % ctx.p1().rev()
408 else:
408 else:
409 return '%d' % rev
409 return '%d' % rev
410 else:
410 else:
411 def formatrev(rev):
411 def formatrev(rev):
412 if rev is None:
412 if rev is None:
413 return '%d+' % ctx.p1().rev()
413 return '%d+' % ctx.p1().rev()
414 else:
414 else:
415 return '%d ' % rev
415 return '%d ' % rev
416 def formathex(hex):
416 def formathex(hex):
417 if hex is None:
417 if hex is None:
418 return '%s+' % fm.hexfunc(ctx.p1().node())
418 return '%s+' % fm.hexfunc(ctx.p1().node())
419 else:
419 else:
420 return '%s ' % hex
420 return '%s ' % hex
421 else:
421 else:
422 hexfn = fm.hexfunc
422 hexfn = fm.hexfunc
423 formatrev = formathex = str
423 formatrev = formathex = str
424
424
425 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
425 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
426 ('number', ' ', lambda x: x[0].rev(), formatrev),
426 ('number', ' ', lambda x: x[0].rev(), formatrev),
427 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
427 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
428 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
428 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
429 ('file', ' ', lambda x: x[0].path(), str),
429 ('file', ' ', lambda x: x[0].path(), str),
430 ('line_number', ':', lambda x: x[1], str),
430 ('line_number', ':', lambda x: x[1], str),
431 ]
431 ]
432 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
432 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
433
433
434 if (not opts.get('user') and not opts.get('changeset')
434 if (not opts.get('user') and not opts.get('changeset')
435 and not opts.get('date') and not opts.get('file')):
435 and not opts.get('date') and not opts.get('file')):
436 opts['number'] = True
436 opts['number'] = True
437
437
438 linenumber = opts.get('line_number') is not None
438 linenumber = opts.get('line_number') is not None
439 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
439 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
440 raise error.Abort(_('at least one of -n/-c is required for -l'))
440 raise error.Abort(_('at least one of -n/-c is required for -l'))
441
441
442 if fm:
442 if fm:
443 def makefunc(get, fmt):
443 def makefunc(get, fmt):
444 return get
444 return get
445 else:
445 else:
446 def makefunc(get, fmt):
446 def makefunc(get, fmt):
447 return lambda x: fmt(get(x))
447 return lambda x: fmt(get(x))
448 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
448 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
449 if opts.get(op)]
449 if opts.get(op)]
450 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
450 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
451 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
451 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
452 if opts.get(op))
452 if opts.get(op))
453
453
454 def bad(x, y):
454 def bad(x, y):
455 raise error.Abort("%s: %s" % (x, y))
455 raise error.Abort("%s: %s" % (x, y))
456
456
457 m = scmutil.match(ctx, pats, opts, badfn=bad)
457 m = scmutil.match(ctx, pats, opts, badfn=bad)
458
458
459 follow = not opts.get('no_follow')
459 follow = not opts.get('no_follow')
460 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
460 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
461 whitespace=True)
461 whitespace=True)
462 for abs in ctx.walk(m):
462 for abs in ctx.walk(m):
463 fctx = ctx[abs]
463 fctx = ctx[abs]
464 if not opts.get('text') and util.binary(fctx.data()):
464 if not opts.get('text') and util.binary(fctx.data()):
465 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
465 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
466 continue
466 continue
467
467
468 lines = fctx.annotate(follow=follow, linenumber=linenumber,
468 lines = fctx.annotate(follow=follow, linenumber=linenumber,
469 diffopts=diffopts)
469 diffopts=diffopts)
470 formats = []
470 formats = []
471 pieces = []
471 pieces = []
472
472
473 for f, sep in funcmap:
473 for f, sep in funcmap:
474 l = [f(n) for n, dummy in lines]
474 l = [f(n) for n, dummy in lines]
475 if l:
475 if l:
476 if fm:
476 if fm:
477 formats.append(['%s' for x in l])
477 formats.append(['%s' for x in l])
478 else:
478 else:
479 sizes = [encoding.colwidth(x) for x in l]
479 sizes = [encoding.colwidth(x) for x in l]
480 ml = max(sizes)
480 ml = max(sizes)
481 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
481 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
482 pieces.append(l)
482 pieces.append(l)
483
483
484 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
484 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
485 fm.startitem()
485 fm.startitem()
486 fm.write(fields, "".join(f), *p)
486 fm.write(fields, "".join(f), *p)
487 fm.write('line', ": %s", l[1])
487 fm.write('line', ": %s", l[1])
488
488
489 if lines and not lines[-1][1].endswith('\n'):
489 if lines and not lines[-1][1].endswith('\n'):
490 fm.plain('\n')
490 fm.plain('\n')
491
491
492 fm.end()
492 fm.end()
493
493
494 @command('archive',
494 @command('archive',
495 [('', 'no-decode', None, _('do not pass files through decoders')),
495 [('', 'no-decode', None, _('do not pass files through decoders')),
496 ('p', 'prefix', '', _('directory prefix for files in archive'),
496 ('p', 'prefix', '', _('directory prefix for files in archive'),
497 _('PREFIX')),
497 _('PREFIX')),
498 ('r', 'rev', '', _('revision to distribute'), _('REV')),
498 ('r', 'rev', '', _('revision to distribute'), _('REV')),
499 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
499 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
500 ] + subrepoopts + walkopts,
500 ] + subrepoopts + walkopts,
501 _('[OPTION]... DEST'))
501 _('[OPTION]... DEST'))
502 def archive(ui, repo, dest, **opts):
502 def archive(ui, repo, dest, **opts):
503 '''create an unversioned archive of a repository revision
503 '''create an unversioned archive of a repository revision
504
504
505 By default, the revision used is the parent of the working
505 By default, the revision used is the parent of the working
506 directory; use -r/--rev to specify a different revision.
506 directory; use -r/--rev to specify a different revision.
507
507
508 The archive type is automatically detected based on file
508 The archive type is automatically detected based on file
509 extension (to override, use -t/--type).
509 extension (to override, use -t/--type).
510
510
511 .. container:: verbose
511 .. container:: verbose
512
512
513 Examples:
513 Examples:
514
514
515 - create a zip file containing the 1.0 release::
515 - create a zip file containing the 1.0 release::
516
516
517 hg archive -r 1.0 project-1.0.zip
517 hg archive -r 1.0 project-1.0.zip
518
518
519 - create a tarball excluding .hg files::
519 - create a tarball excluding .hg files::
520
520
521 hg archive project.tar.gz -X ".hg*"
521 hg archive project.tar.gz -X ".hg*"
522
522
523 Valid types are:
523 Valid types are:
524
524
525 :``files``: a directory full of files (default)
525 :``files``: a directory full of files (default)
526 :``tar``: tar archive, uncompressed
526 :``tar``: tar archive, uncompressed
527 :``tbz2``: tar archive, compressed using bzip2
527 :``tbz2``: tar archive, compressed using bzip2
528 :``tgz``: tar archive, compressed using gzip
528 :``tgz``: tar archive, compressed using gzip
529 :``uzip``: zip archive, uncompressed
529 :``uzip``: zip archive, uncompressed
530 :``zip``: zip archive, compressed using deflate
530 :``zip``: zip archive, compressed using deflate
531
531
532 The exact name of the destination archive or directory is given
532 The exact name of the destination archive or directory is given
533 using a format string; see :hg:`help export` for details.
533 using a format string; see :hg:`help export` for details.
534
534
535 Each member added to an archive file has a directory prefix
535 Each member added to an archive file has a directory prefix
536 prepended. Use -p/--prefix to specify a format string for the
536 prepended. Use -p/--prefix to specify a format string for the
537 prefix. The default is the basename of the archive, with suffixes
537 prefix. The default is the basename of the archive, with suffixes
538 removed.
538 removed.
539
539
540 Returns 0 on success.
540 Returns 0 on success.
541 '''
541 '''
542
542
543 ctx = scmutil.revsingle(repo, opts.get('rev'))
543 ctx = scmutil.revsingle(repo, opts.get('rev'))
544 if not ctx:
544 if not ctx:
545 raise error.Abort(_('no working directory: please specify a revision'))
545 raise error.Abort(_('no working directory: please specify a revision'))
546 node = ctx.node()
546 node = ctx.node()
547 dest = cmdutil.makefilename(repo, dest, node)
547 dest = cmdutil.makefilename(repo, dest, node)
548 if os.path.realpath(dest) == repo.root:
548 if os.path.realpath(dest) == repo.root:
549 raise error.Abort(_('repository root cannot be destination'))
549 raise error.Abort(_('repository root cannot be destination'))
550
550
551 kind = opts.get('type') or archival.guesskind(dest) or 'files'
551 kind = opts.get('type') or archival.guesskind(dest) or 'files'
552 prefix = opts.get('prefix')
552 prefix = opts.get('prefix')
553
553
554 if dest == '-':
554 if dest == '-':
555 if kind == 'files':
555 if kind == 'files':
556 raise error.Abort(_('cannot archive plain files to stdout'))
556 raise error.Abort(_('cannot archive plain files to stdout'))
557 dest = cmdutil.makefileobj(repo, dest)
557 dest = cmdutil.makefileobj(repo, dest)
558 if not prefix:
558 if not prefix:
559 prefix = os.path.basename(repo.root) + '-%h'
559 prefix = os.path.basename(repo.root) + '-%h'
560
560
561 prefix = cmdutil.makefilename(repo, prefix, node)
561 prefix = cmdutil.makefilename(repo, prefix, node)
562 matchfn = scmutil.match(ctx, [], opts)
562 matchfn = scmutil.match(ctx, [], opts)
563 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
563 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
564 matchfn, prefix, subrepos=opts.get('subrepos'))
564 matchfn, prefix, subrepos=opts.get('subrepos'))
565
565
566 @command('backout',
566 @command('backout',
567 [('', 'merge', None, _('merge with old dirstate parent after backout')),
567 [('', 'merge', None, _('merge with old dirstate parent after backout')),
568 ('', 'commit', None,
568 ('', 'commit', None,
569 _('commit if no conflicts were encountered (DEPRECATED)')),
569 _('commit if no conflicts were encountered (DEPRECATED)')),
570 ('', 'no-commit', None, _('do not commit')),
570 ('', 'no-commit', None, _('do not commit')),
571 ('', 'parent', '',
571 ('', 'parent', '',
572 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
572 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
573 ('r', 'rev', '', _('revision to backout'), _('REV')),
573 ('r', 'rev', '', _('revision to backout'), _('REV')),
574 ('e', 'edit', False, _('invoke editor on commit messages')),
574 ('e', 'edit', False, _('invoke editor on commit messages')),
575 ] + mergetoolopts + walkopts + commitopts + commitopts2,
575 ] + mergetoolopts + walkopts + commitopts + commitopts2,
576 _('[OPTION]... [-r] REV'))
576 _('[OPTION]... [-r] REV'))
577 def backout(ui, repo, node=None, rev=None, **opts):
577 def backout(ui, repo, node=None, rev=None, **opts):
578 '''reverse effect of earlier changeset
578 '''reverse effect of earlier changeset
579
579
580 Prepare a new changeset with the effect of REV undone in the
580 Prepare a new changeset with the effect of REV undone in the
581 current working directory. If no conflicts were encountered,
581 current working directory. If no conflicts were encountered,
582 it will be committed immediately.
582 it will be committed immediately.
583
583
584 If REV is the parent of the working directory, then this new changeset
584 If REV is the parent of the working directory, then this new changeset
585 is committed automatically (unless --no-commit is specified).
585 is committed automatically (unless --no-commit is specified).
586
586
587 .. note::
587 .. note::
588
588
589 :hg:`backout` cannot be used to fix either an unwanted or
589 :hg:`backout` cannot be used to fix either an unwanted or
590 incorrect merge.
590 incorrect merge.
591
591
592 .. container:: verbose
592 .. container:: verbose
593
593
594 Examples:
594 Examples:
595
595
596 - Reverse the effect of the parent of the working directory.
596 - Reverse the effect of the parent of the working directory.
597 This backout will be committed immediately::
597 This backout will be committed immediately::
598
598
599 hg backout -r .
599 hg backout -r .
600
600
601 - Reverse the effect of previous bad revision 23::
601 - Reverse the effect of previous bad revision 23::
602
602
603 hg backout -r 23
603 hg backout -r 23
604
604
605 - Reverse the effect of previous bad revision 23 and
605 - Reverse the effect of previous bad revision 23 and
606 leave changes uncommitted::
606 leave changes uncommitted::
607
607
608 hg backout -r 23 --no-commit
608 hg backout -r 23 --no-commit
609 hg commit -m "Backout revision 23"
609 hg commit -m "Backout revision 23"
610
610
611 By default, the pending changeset will have one parent,
611 By default, the pending changeset will have one parent,
612 maintaining a linear history. With --merge, the pending
612 maintaining a linear history. With --merge, the pending
613 changeset will instead have two parents: the old parent of the
613 changeset will instead have two parents: the old parent of the
614 working directory and a new child of REV that simply undoes REV.
614 working directory and a new child of REV that simply undoes REV.
615
615
616 Before version 1.7, the behavior without --merge was equivalent
616 Before version 1.7, the behavior without --merge was equivalent
617 to specifying --merge followed by :hg:`update --clean .` to
617 to specifying --merge followed by :hg:`update --clean .` to
618 cancel the merge and leave the child of REV as a head to be
618 cancel the merge and leave the child of REV as a head to be
619 merged separately.
619 merged separately.
620
620
621 See :hg:`help dates` for a list of formats valid for -d/--date.
621 See :hg:`help dates` for a list of formats valid for -d/--date.
622
622
623 See :hg:`help revert` for a way to restore files to the state
623 See :hg:`help revert` for a way to restore files to the state
624 of another revision.
624 of another revision.
625
625
626 Returns 0 on success, 1 if nothing to backout or there are unresolved
626 Returns 0 on success, 1 if nothing to backout or there are unresolved
627 files.
627 files.
628 '''
628 '''
629 wlock = lock = None
629 wlock = lock = None
630 try:
630 try:
631 wlock = repo.wlock()
631 wlock = repo.wlock()
632 lock = repo.lock()
632 lock = repo.lock()
633 return _dobackout(ui, repo, node, rev, **opts)
633 return _dobackout(ui, repo, node, rev, **opts)
634 finally:
634 finally:
635 release(lock, wlock)
635 release(lock, wlock)
636
636
637 def _dobackout(ui, repo, node=None, rev=None, **opts):
637 def _dobackout(ui, repo, node=None, rev=None, **opts):
638 if opts.get('commit') and opts.get('no_commit'):
638 if opts.get('commit') and opts.get('no_commit'):
639 raise error.Abort(_("cannot use --commit with --no-commit"))
639 raise error.Abort(_("cannot use --commit with --no-commit"))
640 if opts.get('merge') and opts.get('no_commit'):
640 if opts.get('merge') and opts.get('no_commit'):
641 raise error.Abort(_("cannot use --merge with --no-commit"))
641 raise error.Abort(_("cannot use --merge with --no-commit"))
642
642
643 if rev and node:
643 if rev and node:
644 raise error.Abort(_("please specify just one revision"))
644 raise error.Abort(_("please specify just one revision"))
645
645
646 if not rev:
646 if not rev:
647 rev = node
647 rev = node
648
648
649 if not rev:
649 if not rev:
650 raise error.Abort(_("please specify a revision to backout"))
650 raise error.Abort(_("please specify a revision to backout"))
651
651
652 date = opts.get('date')
652 date = opts.get('date')
653 if date:
653 if date:
654 opts['date'] = util.parsedate(date)
654 opts['date'] = util.parsedate(date)
655
655
656 cmdutil.checkunfinished(repo)
656 cmdutil.checkunfinished(repo)
657 cmdutil.bailifchanged(repo)
657 cmdutil.bailifchanged(repo)
658 node = scmutil.revsingle(repo, rev).node()
658 node = scmutil.revsingle(repo, rev).node()
659
659
660 op1, op2 = repo.dirstate.parents()
660 op1, op2 = repo.dirstate.parents()
661 if not repo.changelog.isancestor(node, op1):
661 if not repo.changelog.isancestor(node, op1):
662 raise error.Abort(_('cannot backout change that is not an ancestor'))
662 raise error.Abort(_('cannot backout change that is not an ancestor'))
663
663
664 p1, p2 = repo.changelog.parents(node)
664 p1, p2 = repo.changelog.parents(node)
665 if p1 == nullid:
665 if p1 == nullid:
666 raise error.Abort(_('cannot backout a change with no parents'))
666 raise error.Abort(_('cannot backout a change with no parents'))
667 if p2 != nullid:
667 if p2 != nullid:
668 if not opts.get('parent'):
668 if not opts.get('parent'):
669 raise error.Abort(_('cannot backout a merge changeset'))
669 raise error.Abort(_('cannot backout a merge changeset'))
670 p = repo.lookup(opts['parent'])
670 p = repo.lookup(opts['parent'])
671 if p not in (p1, p2):
671 if p not in (p1, p2):
672 raise error.Abort(_('%s is not a parent of %s') %
672 raise error.Abort(_('%s is not a parent of %s') %
673 (short(p), short(node)))
673 (short(p), short(node)))
674 parent = p
674 parent = p
675 else:
675 else:
676 if opts.get('parent'):
676 if opts.get('parent'):
677 raise error.Abort(_('cannot use --parent on non-merge changeset'))
677 raise error.Abort(_('cannot use --parent on non-merge changeset'))
678 parent = p1
678 parent = p1
679
679
680 # the backout should appear on the same branch
680 # the backout should appear on the same branch
681 branch = repo.dirstate.branch()
681 branch = repo.dirstate.branch()
682 bheads = repo.branchheads(branch)
682 bheads = repo.branchheads(branch)
683 rctx = scmutil.revsingle(repo, hex(parent))
683 rctx = scmutil.revsingle(repo, hex(parent))
684 if not opts.get('merge') and op1 != node:
684 if not opts.get('merge') and op1 != node:
685 dsguard = cmdutil.dirstateguard(repo, 'backout')
685 dsguard = cmdutil.dirstateguard(repo, 'backout')
686 try:
686 try:
687 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
687 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
688 'backout')
688 'backout')
689 stats = mergemod.update(repo, parent, True, True, node, False)
689 stats = mergemod.update(repo, parent, True, True, node, False)
690 repo.setparents(op1, op2)
690 repo.setparents(op1, op2)
691 dsguard.close()
691 dsguard.close()
692 hg._showstats(repo, stats)
692 hg._showstats(repo, stats)
693 if stats[3]:
693 if stats[3]:
694 repo.ui.status(_("use 'hg resolve' to retry unresolved "
694 repo.ui.status(_("use 'hg resolve' to retry unresolved "
695 "file merges\n"))
695 "file merges\n"))
696 return 1
696 return 1
697 finally:
697 finally:
698 ui.setconfig('ui', 'forcemerge', '', '')
698 ui.setconfig('ui', 'forcemerge', '', '')
699 lockmod.release(dsguard)
699 lockmod.release(dsguard)
700 else:
700 else:
701 hg.clean(repo, node, show_stats=False)
701 hg.clean(repo, node, show_stats=False)
702 repo.dirstate.setbranch(branch)
702 repo.dirstate.setbranch(branch)
703 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
703 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
704
704
705 if opts.get('no_commit'):
705 if opts.get('no_commit'):
706 msg = _("changeset %s backed out, "
706 msg = _("changeset %s backed out, "
707 "don't forget to commit.\n")
707 "don't forget to commit.\n")
708 ui.status(msg % short(node))
708 ui.status(msg % short(node))
709 return 0
709 return 0
710
710
711 def commitfunc(ui, repo, message, match, opts):
711 def commitfunc(ui, repo, message, match, opts):
712 editform = 'backout'
712 editform = 'backout'
713 e = cmdutil.getcommiteditor(editform=editform, **opts)
713 e = cmdutil.getcommiteditor(editform=editform, **opts)
714 if not message:
714 if not message:
715 # we don't translate commit messages
715 # we don't translate commit messages
716 message = "Backed out changeset %s" % short(node)
716 message = "Backed out changeset %s" % short(node)
717 e = cmdutil.getcommiteditor(edit=True, editform=editform)
717 e = cmdutil.getcommiteditor(edit=True, editform=editform)
718 return repo.commit(message, opts.get('user'), opts.get('date'),
718 return repo.commit(message, opts.get('user'), opts.get('date'),
719 match, editor=e)
719 match, editor=e)
720 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
720 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
721 if not newnode:
721 if not newnode:
722 ui.status(_("nothing changed\n"))
722 ui.status(_("nothing changed\n"))
723 return 1
723 return 1
724 cmdutil.commitstatus(repo, newnode, branch, bheads)
724 cmdutil.commitstatus(repo, newnode, branch, bheads)
725
725
726 def nice(node):
726 def nice(node):
727 return '%d:%s' % (repo.changelog.rev(node), short(node))
727 return '%d:%s' % (repo.changelog.rev(node), short(node))
728 ui.status(_('changeset %s backs out changeset %s\n') %
728 ui.status(_('changeset %s backs out changeset %s\n') %
729 (nice(repo.changelog.tip()), nice(node)))
729 (nice(repo.changelog.tip()), nice(node)))
730 if opts.get('merge') and op1 != node:
730 if opts.get('merge') and op1 != node:
731 hg.clean(repo, op1, show_stats=False)
731 hg.clean(repo, op1, show_stats=False)
732 ui.status(_('merging with changeset %s\n')
732 ui.status(_('merging with changeset %s\n')
733 % nice(repo.changelog.tip()))
733 % nice(repo.changelog.tip()))
734 try:
734 try:
735 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
735 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
736 'backout')
736 'backout')
737 return hg.merge(repo, hex(repo.changelog.tip()))
737 return hg.merge(repo, hex(repo.changelog.tip()))
738 finally:
738 finally:
739 ui.setconfig('ui', 'forcemerge', '', '')
739 ui.setconfig('ui', 'forcemerge', '', '')
740 return 0
740 return 0
741
741
742 @command('bisect',
742 @command('bisect',
743 [('r', 'reset', False, _('reset bisect state')),
743 [('r', 'reset', False, _('reset bisect state')),
744 ('g', 'good', False, _('mark changeset good')),
744 ('g', 'good', False, _('mark changeset good')),
745 ('b', 'bad', False, _('mark changeset bad')),
745 ('b', 'bad', False, _('mark changeset bad')),
746 ('s', 'skip', False, _('skip testing changeset')),
746 ('s', 'skip', False, _('skip testing changeset')),
747 ('e', 'extend', False, _('extend the bisect range')),
747 ('e', 'extend', False, _('extend the bisect range')),
748 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
748 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
749 ('U', 'noupdate', False, _('do not update to target'))],
749 ('U', 'noupdate', False, _('do not update to target'))],
750 _("[-gbsr] [-U] [-c CMD] [REV]"))
750 _("[-gbsr] [-U] [-c CMD] [REV]"))
751 def bisect(ui, repo, rev=None, extra=None, command=None,
751 def bisect(ui, repo, rev=None, extra=None, command=None,
752 reset=None, good=None, bad=None, skip=None, extend=None,
752 reset=None, good=None, bad=None, skip=None, extend=None,
753 noupdate=None):
753 noupdate=None):
754 """subdivision search of changesets
754 """subdivision search of changesets
755
755
756 This command helps to find changesets which introduce problems. To
756 This command helps to find changesets which introduce problems. To
757 use, mark the earliest changeset you know exhibits the problem as
757 use, mark the earliest changeset you know exhibits the problem as
758 bad, then mark the latest changeset which is free from the problem
758 bad, then mark the latest changeset which is free from the problem
759 as good. Bisect will update your working directory to a revision
759 as good. Bisect will update your working directory to a revision
760 for testing (unless the -U/--noupdate option is specified). Once
760 for testing (unless the -U/--noupdate option is specified). Once
761 you have performed tests, mark the working directory as good or
761 you have performed tests, mark the working directory as good or
762 bad, and bisect will either update to another candidate changeset
762 bad, and bisect will either update to another candidate changeset
763 or announce that it has found the bad revision.
763 or announce that it has found the bad revision.
764
764
765 As a shortcut, you can also use the revision argument to mark a
765 As a shortcut, you can also use the revision argument to mark a
766 revision as good or bad without checking it out first.
766 revision as good or bad without checking it out first.
767
767
768 If you supply a command, it will be used for automatic bisection.
768 If you supply a command, it will be used for automatic bisection.
769 The environment variable HG_NODE will contain the ID of the
769 The environment variable HG_NODE will contain the ID of the
770 changeset being tested. The exit status of the command will be
770 changeset being tested. The exit status of the command will be
771 used to mark revisions as good or bad: status 0 means good, 125
771 used to mark revisions as good or bad: status 0 means good, 125
772 means to skip the revision, 127 (command not found) will abort the
772 means to skip the revision, 127 (command not found) will abort the
773 bisection, and any other non-zero exit status means the revision
773 bisection, and any other non-zero exit status means the revision
774 is bad.
774 is bad.
775
775
776 .. container:: verbose
776 .. container:: verbose
777
777
778 Some examples:
778 Some examples:
779
779
780 - start a bisection with known bad revision 34, and good revision 12::
780 - start a bisection with known bad revision 34, and good revision 12::
781
781
782 hg bisect --bad 34
782 hg bisect --bad 34
783 hg bisect --good 12
783 hg bisect --good 12
784
784
785 - advance the current bisection by marking current revision as good or
785 - advance the current bisection by marking current revision as good or
786 bad::
786 bad::
787
787
788 hg bisect --good
788 hg bisect --good
789 hg bisect --bad
789 hg bisect --bad
790
790
791 - mark the current revision, or a known revision, to be skipped (e.g. if
791 - mark the current revision, or a known revision, to be skipped (e.g. if
792 that revision is not usable because of another issue)::
792 that revision is not usable because of another issue)::
793
793
794 hg bisect --skip
794 hg bisect --skip
795 hg bisect --skip 23
795 hg bisect --skip 23
796
796
797 - skip all revisions that do not touch directories ``foo`` or ``bar``::
797 - skip all revisions that do not touch directories ``foo`` or ``bar``::
798
798
799 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
799 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
800
800
801 - forget the current bisection::
801 - forget the current bisection::
802
802
803 hg bisect --reset
803 hg bisect --reset
804
804
805 - use 'make && make tests' to automatically find the first broken
805 - use 'make && make tests' to automatically find the first broken
806 revision::
806 revision::
807
807
808 hg bisect --reset
808 hg bisect --reset
809 hg bisect --bad 34
809 hg bisect --bad 34
810 hg bisect --good 12
810 hg bisect --good 12
811 hg bisect --command "make && make tests"
811 hg bisect --command "make && make tests"
812
812
813 - see all changesets whose states are already known in the current
813 - see all changesets whose states are already known in the current
814 bisection::
814 bisection::
815
815
816 hg log -r "bisect(pruned)"
816 hg log -r "bisect(pruned)"
817
817
818 - see the changeset currently being bisected (especially useful
818 - see the changeset currently being bisected (especially useful
819 if running with -U/--noupdate)::
819 if running with -U/--noupdate)::
820
820
821 hg log -r "bisect(current)"
821 hg log -r "bisect(current)"
822
822
823 - see all changesets that took part in the current bisection::
823 - see all changesets that took part in the current bisection::
824
824
825 hg log -r "bisect(range)"
825 hg log -r "bisect(range)"
826
826
827 - you can even get a nice graph::
827 - you can even get a nice graph::
828
828
829 hg log --graph -r "bisect(range)"
829 hg log --graph -r "bisect(range)"
830
830
831 See :hg:`help revsets` for more about the `bisect()` keyword.
831 See :hg:`help revsets` for more about the `bisect()` keyword.
832
832
833 Returns 0 on success.
833 Returns 0 on success.
834 """
834 """
835 def extendbisectrange(nodes, good):
835 def extendbisectrange(nodes, good):
836 # bisect is incomplete when it ends on a merge node and
836 # bisect is incomplete when it ends on a merge node and
837 # one of the parent was not checked.
837 # one of the parent was not checked.
838 parents = repo[nodes[0]].parents()
838 parents = repo[nodes[0]].parents()
839 if len(parents) > 1:
839 if len(parents) > 1:
840 if good:
840 if good:
841 side = state['bad']
841 side = state['bad']
842 else:
842 else:
843 side = state['good']
843 side = state['good']
844 num = len(set(i.node() for i in parents) & set(side))
844 num = len(set(i.node() for i in parents) & set(side))
845 if num == 1:
845 if num == 1:
846 return parents[0].ancestor(parents[1])
846 return parents[0].ancestor(parents[1])
847 return None
847 return None
848
848
849 def print_result(nodes, good):
849 def print_result(nodes, good):
850 displayer = cmdutil.show_changeset(ui, repo, {})
850 displayer = cmdutil.show_changeset(ui, repo, {})
851 if len(nodes) == 1:
851 if len(nodes) == 1:
852 # narrowed it down to a single revision
852 # narrowed it down to a single revision
853 if good:
853 if good:
854 ui.write(_("The first good revision is:\n"))
854 ui.write(_("The first good revision is:\n"))
855 else:
855 else:
856 ui.write(_("The first bad revision is:\n"))
856 ui.write(_("The first bad revision is:\n"))
857 displayer.show(repo[nodes[0]])
857 displayer.show(repo[nodes[0]])
858 extendnode = extendbisectrange(nodes, good)
858 extendnode = extendbisectrange(nodes, good)
859 if extendnode is not None:
859 if extendnode is not None:
860 ui.write(_('Not all ancestors of this changeset have been'
860 ui.write(_('Not all ancestors of this changeset have been'
861 ' checked.\nUse bisect --extend to continue the '
861 ' checked.\nUse bisect --extend to continue the '
862 'bisection from\nthe common ancestor, %s.\n')
862 'bisection from\nthe common ancestor, %s.\n')
863 % extendnode)
863 % extendnode)
864 else:
864 else:
865 # multiple possible revisions
865 # multiple possible revisions
866 if good:
866 if good:
867 ui.write(_("Due to skipped revisions, the first "
867 ui.write(_("Due to skipped revisions, the first "
868 "good revision could be any of:\n"))
868 "good revision could be any of:\n"))
869 else:
869 else:
870 ui.write(_("Due to skipped revisions, the first "
870 ui.write(_("Due to skipped revisions, the first "
871 "bad revision could be any of:\n"))
871 "bad revision could be any of:\n"))
872 for n in nodes:
872 for n in nodes:
873 displayer.show(repo[n])
873 displayer.show(repo[n])
874 displayer.close()
874 displayer.close()
875
875
876 def check_state(state, interactive=True):
876 def check_state(state, interactive=True):
877 if not state['good'] or not state['bad']:
877 if not state['good'] or not state['bad']:
878 if (good or bad or skip or reset) and interactive:
878 if (good or bad or skip or reset) and interactive:
879 return
879 return
880 if not state['good']:
880 if not state['good']:
881 raise error.Abort(_('cannot bisect (no known good revisions)'))
881 raise error.Abort(_('cannot bisect (no known good revisions)'))
882 else:
882 else:
883 raise error.Abort(_('cannot bisect (no known bad revisions)'))
883 raise error.Abort(_('cannot bisect (no known bad revisions)'))
884 return True
884 return True
885
885
886 # backward compatibility
886 # backward compatibility
887 if rev in "good bad reset init".split():
887 if rev in "good bad reset init".split():
888 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
888 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
889 cmd, rev, extra = rev, extra, None
889 cmd, rev, extra = rev, extra, None
890 if cmd == "good":
890 if cmd == "good":
891 good = True
891 good = True
892 elif cmd == "bad":
892 elif cmd == "bad":
893 bad = True
893 bad = True
894 else:
894 else:
895 reset = True
895 reset = True
896 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
896 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
897 raise error.Abort(_('incompatible arguments'))
897 raise error.Abort(_('incompatible arguments'))
898
898
899 cmdutil.checkunfinished(repo)
899 cmdutil.checkunfinished(repo)
900
900
901 if reset:
901 if reset:
902 p = repo.join("bisect.state")
902 p = repo.join("bisect.state")
903 if os.path.exists(p):
903 if os.path.exists(p):
904 os.unlink(p)
904 os.unlink(p)
905 return
905 return
906
906
907 state = hbisect.load_state(repo)
907 state = hbisect.load_state(repo)
908
908
909 if command:
909 if command:
910 changesets = 1
910 changesets = 1
911 if noupdate:
911 if noupdate:
912 try:
912 try:
913 node = state['current'][0]
913 node = state['current'][0]
914 except LookupError:
914 except LookupError:
915 raise error.Abort(_('current bisect revision is unknown - '
915 raise error.Abort(_('current bisect revision is unknown - '
916 'start a new bisect to fix'))
916 'start a new bisect to fix'))
917 else:
917 else:
918 node, p2 = repo.dirstate.parents()
918 node, p2 = repo.dirstate.parents()
919 if p2 != nullid:
919 if p2 != nullid:
920 raise error.Abort(_('current bisect revision is a merge'))
920 raise error.Abort(_('current bisect revision is a merge'))
921 try:
921 try:
922 while changesets:
922 while changesets:
923 # update state
923 # update state
924 state['current'] = [node]
924 state['current'] = [node]
925 hbisect.save_state(repo, state)
925 hbisect.save_state(repo, state)
926 status = ui.system(command, environ={'HG_NODE': hex(node)})
926 status = ui.system(command, environ={'HG_NODE': hex(node)})
927 if status == 125:
927 if status == 125:
928 transition = "skip"
928 transition = "skip"
929 elif status == 0:
929 elif status == 0:
930 transition = "good"
930 transition = "good"
931 # status < 0 means process was killed
931 # status < 0 means process was killed
932 elif status == 127:
932 elif status == 127:
933 raise error.Abort(_("failed to execute %s") % command)
933 raise error.Abort(_("failed to execute %s") % command)
934 elif status < 0:
934 elif status < 0:
935 raise error.Abort(_("%s killed") % command)
935 raise error.Abort(_("%s killed") % command)
936 else:
936 else:
937 transition = "bad"
937 transition = "bad"
938 ctx = scmutil.revsingle(repo, rev, node)
938 ctx = scmutil.revsingle(repo, rev, node)
939 rev = None # clear for future iterations
939 rev = None # clear for future iterations
940 state[transition].append(ctx.node())
940 state[transition].append(ctx.node())
941 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
941 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
942 check_state(state, interactive=False)
942 check_state(state, interactive=False)
943 # bisect
943 # bisect
944 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
944 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
945 # update to next check
945 # update to next check
946 node = nodes[0]
946 node = nodes[0]
947 if not noupdate:
947 if not noupdate:
948 cmdutil.bailifchanged(repo)
948 cmdutil.bailifchanged(repo)
949 hg.clean(repo, node, show_stats=False)
949 hg.clean(repo, node, show_stats=False)
950 finally:
950 finally:
951 state['current'] = [node]
951 state['current'] = [node]
952 hbisect.save_state(repo, state)
952 hbisect.save_state(repo, state)
953 print_result(nodes, bgood)
953 print_result(nodes, bgood)
954 return
954 return
955
955
956 # update state
956 # update state
957
957
958 if rev:
958 if rev:
959 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
959 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
960 else:
960 else:
961 nodes = [repo.lookup('.')]
961 nodes = [repo.lookup('.')]
962
962
963 if good or bad or skip:
963 if good or bad or skip:
964 if good:
964 if good:
965 state['good'] += nodes
965 state['good'] += nodes
966 elif bad:
966 elif bad:
967 state['bad'] += nodes
967 state['bad'] += nodes
968 elif skip:
968 elif skip:
969 state['skip'] += nodes
969 state['skip'] += nodes
970 hbisect.save_state(repo, state)
970 hbisect.save_state(repo, state)
971
971
972 if not check_state(state):
972 if not check_state(state):
973 return
973 return
974
974
975 # actually bisect
975 # actually bisect
976 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
976 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
977 if extend:
977 if extend:
978 if not changesets:
978 if not changesets:
979 extendnode = extendbisectrange(nodes, good)
979 extendnode = extendbisectrange(nodes, good)
980 if extendnode is not None:
980 if extendnode is not None:
981 ui.write(_("Extending search to changeset %d:%s\n")
981 ui.write(_("Extending search to changeset %d:%s\n")
982 % (extendnode.rev(), extendnode))
982 % (extendnode.rev(), extendnode))
983 state['current'] = [extendnode.node()]
983 state['current'] = [extendnode.node()]
984 hbisect.save_state(repo, state)
984 hbisect.save_state(repo, state)
985 if noupdate:
985 if noupdate:
986 return
986 return
987 cmdutil.bailifchanged(repo)
987 cmdutil.bailifchanged(repo)
988 return hg.clean(repo, extendnode.node())
988 return hg.clean(repo, extendnode.node())
989 raise error.Abort(_("nothing to extend"))
989 raise error.Abort(_("nothing to extend"))
990
990
991 if changesets == 0:
991 if changesets == 0:
992 print_result(nodes, good)
992 print_result(nodes, good)
993 else:
993 else:
994 assert len(nodes) == 1 # only a single node can be tested next
994 assert len(nodes) == 1 # only a single node can be tested next
995 node = nodes[0]
995 node = nodes[0]
996 # compute the approximate number of remaining tests
996 # compute the approximate number of remaining tests
997 tests, size = 0, 2
997 tests, size = 0, 2
998 while size <= changesets:
998 while size <= changesets:
999 tests, size = tests + 1, size * 2
999 tests, size = tests + 1, size * 2
1000 rev = repo.changelog.rev(node)
1000 rev = repo.changelog.rev(node)
1001 ui.write(_("Testing changeset %d:%s "
1001 ui.write(_("Testing changeset %d:%s "
1002 "(%d changesets remaining, ~%d tests)\n")
1002 "(%d changesets remaining, ~%d tests)\n")
1003 % (rev, short(node), changesets, tests))
1003 % (rev, short(node), changesets, tests))
1004 state['current'] = [node]
1004 state['current'] = [node]
1005 hbisect.save_state(repo, state)
1005 hbisect.save_state(repo, state)
1006 if not noupdate:
1006 if not noupdate:
1007 cmdutil.bailifchanged(repo)
1007 cmdutil.bailifchanged(repo)
1008 return hg.clean(repo, node)
1008 return hg.clean(repo, node)
1009
1009
1010 @command('bookmarks|bookmark',
1010 @command('bookmarks|bookmark',
1011 [('f', 'force', False, _('force')),
1011 [('f', 'force', False, _('force')),
1012 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1012 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1013 ('d', 'delete', False, _('delete a given bookmark')),
1013 ('d', 'delete', False, _('delete a given bookmark')),
1014 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1014 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1015 ('i', 'inactive', False, _('mark a bookmark inactive')),
1015 ('i', 'inactive', False, _('mark a bookmark inactive')),
1016 ] + formatteropts,
1016 ] + formatteropts,
1017 _('hg bookmarks [OPTIONS]... [NAME]...'))
1017 _('hg bookmarks [OPTIONS]... [NAME]...'))
1018 def bookmark(ui, repo, *names, **opts):
1018 def bookmark(ui, repo, *names, **opts):
1019 '''create a new bookmark or list existing bookmarks
1019 '''create a new bookmark or list existing bookmarks
1020
1020
1021 Bookmarks are labels on changesets to help track lines of development.
1021 Bookmarks are labels on changesets to help track lines of development.
1022 Bookmarks are unversioned and can be moved, renamed and deleted.
1022 Bookmarks are unversioned and can be moved, renamed and deleted.
1023 Deleting or moving a bookmark has no effect on the associated changesets.
1023 Deleting or moving a bookmark has no effect on the associated changesets.
1024
1024
1025 Creating or updating to a bookmark causes it to be marked as 'active'.
1025 Creating or updating to a bookmark causes it to be marked as 'active'.
1026 The active bookmark is indicated with a '*'.
1026 The active bookmark is indicated with a '*'.
1027 When a commit is made, the active bookmark will advance to the new commit.
1027 When a commit is made, the active bookmark will advance to the new commit.
1028 A plain :hg:`update` will also advance an active bookmark, if possible.
1028 A plain :hg:`update` will also advance an active bookmark, if possible.
1029 Updating away from a bookmark will cause it to be deactivated.
1029 Updating away from a bookmark will cause it to be deactivated.
1030
1030
1031 Bookmarks can be pushed and pulled between repositories (see
1031 Bookmarks can be pushed and pulled between repositories (see
1032 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1032 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1033 diverged, a new 'divergent bookmark' of the form 'name@path' will
1033 diverged, a new 'divergent bookmark' of the form 'name@path' will
1034 be created. Using :hg:`merge` will resolve the divergence.
1034 be created. Using :hg:`merge` will resolve the divergence.
1035
1035
1036 A bookmark named '@' has the special property that :hg:`clone` will
1036 A bookmark named '@' has the special property that :hg:`clone` will
1037 check it out by default if it exists.
1037 check it out by default if it exists.
1038
1038
1039 .. container:: verbose
1039 .. container:: verbose
1040
1040
1041 Examples:
1041 Examples:
1042
1042
1043 - create an active bookmark for a new line of development::
1043 - create an active bookmark for a new line of development::
1044
1044
1045 hg book new-feature
1045 hg book new-feature
1046
1046
1047 - create an inactive bookmark as a place marker::
1047 - create an inactive bookmark as a place marker::
1048
1048
1049 hg book -i reviewed
1049 hg book -i reviewed
1050
1050
1051 - create an inactive bookmark on another changeset::
1051 - create an inactive bookmark on another changeset::
1052
1052
1053 hg book -r .^ tested
1053 hg book -r .^ tested
1054
1054
1055 - rename bookmark turkey to dinner::
1055 - rename bookmark turkey to dinner::
1056
1056
1057 hg book -m turkey dinner
1057 hg book -m turkey dinner
1058
1058
1059 - move the '@' bookmark from another branch::
1059 - move the '@' bookmark from another branch::
1060
1060
1061 hg book -f @
1061 hg book -f @
1062 '''
1062 '''
1063 force = opts.get('force')
1063 force = opts.get('force')
1064 rev = opts.get('rev')
1064 rev = opts.get('rev')
1065 delete = opts.get('delete')
1065 delete = opts.get('delete')
1066 rename = opts.get('rename')
1066 rename = opts.get('rename')
1067 inactive = opts.get('inactive')
1067 inactive = opts.get('inactive')
1068
1068
1069 def checkformat(mark):
1069 def checkformat(mark):
1070 mark = mark.strip()
1070 mark = mark.strip()
1071 if not mark:
1071 if not mark:
1072 raise error.Abort(_("bookmark names cannot consist entirely of "
1072 raise error.Abort(_("bookmark names cannot consist entirely of "
1073 "whitespace"))
1073 "whitespace"))
1074 scmutil.checknewlabel(repo, mark, 'bookmark')
1074 scmutil.checknewlabel(repo, mark, 'bookmark')
1075 return mark
1075 return mark
1076
1076
1077 def checkconflict(repo, mark, cur, force=False, target=None):
1077 def checkconflict(repo, mark, cur, force=False, target=None):
1078 if mark in marks and not force:
1078 if mark in marks and not force:
1079 if target:
1079 if target:
1080 if marks[mark] == target and target == cur:
1080 if marks[mark] == target and target == cur:
1081 # re-activating a bookmark
1081 # re-activating a bookmark
1082 return
1082 return
1083 anc = repo.changelog.ancestors([repo[target].rev()])
1083 anc = repo.changelog.ancestors([repo[target].rev()])
1084 bmctx = repo[marks[mark]]
1084 bmctx = repo[marks[mark]]
1085 divs = [repo[b].node() for b in marks
1085 divs = [repo[b].node() for b in marks
1086 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1086 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1087
1087
1088 # allow resolving a single divergent bookmark even if moving
1088 # allow resolving a single divergent bookmark even if moving
1089 # the bookmark across branches when a revision is specified
1089 # the bookmark across branches when a revision is specified
1090 # that contains a divergent bookmark
1090 # that contains a divergent bookmark
1091 if bmctx.rev() not in anc and target in divs:
1091 if bmctx.rev() not in anc and target in divs:
1092 bookmarks.deletedivergent(repo, [target], mark)
1092 bookmarks.deletedivergent(repo, [target], mark)
1093 return
1093 return
1094
1094
1095 deletefrom = [b for b in divs
1095 deletefrom = [b for b in divs
1096 if repo[b].rev() in anc or b == target]
1096 if repo[b].rev() in anc or b == target]
1097 bookmarks.deletedivergent(repo, deletefrom, mark)
1097 bookmarks.deletedivergent(repo, deletefrom, mark)
1098 if bookmarks.validdest(repo, bmctx, repo[target]):
1098 if bookmarks.validdest(repo, bmctx, repo[target]):
1099 ui.status(_("moving bookmark '%s' forward from %s\n") %
1099 ui.status(_("moving bookmark '%s' forward from %s\n") %
1100 (mark, short(bmctx.node())))
1100 (mark, short(bmctx.node())))
1101 return
1101 return
1102 raise error.Abort(_("bookmark '%s' already exists "
1102 raise error.Abort(_("bookmark '%s' already exists "
1103 "(use -f to force)") % mark)
1103 "(use -f to force)") % mark)
1104 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1104 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1105 and not force):
1105 and not force):
1106 raise error.Abort(
1106 raise error.Abort(
1107 _("a bookmark cannot have the name of an existing branch"))
1107 _("a bookmark cannot have the name of an existing branch"))
1108
1108
1109 if delete and rename:
1109 if delete and rename:
1110 raise error.Abort(_("--delete and --rename are incompatible"))
1110 raise error.Abort(_("--delete and --rename are incompatible"))
1111 if delete and rev:
1111 if delete and rev:
1112 raise error.Abort(_("--rev is incompatible with --delete"))
1112 raise error.Abort(_("--rev is incompatible with --delete"))
1113 if rename and rev:
1113 if rename and rev:
1114 raise error.Abort(_("--rev is incompatible with --rename"))
1114 raise error.Abort(_("--rev is incompatible with --rename"))
1115 if not names and (delete or rev):
1115 if not names and (delete or rev):
1116 raise error.Abort(_("bookmark name required"))
1116 raise error.Abort(_("bookmark name required"))
1117
1117
1118 if delete or rename or names or inactive:
1118 if delete or rename or names or inactive:
1119 wlock = lock = tr = None
1119 wlock = lock = tr = None
1120 try:
1120 try:
1121 wlock = repo.wlock()
1121 wlock = repo.wlock()
1122 lock = repo.lock()
1122 lock = repo.lock()
1123 cur = repo.changectx('.').node()
1123 cur = repo.changectx('.').node()
1124 marks = repo._bookmarks
1124 marks = repo._bookmarks
1125 if delete:
1125 if delete:
1126 tr = repo.transaction('bookmark')
1126 tr = repo.transaction('bookmark')
1127 for mark in names:
1127 for mark in names:
1128 if mark not in marks:
1128 if mark not in marks:
1129 raise error.Abort(_("bookmark '%s' does not exist") %
1129 raise error.Abort(_("bookmark '%s' does not exist") %
1130 mark)
1130 mark)
1131 if mark == repo._activebookmark:
1131 if mark == repo._activebookmark:
1132 bookmarks.deactivate(repo)
1132 bookmarks.deactivate(repo)
1133 del marks[mark]
1133 del marks[mark]
1134
1134
1135 elif rename:
1135 elif rename:
1136 tr = repo.transaction('bookmark')
1136 tr = repo.transaction('bookmark')
1137 if not names:
1137 if not names:
1138 raise error.Abort(_("new bookmark name required"))
1138 raise error.Abort(_("new bookmark name required"))
1139 elif len(names) > 1:
1139 elif len(names) > 1:
1140 raise error.Abort(_("only one new bookmark name allowed"))
1140 raise error.Abort(_("only one new bookmark name allowed"))
1141 mark = checkformat(names[0])
1141 mark = checkformat(names[0])
1142 if rename not in marks:
1142 if rename not in marks:
1143 raise error.Abort(_("bookmark '%s' does not exist")
1143 raise error.Abort(_("bookmark '%s' does not exist")
1144 % rename)
1144 % rename)
1145 checkconflict(repo, mark, cur, force)
1145 checkconflict(repo, mark, cur, force)
1146 marks[mark] = marks[rename]
1146 marks[mark] = marks[rename]
1147 if repo._activebookmark == rename and not inactive:
1147 if repo._activebookmark == rename and not inactive:
1148 bookmarks.activate(repo, mark)
1148 bookmarks.activate(repo, mark)
1149 del marks[rename]
1149 del marks[rename]
1150 elif names:
1150 elif names:
1151 tr = repo.transaction('bookmark')
1151 tr = repo.transaction('bookmark')
1152 newact = None
1152 newact = None
1153 for mark in names:
1153 for mark in names:
1154 mark = checkformat(mark)
1154 mark = checkformat(mark)
1155 if newact is None:
1155 if newact is None:
1156 newact = mark
1156 newact = mark
1157 if inactive and mark == repo._activebookmark:
1157 if inactive and mark == repo._activebookmark:
1158 bookmarks.deactivate(repo)
1158 bookmarks.deactivate(repo)
1159 return
1159 return
1160 tgt = cur
1160 tgt = cur
1161 if rev:
1161 if rev:
1162 tgt = scmutil.revsingle(repo, rev).node()
1162 tgt = scmutil.revsingle(repo, rev).node()
1163 checkconflict(repo, mark, cur, force, tgt)
1163 checkconflict(repo, mark, cur, force, tgt)
1164 marks[mark] = tgt
1164 marks[mark] = tgt
1165 if not inactive and cur == marks[newact] and not rev:
1165 if not inactive and cur == marks[newact] and not rev:
1166 bookmarks.activate(repo, newact)
1166 bookmarks.activate(repo, newact)
1167 elif cur != tgt and newact == repo._activebookmark:
1167 elif cur != tgt and newact == repo._activebookmark:
1168 bookmarks.deactivate(repo)
1168 bookmarks.deactivate(repo)
1169 elif inactive:
1169 elif inactive:
1170 if len(marks) == 0:
1170 if len(marks) == 0:
1171 ui.status(_("no bookmarks set\n"))
1171 ui.status(_("no bookmarks set\n"))
1172 elif not repo._activebookmark:
1172 elif not repo._activebookmark:
1173 ui.status(_("no active bookmark\n"))
1173 ui.status(_("no active bookmark\n"))
1174 else:
1174 else:
1175 bookmarks.deactivate(repo)
1175 bookmarks.deactivate(repo)
1176 if tr is not None:
1176 if tr is not None:
1177 marks.recordchange(tr)
1177 marks.recordchange(tr)
1178 tr.close()
1178 tr.close()
1179 finally:
1179 finally:
1180 lockmod.release(tr, lock, wlock)
1180 lockmod.release(tr, lock, wlock)
1181 else: # show bookmarks
1181 else: # show bookmarks
1182 fm = ui.formatter('bookmarks', opts)
1182 fm = ui.formatter('bookmarks', opts)
1183 hexfn = fm.hexfunc
1183 hexfn = fm.hexfunc
1184 marks = repo._bookmarks
1184 marks = repo._bookmarks
1185 if len(marks) == 0 and not fm:
1185 if len(marks) == 0 and not fm:
1186 ui.status(_("no bookmarks set\n"))
1186 ui.status(_("no bookmarks set\n"))
1187 for bmark, n in sorted(marks.iteritems()):
1187 for bmark, n in sorted(marks.iteritems()):
1188 active = repo._activebookmark
1188 active = repo._activebookmark
1189 if bmark == active:
1189 if bmark == active:
1190 prefix, label = '*', activebookmarklabel
1190 prefix, label = '*', activebookmarklabel
1191 else:
1191 else:
1192 prefix, label = ' ', ''
1192 prefix, label = ' ', ''
1193
1193
1194 fm.startitem()
1194 fm.startitem()
1195 if not ui.quiet:
1195 if not ui.quiet:
1196 fm.plain(' %s ' % prefix, label=label)
1196 fm.plain(' %s ' % prefix, label=label)
1197 fm.write('bookmark', '%s', bmark, label=label)
1197 fm.write('bookmark', '%s', bmark, label=label)
1198 pad = " " * (25 - encoding.colwidth(bmark))
1198 pad = " " * (25 - encoding.colwidth(bmark))
1199 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1199 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1200 repo.changelog.rev(n), hexfn(n), label=label)
1200 repo.changelog.rev(n), hexfn(n), label=label)
1201 fm.data(active=(bmark == active))
1201 fm.data(active=(bmark == active))
1202 fm.plain('\n')
1202 fm.plain('\n')
1203 fm.end()
1203 fm.end()
1204
1204
1205 @command('branch',
1205 @command('branch',
1206 [('f', 'force', None,
1206 [('f', 'force', None,
1207 _('set branch name even if it shadows an existing branch')),
1207 _('set branch name even if it shadows an existing branch')),
1208 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1208 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1209 _('[-fC] [NAME]'))
1209 _('[-fC] [NAME]'))
1210 def branch(ui, repo, label=None, **opts):
1210 def branch(ui, repo, label=None, **opts):
1211 """set or show the current branch name
1211 """set or show the current branch name
1212
1212
1213 .. note::
1213 .. note::
1214
1214
1215 Branch names are permanent and global. Use :hg:`bookmark` to create a
1215 Branch names are permanent and global. Use :hg:`bookmark` to create a
1216 light-weight bookmark instead. See :hg:`help glossary` for more
1216 light-weight bookmark instead. See :hg:`help glossary` for more
1217 information about named branches and bookmarks.
1217 information about named branches and bookmarks.
1218
1218
1219 With no argument, show the current branch name. With one argument,
1219 With no argument, show the current branch name. With one argument,
1220 set the working directory branch name (the branch will not exist
1220 set the working directory branch name (the branch will not exist
1221 in the repository until the next commit). Standard practice
1221 in the repository until the next commit). Standard practice
1222 recommends that primary development take place on the 'default'
1222 recommends that primary development take place on the 'default'
1223 branch.
1223 branch.
1224
1224
1225 Unless -f/--force is specified, branch will not let you set a
1225 Unless -f/--force is specified, branch will not let you set a
1226 branch name that already exists.
1226 branch name that already exists.
1227
1227
1228 Use -C/--clean to reset the working directory branch to that of
1228 Use -C/--clean to reset the working directory branch to that of
1229 the parent of the working directory, negating a previous branch
1229 the parent of the working directory, negating a previous branch
1230 change.
1230 change.
1231
1231
1232 Use the command :hg:`update` to switch to an existing branch. Use
1232 Use the command :hg:`update` to switch to an existing branch. Use
1233 :hg:`commit --close-branch` to mark this branch head as closed.
1233 :hg:`commit --close-branch` to mark this branch head as closed.
1234 When all heads of a branch are closed, the branch will be
1234 When all heads of a branch are closed, the branch will be
1235 considered closed.
1235 considered closed.
1236
1236
1237 Returns 0 on success.
1237 Returns 0 on success.
1238 """
1238 """
1239 if label:
1239 if label:
1240 label = label.strip()
1240 label = label.strip()
1241
1241
1242 if not opts.get('clean') and not label:
1242 if not opts.get('clean') and not label:
1243 ui.write("%s\n" % repo.dirstate.branch())
1243 ui.write("%s\n" % repo.dirstate.branch())
1244 return
1244 return
1245
1245
1246 with repo.wlock():
1246 with repo.wlock():
1247 if opts.get('clean'):
1247 if opts.get('clean'):
1248 label = repo[None].p1().branch()
1248 label = repo[None].p1().branch()
1249 repo.dirstate.setbranch(label)
1249 repo.dirstate.setbranch(label)
1250 ui.status(_('reset working directory to branch %s\n') % label)
1250 ui.status(_('reset working directory to branch %s\n') % label)
1251 elif label:
1251 elif label:
1252 if not opts.get('force') and label in repo.branchmap():
1252 if not opts.get('force') and label in repo.branchmap():
1253 if label not in [p.branch() for p in repo[None].parents()]:
1253 if label not in [p.branch() for p in repo[None].parents()]:
1254 raise error.Abort(_('a branch of the same name already'
1254 raise error.Abort(_('a branch of the same name already'
1255 ' exists'),
1255 ' exists'),
1256 # i18n: "it" refers to an existing branch
1256 # i18n: "it" refers to an existing branch
1257 hint=_("use 'hg update' to switch to it"))
1257 hint=_("use 'hg update' to switch to it"))
1258 scmutil.checknewlabel(repo, label, 'branch')
1258 scmutil.checknewlabel(repo, label, 'branch')
1259 repo.dirstate.setbranch(label)
1259 repo.dirstate.setbranch(label)
1260 ui.status(_('marked working directory as branch %s\n') % label)
1260 ui.status(_('marked working directory as branch %s\n') % label)
1261
1261
1262 # find any open named branches aside from default
1262 # find any open named branches aside from default
1263 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1263 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1264 if n != "default" and not c]
1264 if n != "default" and not c]
1265 if not others:
1265 if not others:
1266 ui.status(_('(branches are permanent and global, '
1266 ui.status(_('(branches are permanent and global, '
1267 'did you want a bookmark?)\n'))
1267 'did you want a bookmark?)\n'))
1268
1268
1269 @command('branches',
1269 @command('branches',
1270 [('a', 'active', False,
1270 [('a', 'active', False,
1271 _('show only branches that have unmerged heads (DEPRECATED)')),
1271 _('show only branches that have unmerged heads (DEPRECATED)')),
1272 ('c', 'closed', False, _('show normal and closed branches')),
1272 ('c', 'closed', False, _('show normal and closed branches')),
1273 ] + formatteropts,
1273 ] + formatteropts,
1274 _('[-c]'))
1274 _('[-c]'))
1275 def branches(ui, repo, active=False, closed=False, **opts):
1275 def branches(ui, repo, active=False, closed=False, **opts):
1276 """list repository named branches
1276 """list repository named branches
1277
1277
1278 List the repository's named branches, indicating which ones are
1278 List the repository's named branches, indicating which ones are
1279 inactive. If -c/--closed is specified, also list branches which have
1279 inactive. If -c/--closed is specified, also list branches which have
1280 been marked closed (see :hg:`commit --close-branch`).
1280 been marked closed (see :hg:`commit --close-branch`).
1281
1281
1282 Use the command :hg:`update` to switch to an existing branch.
1282 Use the command :hg:`update` to switch to an existing branch.
1283
1283
1284 Returns 0.
1284 Returns 0.
1285 """
1285 """
1286
1286
1287 fm = ui.formatter('branches', opts)
1287 fm = ui.formatter('branches', opts)
1288 hexfunc = fm.hexfunc
1288 hexfunc = fm.hexfunc
1289
1289
1290 allheads = set(repo.heads())
1290 allheads = set(repo.heads())
1291 branches = []
1291 branches = []
1292 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1292 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1293 isactive = not isclosed and bool(set(heads) & allheads)
1293 isactive = not isclosed and bool(set(heads) & allheads)
1294 branches.append((tag, repo[tip], isactive, not isclosed))
1294 branches.append((tag, repo[tip], isactive, not isclosed))
1295 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1295 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1296 reverse=True)
1296 reverse=True)
1297
1297
1298 for tag, ctx, isactive, isopen in branches:
1298 for tag, ctx, isactive, isopen in branches:
1299 if active and not isactive:
1299 if active and not isactive:
1300 continue
1300 continue
1301 if isactive:
1301 if isactive:
1302 label = 'branches.active'
1302 label = 'branches.active'
1303 notice = ''
1303 notice = ''
1304 elif not isopen:
1304 elif not isopen:
1305 if not closed:
1305 if not closed:
1306 continue
1306 continue
1307 label = 'branches.closed'
1307 label = 'branches.closed'
1308 notice = _(' (closed)')
1308 notice = _(' (closed)')
1309 else:
1309 else:
1310 label = 'branches.inactive'
1310 label = 'branches.inactive'
1311 notice = _(' (inactive)')
1311 notice = _(' (inactive)')
1312 current = (tag == repo.dirstate.branch())
1312 current = (tag == repo.dirstate.branch())
1313 if current:
1313 if current:
1314 label = 'branches.current'
1314 label = 'branches.current'
1315
1315
1316 fm.startitem()
1316 fm.startitem()
1317 fm.write('branch', '%s', tag, label=label)
1317 fm.write('branch', '%s', tag, label=label)
1318 rev = ctx.rev()
1318 rev = ctx.rev()
1319 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1319 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1320 fmt = ' ' * padsize + ' %d:%s'
1320 fmt = ' ' * padsize + ' %d:%s'
1321 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1321 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1322 label='log.changeset changeset.%s' % ctx.phasestr())
1322 label='log.changeset changeset.%s' % ctx.phasestr())
1323 fm.data(active=isactive, closed=not isopen, current=current)
1323 fm.data(active=isactive, closed=not isopen, current=current)
1324 if not ui.quiet:
1324 if not ui.quiet:
1325 fm.plain(notice)
1325 fm.plain(notice)
1326 fm.plain('\n')
1326 fm.plain('\n')
1327 fm.end()
1327 fm.end()
1328
1328
1329 @command('bundle',
1329 @command('bundle',
1330 [('f', 'force', None, _('run even when the destination is unrelated')),
1330 [('f', 'force', None, _('run even when the destination is unrelated')),
1331 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1331 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1332 _('REV')),
1332 _('REV')),
1333 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1333 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1334 _('BRANCH')),
1334 _('BRANCH')),
1335 ('', 'base', [],
1335 ('', 'base', [],
1336 _('a base changeset assumed to be available at the destination'),
1336 _('a base changeset assumed to be available at the destination'),
1337 _('REV')),
1337 _('REV')),
1338 ('a', 'all', None, _('bundle all changesets in the repository')),
1338 ('a', 'all', None, _('bundle all changesets in the repository')),
1339 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1339 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1340 ] + remoteopts,
1340 ] + remoteopts,
1341 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1341 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1342 def bundle(ui, repo, fname, dest=None, **opts):
1342 def bundle(ui, repo, fname, dest=None, **opts):
1343 """create a changegroup file
1343 """create a changegroup file
1344
1344
1345 Generate a changegroup file collecting changesets to be added
1345 Generate a changegroup file collecting changesets to be added
1346 to a repository.
1346 to a repository.
1347
1347
1348 To create a bundle containing all changesets, use -a/--all
1348 To create a bundle containing all changesets, use -a/--all
1349 (or --base null). Otherwise, hg assumes the destination will have
1349 (or --base null). Otherwise, hg assumes the destination will have
1350 all the nodes you specify with --base parameters. Otherwise, hg
1350 all the nodes you specify with --base parameters. Otherwise, hg
1351 will assume the repository has all the nodes in destination, or
1351 will assume the repository has all the nodes in destination, or
1352 default-push/default if no destination is specified.
1352 default-push/default if no destination is specified.
1353
1353
1354 You can change bundle format with the -t/--type option. You can
1354 You can change bundle format with the -t/--type option. You can
1355 specify a compression, a bundle version or both using a dash
1355 specify a compression, a bundle version or both using a dash
1356 (comp-version). The available compression methods are: none, bzip2,
1356 (comp-version). The available compression methods are: none, bzip2,
1357 and gzip (by default, bundles are compressed using bzip2). The
1357 and gzip (by default, bundles are compressed using bzip2). The
1358 available formats are: v1, v2 (default to most suitable).
1358 available formats are: v1, v2 (default to most suitable).
1359
1359
1360 The bundle file can then be transferred using conventional means
1360 The bundle file can then be transferred using conventional means
1361 and applied to another repository with the unbundle or pull
1361 and applied to another repository with the unbundle or pull
1362 command. This is useful when direct push and pull are not
1362 command. This is useful when direct push and pull are not
1363 available or when exporting an entire repository is undesirable.
1363 available or when exporting an entire repository is undesirable.
1364
1364
1365 Applying bundles preserves all changeset contents including
1365 Applying bundles preserves all changeset contents including
1366 permissions, copy/rename information, and revision history.
1366 permissions, copy/rename information, and revision history.
1367
1367
1368 Returns 0 on success, 1 if no changes found.
1368 Returns 0 on success, 1 if no changes found.
1369 """
1369 """
1370 revs = None
1370 revs = None
1371 if 'rev' in opts:
1371 if 'rev' in opts:
1372 revstrings = opts['rev']
1372 revstrings = opts['rev']
1373 revs = scmutil.revrange(repo, revstrings)
1373 revs = scmutil.revrange(repo, revstrings)
1374 if revstrings and not revs:
1374 if revstrings and not revs:
1375 raise error.Abort(_('no commits to bundle'))
1375 raise error.Abort(_('no commits to bundle'))
1376
1376
1377 bundletype = opts.get('type', 'bzip2').lower()
1377 bundletype = opts.get('type', 'bzip2').lower()
1378 try:
1378 try:
1379 bcompression, cgversion, params = exchange.parsebundlespec(
1379 bcompression, cgversion, params = exchange.parsebundlespec(
1380 repo, bundletype, strict=False)
1380 repo, bundletype, strict=False)
1381 except error.UnsupportedBundleSpecification as e:
1381 except error.UnsupportedBundleSpecification as e:
1382 raise error.Abort(str(e),
1382 raise error.Abort(str(e),
1383 hint=_('see "hg help bundle" for supported '
1383 hint=_('see "hg help bundle" for supported '
1384 'values for --type'))
1384 'values for --type'))
1385
1385
1386 # Packed bundles are a pseudo bundle format for now.
1386 # Packed bundles are a pseudo bundle format for now.
1387 if cgversion == 's1':
1387 if cgversion == 's1':
1388 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1388 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1389 hint=_('use "hg debugcreatestreamclonebundle"'))
1389 hint=_('use "hg debugcreatestreamclonebundle"'))
1390
1390
1391 if opts.get('all'):
1391 if opts.get('all'):
1392 if dest:
1392 if dest:
1393 raise error.Abort(_("--all is incompatible with specifying "
1393 raise error.Abort(_("--all is incompatible with specifying "
1394 "a destination"))
1394 "a destination"))
1395 if opts.get('base'):
1395 if opts.get('base'):
1396 ui.warn(_("ignoring --base because --all was specified\n"))
1396 ui.warn(_("ignoring --base because --all was specified\n"))
1397 base = ['null']
1397 base = ['null']
1398 else:
1398 else:
1399 base = scmutil.revrange(repo, opts.get('base'))
1399 base = scmutil.revrange(repo, opts.get('base'))
1400 # TODO: get desired bundlecaps from command line.
1400 # TODO: get desired bundlecaps from command line.
1401 bundlecaps = None
1401 bundlecaps = None
1402 if cgversion not in changegroup.supportedoutgoingversions(repo):
1402 if cgversion not in changegroup.supportedoutgoingversions(repo):
1403 raise error.Abort(_("repository does not support bundle version %s") %
1403 raise error.Abort(_("repository does not support bundle version %s") %
1404 cgversion)
1404 cgversion)
1405
1405
1406 if base:
1406 if base:
1407 if dest:
1407 if dest:
1408 raise error.Abort(_("--base is incompatible with specifying "
1408 raise error.Abort(_("--base is incompatible with specifying "
1409 "a destination"))
1409 "a destination"))
1410 common = [repo.lookup(rev) for rev in base]
1410 common = [repo.lookup(rev) for rev in base]
1411 heads = revs and map(repo.lookup, revs) or revs
1411 heads = revs and map(repo.lookup, revs) or revs
1412 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1412 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1413 common=common, bundlecaps=bundlecaps,
1413 common=common, bundlecaps=bundlecaps,
1414 version=cgversion)
1414 version=cgversion)
1415 outgoing = None
1415 outgoing = None
1416 else:
1416 else:
1417 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1417 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1418 dest, branches = hg.parseurl(dest, opts.get('branch'))
1418 dest, branches = hg.parseurl(dest, opts.get('branch'))
1419 other = hg.peer(repo, opts, dest)
1419 other = hg.peer(repo, opts, dest)
1420 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1420 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1421 heads = revs and map(repo.lookup, revs) or revs
1421 heads = revs and map(repo.lookup, revs) or revs
1422 outgoing = discovery.findcommonoutgoing(repo, other,
1422 outgoing = discovery.findcommonoutgoing(repo, other,
1423 onlyheads=heads,
1423 onlyheads=heads,
1424 force=opts.get('force'),
1424 force=opts.get('force'),
1425 portable=True)
1425 portable=True)
1426 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1426 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1427 bundlecaps, version=cgversion)
1427 bundlecaps, version=cgversion)
1428 if not cg:
1428 if not cg:
1429 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1429 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1430 return 1
1430 return 1
1431
1431
1432 if cgversion == '01': #bundle1
1432 if cgversion == '01': #bundle1
1433 if bcompression is None:
1433 if bcompression is None:
1434 bcompression = 'UN'
1434 bcompression = 'UN'
1435 bversion = 'HG10' + bcompression
1435 bversion = 'HG10' + bcompression
1436 bcompression = None
1436 bcompression = None
1437 else:
1437 else:
1438 assert cgversion == '02'
1438 assert cgversion == '02'
1439 bversion = 'HG20'
1439 bversion = 'HG20'
1440
1440
1441 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1441 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1442
1442
1443 @command('cat',
1443 @command('cat',
1444 [('o', 'output', '',
1444 [('o', 'output', '',
1445 _('print output to file with formatted name'), _('FORMAT')),
1445 _('print output to file with formatted name'), _('FORMAT')),
1446 ('r', 'rev', '', _('print the given revision'), _('REV')),
1446 ('r', 'rev', '', _('print the given revision'), _('REV')),
1447 ('', 'decode', None, _('apply any matching decode filter')),
1447 ('', 'decode', None, _('apply any matching decode filter')),
1448 ] + walkopts,
1448 ] + walkopts,
1449 _('[OPTION]... FILE...'),
1449 _('[OPTION]... FILE...'),
1450 inferrepo=True)
1450 inferrepo=True)
1451 def cat(ui, repo, file1, *pats, **opts):
1451 def cat(ui, repo, file1, *pats, **opts):
1452 """output the current or given revision of files
1452 """output the current or given revision of files
1453
1453
1454 Print the specified files as they were at the given revision. If
1454 Print the specified files as they were at the given revision. If
1455 no revision is given, the parent of the working directory is used.
1455 no revision is given, the parent of the working directory is used.
1456
1456
1457 Output may be to a file, in which case the name of the file is
1457 Output may be to a file, in which case the name of the file is
1458 given using a format string. The formatting rules as follows:
1458 given using a format string. The formatting rules as follows:
1459
1459
1460 :``%%``: literal "%" character
1460 :``%%``: literal "%" character
1461 :``%s``: basename of file being printed
1461 :``%s``: basename of file being printed
1462 :``%d``: dirname of file being printed, or '.' if in repository root
1462 :``%d``: dirname of file being printed, or '.' if in repository root
1463 :``%p``: root-relative path name of file being printed
1463 :``%p``: root-relative path name of file being printed
1464 :``%H``: changeset hash (40 hexadecimal digits)
1464 :``%H``: changeset hash (40 hexadecimal digits)
1465 :``%R``: changeset revision number
1465 :``%R``: changeset revision number
1466 :``%h``: short-form changeset hash (12 hexadecimal digits)
1466 :``%h``: short-form changeset hash (12 hexadecimal digits)
1467 :``%r``: zero-padded changeset revision number
1467 :``%r``: zero-padded changeset revision number
1468 :``%b``: basename of the exporting repository
1468 :``%b``: basename of the exporting repository
1469
1469
1470 Returns 0 on success.
1470 Returns 0 on success.
1471 """
1471 """
1472 ctx = scmutil.revsingle(repo, opts.get('rev'))
1472 ctx = scmutil.revsingle(repo, opts.get('rev'))
1473 m = scmutil.match(ctx, (file1,) + pats, opts)
1473 m = scmutil.match(ctx, (file1,) + pats, opts)
1474
1474
1475 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1475 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1476
1476
1477 @command('^clone',
1477 @command('^clone',
1478 [('U', 'noupdate', None, _('the clone will include an empty working '
1478 [('U', 'noupdate', None, _('the clone will include an empty working '
1479 'directory (only a repository)')),
1479 'directory (only a repository)')),
1480 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1480 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1481 _('REV')),
1481 _('REV')),
1482 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1482 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1483 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1483 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1484 ('', 'pull', None, _('use pull protocol to copy metadata')),
1484 ('', 'pull', None, _('use pull protocol to copy metadata')),
1485 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1485 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1486 ] + remoteopts,
1486 ] + remoteopts,
1487 _('[OPTION]... SOURCE [DEST]'),
1487 _('[OPTION]... SOURCE [DEST]'),
1488 norepo=True)
1488 norepo=True)
1489 def clone(ui, source, dest=None, **opts):
1489 def clone(ui, source, dest=None, **opts):
1490 """make a copy of an existing repository
1490 """make a copy of an existing repository
1491
1491
1492 Create a copy of an existing repository in a new directory.
1492 Create a copy of an existing repository in a new directory.
1493
1493
1494 If no destination directory name is specified, it defaults to the
1494 If no destination directory name is specified, it defaults to the
1495 basename of the source.
1495 basename of the source.
1496
1496
1497 The location of the source is added to the new repository's
1497 The location of the source is added to the new repository's
1498 ``.hg/hgrc`` file, as the default to be used for future pulls.
1498 ``.hg/hgrc`` file, as the default to be used for future pulls.
1499
1499
1500 Only local paths and ``ssh://`` URLs are supported as
1500 Only local paths and ``ssh://`` URLs are supported as
1501 destinations. For ``ssh://`` destinations, no working directory or
1501 destinations. For ``ssh://`` destinations, no working directory or
1502 ``.hg/hgrc`` will be created on the remote side.
1502 ``.hg/hgrc`` will be created on the remote side.
1503
1503
1504 If the source repository has a bookmark called '@' set, that
1504 If the source repository has a bookmark called '@' set, that
1505 revision will be checked out in the new repository by default.
1505 revision will be checked out in the new repository by default.
1506
1506
1507 To check out a particular version, use -u/--update, or
1507 To check out a particular version, use -u/--update, or
1508 -U/--noupdate to create a clone with no working directory.
1508 -U/--noupdate to create a clone with no working directory.
1509
1509
1510 To pull only a subset of changesets, specify one or more revisions
1510 To pull only a subset of changesets, specify one or more revisions
1511 identifiers with -r/--rev or branches with -b/--branch. The
1511 identifiers with -r/--rev or branches with -b/--branch. The
1512 resulting clone will contain only the specified changesets and
1512 resulting clone will contain only the specified changesets and
1513 their ancestors. These options (or 'clone src#rev dest') imply
1513 their ancestors. These options (or 'clone src#rev dest') imply
1514 --pull, even for local source repositories.
1514 --pull, even for local source repositories.
1515
1515
1516 .. note::
1516 .. note::
1517
1517
1518 Specifying a tag will include the tagged changeset but not the
1518 Specifying a tag will include the tagged changeset but not the
1519 changeset containing the tag.
1519 changeset containing the tag.
1520
1520
1521 .. container:: verbose
1521 .. container:: verbose
1522
1522
1523 For efficiency, hardlinks are used for cloning whenever the
1523 For efficiency, hardlinks are used for cloning whenever the
1524 source and destination are on the same filesystem (note this
1524 source and destination are on the same filesystem (note this
1525 applies only to the repository data, not to the working
1525 applies only to the repository data, not to the working
1526 directory). Some filesystems, such as AFS, implement hardlinking
1526 directory). Some filesystems, such as AFS, implement hardlinking
1527 incorrectly, but do not report errors. In these cases, use the
1527 incorrectly, but do not report errors. In these cases, use the
1528 --pull option to avoid hardlinking.
1528 --pull option to avoid hardlinking.
1529
1529
1530 In some cases, you can clone repositories and the working
1530 In some cases, you can clone repositories and the working
1531 directory using full hardlinks with ::
1531 directory using full hardlinks with ::
1532
1532
1533 $ cp -al REPO REPOCLONE
1533 $ cp -al REPO REPOCLONE
1534
1534
1535 This is the fastest way to clone, but it is not always safe. The
1535 This is the fastest way to clone, but it is not always safe. The
1536 operation is not atomic (making sure REPO is not modified during
1536 operation is not atomic (making sure REPO is not modified during
1537 the operation is up to you) and you have to make sure your
1537 the operation is up to you) and you have to make sure your
1538 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1538 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1539 so). Also, this is not compatible with certain extensions that
1539 so). Also, this is not compatible with certain extensions that
1540 place their metadata under the .hg directory, such as mq.
1540 place their metadata under the .hg directory, such as mq.
1541
1541
1542 Mercurial will update the working directory to the first applicable
1542 Mercurial will update the working directory to the first applicable
1543 revision from this list:
1543 revision from this list:
1544
1544
1545 a) null if -U or the source repository has no changesets
1545 a) null if -U or the source repository has no changesets
1546 b) if -u . and the source repository is local, the first parent of
1546 b) if -u . and the source repository is local, the first parent of
1547 the source repository's working directory
1547 the source repository's working directory
1548 c) the changeset specified with -u (if a branch name, this means the
1548 c) the changeset specified with -u (if a branch name, this means the
1549 latest head of that branch)
1549 latest head of that branch)
1550 d) the changeset specified with -r
1550 d) the changeset specified with -r
1551 e) the tipmost head specified with -b
1551 e) the tipmost head specified with -b
1552 f) the tipmost head specified with the url#branch source syntax
1552 f) the tipmost head specified with the url#branch source syntax
1553 g) the revision marked with the '@' bookmark, if present
1553 g) the revision marked with the '@' bookmark, if present
1554 h) the tipmost head of the default branch
1554 h) the tipmost head of the default branch
1555 i) tip
1555 i) tip
1556
1556
1557 When cloning from servers that support it, Mercurial may fetch
1557 When cloning from servers that support it, Mercurial may fetch
1558 pre-generated data from a server-advertised URL. When this is done,
1558 pre-generated data from a server-advertised URL. When this is done,
1559 hooks operating on incoming changesets and changegroups may fire twice,
1559 hooks operating on incoming changesets and changegroups may fire twice,
1560 once for the bundle fetched from the URL and another for any additional
1560 once for the bundle fetched from the URL and another for any additional
1561 data not fetched from this URL. In addition, if an error occurs, the
1561 data not fetched from this URL. In addition, if an error occurs, the
1562 repository may be rolled back to a partial clone. This behavior may
1562 repository may be rolled back to a partial clone. This behavior may
1563 change in future releases. See :hg:`help -e clonebundles` for more.
1563 change in future releases. See :hg:`help -e clonebundles` for more.
1564
1564
1565 Examples:
1565 Examples:
1566
1566
1567 - clone a remote repository to a new directory named hg/::
1567 - clone a remote repository to a new directory named hg/::
1568
1568
1569 hg clone http://selenic.com/hg
1569 hg clone http://selenic.com/hg
1570
1570
1571 - create a lightweight local clone::
1571 - create a lightweight local clone::
1572
1572
1573 hg clone project/ project-feature/
1573 hg clone project/ project-feature/
1574
1574
1575 - clone from an absolute path on an ssh server (note double-slash)::
1575 - clone from an absolute path on an ssh server (note double-slash)::
1576
1576
1577 hg clone ssh://user@server//home/projects/alpha/
1577 hg clone ssh://user@server//home/projects/alpha/
1578
1578
1579 - do a high-speed clone over a LAN while checking out a
1579 - do a high-speed clone over a LAN while checking out a
1580 specified version::
1580 specified version::
1581
1581
1582 hg clone --uncompressed http://server/repo -u 1.5
1582 hg clone --uncompressed http://server/repo -u 1.5
1583
1583
1584 - create a repository without changesets after a particular revision::
1584 - create a repository without changesets after a particular revision::
1585
1585
1586 hg clone -r 04e544 experimental/ good/
1586 hg clone -r 04e544 experimental/ good/
1587
1587
1588 - clone (and track) a particular named branch::
1588 - clone (and track) a particular named branch::
1589
1589
1590 hg clone http://selenic.com/hg#stable
1590 hg clone http://selenic.com/hg#stable
1591
1591
1592 See :hg:`help urls` for details on specifying URLs.
1592 See :hg:`help urls` for details on specifying URLs.
1593
1593
1594 Returns 0 on success.
1594 Returns 0 on success.
1595 """
1595 """
1596 if opts.get('noupdate') and opts.get('updaterev'):
1596 if opts.get('noupdate') and opts.get('updaterev'):
1597 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1597 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1598
1598
1599 r = hg.clone(ui, opts, source, dest,
1599 r = hg.clone(ui, opts, source, dest,
1600 pull=opts.get('pull'),
1600 pull=opts.get('pull'),
1601 stream=opts.get('uncompressed'),
1601 stream=opts.get('uncompressed'),
1602 rev=opts.get('rev'),
1602 rev=opts.get('rev'),
1603 update=opts.get('updaterev') or not opts.get('noupdate'),
1603 update=opts.get('updaterev') or not opts.get('noupdate'),
1604 branch=opts.get('branch'),
1604 branch=opts.get('branch'),
1605 shareopts=opts.get('shareopts'))
1605 shareopts=opts.get('shareopts'))
1606
1606
1607 return r is None
1607 return r is None
1608
1608
1609 @command('^commit|ci',
1609 @command('^commit|ci',
1610 [('A', 'addremove', None,
1610 [('A', 'addremove', None,
1611 _('mark new/missing files as added/removed before committing')),
1611 _('mark new/missing files as added/removed before committing')),
1612 ('', 'close-branch', None,
1612 ('', 'close-branch', None,
1613 _('mark a branch head as closed')),
1613 _('mark a branch head as closed')),
1614 ('', 'amend', None, _('amend the parent of the working directory')),
1614 ('', 'amend', None, _('amend the parent of the working directory')),
1615 ('s', 'secret', None, _('use the secret phase for committing')),
1615 ('s', 'secret', None, _('use the secret phase for committing')),
1616 ('e', 'edit', None, _('invoke editor on commit messages')),
1616 ('e', 'edit', None, _('invoke editor on commit messages')),
1617 ('i', 'interactive', None, _('use interactive mode')),
1617 ('i', 'interactive', None, _('use interactive mode')),
1618 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1618 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1619 _('[OPTION]... [FILE]...'),
1619 _('[OPTION]... [FILE]...'),
1620 inferrepo=True)
1620 inferrepo=True)
1621 def commit(ui, repo, *pats, **opts):
1621 def commit(ui, repo, *pats, **opts):
1622 """commit the specified files or all outstanding changes
1622 """commit the specified files or all outstanding changes
1623
1623
1624 Commit changes to the given files into the repository. Unlike a
1624 Commit changes to the given files into the repository. Unlike a
1625 centralized SCM, this operation is a local operation. See
1625 centralized SCM, this operation is a local operation. See
1626 :hg:`push` for a way to actively distribute your changes.
1626 :hg:`push` for a way to actively distribute your changes.
1627
1627
1628 If a list of files is omitted, all changes reported by :hg:`status`
1628 If a list of files is omitted, all changes reported by :hg:`status`
1629 will be committed.
1629 will be committed.
1630
1630
1631 If you are committing the result of a merge, do not provide any
1631 If you are committing the result of a merge, do not provide any
1632 filenames or -I/-X filters.
1632 filenames or -I/-X filters.
1633
1633
1634 If no commit message is specified, Mercurial starts your
1634 If no commit message is specified, Mercurial starts your
1635 configured editor where you can enter a message. In case your
1635 configured editor where you can enter a message. In case your
1636 commit fails, you will find a backup of your message in
1636 commit fails, you will find a backup of your message in
1637 ``.hg/last-message.txt``.
1637 ``.hg/last-message.txt``.
1638
1638
1639 The --close-branch flag can be used to mark the current branch
1639 The --close-branch flag can be used to mark the current branch
1640 head closed. When all heads of a branch are closed, the branch
1640 head closed. When all heads of a branch are closed, the branch
1641 will be considered closed and no longer listed.
1641 will be considered closed and no longer listed.
1642
1642
1643 The --amend flag can be used to amend the parent of the
1643 The --amend flag can be used to amend the parent of the
1644 working directory with a new commit that contains the changes
1644 working directory with a new commit that contains the changes
1645 in the parent in addition to those currently reported by :hg:`status`,
1645 in the parent in addition to those currently reported by :hg:`status`,
1646 if there are any. The old commit is stored in a backup bundle in
1646 if there are any. The old commit is stored in a backup bundle in
1647 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1647 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1648 on how to restore it).
1648 on how to restore it).
1649
1649
1650 Message, user and date are taken from the amended commit unless
1650 Message, user and date are taken from the amended commit unless
1651 specified. When a message isn't specified on the command line,
1651 specified. When a message isn't specified on the command line,
1652 the editor will open with the message of the amended commit.
1652 the editor will open with the message of the amended commit.
1653
1653
1654 It is not possible to amend public changesets (see :hg:`help phases`)
1654 It is not possible to amend public changesets (see :hg:`help phases`)
1655 or changesets that have children.
1655 or changesets that have children.
1656
1656
1657 See :hg:`help dates` for a list of formats valid for -d/--date.
1657 See :hg:`help dates` for a list of formats valid for -d/--date.
1658
1658
1659 Returns 0 on success, 1 if nothing changed.
1659 Returns 0 on success, 1 if nothing changed.
1660
1660
1661 .. container:: verbose
1661 .. container:: verbose
1662
1662
1663 Examples:
1663 Examples:
1664
1664
1665 - commit all files ending in .py::
1665 - commit all files ending in .py::
1666
1666
1667 hg commit --include "set:**.py"
1667 hg commit --include "set:**.py"
1668
1668
1669 - commit all non-binary files::
1669 - commit all non-binary files::
1670
1670
1671 hg commit --exclude "set:binary()"
1671 hg commit --exclude "set:binary()"
1672
1672
1673 - amend the current commit and set the date to now::
1673 - amend the current commit and set the date to now::
1674
1674
1675 hg commit --amend --date now
1675 hg commit --amend --date now
1676 """
1676 """
1677 wlock = lock = None
1677 wlock = lock = None
1678 try:
1678 try:
1679 wlock = repo.wlock()
1679 wlock = repo.wlock()
1680 lock = repo.lock()
1680 lock = repo.lock()
1681 return _docommit(ui, repo, *pats, **opts)
1681 return _docommit(ui, repo, *pats, **opts)
1682 finally:
1682 finally:
1683 release(lock, wlock)
1683 release(lock, wlock)
1684
1684
1685 def _docommit(ui, repo, *pats, **opts):
1685 def _docommit(ui, repo, *pats, **opts):
1686 if opts.get('interactive'):
1686 if opts.get('interactive'):
1687 opts.pop('interactive')
1687 opts.pop('interactive')
1688 cmdutil.dorecord(ui, repo, commit, None, False,
1688 cmdutil.dorecord(ui, repo, commit, None, False,
1689 cmdutil.recordfilter, *pats, **opts)
1689 cmdutil.recordfilter, *pats, **opts)
1690 return
1690 return
1691
1691
1692 if opts.get('subrepos'):
1692 if opts.get('subrepos'):
1693 if opts.get('amend'):
1693 if opts.get('amend'):
1694 raise error.Abort(_('cannot amend with --subrepos'))
1694 raise error.Abort(_('cannot amend with --subrepos'))
1695 # Let --subrepos on the command line override config setting.
1695 # Let --subrepos on the command line override config setting.
1696 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1696 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1697
1697
1698 cmdutil.checkunfinished(repo, commit=True)
1698 cmdutil.checkunfinished(repo, commit=True)
1699
1699
1700 branch = repo[None].branch()
1700 branch = repo[None].branch()
1701 bheads = repo.branchheads(branch)
1701 bheads = repo.branchheads(branch)
1702
1702
1703 extra = {}
1703 extra = {}
1704 if opts.get('close_branch'):
1704 if opts.get('close_branch'):
1705 extra['close'] = 1
1705 extra['close'] = 1
1706
1706
1707 if not bheads:
1707 if not bheads:
1708 raise error.Abort(_('can only close branch heads'))
1708 raise error.Abort(_('can only close branch heads'))
1709 elif opts.get('amend'):
1709 elif opts.get('amend'):
1710 if repo[None].parents()[0].p1().branch() != branch and \
1710 if repo[None].parents()[0].p1().branch() != branch and \
1711 repo[None].parents()[0].p2().branch() != branch:
1711 repo[None].parents()[0].p2().branch() != branch:
1712 raise error.Abort(_('can only close branch heads'))
1712 raise error.Abort(_('can only close branch heads'))
1713
1713
1714 if opts.get('amend'):
1714 if opts.get('amend'):
1715 if ui.configbool('ui', 'commitsubrepos'):
1715 if ui.configbool('ui', 'commitsubrepos'):
1716 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1716 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1717
1717
1718 old = repo['.']
1718 old = repo['.']
1719 if not old.mutable():
1719 if not old.mutable():
1720 raise error.Abort(_('cannot amend public changesets'))
1720 raise error.Abort(_('cannot amend public changesets'))
1721 if len(repo[None].parents()) > 1:
1721 if len(repo[None].parents()) > 1:
1722 raise error.Abort(_('cannot amend while merging'))
1722 raise error.Abort(_('cannot amend while merging'))
1723 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1723 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1724 if not allowunstable and old.children():
1724 if not allowunstable and old.children():
1725 raise error.Abort(_('cannot amend changeset with children'))
1725 raise error.Abort(_('cannot amend changeset with children'))
1726
1726
1727 # Currently histedit gets confused if an amend happens while histedit
1727 # Currently histedit gets confused if an amend happens while histedit
1728 # is in progress. Since we have a checkunfinished command, we are
1728 # is in progress. Since we have a checkunfinished command, we are
1729 # temporarily honoring it.
1729 # temporarily honoring it.
1730 #
1730 #
1731 # Note: eventually this guard will be removed. Please do not expect
1731 # Note: eventually this guard will be removed. Please do not expect
1732 # this behavior to remain.
1732 # this behavior to remain.
1733 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1733 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1734 cmdutil.checkunfinished(repo)
1734 cmdutil.checkunfinished(repo)
1735
1735
1736 # commitfunc is used only for temporary amend commit by cmdutil.amend
1736 # commitfunc is used only for temporary amend commit by cmdutil.amend
1737 def commitfunc(ui, repo, message, match, opts):
1737 def commitfunc(ui, repo, message, match, opts):
1738 return repo.commit(message,
1738 return repo.commit(message,
1739 opts.get('user') or old.user(),
1739 opts.get('user') or old.user(),
1740 opts.get('date') or old.date(),
1740 opts.get('date') or old.date(),
1741 match,
1741 match,
1742 extra=extra)
1742 extra=extra)
1743
1743
1744 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1744 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1745 if node == old.node():
1745 if node == old.node():
1746 ui.status(_("nothing changed\n"))
1746 ui.status(_("nothing changed\n"))
1747 return 1
1747 return 1
1748 else:
1748 else:
1749 def commitfunc(ui, repo, message, match, opts):
1749 def commitfunc(ui, repo, message, match, opts):
1750 backup = ui.backupconfig('phases', 'new-commit')
1750 backup = ui.backupconfig('phases', 'new-commit')
1751 baseui = repo.baseui
1751 baseui = repo.baseui
1752 basebackup = baseui.backupconfig('phases', 'new-commit')
1752 basebackup = baseui.backupconfig('phases', 'new-commit')
1753 try:
1753 try:
1754 if opts.get('secret'):
1754 if opts.get('secret'):
1755 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1755 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1756 # Propagate to subrepos
1756 # Propagate to subrepos
1757 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1757 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1758
1758
1759 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1759 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1760 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1760 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1761 return repo.commit(message, opts.get('user'), opts.get('date'),
1761 return repo.commit(message, opts.get('user'), opts.get('date'),
1762 match,
1762 match,
1763 editor=editor,
1763 editor=editor,
1764 extra=extra)
1764 extra=extra)
1765 finally:
1765 finally:
1766 ui.restoreconfig(backup)
1766 ui.restoreconfig(backup)
1767 repo.baseui.restoreconfig(basebackup)
1767 repo.baseui.restoreconfig(basebackup)
1768
1768
1769
1769
1770 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1770 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1771
1771
1772 if not node:
1772 if not node:
1773 stat = cmdutil.postcommitstatus(repo, pats, opts)
1773 stat = cmdutil.postcommitstatus(repo, pats, opts)
1774 if stat[3]:
1774 if stat[3]:
1775 ui.status(_("nothing changed (%d missing files, see "
1775 ui.status(_("nothing changed (%d missing files, see "
1776 "'hg status')\n") % len(stat[3]))
1776 "'hg status')\n") % len(stat[3]))
1777 else:
1777 else:
1778 ui.status(_("nothing changed\n"))
1778 ui.status(_("nothing changed\n"))
1779 return 1
1779 return 1
1780
1780
1781 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1781 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1782
1782
1783 @command('config|showconfig|debugconfig',
1783 @command('config|showconfig|debugconfig',
1784 [('u', 'untrusted', None, _('show untrusted configuration options')),
1784 [('u', 'untrusted', None, _('show untrusted configuration options')),
1785 ('e', 'edit', None, _('edit user config')),
1785 ('e', 'edit', None, _('edit user config')),
1786 ('l', 'local', None, _('edit repository config')),
1786 ('l', 'local', None, _('edit repository config')),
1787 ('g', 'global', None, _('edit global config'))],
1787 ('g', 'global', None, _('edit global config'))],
1788 _('[-u] [NAME]...'),
1788 _('[-u] [NAME]...'),
1789 optionalrepo=True)
1789 optionalrepo=True)
1790 def config(ui, repo, *values, **opts):
1790 def config(ui, repo, *values, **opts):
1791 """show combined config settings from all hgrc files
1791 """show combined config settings from all hgrc files
1792
1792
1793 With no arguments, print names and values of all config items.
1793 With no arguments, print names and values of all config items.
1794
1794
1795 With one argument of the form section.name, print just the value
1795 With one argument of the form section.name, print just the value
1796 of that config item.
1796 of that config item.
1797
1797
1798 With multiple arguments, print names and values of all config
1798 With multiple arguments, print names and values of all config
1799 items with matching section names.
1799 items with matching section names.
1800
1800
1801 With --edit, start an editor on the user-level config file. With
1801 With --edit, start an editor on the user-level config file. With
1802 --global, edit the system-wide config file. With --local, edit the
1802 --global, edit the system-wide config file. With --local, edit the
1803 repository-level config file.
1803 repository-level config file.
1804
1804
1805 With --debug, the source (filename and line number) is printed
1805 With --debug, the source (filename and line number) is printed
1806 for each config item.
1806 for each config item.
1807
1807
1808 See :hg:`help config` for more information about config files.
1808 See :hg:`help config` for more information about config files.
1809
1809
1810 Returns 0 on success, 1 if NAME does not exist.
1810 Returns 0 on success, 1 if NAME does not exist.
1811
1811
1812 """
1812 """
1813
1813
1814 if opts.get('edit') or opts.get('local') or opts.get('global'):
1814 if opts.get('edit') or opts.get('local') or opts.get('global'):
1815 if opts.get('local') and opts.get('global'):
1815 if opts.get('local') and opts.get('global'):
1816 raise error.Abort(_("can't use --local and --global together"))
1816 raise error.Abort(_("can't use --local and --global together"))
1817
1817
1818 if opts.get('local'):
1818 if opts.get('local'):
1819 if not repo:
1819 if not repo:
1820 raise error.Abort(_("can't use --local outside a repository"))
1820 raise error.Abort(_("can't use --local outside a repository"))
1821 paths = [repo.join('hgrc')]
1821 paths = [repo.join('hgrc')]
1822 elif opts.get('global'):
1822 elif opts.get('global'):
1823 paths = scmutil.systemrcpath()
1823 paths = scmutil.systemrcpath()
1824 else:
1824 else:
1825 paths = scmutil.userrcpath()
1825 paths = scmutil.userrcpath()
1826
1826
1827 for f in paths:
1827 for f in paths:
1828 if os.path.exists(f):
1828 if os.path.exists(f):
1829 break
1829 break
1830 else:
1830 else:
1831 if opts.get('global'):
1831 if opts.get('global'):
1832 samplehgrc = uimod.samplehgrcs['global']
1832 samplehgrc = uimod.samplehgrcs['global']
1833 elif opts.get('local'):
1833 elif opts.get('local'):
1834 samplehgrc = uimod.samplehgrcs['local']
1834 samplehgrc = uimod.samplehgrcs['local']
1835 else:
1835 else:
1836 samplehgrc = uimod.samplehgrcs['user']
1836 samplehgrc = uimod.samplehgrcs['user']
1837
1837
1838 f = paths[0]
1838 f = paths[0]
1839 fp = open(f, "w")
1839 fp = open(f, "w")
1840 fp.write(samplehgrc)
1840 fp.write(samplehgrc)
1841 fp.close()
1841 fp.close()
1842
1842
1843 editor = ui.geteditor()
1843 editor = ui.geteditor()
1844 ui.system("%s \"%s\"" % (editor, f),
1844 ui.system("%s \"%s\"" % (editor, f),
1845 onerr=error.Abort, errprefix=_("edit failed"))
1845 onerr=error.Abort, errprefix=_("edit failed"))
1846 return
1846 return
1847
1847
1848 for f in scmutil.rcpath():
1848 for f in scmutil.rcpath():
1849 ui.debug('read config from: %s\n' % f)
1849 ui.debug('read config from: %s\n' % f)
1850 untrusted = bool(opts.get('untrusted'))
1850 untrusted = bool(opts.get('untrusted'))
1851 if values:
1851 if values:
1852 sections = [v for v in values if '.' not in v]
1852 sections = [v for v in values if '.' not in v]
1853 items = [v for v in values if '.' in v]
1853 items = [v for v in values if '.' in v]
1854 if len(items) > 1 or items and sections:
1854 if len(items) > 1 or items and sections:
1855 raise error.Abort(_('only one config item permitted'))
1855 raise error.Abort(_('only one config item permitted'))
1856 matched = False
1856 matched = False
1857 for section, name, value in ui.walkconfig(untrusted=untrusted):
1857 for section, name, value in ui.walkconfig(untrusted=untrusted):
1858 value = str(value).replace('\n', '\\n')
1858 value = str(value).replace('\n', '\\n')
1859 sectname = section + '.' + name
1859 sectname = section + '.' + name
1860 if values:
1860 if values:
1861 for v in values:
1861 for v in values:
1862 if v == section:
1862 if v == section:
1863 ui.debug('%s: ' %
1863 ui.debug('%s: ' %
1864 ui.configsource(section, name, untrusted))
1864 ui.configsource(section, name, untrusted))
1865 ui.write('%s=%s\n' % (sectname, value))
1865 ui.write('%s=%s\n' % (sectname, value))
1866 matched = True
1866 matched = True
1867 elif v == sectname:
1867 elif v == sectname:
1868 ui.debug('%s: ' %
1868 ui.debug('%s: ' %
1869 ui.configsource(section, name, untrusted))
1869 ui.configsource(section, name, untrusted))
1870 ui.write(value, '\n')
1870 ui.write(value, '\n')
1871 matched = True
1871 matched = True
1872 else:
1872 else:
1873 ui.debug('%s: ' %
1873 ui.debug('%s: ' %
1874 ui.configsource(section, name, untrusted))
1874 ui.configsource(section, name, untrusted))
1875 ui.write('%s=%s\n' % (sectname, value))
1875 ui.write('%s=%s\n' % (sectname, value))
1876 matched = True
1876 matched = True
1877 if matched:
1877 if matched:
1878 return 0
1878 return 0
1879 return 1
1879 return 1
1880
1880
1881 @command('copy|cp',
1881 @command('copy|cp',
1882 [('A', 'after', None, _('record a copy that has already occurred')),
1882 [('A', 'after', None, _('record a copy that has already occurred')),
1883 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1883 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1884 ] + walkopts + dryrunopts,
1884 ] + walkopts + dryrunopts,
1885 _('[OPTION]... [SOURCE]... DEST'))
1885 _('[OPTION]... [SOURCE]... DEST'))
1886 def copy(ui, repo, *pats, **opts):
1886 def copy(ui, repo, *pats, **opts):
1887 """mark files as copied for the next commit
1887 """mark files as copied for the next commit
1888
1888
1889 Mark dest as having copies of source files. If dest is a
1889 Mark dest as having copies of source files. If dest is a
1890 directory, copies are put in that directory. If dest is a file,
1890 directory, copies are put in that directory. If dest is a file,
1891 the source must be a single file.
1891 the source must be a single file.
1892
1892
1893 By default, this command copies the contents of files as they
1893 By default, this command copies the contents of files as they
1894 exist in the working directory. If invoked with -A/--after, the
1894 exist in the working directory. If invoked with -A/--after, the
1895 operation is recorded, but no copying is performed.
1895 operation is recorded, but no copying is performed.
1896
1896
1897 This command takes effect with the next commit. To undo a copy
1897 This command takes effect with the next commit. To undo a copy
1898 before that, see :hg:`revert`.
1898 before that, see :hg:`revert`.
1899
1899
1900 Returns 0 on success, 1 if errors are encountered.
1900 Returns 0 on success, 1 if errors are encountered.
1901 """
1901 """
1902 with repo.wlock(False):
1902 with repo.wlock(False):
1903 return cmdutil.copy(ui, repo, pats, opts)
1903 return cmdutil.copy(ui, repo, pats, opts)
1904
1904
1905 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1905 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1906 def debugancestor(ui, repo, *args):
1906 def debugancestor(ui, repo, *args):
1907 """find the ancestor revision of two revisions in a given index"""
1907 """find the ancestor revision of two revisions in a given index"""
1908 if len(args) == 3:
1908 if len(args) == 3:
1909 index, rev1, rev2 = args
1909 index, rev1, rev2 = args
1910 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1910 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1911 lookup = r.lookup
1911 lookup = r.lookup
1912 elif len(args) == 2:
1912 elif len(args) == 2:
1913 if not repo:
1913 if not repo:
1914 raise error.Abort(_("there is no Mercurial repository here "
1914 raise error.Abort(_("there is no Mercurial repository here "
1915 "(.hg not found)"))
1915 "(.hg not found)"))
1916 rev1, rev2 = args
1916 rev1, rev2 = args
1917 r = repo.changelog
1917 r = repo.changelog
1918 lookup = repo.lookup
1918 lookup = repo.lookup
1919 else:
1919 else:
1920 raise error.Abort(_('either two or three arguments required'))
1920 raise error.Abort(_('either two or three arguments required'))
1921 a = r.ancestor(lookup(rev1), lookup(rev2))
1921 a = r.ancestor(lookup(rev1), lookup(rev2))
1922 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1922 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1923
1923
1924 @command('debugbuilddag',
1924 @command('debugbuilddag',
1925 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1925 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1926 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1926 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1927 ('n', 'new-file', None, _('add new file at each rev'))],
1927 ('n', 'new-file', None, _('add new file at each rev'))],
1928 _('[OPTION]... [TEXT]'))
1928 _('[OPTION]... [TEXT]'))
1929 def debugbuilddag(ui, repo, text=None,
1929 def debugbuilddag(ui, repo, text=None,
1930 mergeable_file=False,
1930 mergeable_file=False,
1931 overwritten_file=False,
1931 overwritten_file=False,
1932 new_file=False):
1932 new_file=False):
1933 """builds a repo with a given DAG from scratch in the current empty repo
1933 """builds a repo with a given DAG from scratch in the current empty repo
1934
1934
1935 The description of the DAG is read from stdin if not given on the
1935 The description of the DAG is read from stdin if not given on the
1936 command line.
1936 command line.
1937
1937
1938 Elements:
1938 Elements:
1939
1939
1940 - "+n" is a linear run of n nodes based on the current default parent
1940 - "+n" is a linear run of n nodes based on the current default parent
1941 - "." is a single node based on the current default parent
1941 - "." is a single node based on the current default parent
1942 - "$" resets the default parent to null (implied at the start);
1942 - "$" resets the default parent to null (implied at the start);
1943 otherwise the default parent is always the last node created
1943 otherwise the default parent is always the last node created
1944 - "<p" sets the default parent to the backref p
1944 - "<p" sets the default parent to the backref p
1945 - "*p" is a fork at parent p, which is a backref
1945 - "*p" is a fork at parent p, which is a backref
1946 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1946 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1947 - "/p2" is a merge of the preceding node and p2
1947 - "/p2" is a merge of the preceding node and p2
1948 - ":tag" defines a local tag for the preceding node
1948 - ":tag" defines a local tag for the preceding node
1949 - "@branch" sets the named branch for subsequent nodes
1949 - "@branch" sets the named branch for subsequent nodes
1950 - "#...\\n" is a comment up to the end of the line
1950 - "#...\\n" is a comment up to the end of the line
1951
1951
1952 Whitespace between the above elements is ignored.
1952 Whitespace between the above elements is ignored.
1953
1953
1954 A backref is either
1954 A backref is either
1955
1955
1956 - a number n, which references the node curr-n, where curr is the current
1956 - a number n, which references the node curr-n, where curr is the current
1957 node, or
1957 node, or
1958 - the name of a local tag you placed earlier using ":tag", or
1958 - the name of a local tag you placed earlier using ":tag", or
1959 - empty to denote the default parent.
1959 - empty to denote the default parent.
1960
1960
1961 All string valued-elements are either strictly alphanumeric, or must
1961 All string valued-elements are either strictly alphanumeric, or must
1962 be enclosed in double quotes ("..."), with "\\" as escape character.
1962 be enclosed in double quotes ("..."), with "\\" as escape character.
1963 """
1963 """
1964
1964
1965 if text is None:
1965 if text is None:
1966 ui.status(_("reading DAG from stdin\n"))
1966 ui.status(_("reading DAG from stdin\n"))
1967 text = ui.fin.read()
1967 text = ui.fin.read()
1968
1968
1969 cl = repo.changelog
1969 cl = repo.changelog
1970 if len(cl) > 0:
1970 if len(cl) > 0:
1971 raise error.Abort(_('repository is not empty'))
1971 raise error.Abort(_('repository is not empty'))
1972
1972
1973 # determine number of revs in DAG
1973 # determine number of revs in DAG
1974 total = 0
1974 total = 0
1975 for type, data in dagparser.parsedag(text):
1975 for type, data in dagparser.parsedag(text):
1976 if type == 'n':
1976 if type == 'n':
1977 total += 1
1977 total += 1
1978
1978
1979 if mergeable_file:
1979 if mergeable_file:
1980 linesperrev = 2
1980 linesperrev = 2
1981 # make a file with k lines per rev
1981 # make a file with k lines per rev
1982 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1982 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1983 initialmergedlines.append("")
1983 initialmergedlines.append("")
1984
1984
1985 tags = []
1985 tags = []
1986
1986
1987 lock = tr = None
1987 lock = tr = None
1988 try:
1988 try:
1989 lock = repo.lock()
1989 lock = repo.lock()
1990 tr = repo.transaction("builddag")
1990 tr = repo.transaction("builddag")
1991
1991
1992 at = -1
1992 at = -1
1993 atbranch = 'default'
1993 atbranch = 'default'
1994 nodeids = []
1994 nodeids = []
1995 id = 0
1995 id = 0
1996 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1996 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1997 for type, data in dagparser.parsedag(text):
1997 for type, data in dagparser.parsedag(text):
1998 if type == 'n':
1998 if type == 'n':
1999 ui.note(('node %s\n' % str(data)))
1999 ui.note(('node %s\n' % str(data)))
2000 id, ps = data
2000 id, ps = data
2001
2001
2002 files = []
2002 files = []
2003 fctxs = {}
2003 fctxs = {}
2004
2004
2005 p2 = None
2005 p2 = None
2006 if mergeable_file:
2006 if mergeable_file:
2007 fn = "mf"
2007 fn = "mf"
2008 p1 = repo[ps[0]]
2008 p1 = repo[ps[0]]
2009 if len(ps) > 1:
2009 if len(ps) > 1:
2010 p2 = repo[ps[1]]
2010 p2 = repo[ps[1]]
2011 pa = p1.ancestor(p2)
2011 pa = p1.ancestor(p2)
2012 base, local, other = [x[fn].data() for x in (pa, p1,
2012 base, local, other = [x[fn].data() for x in (pa, p1,
2013 p2)]
2013 p2)]
2014 m3 = simplemerge.Merge3Text(base, local, other)
2014 m3 = simplemerge.Merge3Text(base, local, other)
2015 ml = [l.strip() for l in m3.merge_lines()]
2015 ml = [l.strip() for l in m3.merge_lines()]
2016 ml.append("")
2016 ml.append("")
2017 elif at > 0:
2017 elif at > 0:
2018 ml = p1[fn].data().split("\n")
2018 ml = p1[fn].data().split("\n")
2019 else:
2019 else:
2020 ml = initialmergedlines
2020 ml = initialmergedlines
2021 ml[id * linesperrev] += " r%i" % id
2021 ml[id * linesperrev] += " r%i" % id
2022 mergedtext = "\n".join(ml)
2022 mergedtext = "\n".join(ml)
2023 files.append(fn)
2023 files.append(fn)
2024 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2024 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2025
2025
2026 if overwritten_file:
2026 if overwritten_file:
2027 fn = "of"
2027 fn = "of"
2028 files.append(fn)
2028 files.append(fn)
2029 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2029 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2030
2030
2031 if new_file:
2031 if new_file:
2032 fn = "nf%i" % id
2032 fn = "nf%i" % id
2033 files.append(fn)
2033 files.append(fn)
2034 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2034 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2035 if len(ps) > 1:
2035 if len(ps) > 1:
2036 if not p2:
2036 if not p2:
2037 p2 = repo[ps[1]]
2037 p2 = repo[ps[1]]
2038 for fn in p2:
2038 for fn in p2:
2039 if fn.startswith("nf"):
2039 if fn.startswith("nf"):
2040 files.append(fn)
2040 files.append(fn)
2041 fctxs[fn] = p2[fn]
2041 fctxs[fn] = p2[fn]
2042
2042
2043 def fctxfn(repo, cx, path):
2043 def fctxfn(repo, cx, path):
2044 return fctxs.get(path)
2044 return fctxs.get(path)
2045
2045
2046 if len(ps) == 0 or ps[0] < 0:
2046 if len(ps) == 0 or ps[0] < 0:
2047 pars = [None, None]
2047 pars = [None, None]
2048 elif len(ps) == 1:
2048 elif len(ps) == 1:
2049 pars = [nodeids[ps[0]], None]
2049 pars = [nodeids[ps[0]], None]
2050 else:
2050 else:
2051 pars = [nodeids[p] for p in ps]
2051 pars = [nodeids[p] for p in ps]
2052 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2052 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2053 date=(id, 0),
2053 date=(id, 0),
2054 user="debugbuilddag",
2054 user="debugbuilddag",
2055 extra={'branch': atbranch})
2055 extra={'branch': atbranch})
2056 nodeid = repo.commitctx(cx)
2056 nodeid = repo.commitctx(cx)
2057 nodeids.append(nodeid)
2057 nodeids.append(nodeid)
2058 at = id
2058 at = id
2059 elif type == 'l':
2059 elif type == 'l':
2060 id, name = data
2060 id, name = data
2061 ui.note(('tag %s\n' % name))
2061 ui.note(('tag %s\n' % name))
2062 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2062 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2063 elif type == 'a':
2063 elif type == 'a':
2064 ui.note(('branch %s\n' % data))
2064 ui.note(('branch %s\n' % data))
2065 atbranch = data
2065 atbranch = data
2066 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2066 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2067 tr.close()
2067 tr.close()
2068
2068
2069 if tags:
2069 if tags:
2070 repo.vfs.write("localtags", "".join(tags))
2070 repo.vfs.write("localtags", "".join(tags))
2071 finally:
2071 finally:
2072 ui.progress(_('building'), None)
2072 ui.progress(_('building'), None)
2073 release(tr, lock)
2073 release(tr, lock)
2074
2074
2075 @command('debugbundle',
2075 @command('debugbundle',
2076 [('a', 'all', None, _('show all details')),
2076 [('a', 'all', None, _('show all details')),
2077 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2077 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2078 _('FILE'),
2078 _('FILE'),
2079 norepo=True)
2079 norepo=True)
2080 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2080 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2081 """lists the contents of a bundle"""
2081 """lists the contents of a bundle"""
2082 with hg.openpath(ui, bundlepath) as f:
2082 with hg.openpath(ui, bundlepath) as f:
2083 if spec:
2083 if spec:
2084 spec = exchange.getbundlespec(ui, f)
2084 spec = exchange.getbundlespec(ui, f)
2085 ui.write('%s\n' % spec)
2085 ui.write('%s\n' % spec)
2086 return
2086 return
2087
2087
2088 gen = exchange.readbundle(ui, f, bundlepath)
2088 gen = exchange.readbundle(ui, f, bundlepath)
2089 if isinstance(gen, bundle2.unbundle20):
2089 if isinstance(gen, bundle2.unbundle20):
2090 return _debugbundle2(ui, gen, all=all, **opts)
2090 return _debugbundle2(ui, gen, all=all, **opts)
2091 if all:
2091 if all:
2092 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2092 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2093
2093
2094 def showchunks(named):
2094 def showchunks(named):
2095 ui.write("\n%s\n" % named)
2095 ui.write("\n%s\n" % named)
2096 chain = None
2096 chain = None
2097 while True:
2097 while True:
2098 chunkdata = gen.deltachunk(chain)
2098 chunkdata = gen.deltachunk(chain)
2099 if not chunkdata:
2099 if not chunkdata:
2100 break
2100 break
2101 node = chunkdata['node']
2101 node = chunkdata['node']
2102 p1 = chunkdata['p1']
2102 p1 = chunkdata['p1']
2103 p2 = chunkdata['p2']
2103 p2 = chunkdata['p2']
2104 cs = chunkdata['cs']
2104 cs = chunkdata['cs']
2105 deltabase = chunkdata['deltabase']
2105 deltabase = chunkdata['deltabase']
2106 delta = chunkdata['delta']
2106 delta = chunkdata['delta']
2107 ui.write("%s %s %s %s %s %s\n" %
2107 ui.write("%s %s %s %s %s %s\n" %
2108 (hex(node), hex(p1), hex(p2),
2108 (hex(node), hex(p1), hex(p2),
2109 hex(cs), hex(deltabase), len(delta)))
2109 hex(cs), hex(deltabase), len(delta)))
2110 chain = node
2110 chain = node
2111
2111
2112 chunkdata = gen.changelogheader()
2112 chunkdata = gen.changelogheader()
2113 showchunks("changelog")
2113 showchunks("changelog")
2114 chunkdata = gen.manifestheader()
2114 chunkdata = gen.manifestheader()
2115 showchunks("manifest")
2115 showchunks("manifest")
2116 while True:
2116 while True:
2117 chunkdata = gen.filelogheader()
2117 chunkdata = gen.filelogheader()
2118 if not chunkdata:
2118 if not chunkdata:
2119 break
2119 break
2120 fname = chunkdata['filename']
2120 fname = chunkdata['filename']
2121 showchunks(fname)
2121 showchunks(fname)
2122 else:
2122 else:
2123 if isinstance(gen, bundle2.unbundle20):
2123 if isinstance(gen, bundle2.unbundle20):
2124 raise error.Abort(_('use debugbundle2 for this file'))
2124 raise error.Abort(_('use debugbundle2 for this file'))
2125 chunkdata = gen.changelogheader()
2125 chunkdata = gen.changelogheader()
2126 chain = None
2126 chain = None
2127 while True:
2127 while True:
2128 chunkdata = gen.deltachunk(chain)
2128 chunkdata = gen.deltachunk(chain)
2129 if not chunkdata:
2129 if not chunkdata:
2130 break
2130 break
2131 node = chunkdata['node']
2131 node = chunkdata['node']
2132 ui.write("%s\n" % hex(node))
2132 ui.write("%s\n" % hex(node))
2133 chain = node
2133 chain = node
2134
2134
2135 def _debugbundle2(ui, gen, **opts):
2135 def _debugbundle2(ui, gen, **opts):
2136 """lists the contents of a bundle2"""
2136 """lists the contents of a bundle2"""
2137 if not isinstance(gen, bundle2.unbundle20):
2137 if not isinstance(gen, bundle2.unbundle20):
2138 raise error.Abort(_('not a bundle2 file'))
2138 raise error.Abort(_('not a bundle2 file'))
2139 ui.write(('Stream params: %s\n' % repr(gen.params)))
2139 ui.write(('Stream params: %s\n' % repr(gen.params)))
2140 for part in gen.iterparts():
2140 for part in gen.iterparts():
2141 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2141 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2142 if part.type == 'changegroup':
2142 if part.type == 'changegroup':
2143 version = part.params.get('version', '01')
2143 version = part.params.get('version', '01')
2144 cg = changegroup.getunbundler(version, part, 'UN')
2144 cg = changegroup.getunbundler(version, part, 'UN')
2145 chunkdata = cg.changelogheader()
2145 chunkdata = cg.changelogheader()
2146 chain = None
2146 chain = None
2147 while True:
2147 while True:
2148 chunkdata = cg.deltachunk(chain)
2148 chunkdata = cg.deltachunk(chain)
2149 if not chunkdata:
2149 if not chunkdata:
2150 break
2150 break
2151 node = chunkdata['node']
2151 node = chunkdata['node']
2152 ui.write(" %s\n" % hex(node))
2152 ui.write(" %s\n" % hex(node))
2153 chain = node
2153 chain = node
2154
2154
2155 @command('debugcreatestreamclonebundle', [], 'FILE')
2155 @command('debugcreatestreamclonebundle', [], 'FILE')
2156 def debugcreatestreamclonebundle(ui, repo, fname):
2156 def debugcreatestreamclonebundle(ui, repo, fname):
2157 """create a stream clone bundle file
2157 """create a stream clone bundle file
2158
2158
2159 Stream bundles are special bundles that are essentially archives of
2159 Stream bundles are special bundles that are essentially archives of
2160 revlog files. They are commonly used for cloning very quickly.
2160 revlog files. They are commonly used for cloning very quickly.
2161 """
2161 """
2162 requirements, gen = streamclone.generatebundlev1(repo)
2162 requirements, gen = streamclone.generatebundlev1(repo)
2163 changegroup.writechunks(ui, gen, fname)
2163 changegroup.writechunks(ui, gen, fname)
2164
2164
2165 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2165 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2166
2166
2167 @command('debugapplystreamclonebundle', [], 'FILE')
2167 @command('debugapplystreamclonebundle', [], 'FILE')
2168 def debugapplystreamclonebundle(ui, repo, fname):
2168 def debugapplystreamclonebundle(ui, repo, fname):
2169 """apply a stream clone bundle file"""
2169 """apply a stream clone bundle file"""
2170 f = hg.openpath(ui, fname)
2170 f = hg.openpath(ui, fname)
2171 gen = exchange.readbundle(ui, f, fname)
2171 gen = exchange.readbundle(ui, f, fname)
2172 gen.apply(repo)
2172 gen.apply(repo)
2173
2173
2174 @command('debugcheckstate', [], '')
2174 @command('debugcheckstate', [], '')
2175 def debugcheckstate(ui, repo):
2175 def debugcheckstate(ui, repo):
2176 """validate the correctness of the current dirstate"""
2176 """validate the correctness of the current dirstate"""
2177 parent1, parent2 = repo.dirstate.parents()
2177 parent1, parent2 = repo.dirstate.parents()
2178 m1 = repo[parent1].manifest()
2178 m1 = repo[parent1].manifest()
2179 m2 = repo[parent2].manifest()
2179 m2 = repo[parent2].manifest()
2180 errors = 0
2180 errors = 0
2181 for f in repo.dirstate:
2181 for f in repo.dirstate:
2182 state = repo.dirstate[f]
2182 state = repo.dirstate[f]
2183 if state in "nr" and f not in m1:
2183 if state in "nr" and f not in m1:
2184 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2184 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2185 errors += 1
2185 errors += 1
2186 if state in "a" and f in m1:
2186 if state in "a" and f in m1:
2187 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2187 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2188 errors += 1
2188 errors += 1
2189 if state in "m" and f not in m1 and f not in m2:
2189 if state in "m" and f not in m1 and f not in m2:
2190 ui.warn(_("%s in state %s, but not in either manifest\n") %
2190 ui.warn(_("%s in state %s, but not in either manifest\n") %
2191 (f, state))
2191 (f, state))
2192 errors += 1
2192 errors += 1
2193 for f in m1:
2193 for f in m1:
2194 state = repo.dirstate[f]
2194 state = repo.dirstate[f]
2195 if state not in "nrm":
2195 if state not in "nrm":
2196 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2196 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2197 errors += 1
2197 errors += 1
2198 if errors:
2198 if errors:
2199 error = _(".hg/dirstate inconsistent with current parent's manifest")
2199 error = _(".hg/dirstate inconsistent with current parent's manifest")
2200 raise error.Abort(error)
2200 raise error.Abort(error)
2201
2201
2202 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2202 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2203 def debugcommands(ui, cmd='', *args):
2203 def debugcommands(ui, cmd='', *args):
2204 """list all available commands and options"""
2204 """list all available commands and options"""
2205 for cmd, vals in sorted(table.iteritems()):
2205 for cmd, vals in sorted(table.iteritems()):
2206 cmd = cmd.split('|')[0].strip('^')
2206 cmd = cmd.split('|')[0].strip('^')
2207 opts = ', '.join([i[1] for i in vals[1]])
2207 opts = ', '.join([i[1] for i in vals[1]])
2208 ui.write('%s: %s\n' % (cmd, opts))
2208 ui.write('%s: %s\n' % (cmd, opts))
2209
2209
2210 @command('debugcomplete',
2210 @command('debugcomplete',
2211 [('o', 'options', None, _('show the command options'))],
2211 [('o', 'options', None, _('show the command options'))],
2212 _('[-o] CMD'),
2212 _('[-o] CMD'),
2213 norepo=True)
2213 norepo=True)
2214 def debugcomplete(ui, cmd='', **opts):
2214 def debugcomplete(ui, cmd='', **opts):
2215 """returns the completion list associated with the given command"""
2215 """returns the completion list associated with the given command"""
2216
2216
2217 if opts.get('options'):
2217 if opts.get('options'):
2218 options = []
2218 options = []
2219 otables = [globalopts]
2219 otables = [globalopts]
2220 if cmd:
2220 if cmd:
2221 aliases, entry = cmdutil.findcmd(cmd, table, False)
2221 aliases, entry = cmdutil.findcmd(cmd, table, False)
2222 otables.append(entry[1])
2222 otables.append(entry[1])
2223 for t in otables:
2223 for t in otables:
2224 for o in t:
2224 for o in t:
2225 if "(DEPRECATED)" in o[3]:
2225 if "(DEPRECATED)" in o[3]:
2226 continue
2226 continue
2227 if o[0]:
2227 if o[0]:
2228 options.append('-%s' % o[0])
2228 options.append('-%s' % o[0])
2229 options.append('--%s' % o[1])
2229 options.append('--%s' % o[1])
2230 ui.write("%s\n" % "\n".join(options))
2230 ui.write("%s\n" % "\n".join(options))
2231 return
2231 return
2232
2232
2233 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2233 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2234 if ui.verbose:
2234 if ui.verbose:
2235 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2235 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2236 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2236 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2237
2237
2238 @command('debugdag',
2238 @command('debugdag',
2239 [('t', 'tags', None, _('use tags as labels')),
2239 [('t', 'tags', None, _('use tags as labels')),
2240 ('b', 'branches', None, _('annotate with branch names')),
2240 ('b', 'branches', None, _('annotate with branch names')),
2241 ('', 'dots', None, _('use dots for runs')),
2241 ('', 'dots', None, _('use dots for runs')),
2242 ('s', 'spaces', None, _('separate elements by spaces'))],
2242 ('s', 'spaces', None, _('separate elements by spaces'))],
2243 _('[OPTION]... [FILE [REV]...]'),
2243 _('[OPTION]... [FILE [REV]...]'),
2244 optionalrepo=True)
2244 optionalrepo=True)
2245 def debugdag(ui, repo, file_=None, *revs, **opts):
2245 def debugdag(ui, repo, file_=None, *revs, **opts):
2246 """format the changelog or an index DAG as a concise textual description
2246 """format the changelog or an index DAG as a concise textual description
2247
2247
2248 If you pass a revlog index, the revlog's DAG is emitted. If you list
2248 If you pass a revlog index, the revlog's DAG is emitted. If you list
2249 revision numbers, they get labeled in the output as rN.
2249 revision numbers, they get labeled in the output as rN.
2250
2250
2251 Otherwise, the changelog DAG of the current repo is emitted.
2251 Otherwise, the changelog DAG of the current repo is emitted.
2252 """
2252 """
2253 spaces = opts.get('spaces')
2253 spaces = opts.get('spaces')
2254 dots = opts.get('dots')
2254 dots = opts.get('dots')
2255 if file_:
2255 if file_:
2256 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2256 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2257 revs = set((int(r) for r in revs))
2257 revs = set((int(r) for r in revs))
2258 def events():
2258 def events():
2259 for r in rlog:
2259 for r in rlog:
2260 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2260 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2261 if p != -1))
2261 if p != -1))
2262 if r in revs:
2262 if r in revs:
2263 yield 'l', (r, "r%i" % r)
2263 yield 'l', (r, "r%i" % r)
2264 elif repo:
2264 elif repo:
2265 cl = repo.changelog
2265 cl = repo.changelog
2266 tags = opts.get('tags')
2266 tags = opts.get('tags')
2267 branches = opts.get('branches')
2267 branches = opts.get('branches')
2268 if tags:
2268 if tags:
2269 labels = {}
2269 labels = {}
2270 for l, n in repo.tags().items():
2270 for l, n in repo.tags().items():
2271 labels.setdefault(cl.rev(n), []).append(l)
2271 labels.setdefault(cl.rev(n), []).append(l)
2272 def events():
2272 def events():
2273 b = "default"
2273 b = "default"
2274 for r in cl:
2274 for r in cl:
2275 if branches:
2275 if branches:
2276 newb = cl.read(cl.node(r))[5]['branch']
2276 newb = cl.read(cl.node(r))[5]['branch']
2277 if newb != b:
2277 if newb != b:
2278 yield 'a', newb
2278 yield 'a', newb
2279 b = newb
2279 b = newb
2280 yield 'n', (r, list(p for p in cl.parentrevs(r)
2280 yield 'n', (r, list(p for p in cl.parentrevs(r)
2281 if p != -1))
2281 if p != -1))
2282 if tags:
2282 if tags:
2283 ls = labels.get(r)
2283 ls = labels.get(r)
2284 if ls:
2284 if ls:
2285 for l in ls:
2285 for l in ls:
2286 yield 'l', (r, l)
2286 yield 'l', (r, l)
2287 else:
2287 else:
2288 raise error.Abort(_('need repo for changelog dag'))
2288 raise error.Abort(_('need repo for changelog dag'))
2289
2289
2290 for line in dagparser.dagtextlines(events(),
2290 for line in dagparser.dagtextlines(events(),
2291 addspaces=spaces,
2291 addspaces=spaces,
2292 wraplabels=True,
2292 wraplabels=True,
2293 wrapannotations=True,
2293 wrapannotations=True,
2294 wrapnonlinear=dots,
2294 wrapnonlinear=dots,
2295 usedots=dots,
2295 usedots=dots,
2296 maxlinewidth=70):
2296 maxlinewidth=70):
2297 ui.write(line)
2297 ui.write(line)
2298 ui.write("\n")
2298 ui.write("\n")
2299
2299
2300 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2300 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2301 def debugdata(ui, repo, file_, rev=None, **opts):
2301 def debugdata(ui, repo, file_, rev=None, **opts):
2302 """dump the contents of a data file revision"""
2302 """dump the contents of a data file revision"""
2303 if opts.get('changelog') or opts.get('manifest'):
2303 if opts.get('changelog') or opts.get('manifest'):
2304 file_, rev = None, file_
2304 file_, rev = None, file_
2305 elif rev is None:
2305 elif rev is None:
2306 raise error.CommandError('debugdata', _('invalid arguments'))
2306 raise error.CommandError('debugdata', _('invalid arguments'))
2307 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2307 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2308 try:
2308 try:
2309 ui.write(r.revision(r.lookup(rev)))
2309 ui.write(r.revision(r.lookup(rev)))
2310 except KeyError:
2310 except KeyError:
2311 raise error.Abort(_('invalid revision identifier %s') % rev)
2311 raise error.Abort(_('invalid revision identifier %s') % rev)
2312
2312
2313 @command('debugdate',
2313 @command('debugdate',
2314 [('e', 'extended', None, _('try extended date formats'))],
2314 [('e', 'extended', None, _('try extended date formats'))],
2315 _('[-e] DATE [RANGE]'),
2315 _('[-e] DATE [RANGE]'),
2316 norepo=True, optionalrepo=True)
2316 norepo=True, optionalrepo=True)
2317 def debugdate(ui, date, range=None, **opts):
2317 def debugdate(ui, date, range=None, **opts):
2318 """parse and display a date"""
2318 """parse and display a date"""
2319 if opts["extended"]:
2319 if opts["extended"]:
2320 d = util.parsedate(date, util.extendeddateformats)
2320 d = util.parsedate(date, util.extendeddateformats)
2321 else:
2321 else:
2322 d = util.parsedate(date)
2322 d = util.parsedate(date)
2323 ui.write(("internal: %s %s\n") % d)
2323 ui.write(("internal: %s %s\n") % d)
2324 ui.write(("standard: %s\n") % util.datestr(d))
2324 ui.write(("standard: %s\n") % util.datestr(d))
2325 if range:
2325 if range:
2326 m = util.matchdate(range)
2326 m = util.matchdate(range)
2327 ui.write(("match: %s\n") % m(d[0]))
2327 ui.write(("match: %s\n") % m(d[0]))
2328
2328
2329 @command('debugdiscovery',
2329 @command('debugdiscovery',
2330 [('', 'old', None, _('use old-style discovery')),
2330 [('', 'old', None, _('use old-style discovery')),
2331 ('', 'nonheads', None,
2331 ('', 'nonheads', None,
2332 _('use old-style discovery with non-heads included')),
2332 _('use old-style discovery with non-heads included')),
2333 ] + remoteopts,
2333 ] + remoteopts,
2334 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2334 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2335 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2335 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2336 """runs the changeset discovery protocol in isolation"""
2336 """runs the changeset discovery protocol in isolation"""
2337 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2337 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2338 opts.get('branch'))
2338 opts.get('branch'))
2339 remote = hg.peer(repo, opts, remoteurl)
2339 remote = hg.peer(repo, opts, remoteurl)
2340 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2340 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2341
2341
2342 # make sure tests are repeatable
2342 # make sure tests are repeatable
2343 random.seed(12323)
2343 random.seed(12323)
2344
2344
2345 def doit(localheads, remoteheads, remote=remote):
2345 def doit(localheads, remoteheads, remote=remote):
2346 if opts.get('old'):
2346 if opts.get('old'):
2347 if localheads:
2347 if localheads:
2348 raise error.Abort('cannot use localheads with old style '
2348 raise error.Abort('cannot use localheads with old style '
2349 'discovery')
2349 'discovery')
2350 if not util.safehasattr(remote, 'branches'):
2350 if not util.safehasattr(remote, 'branches'):
2351 # enable in-client legacy support
2351 # enable in-client legacy support
2352 remote = localrepo.locallegacypeer(remote.local())
2352 remote = localrepo.locallegacypeer(remote.local())
2353 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2353 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2354 force=True)
2354 force=True)
2355 common = set(common)
2355 common = set(common)
2356 if not opts.get('nonheads'):
2356 if not opts.get('nonheads'):
2357 ui.write(("unpruned common: %s\n") %
2357 ui.write(("unpruned common: %s\n") %
2358 " ".join(sorted(short(n) for n in common)))
2358 " ".join(sorted(short(n) for n in common)))
2359 dag = dagutil.revlogdag(repo.changelog)
2359 dag = dagutil.revlogdag(repo.changelog)
2360 all = dag.ancestorset(dag.internalizeall(common))
2360 all = dag.ancestorset(dag.internalizeall(common))
2361 common = dag.externalizeall(dag.headsetofconnecteds(all))
2361 common = dag.externalizeall(dag.headsetofconnecteds(all))
2362 else:
2362 else:
2363 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2363 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2364 common = set(common)
2364 common = set(common)
2365 rheads = set(hds)
2365 rheads = set(hds)
2366 lheads = set(repo.heads())
2366 lheads = set(repo.heads())
2367 ui.write(("common heads: %s\n") %
2367 ui.write(("common heads: %s\n") %
2368 " ".join(sorted(short(n) for n in common)))
2368 " ".join(sorted(short(n) for n in common)))
2369 if lheads <= common:
2369 if lheads <= common:
2370 ui.write(("local is subset\n"))
2370 ui.write(("local is subset\n"))
2371 elif rheads <= common:
2371 elif rheads <= common:
2372 ui.write(("remote is subset\n"))
2372 ui.write(("remote is subset\n"))
2373
2373
2374 serverlogs = opts.get('serverlog')
2374 serverlogs = opts.get('serverlog')
2375 if serverlogs:
2375 if serverlogs:
2376 for filename in serverlogs:
2376 for filename in serverlogs:
2377 with open(filename, 'r') as logfile:
2377 with open(filename, 'r') as logfile:
2378 line = logfile.readline()
2378 line = logfile.readline()
2379 while line:
2379 while line:
2380 parts = line.strip().split(';')
2380 parts = line.strip().split(';')
2381 op = parts[1]
2381 op = parts[1]
2382 if op == 'cg':
2382 if op == 'cg':
2383 pass
2383 pass
2384 elif op == 'cgss':
2384 elif op == 'cgss':
2385 doit(parts[2].split(' '), parts[3].split(' '))
2385 doit(parts[2].split(' '), parts[3].split(' '))
2386 elif op == 'unb':
2386 elif op == 'unb':
2387 doit(parts[3].split(' '), parts[2].split(' '))
2387 doit(parts[3].split(' '), parts[2].split(' '))
2388 line = logfile.readline()
2388 line = logfile.readline()
2389 else:
2389 else:
2390 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2390 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2391 opts.get('remote_head'))
2391 opts.get('remote_head'))
2392 localrevs = opts.get('local_head')
2392 localrevs = opts.get('local_head')
2393 doit(localrevs, remoterevs)
2393 doit(localrevs, remoterevs)
2394
2394
2395 @command('debugextensions', formatteropts, [], norepo=True)
2395 @command('debugextensions', formatteropts, [], norepo=True)
2396 def debugextensions(ui, **opts):
2396 def debugextensions(ui, **opts):
2397 '''show information about active extensions'''
2397 '''show information about active extensions'''
2398 exts = extensions.extensions(ui)
2398 exts = extensions.extensions(ui)
2399 fm = ui.formatter('debugextensions', opts)
2399 fm = ui.formatter('debugextensions', opts)
2400 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2400 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2401 extsource = extmod.__file__
2401 extsource = extmod.__file__
2402 exttestedwith = getattr(extmod, 'testedwith', None)
2402 exttestedwith = getattr(extmod, 'testedwith', None)
2403 if exttestedwith is not None:
2403 if exttestedwith is not None:
2404 exttestedwith = exttestedwith.split()
2404 exttestedwith = exttestedwith.split()
2405 extbuglink = getattr(extmod, 'buglink', None)
2405 extbuglink = getattr(extmod, 'buglink', None)
2406
2406
2407 fm.startitem()
2407 fm.startitem()
2408
2408
2409 if ui.quiet or ui.verbose:
2409 if ui.quiet or ui.verbose:
2410 fm.write('name', '%s\n', extname)
2410 fm.write('name', '%s\n', extname)
2411 else:
2411 else:
2412 fm.write('name', '%s', extname)
2412 fm.write('name', '%s', extname)
2413 if not exttestedwith:
2413 if not exttestedwith:
2414 fm.plain(_(' (untested!)\n'))
2414 fm.plain(_(' (untested!)\n'))
2415 else:
2415 else:
2416 if exttestedwith == ['internal'] or \
2416 if exttestedwith == ['internal'] or \
2417 util.version() in exttestedwith:
2417 util.version() in exttestedwith:
2418 fm.plain('\n')
2418 fm.plain('\n')
2419 else:
2419 else:
2420 lasttestedversion = exttestedwith[-1]
2420 lasttestedversion = exttestedwith[-1]
2421 fm.plain(' (%s!)\n' % lasttestedversion)
2421 fm.plain(' (%s!)\n' % lasttestedversion)
2422
2422
2423 fm.condwrite(ui.verbose and extsource, 'source',
2423 fm.condwrite(ui.verbose and extsource, 'source',
2424 _(' location: %s\n'), extsource or "")
2424 _(' location: %s\n'), extsource or "")
2425
2425
2426 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2426 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2427 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2427 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2428
2428
2429 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2429 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2430 _(' bug reporting: %s\n'), extbuglink or "")
2430 _(' bug reporting: %s\n'), extbuglink or "")
2431
2431
2432 fm.end()
2432 fm.end()
2433
2433
2434 @command('debugfileset',
2434 @command('debugfileset',
2435 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2435 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2436 _('[-r REV] FILESPEC'))
2436 _('[-r REV] FILESPEC'))
2437 def debugfileset(ui, repo, expr, **opts):
2437 def debugfileset(ui, repo, expr, **opts):
2438 '''parse and apply a fileset specification'''
2438 '''parse and apply a fileset specification'''
2439 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2439 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2440 if ui.verbose:
2440 if ui.verbose:
2441 tree = fileset.parse(expr)
2441 tree = fileset.parse(expr)
2442 ui.note(fileset.prettyformat(tree), "\n")
2442 ui.note(fileset.prettyformat(tree), "\n")
2443
2443
2444 for f in ctx.getfileset(expr):
2444 for f in ctx.getfileset(expr):
2445 ui.write("%s\n" % f)
2445 ui.write("%s\n" % f)
2446
2446
2447 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2447 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2448 def debugfsinfo(ui, path="."):
2448 def debugfsinfo(ui, path="."):
2449 """show information detected about current filesystem"""
2449 """show information detected about current filesystem"""
2450 util.writefile('.debugfsinfo', '')
2450 util.writefile('.debugfsinfo', '')
2451 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2451 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2452 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2452 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2453 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2453 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2454 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2454 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2455 and 'yes' or 'no'))
2455 and 'yes' or 'no'))
2456 os.unlink('.debugfsinfo')
2456 os.unlink('.debugfsinfo')
2457
2457
2458 @command('debuggetbundle',
2458 @command('debuggetbundle',
2459 [('H', 'head', [], _('id of head node'), _('ID')),
2459 [('H', 'head', [], _('id of head node'), _('ID')),
2460 ('C', 'common', [], _('id of common node'), _('ID')),
2460 ('C', 'common', [], _('id of common node'), _('ID')),
2461 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2461 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2462 _('REPO FILE [-H|-C ID]...'),
2462 _('REPO FILE [-H|-C ID]...'),
2463 norepo=True)
2463 norepo=True)
2464 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2464 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2465 """retrieves a bundle from a repo
2465 """retrieves a bundle from a repo
2466
2466
2467 Every ID must be a full-length hex node id string. Saves the bundle to the
2467 Every ID must be a full-length hex node id string. Saves the bundle to the
2468 given file.
2468 given file.
2469 """
2469 """
2470 repo = hg.peer(ui, opts, repopath)
2470 repo = hg.peer(ui, opts, repopath)
2471 if not repo.capable('getbundle'):
2471 if not repo.capable('getbundle'):
2472 raise error.Abort("getbundle() not supported by target repository")
2472 raise error.Abort("getbundle() not supported by target repository")
2473 args = {}
2473 args = {}
2474 if common:
2474 if common:
2475 args['common'] = [bin(s) for s in common]
2475 args['common'] = [bin(s) for s in common]
2476 if head:
2476 if head:
2477 args['heads'] = [bin(s) for s in head]
2477 args['heads'] = [bin(s) for s in head]
2478 # TODO: get desired bundlecaps from command line.
2478 # TODO: get desired bundlecaps from command line.
2479 args['bundlecaps'] = None
2479 args['bundlecaps'] = None
2480 bundle = repo.getbundle('debug', **args)
2480 bundle = repo.getbundle('debug', **args)
2481
2481
2482 bundletype = opts.get('type', 'bzip2').lower()
2482 bundletype = opts.get('type', 'bzip2').lower()
2483 btypes = {'none': 'HG10UN',
2483 btypes = {'none': 'HG10UN',
2484 'bzip2': 'HG10BZ',
2484 'bzip2': 'HG10BZ',
2485 'gzip': 'HG10GZ',
2485 'gzip': 'HG10GZ',
2486 'bundle2': 'HG20'}
2486 'bundle2': 'HG20'}
2487 bundletype = btypes.get(bundletype)
2487 bundletype = btypes.get(bundletype)
2488 if bundletype not in bundle2.bundletypes:
2488 if bundletype not in bundle2.bundletypes:
2489 raise error.Abort(_('unknown bundle type specified with --type'))
2489 raise error.Abort(_('unknown bundle type specified with --type'))
2490 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2490 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2491
2491
2492 @command('debugignore', [], '[FILE]')
2492 @command('debugignore', [], '[FILE]')
2493 def debugignore(ui, repo, *files, **opts):
2493 def debugignore(ui, repo, *files, **opts):
2494 """display the combined ignore pattern and information about ignored files
2494 """display the combined ignore pattern and information about ignored files
2495
2495
2496 With no argument display the combined ignore pattern.
2496 With no argument display the combined ignore pattern.
2497
2497
2498 Given space separated file names, shows if the given file is ignored and
2498 Given space separated file names, shows if the given file is ignored and
2499 if so, show the ignore rule (file and line number) that matched it.
2499 if so, show the ignore rule (file and line number) that matched it.
2500 """
2500 """
2501 ignore = repo.dirstate._ignore
2501 ignore = repo.dirstate._ignore
2502 if not files:
2502 if not files:
2503 # Show all the patterns
2503 # Show all the patterns
2504 includepat = getattr(ignore, 'includepat', None)
2504 includepat = getattr(ignore, 'includepat', None)
2505 if includepat is not None:
2505 if includepat is not None:
2506 ui.write("%s\n" % includepat)
2506 ui.write("%s\n" % includepat)
2507 else:
2507 else:
2508 raise error.Abort(_("no ignore patterns found"))
2508 raise error.Abort(_("no ignore patterns found"))
2509 else:
2509 else:
2510 for f in files:
2510 for f in files:
2511 nf = util.normpath(f)
2511 nf = util.normpath(f)
2512 ignored = None
2512 ignored = None
2513 ignoredata = None
2513 ignoredata = None
2514 if nf != '.':
2514 if nf != '.':
2515 if ignore(nf):
2515 if ignore(nf):
2516 ignored = nf
2516 ignored = nf
2517 ignoredata = repo.dirstate._ignorefileandline(nf)
2517 ignoredata = repo.dirstate._ignorefileandline(nf)
2518 else:
2518 else:
2519 for p in util.finddirs(nf):
2519 for p in util.finddirs(nf):
2520 if ignore(p):
2520 if ignore(p):
2521 ignored = p
2521 ignored = p
2522 ignoredata = repo.dirstate._ignorefileandline(p)
2522 ignoredata = repo.dirstate._ignorefileandline(p)
2523 break
2523 break
2524 if ignored:
2524 if ignored:
2525 if ignored == nf:
2525 if ignored == nf:
2526 ui.write("%s is ignored\n" % f)
2526 ui.write("%s is ignored\n" % f)
2527 else:
2527 else:
2528 ui.write("%s is ignored because of containing folder %s\n"
2528 ui.write("%s is ignored because of containing folder %s\n"
2529 % (f, ignored))
2529 % (f, ignored))
2530 ignorefile, lineno, line = ignoredata
2530 ignorefile, lineno, line = ignoredata
2531 ui.write("(ignore rule in %s, line %d: '%s')\n"
2531 ui.write("(ignore rule in %s, line %d: '%s')\n"
2532 % (ignorefile, lineno, line))
2532 % (ignorefile, lineno, line))
2533 else:
2533 else:
2534 ui.write("%s is not ignored\n" % f)
2534 ui.write("%s is not ignored\n" % f)
2535
2535
2536 @command('debugindex', debugrevlogopts +
2536 @command('debugindex', debugrevlogopts +
2537 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2537 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2538 _('[-f FORMAT] -c|-m|FILE'),
2538 _('[-f FORMAT] -c|-m|FILE'),
2539 optionalrepo=True)
2539 optionalrepo=True)
2540 def debugindex(ui, repo, file_=None, **opts):
2540 def debugindex(ui, repo, file_=None, **opts):
2541 """dump the contents of an index file"""
2541 """dump the contents of an index file"""
2542 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2542 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2543 format = opts.get('format', 0)
2543 format = opts.get('format', 0)
2544 if format not in (0, 1):
2544 if format not in (0, 1):
2545 raise error.Abort(_("unknown format %d") % format)
2545 raise error.Abort(_("unknown format %d") % format)
2546
2546
2547 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2547 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2548 if generaldelta:
2548 if generaldelta:
2549 basehdr = ' delta'
2549 basehdr = ' delta'
2550 else:
2550 else:
2551 basehdr = ' base'
2551 basehdr = ' base'
2552
2552
2553 if ui.debugflag:
2553 if ui.debugflag:
2554 shortfn = hex
2554 shortfn = hex
2555 else:
2555 else:
2556 shortfn = short
2556 shortfn = short
2557
2557
2558 # There might not be anything in r, so have a sane default
2558 # There might not be anything in r, so have a sane default
2559 idlen = 12
2559 idlen = 12
2560 for i in r:
2560 for i in r:
2561 idlen = len(shortfn(r.node(i)))
2561 idlen = len(shortfn(r.node(i)))
2562 break
2562 break
2563
2563
2564 if format == 0:
2564 if format == 0:
2565 ui.write(" rev offset length " + basehdr + " linkrev"
2565 ui.write(" rev offset length " + basehdr + " linkrev"
2566 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2566 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2567 elif format == 1:
2567 elif format == 1:
2568 ui.write(" rev flag offset length"
2568 ui.write(" rev flag offset length"
2569 " size " + basehdr + " link p1 p2"
2569 " size " + basehdr + " link p1 p2"
2570 " %s\n" % "nodeid".rjust(idlen))
2570 " %s\n" % "nodeid".rjust(idlen))
2571
2571
2572 for i in r:
2572 for i in r:
2573 node = r.node(i)
2573 node = r.node(i)
2574 if generaldelta:
2574 if generaldelta:
2575 base = r.deltaparent(i)
2575 base = r.deltaparent(i)
2576 else:
2576 else:
2577 base = r.chainbase(i)
2577 base = r.chainbase(i)
2578 if format == 0:
2578 if format == 0:
2579 try:
2579 try:
2580 pp = r.parents(node)
2580 pp = r.parents(node)
2581 except Exception:
2581 except Exception:
2582 pp = [nullid, nullid]
2582 pp = [nullid, nullid]
2583 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2583 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2584 i, r.start(i), r.length(i), base, r.linkrev(i),
2584 i, r.start(i), r.length(i), base, r.linkrev(i),
2585 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2585 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2586 elif format == 1:
2586 elif format == 1:
2587 pr = r.parentrevs(i)
2587 pr = r.parentrevs(i)
2588 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2588 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2589 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2589 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2590 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2590 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2591
2591
2592 @command('debugindexdot', debugrevlogopts,
2592 @command('debugindexdot', debugrevlogopts,
2593 _('-c|-m|FILE'), optionalrepo=True)
2593 _('-c|-m|FILE'), optionalrepo=True)
2594 def debugindexdot(ui, repo, file_=None, **opts):
2594 def debugindexdot(ui, repo, file_=None, **opts):
2595 """dump an index DAG as a graphviz dot file"""
2595 """dump an index DAG as a graphviz dot file"""
2596 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2596 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2597 ui.write(("digraph G {\n"))
2597 ui.write(("digraph G {\n"))
2598 for i in r:
2598 for i in r:
2599 node = r.node(i)
2599 node = r.node(i)
2600 pp = r.parents(node)
2600 pp = r.parents(node)
2601 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2601 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2602 if pp[1] != nullid:
2602 if pp[1] != nullid:
2603 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2603 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2604 ui.write("}\n")
2604 ui.write("}\n")
2605
2605
2606 @command('debugdeltachain',
2606 @command('debugdeltachain',
2607 debugrevlogopts + formatteropts,
2607 debugrevlogopts + formatteropts,
2608 _('-c|-m|FILE'),
2608 _('-c|-m|FILE'),
2609 optionalrepo=True)
2609 optionalrepo=True)
2610 def debugdeltachain(ui, repo, file_=None, **opts):
2610 def debugdeltachain(ui, repo, file_=None, **opts):
2611 """dump information about delta chains in a revlog
2611 """dump information about delta chains in a revlog
2612
2612
2613 Output can be templatized. Available template keywords are:
2613 Output can be templatized. Available template keywords are:
2614
2614
2615 rev revision number
2615 rev revision number
2616 chainid delta chain identifier (numbered by unique base)
2616 chainid delta chain identifier (numbered by unique base)
2617 chainlen delta chain length to this revision
2617 chainlen delta chain length to this revision
2618 prevrev previous revision in delta chain
2618 prevrev previous revision in delta chain
2619 deltatype role of delta / how it was computed
2619 deltatype role of delta / how it was computed
2620 compsize compressed size of revision
2620 compsize compressed size of revision
2621 uncompsize uncompressed size of revision
2621 uncompsize uncompressed size of revision
2622 chainsize total size of compressed revisions in chain
2622 chainsize total size of compressed revisions in chain
2623 chainratio total chain size divided by uncompressed revision size
2623 chainratio total chain size divided by uncompressed revision size
2624 (new delta chains typically start at ratio 2.00)
2624 (new delta chains typically start at ratio 2.00)
2625 lindist linear distance from base revision in delta chain to end
2625 lindist linear distance from base revision in delta chain to end
2626 of this revision
2626 of this revision
2627 extradist total size of revisions not part of this delta chain from
2627 extradist total size of revisions not part of this delta chain from
2628 base of delta chain to end of this revision; a measurement
2628 base of delta chain to end of this revision; a measurement
2629 of how much extra data we need to read/seek across to read
2629 of how much extra data we need to read/seek across to read
2630 the delta chain for this revision
2630 the delta chain for this revision
2631 extraratio extradist divided by chainsize; another representation of
2631 extraratio extradist divided by chainsize; another representation of
2632 how much unrelated data is needed to load this delta chain
2632 how much unrelated data is needed to load this delta chain
2633 """
2633 """
2634 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2634 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2635 index = r.index
2635 index = r.index
2636 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2636 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2637
2637
2638 def revinfo(rev):
2638 def revinfo(rev):
2639 e = index[rev]
2639 e = index[rev]
2640 compsize = e[1]
2640 compsize = e[1]
2641 uncompsize = e[2]
2641 uncompsize = e[2]
2642 chainsize = 0
2642 chainsize = 0
2643
2643
2644 if generaldelta:
2644 if generaldelta:
2645 if e[3] == e[5]:
2645 if e[3] == e[5]:
2646 deltatype = 'p1'
2646 deltatype = 'p1'
2647 elif e[3] == e[6]:
2647 elif e[3] == e[6]:
2648 deltatype = 'p2'
2648 deltatype = 'p2'
2649 elif e[3] == rev - 1:
2649 elif e[3] == rev - 1:
2650 deltatype = 'prev'
2650 deltatype = 'prev'
2651 elif e[3] == rev:
2651 elif e[3] == rev:
2652 deltatype = 'base'
2652 deltatype = 'base'
2653 else:
2653 else:
2654 deltatype = 'other'
2654 deltatype = 'other'
2655 else:
2655 else:
2656 if e[3] == rev:
2656 if e[3] == rev:
2657 deltatype = 'base'
2657 deltatype = 'base'
2658 else:
2658 else:
2659 deltatype = 'prev'
2659 deltatype = 'prev'
2660
2660
2661 chain = r._deltachain(rev)[0]
2661 chain = r._deltachain(rev)[0]
2662 for iterrev in chain:
2662 for iterrev in chain:
2663 e = index[iterrev]
2663 e = index[iterrev]
2664 chainsize += e[1]
2664 chainsize += e[1]
2665
2665
2666 return compsize, uncompsize, deltatype, chain, chainsize
2666 return compsize, uncompsize, deltatype, chain, chainsize
2667
2667
2668 fm = ui.formatter('debugdeltachain', opts)
2668 fm = ui.formatter('debugdeltachain', opts)
2669
2669
2670 fm.plain(' rev chain# chainlen prev delta '
2670 fm.plain(' rev chain# chainlen prev delta '
2671 'size rawsize chainsize ratio lindist extradist '
2671 'size rawsize chainsize ratio lindist extradist '
2672 'extraratio\n')
2672 'extraratio\n')
2673
2673
2674 chainbases = {}
2674 chainbases = {}
2675 for rev in r:
2675 for rev in r:
2676 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2676 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2677 chainbase = chain[0]
2677 chainbase = chain[0]
2678 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2678 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2679 basestart = r.start(chainbase)
2679 basestart = r.start(chainbase)
2680 revstart = r.start(rev)
2680 revstart = r.start(rev)
2681 lineardist = revstart + comp - basestart
2681 lineardist = revstart + comp - basestart
2682 extradist = lineardist - chainsize
2682 extradist = lineardist - chainsize
2683 try:
2683 try:
2684 prevrev = chain[-2]
2684 prevrev = chain[-2]
2685 except IndexError:
2685 except IndexError:
2686 prevrev = -1
2686 prevrev = -1
2687
2687
2688 chainratio = float(chainsize) / float(uncomp)
2688 chainratio = float(chainsize) / float(uncomp)
2689 extraratio = float(extradist) / float(chainsize)
2689 extraratio = float(extradist) / float(chainsize)
2690
2690
2691 fm.startitem()
2691 fm.startitem()
2692 fm.write('rev chainid chainlen prevrev deltatype compsize '
2692 fm.write('rev chainid chainlen prevrev deltatype compsize '
2693 'uncompsize chainsize chainratio lindist extradist '
2693 'uncompsize chainsize chainratio lindist extradist '
2694 'extraratio',
2694 'extraratio',
2695 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2695 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2696 rev, chainid, len(chain), prevrev, deltatype, comp,
2696 rev, chainid, len(chain), prevrev, deltatype, comp,
2697 uncomp, chainsize, chainratio, lineardist, extradist,
2697 uncomp, chainsize, chainratio, lineardist, extradist,
2698 extraratio,
2698 extraratio,
2699 rev=rev, chainid=chainid, chainlen=len(chain),
2699 rev=rev, chainid=chainid, chainlen=len(chain),
2700 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2700 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2701 uncompsize=uncomp, chainsize=chainsize,
2701 uncompsize=uncomp, chainsize=chainsize,
2702 chainratio=chainratio, lindist=lineardist,
2702 chainratio=chainratio, lindist=lineardist,
2703 extradist=extradist, extraratio=extraratio)
2703 extradist=extradist, extraratio=extraratio)
2704
2704
2705 fm.end()
2705 fm.end()
2706
2706
2707 @command('debuginstall', [] + formatteropts, '', norepo=True)
2707 @command('debuginstall', [] + formatteropts, '', norepo=True)
2708 def debuginstall(ui, **opts):
2708 def debuginstall(ui, **opts):
2709 '''test Mercurial installation
2709 '''test Mercurial installation
2710
2710
2711 Returns 0 on success.
2711 Returns 0 on success.
2712 '''
2712 '''
2713
2713
2714 def writetemp(contents):
2714 def writetemp(contents):
2715 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2715 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2716 f = os.fdopen(fd, "wb")
2716 f = os.fdopen(fd, "wb")
2717 f.write(contents)
2717 f.write(contents)
2718 f.close()
2718 f.close()
2719 return name
2719 return name
2720
2720
2721 problems = 0
2721 problems = 0
2722
2722
2723 fm = ui.formatter('debuginstall', opts)
2723 fm = ui.formatter('debuginstall', opts)
2724 fm.startitem()
2724 fm.startitem()
2725
2725
2726 # encoding
2726 # encoding
2727 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2727 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2728 err = None
2728 err = None
2729 try:
2729 try:
2730 encoding.fromlocal("test")
2730 encoding.fromlocal("test")
2731 except error.Abort as inst:
2731 except error.Abort as inst:
2732 err = inst
2732 err = inst
2733 problems += 1
2733 problems += 1
2734 fm.condwrite(err, 'encodingerror', _(" %s\n"
2734 fm.condwrite(err, 'encodingerror', _(" %s\n"
2735 " (check that your locale is properly set)\n"), err)
2735 " (check that your locale is properly set)\n"), err)
2736
2736
2737 # Python
2737 # Python
2738 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2738 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2739 sys.executable)
2739 sys.executable)
2740 fm.write('pythonver', _("checking Python version (%s)\n"),
2740 fm.write('pythonver', _("checking Python version (%s)\n"),
2741 ("%s.%s.%s" % sys.version_info[:3]))
2741 ("%s.%s.%s" % sys.version_info[:3]))
2742 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2742 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2743 os.path.dirname(os.__file__))
2743 os.path.dirname(os.__file__))
2744
2744
2745 # compiled modules
2745 # compiled modules
2746 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2746 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2747 os.path.dirname(__file__))
2747 os.path.dirname(__file__))
2748
2748
2749 err = None
2749 err = None
2750 try:
2750 try:
2751 from . import (
2751 from . import (
2752 base85,
2752 base85,
2753 bdiff,
2753 bdiff,
2754 mpatch,
2754 mpatch,
2755 osutil,
2755 osutil,
2756 )
2756 )
2757 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2757 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2758 except Exception as inst:
2758 except Exception as inst:
2759 err = inst
2759 err = inst
2760 problems += 1
2760 problems += 1
2761 fm.condwrite(err, 'extensionserror', " %s\n", err)
2761 fm.condwrite(err, 'extensionserror', " %s\n", err)
2762
2762
2763 # templates
2763 # templates
2764 p = templater.templatepaths()
2764 p = templater.templatepaths()
2765 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2765 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2766 fm.condwrite(not p, '', _(" no template directories found\n"))
2766 fm.condwrite(not p, '', _(" no template directories found\n"))
2767 if p:
2767 if p:
2768 m = templater.templatepath("map-cmdline.default")
2768 m = templater.templatepath("map-cmdline.default")
2769 if m:
2769 if m:
2770 # template found, check if it is working
2770 # template found, check if it is working
2771 err = None
2771 err = None
2772 try:
2772 try:
2773 templater.templater(m)
2773 templater.templater(m)
2774 except Exception as inst:
2774 except Exception as inst:
2775 err = inst
2775 err = inst
2776 p = None
2776 p = None
2777 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2777 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2778 else:
2778 else:
2779 p = None
2779 p = None
2780 fm.condwrite(p, 'defaulttemplate',
2780 fm.condwrite(p, 'defaulttemplate',
2781 _("checking default template (%s)\n"), m)
2781 _("checking default template (%s)\n"), m)
2782 fm.condwrite(not m, 'defaulttemplatenotfound',
2782 fm.condwrite(not m, 'defaulttemplatenotfound',
2783 _(" template '%s' not found\n"), "default")
2783 _(" template '%s' not found\n"), "default")
2784 if not p:
2784 if not p:
2785 problems += 1
2785 problems += 1
2786 fm.condwrite(not p, '',
2786 fm.condwrite(not p, '',
2787 _(" (templates seem to have been installed incorrectly)\n"))
2787 _(" (templates seem to have been installed incorrectly)\n"))
2788
2788
2789 # editor
2789 # editor
2790 editor = ui.geteditor()
2790 editor = ui.geteditor()
2791 editor = util.expandpath(editor)
2791 editor = util.expandpath(editor)
2792 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2792 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2793 cmdpath = util.findexe(shlex.split(editor)[0])
2793 cmdpath = util.findexe(shlex.split(editor)[0])
2794 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2794 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2795 _(" No commit editor set and can't find %s in PATH\n"
2795 _(" No commit editor set and can't find %s in PATH\n"
2796 " (specify a commit editor in your configuration"
2796 " (specify a commit editor in your configuration"
2797 " file)\n"), not cmdpath and editor == 'vi' and editor)
2797 " file)\n"), not cmdpath and editor == 'vi' and editor)
2798 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2798 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2799 _(" Can't find editor '%s' in PATH\n"
2799 _(" Can't find editor '%s' in PATH\n"
2800 " (specify a commit editor in your configuration"
2800 " (specify a commit editor in your configuration"
2801 " file)\n"), not cmdpath and editor)
2801 " file)\n"), not cmdpath and editor)
2802 if not cmdpath and editor != 'vi':
2802 if not cmdpath and editor != 'vi':
2803 problems += 1
2803 problems += 1
2804
2804
2805 # check username
2805 # check username
2806 username = None
2806 username = None
2807 err = None
2807 err = None
2808 try:
2808 try:
2809 username = ui.username()
2809 username = ui.username()
2810 except error.Abort as e:
2810 except error.Abort as e:
2811 err = e
2811 err = e
2812 problems += 1
2812 problems += 1
2813
2813
2814 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2814 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2815 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2815 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2816 " (specify a username in your configuration file)\n"), err)
2816 " (specify a username in your configuration file)\n"), err)
2817
2817
2818 fm.condwrite(not problems, '',
2818 fm.condwrite(not problems, '',
2819 _("no problems detected\n"))
2819 _("no problems detected\n"))
2820 if not problems:
2820 if not problems:
2821 fm.data(problems=problems)
2821 fm.data(problems=problems)
2822 fm.condwrite(problems, 'problems',
2822 fm.condwrite(problems, 'problems',
2823 _("%s problems detected,"
2823 _("%s problems detected,"
2824 " please check your install!\n"), problems)
2824 " please check your install!\n"), problems)
2825 fm.end()
2825 fm.end()
2826
2826
2827 return problems
2827 return problems
2828
2828
2829 @command('debugknown', [], _('REPO ID...'), norepo=True)
2829 @command('debugknown', [], _('REPO ID...'), norepo=True)
2830 def debugknown(ui, repopath, *ids, **opts):
2830 def debugknown(ui, repopath, *ids, **opts):
2831 """test whether node ids are known to a repo
2831 """test whether node ids are known to a repo
2832
2832
2833 Every ID must be a full-length hex node id string. Returns a list of 0s
2833 Every ID must be a full-length hex node id string. Returns a list of 0s
2834 and 1s indicating unknown/known.
2834 and 1s indicating unknown/known.
2835 """
2835 """
2836 repo = hg.peer(ui, opts, repopath)
2836 repo = hg.peer(ui, opts, repopath)
2837 if not repo.capable('known'):
2837 if not repo.capable('known'):
2838 raise error.Abort("known() not supported by target repository")
2838 raise error.Abort("known() not supported by target repository")
2839 flags = repo.known([bin(s) for s in ids])
2839 flags = repo.known([bin(s) for s in ids])
2840 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2840 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2841
2841
2842 @command('debuglabelcomplete', [], _('LABEL...'))
2842 @command('debuglabelcomplete', [], _('LABEL...'))
2843 def debuglabelcomplete(ui, repo, *args):
2843 def debuglabelcomplete(ui, repo, *args):
2844 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2844 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2845 debugnamecomplete(ui, repo, *args)
2845 debugnamecomplete(ui, repo, *args)
2846
2846
2847 @command('debugmergestate', [], '')
2847 @command('debugmergestate', [], '')
2848 def debugmergestate(ui, repo, *args):
2848 def debugmergestate(ui, repo, *args):
2849 """print merge state
2849 """print merge state
2850
2850
2851 Use --verbose to print out information about whether v1 or v2 merge state
2851 Use --verbose to print out information about whether v1 or v2 merge state
2852 was chosen."""
2852 was chosen."""
2853 def _hashornull(h):
2853 def _hashornull(h):
2854 if h == nullhex:
2854 if h == nullhex:
2855 return 'null'
2855 return 'null'
2856 else:
2856 else:
2857 return h
2857 return h
2858
2858
2859 def printrecords(version):
2859 def printrecords(version):
2860 ui.write(('* version %s records\n') % version)
2860 ui.write(('* version %s records\n') % version)
2861 if version == 1:
2861 if version == 1:
2862 records = v1records
2862 records = v1records
2863 else:
2863 else:
2864 records = v2records
2864 records = v2records
2865
2865
2866 for rtype, record in records:
2866 for rtype, record in records:
2867 # pretty print some record types
2867 # pretty print some record types
2868 if rtype == 'L':
2868 if rtype == 'L':
2869 ui.write(('local: %s\n') % record)
2869 ui.write(('local: %s\n') % record)
2870 elif rtype == 'O':
2870 elif rtype == 'O':
2871 ui.write(('other: %s\n') % record)
2871 ui.write(('other: %s\n') % record)
2872 elif rtype == 'm':
2872 elif rtype == 'm':
2873 driver, mdstate = record.split('\0', 1)
2873 driver, mdstate = record.split('\0', 1)
2874 ui.write(('merge driver: %s (state "%s")\n')
2874 ui.write(('merge driver: %s (state "%s")\n')
2875 % (driver, mdstate))
2875 % (driver, mdstate))
2876 elif rtype in 'FDC':
2876 elif rtype in 'FDC':
2877 r = record.split('\0')
2877 r = record.split('\0')
2878 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2878 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2879 if version == 1:
2879 if version == 1:
2880 onode = 'not stored in v1 format'
2880 onode = 'not stored in v1 format'
2881 flags = r[7]
2881 flags = r[7]
2882 else:
2882 else:
2883 onode, flags = r[7:9]
2883 onode, flags = r[7:9]
2884 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2884 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2885 % (f, rtype, state, _hashornull(hash)))
2885 % (f, rtype, state, _hashornull(hash)))
2886 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2886 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2887 ui.write((' ancestor path: %s (node %s)\n')
2887 ui.write((' ancestor path: %s (node %s)\n')
2888 % (afile, _hashornull(anode)))
2888 % (afile, _hashornull(anode)))
2889 ui.write((' other path: %s (node %s)\n')
2889 ui.write((' other path: %s (node %s)\n')
2890 % (ofile, _hashornull(onode)))
2890 % (ofile, _hashornull(onode)))
2891 elif rtype == 'f':
2891 elif rtype == 'f':
2892 filename, rawextras = record.split('\0', 1)
2892 filename, rawextras = record.split('\0', 1)
2893 extras = rawextras.split('\0')
2893 extras = rawextras.split('\0')
2894 i = 0
2894 i = 0
2895 extrastrings = []
2895 extrastrings = []
2896 while i < len(extras):
2896 while i < len(extras):
2897 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2897 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2898 i += 2
2898 i += 2
2899
2899
2900 ui.write(('file extras: %s (%s)\n')
2900 ui.write(('file extras: %s (%s)\n')
2901 % (filename, ', '.join(extrastrings)))
2901 % (filename, ', '.join(extrastrings)))
2902 elif rtype == 'l':
2902 elif rtype == 'l':
2903 labels = record.split('\0', 2)
2903 labels = record.split('\0', 2)
2904 labels = [l for l in labels if len(l) > 0]
2904 labels = [l for l in labels if len(l) > 0]
2905 ui.write(('labels:\n'))
2905 ui.write(('labels:\n'))
2906 ui.write((' local: %s\n' % labels[0]))
2906 ui.write((' local: %s\n' % labels[0]))
2907 ui.write((' other: %s\n' % labels[1]))
2907 ui.write((' other: %s\n' % labels[1]))
2908 if len(labels) > 2:
2908 if len(labels) > 2:
2909 ui.write((' base: %s\n' % labels[2]))
2909 ui.write((' base: %s\n' % labels[2]))
2910 else:
2910 else:
2911 ui.write(('unrecognized entry: %s\t%s\n')
2911 ui.write(('unrecognized entry: %s\t%s\n')
2912 % (rtype, record.replace('\0', '\t')))
2912 % (rtype, record.replace('\0', '\t')))
2913
2913
2914 # Avoid mergestate.read() since it may raise an exception for unsupported
2914 # Avoid mergestate.read() since it may raise an exception for unsupported
2915 # merge state records. We shouldn't be doing this, but this is OK since this
2915 # merge state records. We shouldn't be doing this, but this is OK since this
2916 # command is pretty low-level.
2916 # command is pretty low-level.
2917 ms = mergemod.mergestate(repo)
2917 ms = mergemod.mergestate(repo)
2918
2918
2919 # sort so that reasonable information is on top
2919 # sort so that reasonable information is on top
2920 v1records = ms._readrecordsv1()
2920 v1records = ms._readrecordsv1()
2921 v2records = ms._readrecordsv2()
2921 v2records = ms._readrecordsv2()
2922 order = 'LOml'
2922 order = 'LOml'
2923 def key(r):
2923 def key(r):
2924 idx = order.find(r[0])
2924 idx = order.find(r[0])
2925 if idx == -1:
2925 if idx == -1:
2926 return (1, r[1])
2926 return (1, r[1])
2927 else:
2927 else:
2928 return (0, idx)
2928 return (0, idx)
2929 v1records.sort(key=key)
2929 v1records.sort(key=key)
2930 v2records.sort(key=key)
2930 v2records.sort(key=key)
2931
2931
2932 if not v1records and not v2records:
2932 if not v1records and not v2records:
2933 ui.write(('no merge state found\n'))
2933 ui.write(('no merge state found\n'))
2934 elif not v2records:
2934 elif not v2records:
2935 ui.note(('no version 2 merge state\n'))
2935 ui.note(('no version 2 merge state\n'))
2936 printrecords(1)
2936 printrecords(1)
2937 elif ms._v1v2match(v1records, v2records):
2937 elif ms._v1v2match(v1records, v2records):
2938 ui.note(('v1 and v2 states match: using v2\n'))
2938 ui.note(('v1 and v2 states match: using v2\n'))
2939 printrecords(2)
2939 printrecords(2)
2940 else:
2940 else:
2941 ui.note(('v1 and v2 states mismatch: using v1\n'))
2941 ui.note(('v1 and v2 states mismatch: using v1\n'))
2942 printrecords(1)
2942 printrecords(1)
2943 if ui.verbose:
2943 if ui.verbose:
2944 printrecords(2)
2944 printrecords(2)
2945
2945
2946 @command('debugnamecomplete', [], _('NAME...'))
2946 @command('debugnamecomplete', [], _('NAME...'))
2947 def debugnamecomplete(ui, repo, *args):
2947 def debugnamecomplete(ui, repo, *args):
2948 '''complete "names" - tags, open branch names, bookmark names'''
2948 '''complete "names" - tags, open branch names, bookmark names'''
2949
2949
2950 names = set()
2950 names = set()
2951 # since we previously only listed open branches, we will handle that
2951 # since we previously only listed open branches, we will handle that
2952 # specially (after this for loop)
2952 # specially (after this for loop)
2953 for name, ns in repo.names.iteritems():
2953 for name, ns in repo.names.iteritems():
2954 if name != 'branches':
2954 if name != 'branches':
2955 names.update(ns.listnames(repo))
2955 names.update(ns.listnames(repo))
2956 names.update(tag for (tag, heads, tip, closed)
2956 names.update(tag for (tag, heads, tip, closed)
2957 in repo.branchmap().iterbranches() if not closed)
2957 in repo.branchmap().iterbranches() if not closed)
2958 completions = set()
2958 completions = set()
2959 if not args:
2959 if not args:
2960 args = ['']
2960 args = ['']
2961 for a in args:
2961 for a in args:
2962 completions.update(n for n in names if n.startswith(a))
2962 completions.update(n for n in names if n.startswith(a))
2963 ui.write('\n'.join(sorted(completions)))
2963 ui.write('\n'.join(sorted(completions)))
2964 ui.write('\n')
2964 ui.write('\n')
2965
2965
2966 @command('debuglocks',
2966 @command('debuglocks',
2967 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2967 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2968 ('W', 'force-wlock', None,
2968 ('W', 'force-wlock', None,
2969 _('free the working state lock (DANGEROUS)'))],
2969 _('free the working state lock (DANGEROUS)'))],
2970 _('[OPTION]...'))
2970 _('[OPTION]...'))
2971 def debuglocks(ui, repo, **opts):
2971 def debuglocks(ui, repo, **opts):
2972 """show or modify state of locks
2972 """show or modify state of locks
2973
2973
2974 By default, this command will show which locks are held. This
2974 By default, this command will show which locks are held. This
2975 includes the user and process holding the lock, the amount of time
2975 includes the user and process holding the lock, the amount of time
2976 the lock has been held, and the machine name where the process is
2976 the lock has been held, and the machine name where the process is
2977 running if it's not local.
2977 running if it's not local.
2978
2978
2979 Locks protect the integrity of Mercurial's data, so should be
2979 Locks protect the integrity of Mercurial's data, so should be
2980 treated with care. System crashes or other interruptions may cause
2980 treated with care. System crashes or other interruptions may cause
2981 locks to not be properly released, though Mercurial will usually
2981 locks to not be properly released, though Mercurial will usually
2982 detect and remove such stale locks automatically.
2982 detect and remove such stale locks automatically.
2983
2983
2984 However, detecting stale locks may not always be possible (for
2984 However, detecting stale locks may not always be possible (for
2985 instance, on a shared filesystem). Removing locks may also be
2985 instance, on a shared filesystem). Removing locks may also be
2986 blocked by filesystem permissions.
2986 blocked by filesystem permissions.
2987
2987
2988 Returns 0 if no locks are held.
2988 Returns 0 if no locks are held.
2989
2989
2990 """
2990 """
2991
2991
2992 if opts.get('force_lock'):
2992 if opts.get('force_lock'):
2993 repo.svfs.unlink('lock')
2993 repo.svfs.unlink('lock')
2994 if opts.get('force_wlock'):
2994 if opts.get('force_wlock'):
2995 repo.vfs.unlink('wlock')
2995 repo.vfs.unlink('wlock')
2996 if opts.get('force_lock') or opts.get('force_lock'):
2996 if opts.get('force_lock') or opts.get('force_lock'):
2997 return 0
2997 return 0
2998
2998
2999 now = time.time()
2999 now = time.time()
3000 held = 0
3000 held = 0
3001
3001
3002 def report(vfs, name, method):
3002 def report(vfs, name, method):
3003 # this causes stale locks to get reaped for more accurate reporting
3003 # this causes stale locks to get reaped for more accurate reporting
3004 try:
3004 try:
3005 l = method(False)
3005 l = method(False)
3006 except error.LockHeld:
3006 except error.LockHeld:
3007 l = None
3007 l = None
3008
3008
3009 if l:
3009 if l:
3010 l.release()
3010 l.release()
3011 else:
3011 else:
3012 try:
3012 try:
3013 stat = vfs.lstat(name)
3013 stat = vfs.lstat(name)
3014 age = now - stat.st_mtime
3014 age = now - stat.st_mtime
3015 user = util.username(stat.st_uid)
3015 user = util.username(stat.st_uid)
3016 locker = vfs.readlock(name)
3016 locker = vfs.readlock(name)
3017 if ":" in locker:
3017 if ":" in locker:
3018 host, pid = locker.split(':')
3018 host, pid = locker.split(':')
3019 if host == socket.gethostname():
3019 if host == socket.gethostname():
3020 locker = 'user %s, process %s' % (user, pid)
3020 locker = 'user %s, process %s' % (user, pid)
3021 else:
3021 else:
3022 locker = 'user %s, process %s, host %s' \
3022 locker = 'user %s, process %s, host %s' \
3023 % (user, pid, host)
3023 % (user, pid, host)
3024 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3024 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3025 return 1
3025 return 1
3026 except OSError as e:
3026 except OSError as e:
3027 if e.errno != errno.ENOENT:
3027 if e.errno != errno.ENOENT:
3028 raise
3028 raise
3029
3029
3030 ui.write("%-6s free\n" % (name + ":"))
3030 ui.write("%-6s free\n" % (name + ":"))
3031 return 0
3031 return 0
3032
3032
3033 held += report(repo.svfs, "lock", repo.lock)
3033 held += report(repo.svfs, "lock", repo.lock)
3034 held += report(repo.vfs, "wlock", repo.wlock)
3034 held += report(repo.vfs, "wlock", repo.wlock)
3035
3035
3036 return held
3036 return held
3037
3037
3038 @command('debugobsolete',
3038 @command('debugobsolete',
3039 [('', 'flags', 0, _('markers flag')),
3039 [('', 'flags', 0, _('markers flag')),
3040 ('', 'record-parents', False,
3040 ('', 'record-parents', False,
3041 _('record parent information for the precursor')),
3041 _('record parent information for the precursor')),
3042 ('r', 'rev', [], _('display markers relevant to REV')),
3042 ('r', 'rev', [], _('display markers relevant to REV')),
3043 ('', 'index', False, _('display index of the marker')),
3043 ('', 'index', False, _('display index of the marker')),
3044 ('', 'delete', [], _('delete markers specified by indices')),
3044 ('', 'delete', [], _('delete markers specified by indices')),
3045 ] + commitopts2,
3045 ] + commitopts2,
3046 _('[OBSOLETED [REPLACEMENT ...]]'))
3046 _('[OBSOLETED [REPLACEMENT ...]]'))
3047 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3047 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3048 """create arbitrary obsolete marker
3048 """create arbitrary obsolete marker
3049
3049
3050 With no arguments, displays the list of obsolescence markers."""
3050 With no arguments, displays the list of obsolescence markers."""
3051
3051
3052 def parsenodeid(s):
3052 def parsenodeid(s):
3053 try:
3053 try:
3054 # We do not use revsingle/revrange functions here to accept
3054 # We do not use revsingle/revrange functions here to accept
3055 # arbitrary node identifiers, possibly not present in the
3055 # arbitrary node identifiers, possibly not present in the
3056 # local repository.
3056 # local repository.
3057 n = bin(s)
3057 n = bin(s)
3058 if len(n) != len(nullid):
3058 if len(n) != len(nullid):
3059 raise TypeError()
3059 raise TypeError()
3060 return n
3060 return n
3061 except TypeError:
3061 except TypeError:
3062 raise error.Abort('changeset references must be full hexadecimal '
3062 raise error.Abort('changeset references must be full hexadecimal '
3063 'node identifiers')
3063 'node identifiers')
3064
3064
3065 if opts.get('delete'):
3065 if opts.get('delete'):
3066 indices = []
3066 indices = []
3067 for v in opts.get('delete'):
3067 for v in opts.get('delete'):
3068 try:
3068 try:
3069 indices.append(int(v))
3069 indices.append(int(v))
3070 except ValueError:
3070 except ValueError:
3071 raise error.Abort(_('invalid index value: %r') % v,
3071 raise error.Abort(_('invalid index value: %r') % v,
3072 hint=_('use integers for indices'))
3072 hint=_('use integers for indices'))
3073
3073
3074 if repo.currenttransaction():
3074 if repo.currenttransaction():
3075 raise error.Abort(_('cannot delete obsmarkers in the middle '
3075 raise error.Abort(_('cannot delete obsmarkers in the middle '
3076 'of transaction.'))
3076 'of transaction.'))
3077
3077
3078 with repo.lock():
3078 with repo.lock():
3079 n = repair.deleteobsmarkers(repo.obsstore, indices)
3079 n = repair.deleteobsmarkers(repo.obsstore, indices)
3080 ui.write(_('deleted %i obsolescense markers\n') % n)
3080 ui.write(_('deleted %i obsolescense markers\n') % n)
3081
3081
3082 return
3082 return
3083
3083
3084 if precursor is not None:
3084 if precursor is not None:
3085 if opts['rev']:
3085 if opts['rev']:
3086 raise error.Abort('cannot select revision when creating marker')
3086 raise error.Abort('cannot select revision when creating marker')
3087 metadata = {}
3087 metadata = {}
3088 metadata['user'] = opts['user'] or ui.username()
3088 metadata['user'] = opts['user'] or ui.username()
3089 succs = tuple(parsenodeid(succ) for succ in successors)
3089 succs = tuple(parsenodeid(succ) for succ in successors)
3090 l = repo.lock()
3090 l = repo.lock()
3091 try:
3091 try:
3092 tr = repo.transaction('debugobsolete')
3092 tr = repo.transaction('debugobsolete')
3093 try:
3093 try:
3094 date = opts.get('date')
3094 date = opts.get('date')
3095 if date:
3095 if date:
3096 date = util.parsedate(date)
3096 date = util.parsedate(date)
3097 else:
3097 else:
3098 date = None
3098 date = None
3099 prec = parsenodeid(precursor)
3099 prec = parsenodeid(precursor)
3100 parents = None
3100 parents = None
3101 if opts['record_parents']:
3101 if opts['record_parents']:
3102 if prec not in repo.unfiltered():
3102 if prec not in repo.unfiltered():
3103 raise error.Abort('cannot used --record-parents on '
3103 raise error.Abort('cannot used --record-parents on '
3104 'unknown changesets')
3104 'unknown changesets')
3105 parents = repo.unfiltered()[prec].parents()
3105 parents = repo.unfiltered()[prec].parents()
3106 parents = tuple(p.node() for p in parents)
3106 parents = tuple(p.node() for p in parents)
3107 repo.obsstore.create(tr, prec, succs, opts['flags'],
3107 repo.obsstore.create(tr, prec, succs, opts['flags'],
3108 parents=parents, date=date,
3108 parents=parents, date=date,
3109 metadata=metadata)
3109 metadata=metadata)
3110 tr.close()
3110 tr.close()
3111 except ValueError as exc:
3111 except ValueError as exc:
3112 raise error.Abort(_('bad obsmarker input: %s') % exc)
3112 raise error.Abort(_('bad obsmarker input: %s') % exc)
3113 finally:
3113 finally:
3114 tr.release()
3114 tr.release()
3115 finally:
3115 finally:
3116 l.release()
3116 l.release()
3117 else:
3117 else:
3118 if opts['rev']:
3118 if opts['rev']:
3119 revs = scmutil.revrange(repo, opts['rev'])
3119 revs = scmutil.revrange(repo, opts['rev'])
3120 nodes = [repo[r].node() for r in revs]
3120 nodes = [repo[r].node() for r in revs]
3121 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3121 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3122 markers.sort(key=lambda x: x._data)
3122 markers.sort(key=lambda x: x._data)
3123 else:
3123 else:
3124 markers = obsolete.getmarkers(repo)
3124 markers = obsolete.getmarkers(repo)
3125
3125
3126 markerstoiter = markers
3126 markerstoiter = markers
3127 isrelevant = lambda m: True
3127 isrelevant = lambda m: True
3128 if opts.get('rev') and opts.get('index'):
3128 if opts.get('rev') and opts.get('index'):
3129 markerstoiter = obsolete.getmarkers(repo)
3129 markerstoiter = obsolete.getmarkers(repo)
3130 markerset = set(markers)
3130 markerset = set(markers)
3131 isrelevant = lambda m: m in markerset
3131 isrelevant = lambda m: m in markerset
3132
3132
3133 for i, m in enumerate(markerstoiter):
3133 for i, m in enumerate(markerstoiter):
3134 if not isrelevant(m):
3134 if not isrelevant(m):
3135 # marker can be irrelevant when we're iterating over a set
3135 # marker can be irrelevant when we're iterating over a set
3136 # of markers (markerstoiter) which is bigger than the set
3136 # of markers (markerstoiter) which is bigger than the set
3137 # of markers we want to display (markers)
3137 # of markers we want to display (markers)
3138 # this can happen if both --index and --rev options are
3138 # this can happen if both --index and --rev options are
3139 # provided and thus we need to iterate over all of the markers
3139 # provided and thus we need to iterate over all of the markers
3140 # to get the correct indices, but only display the ones that
3140 # to get the correct indices, but only display the ones that
3141 # are relevant to --rev value
3141 # are relevant to --rev value
3142 continue
3142 continue
3143 ind = i if opts.get('index') else None
3143 ind = i if opts.get('index') else None
3144 cmdutil.showmarker(ui, m, index=ind)
3144 cmdutil.showmarker(ui, m, index=ind)
3145
3145
3146 @command('debugpathcomplete',
3146 @command('debugpathcomplete',
3147 [('f', 'full', None, _('complete an entire path')),
3147 [('f', 'full', None, _('complete an entire path')),
3148 ('n', 'normal', None, _('show only normal files')),
3148 ('n', 'normal', None, _('show only normal files')),
3149 ('a', 'added', None, _('show only added files')),
3149 ('a', 'added', None, _('show only added files')),
3150 ('r', 'removed', None, _('show only removed files'))],
3150 ('r', 'removed', None, _('show only removed files'))],
3151 _('FILESPEC...'))
3151 _('FILESPEC...'))
3152 def debugpathcomplete(ui, repo, *specs, **opts):
3152 def debugpathcomplete(ui, repo, *specs, **opts):
3153 '''complete part or all of a tracked path
3153 '''complete part or all of a tracked path
3154
3154
3155 This command supports shells that offer path name completion. It
3155 This command supports shells that offer path name completion. It
3156 currently completes only files already known to the dirstate.
3156 currently completes only files already known to the dirstate.
3157
3157
3158 Completion extends only to the next path segment unless
3158 Completion extends only to the next path segment unless
3159 --full is specified, in which case entire paths are used.'''
3159 --full is specified, in which case entire paths are used.'''
3160
3160
3161 def complete(path, acceptable):
3161 def complete(path, acceptable):
3162 dirstate = repo.dirstate
3162 dirstate = repo.dirstate
3163 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3163 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3164 rootdir = repo.root + os.sep
3164 rootdir = repo.root + os.sep
3165 if spec != repo.root and not spec.startswith(rootdir):
3165 if spec != repo.root and not spec.startswith(rootdir):
3166 return [], []
3166 return [], []
3167 if os.path.isdir(spec):
3167 if os.path.isdir(spec):
3168 spec += '/'
3168 spec += '/'
3169 spec = spec[len(rootdir):]
3169 spec = spec[len(rootdir):]
3170 fixpaths = os.sep != '/'
3170 fixpaths = os.sep != '/'
3171 if fixpaths:
3171 if fixpaths:
3172 spec = spec.replace(os.sep, '/')
3172 spec = spec.replace(os.sep, '/')
3173 speclen = len(spec)
3173 speclen = len(spec)
3174 fullpaths = opts['full']
3174 fullpaths = opts['full']
3175 files, dirs = set(), set()
3175 files, dirs = set(), set()
3176 adddir, addfile = dirs.add, files.add
3176 adddir, addfile = dirs.add, files.add
3177 for f, st in dirstate.iteritems():
3177 for f, st in dirstate.iteritems():
3178 if f.startswith(spec) and st[0] in acceptable:
3178 if f.startswith(spec) and st[0] in acceptable:
3179 if fixpaths:
3179 if fixpaths:
3180 f = f.replace('/', os.sep)
3180 f = f.replace('/', os.sep)
3181 if fullpaths:
3181 if fullpaths:
3182 addfile(f)
3182 addfile(f)
3183 continue
3183 continue
3184 s = f.find(os.sep, speclen)
3184 s = f.find(os.sep, speclen)
3185 if s >= 0:
3185 if s >= 0:
3186 adddir(f[:s])
3186 adddir(f[:s])
3187 else:
3187 else:
3188 addfile(f)
3188 addfile(f)
3189 return files, dirs
3189 return files, dirs
3190
3190
3191 acceptable = ''
3191 acceptable = ''
3192 if opts['normal']:
3192 if opts['normal']:
3193 acceptable += 'nm'
3193 acceptable += 'nm'
3194 if opts['added']:
3194 if opts['added']:
3195 acceptable += 'a'
3195 acceptable += 'a'
3196 if opts['removed']:
3196 if opts['removed']:
3197 acceptable += 'r'
3197 acceptable += 'r'
3198 cwd = repo.getcwd()
3198 cwd = repo.getcwd()
3199 if not specs:
3199 if not specs:
3200 specs = ['.']
3200 specs = ['.']
3201
3201
3202 files, dirs = set(), set()
3202 files, dirs = set(), set()
3203 for spec in specs:
3203 for spec in specs:
3204 f, d = complete(spec, acceptable or 'nmar')
3204 f, d = complete(spec, acceptable or 'nmar')
3205 files.update(f)
3205 files.update(f)
3206 dirs.update(d)
3206 dirs.update(d)
3207 files.update(dirs)
3207 files.update(dirs)
3208 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3208 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3209 ui.write('\n')
3209 ui.write('\n')
3210
3210
3211 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3211 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3212 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3212 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3213 '''access the pushkey key/value protocol
3213 '''access the pushkey key/value protocol
3214
3214
3215 With two args, list the keys in the given namespace.
3215 With two args, list the keys in the given namespace.
3216
3216
3217 With five args, set a key to new if it currently is set to old.
3217 With five args, set a key to new if it currently is set to old.
3218 Reports success or failure.
3218 Reports success or failure.
3219 '''
3219 '''
3220
3220
3221 target = hg.peer(ui, {}, repopath)
3221 target = hg.peer(ui, {}, repopath)
3222 if keyinfo:
3222 if keyinfo:
3223 key, old, new = keyinfo
3223 key, old, new = keyinfo
3224 r = target.pushkey(namespace, key, old, new)
3224 r = target.pushkey(namespace, key, old, new)
3225 ui.status(str(r) + '\n')
3225 ui.status(str(r) + '\n')
3226 return not r
3226 return not r
3227 else:
3227 else:
3228 for k, v in sorted(target.listkeys(namespace).iteritems()):
3228 for k, v in sorted(target.listkeys(namespace).iteritems()):
3229 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3229 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3230 v.encode('string-escape')))
3230 v.encode('string-escape')))
3231
3231
3232 @command('debugpvec', [], _('A B'))
3232 @command('debugpvec', [], _('A B'))
3233 def debugpvec(ui, repo, a, b=None):
3233 def debugpvec(ui, repo, a, b=None):
3234 ca = scmutil.revsingle(repo, a)
3234 ca = scmutil.revsingle(repo, a)
3235 cb = scmutil.revsingle(repo, b)
3235 cb = scmutil.revsingle(repo, b)
3236 pa = pvec.ctxpvec(ca)
3236 pa = pvec.ctxpvec(ca)
3237 pb = pvec.ctxpvec(cb)
3237 pb = pvec.ctxpvec(cb)
3238 if pa == pb:
3238 if pa == pb:
3239 rel = "="
3239 rel = "="
3240 elif pa > pb:
3240 elif pa > pb:
3241 rel = ">"
3241 rel = ">"
3242 elif pa < pb:
3242 elif pa < pb:
3243 rel = "<"
3243 rel = "<"
3244 elif pa | pb:
3244 elif pa | pb:
3245 rel = "|"
3245 rel = "|"
3246 ui.write(_("a: %s\n") % pa)
3246 ui.write(_("a: %s\n") % pa)
3247 ui.write(_("b: %s\n") % pb)
3247 ui.write(_("b: %s\n") % pb)
3248 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3248 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3249 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3249 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3250 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3250 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3251 pa.distance(pb), rel))
3251 pa.distance(pb), rel))
3252
3252
3253 @command('debugrebuilddirstate|debugrebuildstate',
3253 @command('debugrebuilddirstate|debugrebuildstate',
3254 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3254 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3255 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3255 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3256 'the working copy parent')),
3256 'the working copy parent')),
3257 ],
3257 ],
3258 _('[-r REV]'))
3258 _('[-r REV]'))
3259 def debugrebuilddirstate(ui, repo, rev, **opts):
3259 def debugrebuilddirstate(ui, repo, rev, **opts):
3260 """rebuild the dirstate as it would look like for the given revision
3260 """rebuild the dirstate as it would look like for the given revision
3261
3261
3262 If no revision is specified the first current parent will be used.
3262 If no revision is specified the first current parent will be used.
3263
3263
3264 The dirstate will be set to the files of the given revision.
3264 The dirstate will be set to the files of the given revision.
3265 The actual working directory content or existing dirstate
3265 The actual working directory content or existing dirstate
3266 information such as adds or removes is not considered.
3266 information such as adds or removes is not considered.
3267
3267
3268 ``minimal`` will only rebuild the dirstate status for files that claim to be
3268 ``minimal`` will only rebuild the dirstate status for files that claim to be
3269 tracked but are not in the parent manifest, or that exist in the parent
3269 tracked but are not in the parent manifest, or that exist in the parent
3270 manifest but are not in the dirstate. It will not change adds, removes, or
3270 manifest but are not in the dirstate. It will not change adds, removes, or
3271 modified files that are in the working copy parent.
3271 modified files that are in the working copy parent.
3272
3272
3273 One use of this command is to make the next :hg:`status` invocation
3273 One use of this command is to make the next :hg:`status` invocation
3274 check the actual file content.
3274 check the actual file content.
3275 """
3275 """
3276 ctx = scmutil.revsingle(repo, rev)
3276 ctx = scmutil.revsingle(repo, rev)
3277 with repo.wlock():
3277 with repo.wlock():
3278 dirstate = repo.dirstate
3278 dirstate = repo.dirstate
3279 changedfiles = None
3279 changedfiles = None
3280 # See command doc for what minimal does.
3280 # See command doc for what minimal does.
3281 if opts.get('minimal'):
3281 if opts.get('minimal'):
3282 manifestfiles = set(ctx.manifest().keys())
3282 manifestfiles = set(ctx.manifest().keys())
3283 dirstatefiles = set(dirstate)
3283 dirstatefiles = set(dirstate)
3284 manifestonly = manifestfiles - dirstatefiles
3284 manifestonly = manifestfiles - dirstatefiles
3285 dsonly = dirstatefiles - manifestfiles
3285 dsonly = dirstatefiles - manifestfiles
3286 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3286 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3287 changedfiles = manifestonly | dsnotadded
3287 changedfiles = manifestonly | dsnotadded
3288
3288
3289 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3289 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3290
3290
3291 @command('debugrebuildfncache', [], '')
3291 @command('debugrebuildfncache', [], '')
3292 def debugrebuildfncache(ui, repo):
3292 def debugrebuildfncache(ui, repo):
3293 """rebuild the fncache file"""
3293 """rebuild the fncache file"""
3294 repair.rebuildfncache(ui, repo)
3294 repair.rebuildfncache(ui, repo)
3295
3295
3296 @command('debugrename',
3296 @command('debugrename',
3297 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3297 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3298 _('[-r REV] FILE'))
3298 _('[-r REV] FILE'))
3299 def debugrename(ui, repo, file1, *pats, **opts):
3299 def debugrename(ui, repo, file1, *pats, **opts):
3300 """dump rename information"""
3300 """dump rename information"""
3301
3301
3302 ctx = scmutil.revsingle(repo, opts.get('rev'))
3302 ctx = scmutil.revsingle(repo, opts.get('rev'))
3303 m = scmutil.match(ctx, (file1,) + pats, opts)
3303 m = scmutil.match(ctx, (file1,) + pats, opts)
3304 for abs in ctx.walk(m):
3304 for abs in ctx.walk(m):
3305 fctx = ctx[abs]
3305 fctx = ctx[abs]
3306 o = fctx.filelog().renamed(fctx.filenode())
3306 o = fctx.filelog().renamed(fctx.filenode())
3307 rel = m.rel(abs)
3307 rel = m.rel(abs)
3308 if o:
3308 if o:
3309 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3309 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3310 else:
3310 else:
3311 ui.write(_("%s not renamed\n") % rel)
3311 ui.write(_("%s not renamed\n") % rel)
3312
3312
3313 @command('debugrevlog', debugrevlogopts +
3313 @command('debugrevlog', debugrevlogopts +
3314 [('d', 'dump', False, _('dump index data'))],
3314 [('d', 'dump', False, _('dump index data'))],
3315 _('-c|-m|FILE'),
3315 _('-c|-m|FILE'),
3316 optionalrepo=True)
3316 optionalrepo=True)
3317 def debugrevlog(ui, repo, file_=None, **opts):
3317 def debugrevlog(ui, repo, file_=None, **opts):
3318 """show data and statistics about a revlog"""
3318 """show data and statistics about a revlog"""
3319 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3319 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3320
3320
3321 if opts.get("dump"):
3321 if opts.get("dump"):
3322 numrevs = len(r)
3322 numrevs = len(r)
3323 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3323 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3324 " rawsize totalsize compression heads chainlen\n")
3324 " rawsize totalsize compression heads chainlen\n")
3325 ts = 0
3325 ts = 0
3326 heads = set()
3326 heads = set()
3327
3327
3328 for rev in xrange(numrevs):
3328 for rev in xrange(numrevs):
3329 dbase = r.deltaparent(rev)
3329 dbase = r.deltaparent(rev)
3330 if dbase == -1:
3330 if dbase == -1:
3331 dbase = rev
3331 dbase = rev
3332 cbase = r.chainbase(rev)
3332 cbase = r.chainbase(rev)
3333 clen = r.chainlen(rev)
3333 clen = r.chainlen(rev)
3334 p1, p2 = r.parentrevs(rev)
3334 p1, p2 = r.parentrevs(rev)
3335 rs = r.rawsize(rev)
3335 rs = r.rawsize(rev)
3336 ts = ts + rs
3336 ts = ts + rs
3337 heads -= set(r.parentrevs(rev))
3337 heads -= set(r.parentrevs(rev))
3338 heads.add(rev)
3338 heads.add(rev)
3339 try:
3339 try:
3340 compression = ts / r.end(rev)
3340 compression = ts / r.end(rev)
3341 except ZeroDivisionError:
3341 except ZeroDivisionError:
3342 compression = 0
3342 compression = 0
3343 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3343 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3344 "%11d %5d %8d\n" %
3344 "%11d %5d %8d\n" %
3345 (rev, p1, p2, r.start(rev), r.end(rev),
3345 (rev, p1, p2, r.start(rev), r.end(rev),
3346 r.start(dbase), r.start(cbase),
3346 r.start(dbase), r.start(cbase),
3347 r.start(p1), r.start(p2),
3347 r.start(p1), r.start(p2),
3348 rs, ts, compression, len(heads), clen))
3348 rs, ts, compression, len(heads), clen))
3349 return 0
3349 return 0
3350
3350
3351 v = r.version
3351 v = r.version
3352 format = v & 0xFFFF
3352 format = v & 0xFFFF
3353 flags = []
3353 flags = []
3354 gdelta = False
3354 gdelta = False
3355 if v & revlog.REVLOGNGINLINEDATA:
3355 if v & revlog.REVLOGNGINLINEDATA:
3356 flags.append('inline')
3356 flags.append('inline')
3357 if v & revlog.REVLOGGENERALDELTA:
3357 if v & revlog.REVLOGGENERALDELTA:
3358 gdelta = True
3358 gdelta = True
3359 flags.append('generaldelta')
3359 flags.append('generaldelta')
3360 if not flags:
3360 if not flags:
3361 flags = ['(none)']
3361 flags = ['(none)']
3362
3362
3363 nummerges = 0
3363 nummerges = 0
3364 numfull = 0
3364 numfull = 0
3365 numprev = 0
3365 numprev = 0
3366 nump1 = 0
3366 nump1 = 0
3367 nump2 = 0
3367 nump2 = 0
3368 numother = 0
3368 numother = 0
3369 nump1prev = 0
3369 nump1prev = 0
3370 nump2prev = 0
3370 nump2prev = 0
3371 chainlengths = []
3371 chainlengths = []
3372
3372
3373 datasize = [None, 0, 0L]
3373 datasize = [None, 0, 0L]
3374 fullsize = [None, 0, 0L]
3374 fullsize = [None, 0, 0L]
3375 deltasize = [None, 0, 0L]
3375 deltasize = [None, 0, 0L]
3376
3376
3377 def addsize(size, l):
3377 def addsize(size, l):
3378 if l[0] is None or size < l[0]:
3378 if l[0] is None or size < l[0]:
3379 l[0] = size
3379 l[0] = size
3380 if size > l[1]:
3380 if size > l[1]:
3381 l[1] = size
3381 l[1] = size
3382 l[2] += size
3382 l[2] += size
3383
3383
3384 numrevs = len(r)
3384 numrevs = len(r)
3385 for rev in xrange(numrevs):
3385 for rev in xrange(numrevs):
3386 p1, p2 = r.parentrevs(rev)
3386 p1, p2 = r.parentrevs(rev)
3387 delta = r.deltaparent(rev)
3387 delta = r.deltaparent(rev)
3388 if format > 0:
3388 if format > 0:
3389 addsize(r.rawsize(rev), datasize)
3389 addsize(r.rawsize(rev), datasize)
3390 if p2 != nullrev:
3390 if p2 != nullrev:
3391 nummerges += 1
3391 nummerges += 1
3392 size = r.length(rev)
3392 size = r.length(rev)
3393 if delta == nullrev:
3393 if delta == nullrev:
3394 chainlengths.append(0)
3394 chainlengths.append(0)
3395 numfull += 1
3395 numfull += 1
3396 addsize(size, fullsize)
3396 addsize(size, fullsize)
3397 else:
3397 else:
3398 chainlengths.append(chainlengths[delta] + 1)
3398 chainlengths.append(chainlengths[delta] + 1)
3399 addsize(size, deltasize)
3399 addsize(size, deltasize)
3400 if delta == rev - 1:
3400 if delta == rev - 1:
3401 numprev += 1
3401 numprev += 1
3402 if delta == p1:
3402 if delta == p1:
3403 nump1prev += 1
3403 nump1prev += 1
3404 elif delta == p2:
3404 elif delta == p2:
3405 nump2prev += 1
3405 nump2prev += 1
3406 elif delta == p1:
3406 elif delta == p1:
3407 nump1 += 1
3407 nump1 += 1
3408 elif delta == p2:
3408 elif delta == p2:
3409 nump2 += 1
3409 nump2 += 1
3410 elif delta != nullrev:
3410 elif delta != nullrev:
3411 numother += 1
3411 numother += 1
3412
3412
3413 # Adjust size min value for empty cases
3413 # Adjust size min value for empty cases
3414 for size in (datasize, fullsize, deltasize):
3414 for size in (datasize, fullsize, deltasize):
3415 if size[0] is None:
3415 if size[0] is None:
3416 size[0] = 0
3416 size[0] = 0
3417
3417
3418 numdeltas = numrevs - numfull
3418 numdeltas = numrevs - numfull
3419 numoprev = numprev - nump1prev - nump2prev
3419 numoprev = numprev - nump1prev - nump2prev
3420 totalrawsize = datasize[2]
3420 totalrawsize = datasize[2]
3421 datasize[2] /= numrevs
3421 datasize[2] /= numrevs
3422 fulltotal = fullsize[2]
3422 fulltotal = fullsize[2]
3423 fullsize[2] /= numfull
3423 fullsize[2] /= numfull
3424 deltatotal = deltasize[2]
3424 deltatotal = deltasize[2]
3425 if numrevs - numfull > 0:
3425 if numrevs - numfull > 0:
3426 deltasize[2] /= numrevs - numfull
3426 deltasize[2] /= numrevs - numfull
3427 totalsize = fulltotal + deltatotal
3427 totalsize = fulltotal + deltatotal
3428 avgchainlen = sum(chainlengths) / numrevs
3428 avgchainlen = sum(chainlengths) / numrevs
3429 maxchainlen = max(chainlengths)
3429 maxchainlen = max(chainlengths)
3430 compratio = 1
3430 compratio = 1
3431 if totalsize:
3431 if totalsize:
3432 compratio = totalrawsize / totalsize
3432 compratio = totalrawsize / totalsize
3433
3433
3434 basedfmtstr = '%%%dd\n'
3434 basedfmtstr = '%%%dd\n'
3435 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3435 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3436
3436
3437 def dfmtstr(max):
3437 def dfmtstr(max):
3438 return basedfmtstr % len(str(max))
3438 return basedfmtstr % len(str(max))
3439 def pcfmtstr(max, padding=0):
3439 def pcfmtstr(max, padding=0):
3440 return basepcfmtstr % (len(str(max)), ' ' * padding)
3440 return basepcfmtstr % (len(str(max)), ' ' * padding)
3441
3441
3442 def pcfmt(value, total):
3442 def pcfmt(value, total):
3443 if total:
3443 if total:
3444 return (value, 100 * float(value) / total)
3444 return (value, 100 * float(value) / total)
3445 else:
3445 else:
3446 return value, 100.0
3446 return value, 100.0
3447
3447
3448 ui.write(('format : %d\n') % format)
3448 ui.write(('format : %d\n') % format)
3449 ui.write(('flags : %s\n') % ', '.join(flags))
3449 ui.write(('flags : %s\n') % ', '.join(flags))
3450
3450
3451 ui.write('\n')
3451 ui.write('\n')
3452 fmt = pcfmtstr(totalsize)
3452 fmt = pcfmtstr(totalsize)
3453 fmt2 = dfmtstr(totalsize)
3453 fmt2 = dfmtstr(totalsize)
3454 ui.write(('revisions : ') + fmt2 % numrevs)
3454 ui.write(('revisions : ') + fmt2 % numrevs)
3455 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3455 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3456 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3456 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3457 ui.write(('revisions : ') + fmt2 % numrevs)
3457 ui.write(('revisions : ') + fmt2 % numrevs)
3458 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3458 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3459 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3459 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3460 ui.write(('revision size : ') + fmt2 % totalsize)
3460 ui.write(('revision size : ') + fmt2 % totalsize)
3461 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3461 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3462 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3462 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3463
3463
3464 ui.write('\n')
3464 ui.write('\n')
3465 fmt = dfmtstr(max(avgchainlen, compratio))
3465 fmt = dfmtstr(max(avgchainlen, compratio))
3466 ui.write(('avg chain length : ') + fmt % avgchainlen)
3466 ui.write(('avg chain length : ') + fmt % avgchainlen)
3467 ui.write(('max chain length : ') + fmt % maxchainlen)
3467 ui.write(('max chain length : ') + fmt % maxchainlen)
3468 ui.write(('compression ratio : ') + fmt % compratio)
3468 ui.write(('compression ratio : ') + fmt % compratio)
3469
3469
3470 if format > 0:
3470 if format > 0:
3471 ui.write('\n')
3471 ui.write('\n')
3472 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3472 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3473 % tuple(datasize))
3473 % tuple(datasize))
3474 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3474 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3475 % tuple(fullsize))
3475 % tuple(fullsize))
3476 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3476 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3477 % tuple(deltasize))
3477 % tuple(deltasize))
3478
3478
3479 if numdeltas > 0:
3479 if numdeltas > 0:
3480 ui.write('\n')
3480 ui.write('\n')
3481 fmt = pcfmtstr(numdeltas)
3481 fmt = pcfmtstr(numdeltas)
3482 fmt2 = pcfmtstr(numdeltas, 4)
3482 fmt2 = pcfmtstr(numdeltas, 4)
3483 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3483 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3484 if numprev > 0:
3484 if numprev > 0:
3485 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3485 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3486 numprev))
3486 numprev))
3487 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3487 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3488 numprev))
3488 numprev))
3489 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3489 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3490 numprev))
3490 numprev))
3491 if gdelta:
3491 if gdelta:
3492 ui.write(('deltas against p1 : ')
3492 ui.write(('deltas against p1 : ')
3493 + fmt % pcfmt(nump1, numdeltas))
3493 + fmt % pcfmt(nump1, numdeltas))
3494 ui.write(('deltas against p2 : ')
3494 ui.write(('deltas against p2 : ')
3495 + fmt % pcfmt(nump2, numdeltas))
3495 + fmt % pcfmt(nump2, numdeltas))
3496 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3496 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3497 numdeltas))
3497 numdeltas))
3498
3498
3499 @command('debugrevspec',
3499 @command('debugrevspec',
3500 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3500 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3501 ('REVSPEC'))
3501 ('REVSPEC'))
3502 def debugrevspec(ui, repo, expr, **opts):
3502 def debugrevspec(ui, repo, expr, **opts):
3503 """parse and apply a revision specification
3503 """parse and apply a revision specification
3504
3504
3505 Use --verbose to print the parsed tree before and after aliases
3505 Use --verbose to print the parsed tree before and after aliases
3506 expansion.
3506 expansion.
3507 """
3507 """
3508 if ui.verbose:
3508 if ui.verbose:
3509 tree = revset.parse(expr, lookup=repo.__contains__)
3509 tree = revset.parse(expr, lookup=repo.__contains__)
3510 ui.note(revset.prettyformat(tree), "\n")
3510 ui.note(revset.prettyformat(tree), "\n")
3511 newtree = revset.expandaliases(ui, tree)
3511 newtree = revset.expandaliases(ui, tree)
3512 if newtree != tree:
3512 if newtree != tree:
3513 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3513 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3514 tree = newtree
3514 tree = newtree
3515 newtree = revset.foldconcat(tree)
3515 newtree = revset.foldconcat(tree)
3516 if newtree != tree:
3516 if newtree != tree:
3517 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3517 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3518 if opts["optimize"]:
3518 if opts["optimize"]:
3519 weight, optimizedtree = revset.optimize(newtree, True)
3519 weight, optimizedtree = revset.optimize(newtree, True)
3520 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3520 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3521 func = revset.match(ui, expr, repo)
3521 func = revset.match(ui, expr, repo)
3522 revs = func(repo)
3522 revs = func(repo)
3523 if ui.verbose:
3523 if ui.verbose:
3524 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3524 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3525 for c in revs:
3525 for c in revs:
3526 ui.write("%s\n" % c)
3526 ui.write("%s\n" % c)
3527
3527
3528 @command('debugsetparents', [], _('REV1 [REV2]'))
3528 @command('debugsetparents', [], _('REV1 [REV2]'))
3529 def debugsetparents(ui, repo, rev1, rev2=None):
3529 def debugsetparents(ui, repo, rev1, rev2=None):
3530 """manually set the parents of the current working directory
3530 """manually set the parents of the current working directory
3531
3531
3532 This is useful for writing repository conversion tools, but should
3532 This is useful for writing repository conversion tools, but should
3533 be used with care. For example, neither the working directory nor the
3533 be used with care. For example, neither the working directory nor the
3534 dirstate is updated, so file status may be incorrect after running this
3534 dirstate is updated, so file status may be incorrect after running this
3535 command.
3535 command.
3536
3536
3537 Returns 0 on success.
3537 Returns 0 on success.
3538 """
3538 """
3539
3539
3540 r1 = scmutil.revsingle(repo, rev1).node()
3540 r1 = scmutil.revsingle(repo, rev1).node()
3541 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3541 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3542
3542
3543 with repo.wlock():
3543 with repo.wlock():
3544 repo.setparents(r1, r2)
3544 repo.setparents(r1, r2)
3545
3545
3546 @command('debugdirstate|debugstate',
3546 @command('debugdirstate|debugstate',
3547 [('', 'nodates', None, _('do not display the saved mtime')),
3547 [('', 'nodates', None, _('do not display the saved mtime')),
3548 ('', 'datesort', None, _('sort by saved mtime'))],
3548 ('', 'datesort', None, _('sort by saved mtime'))],
3549 _('[OPTION]...'))
3549 _('[OPTION]...'))
3550 def debugstate(ui, repo, **opts):
3550 def debugstate(ui, repo, **opts):
3551 """show the contents of the current dirstate"""
3551 """show the contents of the current dirstate"""
3552
3552
3553 nodates = opts.get('nodates')
3553 nodates = opts.get('nodates')
3554 datesort = opts.get('datesort')
3554 datesort = opts.get('datesort')
3555
3555
3556 timestr = ""
3556 timestr = ""
3557 if datesort:
3557 if datesort:
3558 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3558 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3559 else:
3559 else:
3560 keyfunc = None # sort by filename
3560 keyfunc = None # sort by filename
3561 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3561 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3562 if ent[3] == -1:
3562 if ent[3] == -1:
3563 timestr = 'unset '
3563 timestr = 'unset '
3564 elif nodates:
3564 elif nodates:
3565 timestr = 'set '
3565 timestr = 'set '
3566 else:
3566 else:
3567 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3567 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3568 time.localtime(ent[3]))
3568 time.localtime(ent[3]))
3569 if ent[1] & 0o20000:
3569 if ent[1] & 0o20000:
3570 mode = 'lnk'
3570 mode = 'lnk'
3571 else:
3571 else:
3572 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3572 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3573 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3573 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3574 for f in repo.dirstate.copies():
3574 for f in repo.dirstate.copies():
3575 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3575 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3576
3576
3577 @command('debugsub',
3577 @command('debugsub',
3578 [('r', 'rev', '',
3578 [('r', 'rev', '',
3579 _('revision to check'), _('REV'))],
3579 _('revision to check'), _('REV'))],
3580 _('[-r REV] [REV]'))
3580 _('[-r REV] [REV]'))
3581 def debugsub(ui, repo, rev=None):
3581 def debugsub(ui, repo, rev=None):
3582 ctx = scmutil.revsingle(repo, rev, None)
3582 ctx = scmutil.revsingle(repo, rev, None)
3583 for k, v in sorted(ctx.substate.items()):
3583 for k, v in sorted(ctx.substate.items()):
3584 ui.write(('path %s\n') % k)
3584 ui.write(('path %s\n') % k)
3585 ui.write((' source %s\n') % v[0])
3585 ui.write((' source %s\n') % v[0])
3586 ui.write((' revision %s\n') % v[1])
3586 ui.write((' revision %s\n') % v[1])
3587
3587
3588 @command('debugsuccessorssets',
3588 @command('debugsuccessorssets',
3589 [],
3589 [],
3590 _('[REV]'))
3590 _('[REV]'))
3591 def debugsuccessorssets(ui, repo, *revs):
3591 def debugsuccessorssets(ui, repo, *revs):
3592 """show set of successors for revision
3592 """show set of successors for revision
3593
3593
3594 A successors set of changeset A is a consistent group of revisions that
3594 A successors set of changeset A is a consistent group of revisions that
3595 succeed A. It contains non-obsolete changesets only.
3595 succeed A. It contains non-obsolete changesets only.
3596
3596
3597 In most cases a changeset A has a single successors set containing a single
3597 In most cases a changeset A has a single successors set containing a single
3598 successor (changeset A replaced by A').
3598 successor (changeset A replaced by A').
3599
3599
3600 A changeset that is made obsolete with no successors are called "pruned".
3600 A changeset that is made obsolete with no successors are called "pruned".
3601 Such changesets have no successors sets at all.
3601 Such changesets have no successors sets at all.
3602
3602
3603 A changeset that has been "split" will have a successors set containing
3603 A changeset that has been "split" will have a successors set containing
3604 more than one successor.
3604 more than one successor.
3605
3605
3606 A changeset that has been rewritten in multiple different ways is called
3606 A changeset that has been rewritten in multiple different ways is called
3607 "divergent". Such changesets have multiple successor sets (each of which
3607 "divergent". Such changesets have multiple successor sets (each of which
3608 may also be split, i.e. have multiple successors).
3608 may also be split, i.e. have multiple successors).
3609
3609
3610 Results are displayed as follows::
3610 Results are displayed as follows::
3611
3611
3612 <rev1>
3612 <rev1>
3613 <successors-1A>
3613 <successors-1A>
3614 <rev2>
3614 <rev2>
3615 <successors-2A>
3615 <successors-2A>
3616 <successors-2B1> <successors-2B2> <successors-2B3>
3616 <successors-2B1> <successors-2B2> <successors-2B3>
3617
3617
3618 Here rev2 has two possible (i.e. divergent) successors sets. The first
3618 Here rev2 has two possible (i.e. divergent) successors sets. The first
3619 holds one element, whereas the second holds three (i.e. the changeset has
3619 holds one element, whereas the second holds three (i.e. the changeset has
3620 been split).
3620 been split).
3621 """
3621 """
3622 # passed to successorssets caching computation from one call to another
3622 # passed to successorssets caching computation from one call to another
3623 cache = {}
3623 cache = {}
3624 ctx2str = str
3624 ctx2str = str
3625 node2str = short
3625 node2str = short
3626 if ui.debug():
3626 if ui.debug():
3627 def ctx2str(ctx):
3627 def ctx2str(ctx):
3628 return ctx.hex()
3628 return ctx.hex()
3629 node2str = hex
3629 node2str = hex
3630 for rev in scmutil.revrange(repo, revs):
3630 for rev in scmutil.revrange(repo, revs):
3631 ctx = repo[rev]
3631 ctx = repo[rev]
3632 ui.write('%s\n'% ctx2str(ctx))
3632 ui.write('%s\n'% ctx2str(ctx))
3633 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3633 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3634 if succsset:
3634 if succsset:
3635 ui.write(' ')
3635 ui.write(' ')
3636 ui.write(node2str(succsset[0]))
3636 ui.write(node2str(succsset[0]))
3637 for node in succsset[1:]:
3637 for node in succsset[1:]:
3638 ui.write(' ')
3638 ui.write(' ')
3639 ui.write(node2str(node))
3639 ui.write(node2str(node))
3640 ui.write('\n')
3640 ui.write('\n')
3641
3641
3642 @command('debugtemplate',
3642 @command('debugtemplate',
3643 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3643 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3644 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3644 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3645 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3645 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3646 optionalrepo=True)
3646 optionalrepo=True)
3647 def debugtemplate(ui, repo, tmpl, **opts):
3647 def debugtemplate(ui, repo, tmpl, **opts):
3648 """parse and apply a template
3648 """parse and apply a template
3649
3649
3650 If -r/--rev is given, the template is processed as a log template and
3650 If -r/--rev is given, the template is processed as a log template and
3651 applied to the given changesets. Otherwise, it is processed as a generic
3651 applied to the given changesets. Otherwise, it is processed as a generic
3652 template.
3652 template.
3653
3653
3654 Use --verbose to print the parsed tree.
3654 Use --verbose to print the parsed tree.
3655 """
3655 """
3656 revs = None
3656 revs = None
3657 if opts['rev']:
3657 if opts['rev']:
3658 if repo is None:
3658 if repo is None:
3659 raise error.RepoError(_('there is no Mercurial repository here '
3659 raise error.RepoError(_('there is no Mercurial repository here '
3660 '(.hg not found)'))
3660 '(.hg not found)'))
3661 revs = scmutil.revrange(repo, opts['rev'])
3661 revs = scmutil.revrange(repo, opts['rev'])
3662
3662
3663 props = {}
3663 props = {}
3664 for d in opts['define']:
3664 for d in opts['define']:
3665 try:
3665 try:
3666 k, v = (e.strip() for e in d.split('=', 1))
3666 k, v = (e.strip() for e in d.split('=', 1))
3667 if not k:
3667 if not k:
3668 raise ValueError
3668 raise ValueError
3669 props[k] = v
3669 props[k] = v
3670 except ValueError:
3670 except ValueError:
3671 raise error.Abort(_('malformed keyword definition: %s') % d)
3671 raise error.Abort(_('malformed keyword definition: %s') % d)
3672
3672
3673 if ui.verbose:
3673 if ui.verbose:
3674 aliases = ui.configitems('templatealias')
3674 tree = templater.parse(tmpl)
3675 tree = templater.parse(tmpl)
3675 ui.note(templater.prettyformat(tree), '\n')
3676 ui.note(templater.prettyformat(tree), '\n')
3677 newtree = templater.expandaliases(tree, aliases)
3678 if newtree != tree:
3679 ui.note("* expanded:\n", templater.prettyformat(newtree), '\n')
3676
3680
3677 mapfile = None
3681 mapfile = None
3678 if revs is None:
3682 if revs is None:
3679 k = 'debugtemplate'
3683 k = 'debugtemplate'
3680 t = templater.templater(mapfile)
3684 t = templater.templater(mapfile)
3681 t.cache[k] = tmpl
3685 t.cache[k] = tmpl
3682 ui.write(templater.stringify(t(k, **props)))
3686 ui.write(templater.stringify(t(k, **props)))
3683 else:
3687 else:
3684 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3688 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3685 mapfile, buffered=False)
3689 mapfile, buffered=False)
3686 for r in revs:
3690 for r in revs:
3687 displayer.show(repo[r], **props)
3691 displayer.show(repo[r], **props)
3688 displayer.close()
3692 displayer.close()
3689
3693
3690 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3694 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3691 def debugwalk(ui, repo, *pats, **opts):
3695 def debugwalk(ui, repo, *pats, **opts):
3692 """show how files match on given patterns"""
3696 """show how files match on given patterns"""
3693 m = scmutil.match(repo[None], pats, opts)
3697 m = scmutil.match(repo[None], pats, opts)
3694 items = list(repo.walk(m))
3698 items = list(repo.walk(m))
3695 if not items:
3699 if not items:
3696 return
3700 return
3697 f = lambda fn: fn
3701 f = lambda fn: fn
3698 if ui.configbool('ui', 'slash') and os.sep != '/':
3702 if ui.configbool('ui', 'slash') and os.sep != '/':
3699 f = lambda fn: util.normpath(fn)
3703 f = lambda fn: util.normpath(fn)
3700 fmt = 'f %%-%ds %%-%ds %%s' % (
3704 fmt = 'f %%-%ds %%-%ds %%s' % (
3701 max([len(abs) for abs in items]),
3705 max([len(abs) for abs in items]),
3702 max([len(m.rel(abs)) for abs in items]))
3706 max([len(m.rel(abs)) for abs in items]))
3703 for abs in items:
3707 for abs in items:
3704 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3708 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3705 ui.write("%s\n" % line.rstrip())
3709 ui.write("%s\n" % line.rstrip())
3706
3710
3707 @command('debugwireargs',
3711 @command('debugwireargs',
3708 [('', 'three', '', 'three'),
3712 [('', 'three', '', 'three'),
3709 ('', 'four', '', 'four'),
3713 ('', 'four', '', 'four'),
3710 ('', 'five', '', 'five'),
3714 ('', 'five', '', 'five'),
3711 ] + remoteopts,
3715 ] + remoteopts,
3712 _('REPO [OPTIONS]... [ONE [TWO]]'),
3716 _('REPO [OPTIONS]... [ONE [TWO]]'),
3713 norepo=True)
3717 norepo=True)
3714 def debugwireargs(ui, repopath, *vals, **opts):
3718 def debugwireargs(ui, repopath, *vals, **opts):
3715 repo = hg.peer(ui, opts, repopath)
3719 repo = hg.peer(ui, opts, repopath)
3716 for opt in remoteopts:
3720 for opt in remoteopts:
3717 del opts[opt[1]]
3721 del opts[opt[1]]
3718 args = {}
3722 args = {}
3719 for k, v in opts.iteritems():
3723 for k, v in opts.iteritems():
3720 if v:
3724 if v:
3721 args[k] = v
3725 args[k] = v
3722 # run twice to check that we don't mess up the stream for the next command
3726 # run twice to check that we don't mess up the stream for the next command
3723 res1 = repo.debugwireargs(*vals, **args)
3727 res1 = repo.debugwireargs(*vals, **args)
3724 res2 = repo.debugwireargs(*vals, **args)
3728 res2 = repo.debugwireargs(*vals, **args)
3725 ui.write("%s\n" % res1)
3729 ui.write("%s\n" % res1)
3726 if res1 != res2:
3730 if res1 != res2:
3727 ui.warn("%s\n" % res2)
3731 ui.warn("%s\n" % res2)
3728
3732
3729 @command('^diff',
3733 @command('^diff',
3730 [('r', 'rev', [], _('revision'), _('REV')),
3734 [('r', 'rev', [], _('revision'), _('REV')),
3731 ('c', 'change', '', _('change made by revision'), _('REV'))
3735 ('c', 'change', '', _('change made by revision'), _('REV'))
3732 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3736 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3733 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3737 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3734 inferrepo=True)
3738 inferrepo=True)
3735 def diff(ui, repo, *pats, **opts):
3739 def diff(ui, repo, *pats, **opts):
3736 """diff repository (or selected files)
3740 """diff repository (or selected files)
3737
3741
3738 Show differences between revisions for the specified files.
3742 Show differences between revisions for the specified files.
3739
3743
3740 Differences between files are shown using the unified diff format.
3744 Differences between files are shown using the unified diff format.
3741
3745
3742 .. note::
3746 .. note::
3743
3747
3744 :hg:`diff` may generate unexpected results for merges, as it will
3748 :hg:`diff` may generate unexpected results for merges, as it will
3745 default to comparing against the working directory's first
3749 default to comparing against the working directory's first
3746 parent changeset if no revisions are specified.
3750 parent changeset if no revisions are specified.
3747
3751
3748 When two revision arguments are given, then changes are shown
3752 When two revision arguments are given, then changes are shown
3749 between those revisions. If only one revision is specified then
3753 between those revisions. If only one revision is specified then
3750 that revision is compared to the working directory, and, when no
3754 that revision is compared to the working directory, and, when no
3751 revisions are specified, the working directory files are compared
3755 revisions are specified, the working directory files are compared
3752 to its first parent.
3756 to its first parent.
3753
3757
3754 Alternatively you can specify -c/--change with a revision to see
3758 Alternatively you can specify -c/--change with a revision to see
3755 the changes in that changeset relative to its first parent.
3759 the changes in that changeset relative to its first parent.
3756
3760
3757 Without the -a/--text option, diff will avoid generating diffs of
3761 Without the -a/--text option, diff will avoid generating diffs of
3758 files it detects as binary. With -a, diff will generate a diff
3762 files it detects as binary. With -a, diff will generate a diff
3759 anyway, probably with undesirable results.
3763 anyway, probably with undesirable results.
3760
3764
3761 Use the -g/--git option to generate diffs in the git extended diff
3765 Use the -g/--git option to generate diffs in the git extended diff
3762 format. For more information, read :hg:`help diffs`.
3766 format. For more information, read :hg:`help diffs`.
3763
3767
3764 .. container:: verbose
3768 .. container:: verbose
3765
3769
3766 Examples:
3770 Examples:
3767
3771
3768 - compare a file in the current working directory to its parent::
3772 - compare a file in the current working directory to its parent::
3769
3773
3770 hg diff foo.c
3774 hg diff foo.c
3771
3775
3772 - compare two historical versions of a directory, with rename info::
3776 - compare two historical versions of a directory, with rename info::
3773
3777
3774 hg diff --git -r 1.0:1.2 lib/
3778 hg diff --git -r 1.0:1.2 lib/
3775
3779
3776 - get change stats relative to the last change on some date::
3780 - get change stats relative to the last change on some date::
3777
3781
3778 hg diff --stat -r "date('may 2')"
3782 hg diff --stat -r "date('may 2')"
3779
3783
3780 - diff all newly-added files that contain a keyword::
3784 - diff all newly-added files that contain a keyword::
3781
3785
3782 hg diff "set:added() and grep(GNU)"
3786 hg diff "set:added() and grep(GNU)"
3783
3787
3784 - compare a revision and its parents::
3788 - compare a revision and its parents::
3785
3789
3786 hg diff -c 9353 # compare against first parent
3790 hg diff -c 9353 # compare against first parent
3787 hg diff -r 9353^:9353 # same using revset syntax
3791 hg diff -r 9353^:9353 # same using revset syntax
3788 hg diff -r 9353^2:9353 # compare against the second parent
3792 hg diff -r 9353^2:9353 # compare against the second parent
3789
3793
3790 Returns 0 on success.
3794 Returns 0 on success.
3791 """
3795 """
3792
3796
3793 revs = opts.get('rev')
3797 revs = opts.get('rev')
3794 change = opts.get('change')
3798 change = opts.get('change')
3795 stat = opts.get('stat')
3799 stat = opts.get('stat')
3796 reverse = opts.get('reverse')
3800 reverse = opts.get('reverse')
3797
3801
3798 if revs and change:
3802 if revs and change:
3799 msg = _('cannot specify --rev and --change at the same time')
3803 msg = _('cannot specify --rev and --change at the same time')
3800 raise error.Abort(msg)
3804 raise error.Abort(msg)
3801 elif change:
3805 elif change:
3802 node2 = scmutil.revsingle(repo, change, None).node()
3806 node2 = scmutil.revsingle(repo, change, None).node()
3803 node1 = repo[node2].p1().node()
3807 node1 = repo[node2].p1().node()
3804 else:
3808 else:
3805 node1, node2 = scmutil.revpair(repo, revs)
3809 node1, node2 = scmutil.revpair(repo, revs)
3806
3810
3807 if reverse:
3811 if reverse:
3808 node1, node2 = node2, node1
3812 node1, node2 = node2, node1
3809
3813
3810 diffopts = patch.diffallopts(ui, opts)
3814 diffopts = patch.diffallopts(ui, opts)
3811 m = scmutil.match(repo[node2], pats, opts)
3815 m = scmutil.match(repo[node2], pats, opts)
3812 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3816 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3813 listsubrepos=opts.get('subrepos'),
3817 listsubrepos=opts.get('subrepos'),
3814 root=opts.get('root'))
3818 root=opts.get('root'))
3815
3819
3816 @command('^export',
3820 @command('^export',
3817 [('o', 'output', '',
3821 [('o', 'output', '',
3818 _('print output to file with formatted name'), _('FORMAT')),
3822 _('print output to file with formatted name'), _('FORMAT')),
3819 ('', 'switch-parent', None, _('diff against the second parent')),
3823 ('', 'switch-parent', None, _('diff against the second parent')),
3820 ('r', 'rev', [], _('revisions to export'), _('REV')),
3824 ('r', 'rev', [], _('revisions to export'), _('REV')),
3821 ] + diffopts,
3825 ] + diffopts,
3822 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3826 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3823 def export(ui, repo, *changesets, **opts):
3827 def export(ui, repo, *changesets, **opts):
3824 """dump the header and diffs for one or more changesets
3828 """dump the header and diffs for one or more changesets
3825
3829
3826 Print the changeset header and diffs for one or more revisions.
3830 Print the changeset header and diffs for one or more revisions.
3827 If no revision is given, the parent of the working directory is used.
3831 If no revision is given, the parent of the working directory is used.
3828
3832
3829 The information shown in the changeset header is: author, date,
3833 The information shown in the changeset header is: author, date,
3830 branch name (if non-default), changeset hash, parent(s) and commit
3834 branch name (if non-default), changeset hash, parent(s) and commit
3831 comment.
3835 comment.
3832
3836
3833 .. note::
3837 .. note::
3834
3838
3835 :hg:`export` may generate unexpected diff output for merge
3839 :hg:`export` may generate unexpected diff output for merge
3836 changesets, as it will compare the merge changeset against its
3840 changesets, as it will compare the merge changeset against its
3837 first parent only.
3841 first parent only.
3838
3842
3839 Output may be to a file, in which case the name of the file is
3843 Output may be to a file, in which case the name of the file is
3840 given using a format string. The formatting rules are as follows:
3844 given using a format string. The formatting rules are as follows:
3841
3845
3842 :``%%``: literal "%" character
3846 :``%%``: literal "%" character
3843 :``%H``: changeset hash (40 hexadecimal digits)
3847 :``%H``: changeset hash (40 hexadecimal digits)
3844 :``%N``: number of patches being generated
3848 :``%N``: number of patches being generated
3845 :``%R``: changeset revision number
3849 :``%R``: changeset revision number
3846 :``%b``: basename of the exporting repository
3850 :``%b``: basename of the exporting repository
3847 :``%h``: short-form changeset hash (12 hexadecimal digits)
3851 :``%h``: short-form changeset hash (12 hexadecimal digits)
3848 :``%m``: first line of the commit message (only alphanumeric characters)
3852 :``%m``: first line of the commit message (only alphanumeric characters)
3849 :``%n``: zero-padded sequence number, starting at 1
3853 :``%n``: zero-padded sequence number, starting at 1
3850 :``%r``: zero-padded changeset revision number
3854 :``%r``: zero-padded changeset revision number
3851
3855
3852 Without the -a/--text option, export will avoid generating diffs
3856 Without the -a/--text option, export will avoid generating diffs
3853 of files it detects as binary. With -a, export will generate a
3857 of files it detects as binary. With -a, export will generate a
3854 diff anyway, probably with undesirable results.
3858 diff anyway, probably with undesirable results.
3855
3859
3856 Use the -g/--git option to generate diffs in the git extended diff
3860 Use the -g/--git option to generate diffs in the git extended diff
3857 format. See :hg:`help diffs` for more information.
3861 format. See :hg:`help diffs` for more information.
3858
3862
3859 With the --switch-parent option, the diff will be against the
3863 With the --switch-parent option, the diff will be against the
3860 second parent. It can be useful to review a merge.
3864 second parent. It can be useful to review a merge.
3861
3865
3862 .. container:: verbose
3866 .. container:: verbose
3863
3867
3864 Examples:
3868 Examples:
3865
3869
3866 - use export and import to transplant a bugfix to the current
3870 - use export and import to transplant a bugfix to the current
3867 branch::
3871 branch::
3868
3872
3869 hg export -r 9353 | hg import -
3873 hg export -r 9353 | hg import -
3870
3874
3871 - export all the changesets between two revisions to a file with
3875 - export all the changesets between two revisions to a file with
3872 rename information::
3876 rename information::
3873
3877
3874 hg export --git -r 123:150 > changes.txt
3878 hg export --git -r 123:150 > changes.txt
3875
3879
3876 - split outgoing changes into a series of patches with
3880 - split outgoing changes into a series of patches with
3877 descriptive names::
3881 descriptive names::
3878
3882
3879 hg export -r "outgoing()" -o "%n-%m.patch"
3883 hg export -r "outgoing()" -o "%n-%m.patch"
3880
3884
3881 Returns 0 on success.
3885 Returns 0 on success.
3882 """
3886 """
3883 changesets += tuple(opts.get('rev', []))
3887 changesets += tuple(opts.get('rev', []))
3884 if not changesets:
3888 if not changesets:
3885 changesets = ['.']
3889 changesets = ['.']
3886 revs = scmutil.revrange(repo, changesets)
3890 revs = scmutil.revrange(repo, changesets)
3887 if not revs:
3891 if not revs:
3888 raise error.Abort(_("export requires at least one changeset"))
3892 raise error.Abort(_("export requires at least one changeset"))
3889 if len(revs) > 1:
3893 if len(revs) > 1:
3890 ui.note(_('exporting patches:\n'))
3894 ui.note(_('exporting patches:\n'))
3891 else:
3895 else:
3892 ui.note(_('exporting patch:\n'))
3896 ui.note(_('exporting patch:\n'))
3893 cmdutil.export(repo, revs, template=opts.get('output'),
3897 cmdutil.export(repo, revs, template=opts.get('output'),
3894 switch_parent=opts.get('switch_parent'),
3898 switch_parent=opts.get('switch_parent'),
3895 opts=patch.diffallopts(ui, opts))
3899 opts=patch.diffallopts(ui, opts))
3896
3900
3897 @command('files',
3901 @command('files',
3898 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3902 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3899 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3903 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3900 ] + walkopts + formatteropts + subrepoopts,
3904 ] + walkopts + formatteropts + subrepoopts,
3901 _('[OPTION]... [PATTERN]...'))
3905 _('[OPTION]... [PATTERN]...'))
3902 def files(ui, repo, *pats, **opts):
3906 def files(ui, repo, *pats, **opts):
3903 """list tracked files
3907 """list tracked files
3904
3908
3905 Print files under Mercurial control in the working directory or
3909 Print files under Mercurial control in the working directory or
3906 specified revision whose names match the given patterns (excluding
3910 specified revision whose names match the given patterns (excluding
3907 removed files).
3911 removed files).
3908
3912
3909 If no patterns are given to match, this command prints the names
3913 If no patterns are given to match, this command prints the names
3910 of all files under Mercurial control in the working directory.
3914 of all files under Mercurial control in the working directory.
3911
3915
3912 .. container:: verbose
3916 .. container:: verbose
3913
3917
3914 Examples:
3918 Examples:
3915
3919
3916 - list all files under the current directory::
3920 - list all files under the current directory::
3917
3921
3918 hg files .
3922 hg files .
3919
3923
3920 - shows sizes and flags for current revision::
3924 - shows sizes and flags for current revision::
3921
3925
3922 hg files -vr .
3926 hg files -vr .
3923
3927
3924 - list all files named README::
3928 - list all files named README::
3925
3929
3926 hg files -I "**/README"
3930 hg files -I "**/README"
3927
3931
3928 - list all binary files::
3932 - list all binary files::
3929
3933
3930 hg files "set:binary()"
3934 hg files "set:binary()"
3931
3935
3932 - find files containing a regular expression::
3936 - find files containing a regular expression::
3933
3937
3934 hg files "set:grep('bob')"
3938 hg files "set:grep('bob')"
3935
3939
3936 - search tracked file contents with xargs and grep::
3940 - search tracked file contents with xargs and grep::
3937
3941
3938 hg files -0 | xargs -0 grep foo
3942 hg files -0 | xargs -0 grep foo
3939
3943
3940 See :hg:`help patterns` and :hg:`help filesets` for more information
3944 See :hg:`help patterns` and :hg:`help filesets` for more information
3941 on specifying file patterns.
3945 on specifying file patterns.
3942
3946
3943 Returns 0 if a match is found, 1 otherwise.
3947 Returns 0 if a match is found, 1 otherwise.
3944
3948
3945 """
3949 """
3946 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3950 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3947
3951
3948 end = '\n'
3952 end = '\n'
3949 if opts.get('print0'):
3953 if opts.get('print0'):
3950 end = '\0'
3954 end = '\0'
3951 fm = ui.formatter('files', opts)
3955 fm = ui.formatter('files', opts)
3952 fmt = '%s' + end
3956 fmt = '%s' + end
3953
3957
3954 m = scmutil.match(ctx, pats, opts)
3958 m = scmutil.match(ctx, pats, opts)
3955 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3959 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3956
3960
3957 fm.end()
3961 fm.end()
3958
3962
3959 return ret
3963 return ret
3960
3964
3961 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3965 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3962 def forget(ui, repo, *pats, **opts):
3966 def forget(ui, repo, *pats, **opts):
3963 """forget the specified files on the next commit
3967 """forget the specified files on the next commit
3964
3968
3965 Mark the specified files so they will no longer be tracked
3969 Mark the specified files so they will no longer be tracked
3966 after the next commit.
3970 after the next commit.
3967
3971
3968 This only removes files from the current branch, not from the
3972 This only removes files from the current branch, not from the
3969 entire project history, and it does not delete them from the
3973 entire project history, and it does not delete them from the
3970 working directory.
3974 working directory.
3971
3975
3972 To delete the file from the working directory, see :hg:`remove`.
3976 To delete the file from the working directory, see :hg:`remove`.
3973
3977
3974 To undo a forget before the next commit, see :hg:`add`.
3978 To undo a forget before the next commit, see :hg:`add`.
3975
3979
3976 .. container:: verbose
3980 .. container:: verbose
3977
3981
3978 Examples:
3982 Examples:
3979
3983
3980 - forget newly-added binary files::
3984 - forget newly-added binary files::
3981
3985
3982 hg forget "set:added() and binary()"
3986 hg forget "set:added() and binary()"
3983
3987
3984 - forget files that would be excluded by .hgignore::
3988 - forget files that would be excluded by .hgignore::
3985
3989
3986 hg forget "set:hgignore()"
3990 hg forget "set:hgignore()"
3987
3991
3988 Returns 0 on success.
3992 Returns 0 on success.
3989 """
3993 """
3990
3994
3991 if not pats:
3995 if not pats:
3992 raise error.Abort(_('no files specified'))
3996 raise error.Abort(_('no files specified'))
3993
3997
3994 m = scmutil.match(repo[None], pats, opts)
3998 m = scmutil.match(repo[None], pats, opts)
3995 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3999 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3996 return rejected and 1 or 0
4000 return rejected and 1 or 0
3997
4001
3998 @command(
4002 @command(
3999 'graft',
4003 'graft',
4000 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4004 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4001 ('c', 'continue', False, _('resume interrupted graft')),
4005 ('c', 'continue', False, _('resume interrupted graft')),
4002 ('e', 'edit', False, _('invoke editor on commit messages')),
4006 ('e', 'edit', False, _('invoke editor on commit messages')),
4003 ('', 'log', None, _('append graft info to log message')),
4007 ('', 'log', None, _('append graft info to log message')),
4004 ('f', 'force', False, _('force graft')),
4008 ('f', 'force', False, _('force graft')),
4005 ('D', 'currentdate', False,
4009 ('D', 'currentdate', False,
4006 _('record the current date as commit date')),
4010 _('record the current date as commit date')),
4007 ('U', 'currentuser', False,
4011 ('U', 'currentuser', False,
4008 _('record the current user as committer'), _('DATE'))]
4012 _('record the current user as committer'), _('DATE'))]
4009 + commitopts2 + mergetoolopts + dryrunopts,
4013 + commitopts2 + mergetoolopts + dryrunopts,
4010 _('[OPTION]... [-r REV]... REV...'))
4014 _('[OPTION]... [-r REV]... REV...'))
4011 def graft(ui, repo, *revs, **opts):
4015 def graft(ui, repo, *revs, **opts):
4012 '''copy changes from other branches onto the current branch
4016 '''copy changes from other branches onto the current branch
4013
4017
4014 This command uses Mercurial's merge logic to copy individual
4018 This command uses Mercurial's merge logic to copy individual
4015 changes from other branches without merging branches in the
4019 changes from other branches without merging branches in the
4016 history graph. This is sometimes known as 'backporting' or
4020 history graph. This is sometimes known as 'backporting' or
4017 'cherry-picking'. By default, graft will copy user, date, and
4021 'cherry-picking'. By default, graft will copy user, date, and
4018 description from the source changesets.
4022 description from the source changesets.
4019
4023
4020 Changesets that are ancestors of the current revision, that have
4024 Changesets that are ancestors of the current revision, that have
4021 already been grafted, or that are merges will be skipped.
4025 already been grafted, or that are merges will be skipped.
4022
4026
4023 If --log is specified, log messages will have a comment appended
4027 If --log is specified, log messages will have a comment appended
4024 of the form::
4028 of the form::
4025
4029
4026 (grafted from CHANGESETHASH)
4030 (grafted from CHANGESETHASH)
4027
4031
4028 If --force is specified, revisions will be grafted even if they
4032 If --force is specified, revisions will be grafted even if they
4029 are already ancestors of or have been grafted to the destination.
4033 are already ancestors of or have been grafted to the destination.
4030 This is useful when the revisions have since been backed out.
4034 This is useful when the revisions have since been backed out.
4031
4035
4032 If a graft merge results in conflicts, the graft process is
4036 If a graft merge results in conflicts, the graft process is
4033 interrupted so that the current merge can be manually resolved.
4037 interrupted so that the current merge can be manually resolved.
4034 Once all conflicts are addressed, the graft process can be
4038 Once all conflicts are addressed, the graft process can be
4035 continued with the -c/--continue option.
4039 continued with the -c/--continue option.
4036
4040
4037 .. note::
4041 .. note::
4038
4042
4039 The -c/--continue option does not reapply earlier options, except
4043 The -c/--continue option does not reapply earlier options, except
4040 for --force.
4044 for --force.
4041
4045
4042 .. container:: verbose
4046 .. container:: verbose
4043
4047
4044 Examples:
4048 Examples:
4045
4049
4046 - copy a single change to the stable branch and edit its description::
4050 - copy a single change to the stable branch and edit its description::
4047
4051
4048 hg update stable
4052 hg update stable
4049 hg graft --edit 9393
4053 hg graft --edit 9393
4050
4054
4051 - graft a range of changesets with one exception, updating dates::
4055 - graft a range of changesets with one exception, updating dates::
4052
4056
4053 hg graft -D "2085::2093 and not 2091"
4057 hg graft -D "2085::2093 and not 2091"
4054
4058
4055 - continue a graft after resolving conflicts::
4059 - continue a graft after resolving conflicts::
4056
4060
4057 hg graft -c
4061 hg graft -c
4058
4062
4059 - show the source of a grafted changeset::
4063 - show the source of a grafted changeset::
4060
4064
4061 hg log --debug -r .
4065 hg log --debug -r .
4062
4066
4063 - show revisions sorted by date::
4067 - show revisions sorted by date::
4064
4068
4065 hg log -r "sort(all(), date)"
4069 hg log -r "sort(all(), date)"
4066
4070
4067 See :hg:`help revisions` and :hg:`help revsets` for more about
4071 See :hg:`help revisions` and :hg:`help revsets` for more about
4068 specifying revisions.
4072 specifying revisions.
4069
4073
4070 Returns 0 on successful completion.
4074 Returns 0 on successful completion.
4071 '''
4075 '''
4072 with repo.wlock():
4076 with repo.wlock():
4073 return _dograft(ui, repo, *revs, **opts)
4077 return _dograft(ui, repo, *revs, **opts)
4074
4078
4075 def _dograft(ui, repo, *revs, **opts):
4079 def _dograft(ui, repo, *revs, **opts):
4076 if revs and opts['rev']:
4080 if revs and opts['rev']:
4077 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4081 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4078 'revision ordering!\n'))
4082 'revision ordering!\n'))
4079
4083
4080 revs = list(revs)
4084 revs = list(revs)
4081 revs.extend(opts['rev'])
4085 revs.extend(opts['rev'])
4082
4086
4083 if not opts.get('user') and opts.get('currentuser'):
4087 if not opts.get('user') and opts.get('currentuser'):
4084 opts['user'] = ui.username()
4088 opts['user'] = ui.username()
4085 if not opts.get('date') and opts.get('currentdate'):
4089 if not opts.get('date') and opts.get('currentdate'):
4086 opts['date'] = "%d %d" % util.makedate()
4090 opts['date'] = "%d %d" % util.makedate()
4087
4091
4088 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4092 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4089
4093
4090 cont = False
4094 cont = False
4091 if opts['continue']:
4095 if opts['continue']:
4092 cont = True
4096 cont = True
4093 if revs:
4097 if revs:
4094 raise error.Abort(_("can't specify --continue and revisions"))
4098 raise error.Abort(_("can't specify --continue and revisions"))
4095 # read in unfinished revisions
4099 # read in unfinished revisions
4096 try:
4100 try:
4097 nodes = repo.vfs.read('graftstate').splitlines()
4101 nodes = repo.vfs.read('graftstate').splitlines()
4098 revs = [repo[node].rev() for node in nodes]
4102 revs = [repo[node].rev() for node in nodes]
4099 except IOError as inst:
4103 except IOError as inst:
4100 if inst.errno != errno.ENOENT:
4104 if inst.errno != errno.ENOENT:
4101 raise
4105 raise
4102 cmdutil.wrongtooltocontinue(repo, _('graft'))
4106 cmdutil.wrongtooltocontinue(repo, _('graft'))
4103 else:
4107 else:
4104 cmdutil.checkunfinished(repo)
4108 cmdutil.checkunfinished(repo)
4105 cmdutil.bailifchanged(repo)
4109 cmdutil.bailifchanged(repo)
4106 if not revs:
4110 if not revs:
4107 raise error.Abort(_('no revisions specified'))
4111 raise error.Abort(_('no revisions specified'))
4108 revs = scmutil.revrange(repo, revs)
4112 revs = scmutil.revrange(repo, revs)
4109
4113
4110 skipped = set()
4114 skipped = set()
4111 # check for merges
4115 # check for merges
4112 for rev in repo.revs('%ld and merge()', revs):
4116 for rev in repo.revs('%ld and merge()', revs):
4113 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4117 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4114 skipped.add(rev)
4118 skipped.add(rev)
4115 revs = [r for r in revs if r not in skipped]
4119 revs = [r for r in revs if r not in skipped]
4116 if not revs:
4120 if not revs:
4117 return -1
4121 return -1
4118
4122
4119 # Don't check in the --continue case, in effect retaining --force across
4123 # Don't check in the --continue case, in effect retaining --force across
4120 # --continues. That's because without --force, any revisions we decided to
4124 # --continues. That's because without --force, any revisions we decided to
4121 # skip would have been filtered out here, so they wouldn't have made their
4125 # skip would have been filtered out here, so they wouldn't have made their
4122 # way to the graftstate. With --force, any revisions we would have otherwise
4126 # way to the graftstate. With --force, any revisions we would have otherwise
4123 # skipped would not have been filtered out, and if they hadn't been applied
4127 # skipped would not have been filtered out, and if they hadn't been applied
4124 # already, they'd have been in the graftstate.
4128 # already, they'd have been in the graftstate.
4125 if not (cont or opts.get('force')):
4129 if not (cont or opts.get('force')):
4126 # check for ancestors of dest branch
4130 # check for ancestors of dest branch
4127 crev = repo['.'].rev()
4131 crev = repo['.'].rev()
4128 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4132 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4129 # Cannot use x.remove(y) on smart set, this has to be a list.
4133 # Cannot use x.remove(y) on smart set, this has to be a list.
4130 # XXX make this lazy in the future
4134 # XXX make this lazy in the future
4131 revs = list(revs)
4135 revs = list(revs)
4132 # don't mutate while iterating, create a copy
4136 # don't mutate while iterating, create a copy
4133 for rev in list(revs):
4137 for rev in list(revs):
4134 if rev in ancestors:
4138 if rev in ancestors:
4135 ui.warn(_('skipping ancestor revision %d:%s\n') %
4139 ui.warn(_('skipping ancestor revision %d:%s\n') %
4136 (rev, repo[rev]))
4140 (rev, repo[rev]))
4137 # XXX remove on list is slow
4141 # XXX remove on list is slow
4138 revs.remove(rev)
4142 revs.remove(rev)
4139 if not revs:
4143 if not revs:
4140 return -1
4144 return -1
4141
4145
4142 # analyze revs for earlier grafts
4146 # analyze revs for earlier grafts
4143 ids = {}
4147 ids = {}
4144 for ctx in repo.set("%ld", revs):
4148 for ctx in repo.set("%ld", revs):
4145 ids[ctx.hex()] = ctx.rev()
4149 ids[ctx.hex()] = ctx.rev()
4146 n = ctx.extra().get('source')
4150 n = ctx.extra().get('source')
4147 if n:
4151 if n:
4148 ids[n] = ctx.rev()
4152 ids[n] = ctx.rev()
4149
4153
4150 # check ancestors for earlier grafts
4154 # check ancestors for earlier grafts
4151 ui.debug('scanning for duplicate grafts\n')
4155 ui.debug('scanning for duplicate grafts\n')
4152
4156
4153 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4157 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4154 ctx = repo[rev]
4158 ctx = repo[rev]
4155 n = ctx.extra().get('source')
4159 n = ctx.extra().get('source')
4156 if n in ids:
4160 if n in ids:
4157 try:
4161 try:
4158 r = repo[n].rev()
4162 r = repo[n].rev()
4159 except error.RepoLookupError:
4163 except error.RepoLookupError:
4160 r = None
4164 r = None
4161 if r in revs:
4165 if r in revs:
4162 ui.warn(_('skipping revision %d:%s '
4166 ui.warn(_('skipping revision %d:%s '
4163 '(already grafted to %d:%s)\n')
4167 '(already grafted to %d:%s)\n')
4164 % (r, repo[r], rev, ctx))
4168 % (r, repo[r], rev, ctx))
4165 revs.remove(r)
4169 revs.remove(r)
4166 elif ids[n] in revs:
4170 elif ids[n] in revs:
4167 if r is None:
4171 if r is None:
4168 ui.warn(_('skipping already grafted revision %d:%s '
4172 ui.warn(_('skipping already grafted revision %d:%s '
4169 '(%d:%s also has unknown origin %s)\n')
4173 '(%d:%s also has unknown origin %s)\n')
4170 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4174 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4171 else:
4175 else:
4172 ui.warn(_('skipping already grafted revision %d:%s '
4176 ui.warn(_('skipping already grafted revision %d:%s '
4173 '(%d:%s also has origin %d:%s)\n')
4177 '(%d:%s also has origin %d:%s)\n')
4174 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4178 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4175 revs.remove(ids[n])
4179 revs.remove(ids[n])
4176 elif ctx.hex() in ids:
4180 elif ctx.hex() in ids:
4177 r = ids[ctx.hex()]
4181 r = ids[ctx.hex()]
4178 ui.warn(_('skipping already grafted revision %d:%s '
4182 ui.warn(_('skipping already grafted revision %d:%s '
4179 '(was grafted from %d:%s)\n') %
4183 '(was grafted from %d:%s)\n') %
4180 (r, repo[r], rev, ctx))
4184 (r, repo[r], rev, ctx))
4181 revs.remove(r)
4185 revs.remove(r)
4182 if not revs:
4186 if not revs:
4183 return -1
4187 return -1
4184
4188
4185 for pos, ctx in enumerate(repo.set("%ld", revs)):
4189 for pos, ctx in enumerate(repo.set("%ld", revs)):
4186 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4190 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4187 ctx.description().split('\n', 1)[0])
4191 ctx.description().split('\n', 1)[0])
4188 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4192 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4189 if names:
4193 if names:
4190 desc += ' (%s)' % ' '.join(names)
4194 desc += ' (%s)' % ' '.join(names)
4191 ui.status(_('grafting %s\n') % desc)
4195 ui.status(_('grafting %s\n') % desc)
4192 if opts.get('dry_run'):
4196 if opts.get('dry_run'):
4193 continue
4197 continue
4194
4198
4195 source = ctx.extra().get('source')
4199 source = ctx.extra().get('source')
4196 extra = {}
4200 extra = {}
4197 if source:
4201 if source:
4198 extra['source'] = source
4202 extra['source'] = source
4199 extra['intermediate-source'] = ctx.hex()
4203 extra['intermediate-source'] = ctx.hex()
4200 else:
4204 else:
4201 extra['source'] = ctx.hex()
4205 extra['source'] = ctx.hex()
4202 user = ctx.user()
4206 user = ctx.user()
4203 if opts.get('user'):
4207 if opts.get('user'):
4204 user = opts['user']
4208 user = opts['user']
4205 date = ctx.date()
4209 date = ctx.date()
4206 if opts.get('date'):
4210 if opts.get('date'):
4207 date = opts['date']
4211 date = opts['date']
4208 message = ctx.description()
4212 message = ctx.description()
4209 if opts.get('log'):
4213 if opts.get('log'):
4210 message += '\n(grafted from %s)' % ctx.hex()
4214 message += '\n(grafted from %s)' % ctx.hex()
4211
4215
4212 # we don't merge the first commit when continuing
4216 # we don't merge the first commit when continuing
4213 if not cont:
4217 if not cont:
4214 # perform the graft merge with p1(rev) as 'ancestor'
4218 # perform the graft merge with p1(rev) as 'ancestor'
4215 try:
4219 try:
4216 # ui.forcemerge is an internal variable, do not document
4220 # ui.forcemerge is an internal variable, do not document
4217 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4221 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4218 'graft')
4222 'graft')
4219 stats = mergemod.graft(repo, ctx, ctx.p1(),
4223 stats = mergemod.graft(repo, ctx, ctx.p1(),
4220 ['local', 'graft'])
4224 ['local', 'graft'])
4221 finally:
4225 finally:
4222 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4226 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4223 # report any conflicts
4227 # report any conflicts
4224 if stats and stats[3] > 0:
4228 if stats and stats[3] > 0:
4225 # write out state for --continue
4229 # write out state for --continue
4226 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4230 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4227 repo.vfs.write('graftstate', ''.join(nodelines))
4231 repo.vfs.write('graftstate', ''.join(nodelines))
4228 extra = ''
4232 extra = ''
4229 if opts.get('user'):
4233 if opts.get('user'):
4230 extra += ' --user %s' % opts['user']
4234 extra += ' --user %s' % opts['user']
4231 if opts.get('date'):
4235 if opts.get('date'):
4232 extra += ' --date %s' % opts['date']
4236 extra += ' --date %s' % opts['date']
4233 if opts.get('log'):
4237 if opts.get('log'):
4234 extra += ' --log'
4238 extra += ' --log'
4235 hint=_('use hg resolve and hg graft --continue%s') % extra
4239 hint=_('use hg resolve and hg graft --continue%s') % extra
4236 raise error.Abort(
4240 raise error.Abort(
4237 _("unresolved conflicts, can't continue"),
4241 _("unresolved conflicts, can't continue"),
4238 hint=hint)
4242 hint=hint)
4239 else:
4243 else:
4240 cont = False
4244 cont = False
4241
4245
4242 # commit
4246 # commit
4243 node = repo.commit(text=message, user=user,
4247 node = repo.commit(text=message, user=user,
4244 date=date, extra=extra, editor=editor)
4248 date=date, extra=extra, editor=editor)
4245 if node is None:
4249 if node is None:
4246 ui.warn(
4250 ui.warn(
4247 _('note: graft of %d:%s created no changes to commit\n') %
4251 _('note: graft of %d:%s created no changes to commit\n') %
4248 (ctx.rev(), ctx))
4252 (ctx.rev(), ctx))
4249
4253
4250 # remove state when we complete successfully
4254 # remove state when we complete successfully
4251 if not opts.get('dry_run'):
4255 if not opts.get('dry_run'):
4252 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4256 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4253
4257
4254 return 0
4258 return 0
4255
4259
4256 @command('grep',
4260 @command('grep',
4257 [('0', 'print0', None, _('end fields with NUL')),
4261 [('0', 'print0', None, _('end fields with NUL')),
4258 ('', 'all', None, _('print all revisions that match')),
4262 ('', 'all', None, _('print all revisions that match')),
4259 ('a', 'text', None, _('treat all files as text')),
4263 ('a', 'text', None, _('treat all files as text')),
4260 ('f', 'follow', None,
4264 ('f', 'follow', None,
4261 _('follow changeset history,'
4265 _('follow changeset history,'
4262 ' or file history across copies and renames')),
4266 ' or file history across copies and renames')),
4263 ('i', 'ignore-case', None, _('ignore case when matching')),
4267 ('i', 'ignore-case', None, _('ignore case when matching')),
4264 ('l', 'files-with-matches', None,
4268 ('l', 'files-with-matches', None,
4265 _('print only filenames and revisions that match')),
4269 _('print only filenames and revisions that match')),
4266 ('n', 'line-number', None, _('print matching line numbers')),
4270 ('n', 'line-number', None, _('print matching line numbers')),
4267 ('r', 'rev', [],
4271 ('r', 'rev', [],
4268 _('only search files changed within revision range'), _('REV')),
4272 _('only search files changed within revision range'), _('REV')),
4269 ('u', 'user', None, _('list the author (long with -v)')),
4273 ('u', 'user', None, _('list the author (long with -v)')),
4270 ('d', 'date', None, _('list the date (short with -q)')),
4274 ('d', 'date', None, _('list the date (short with -q)')),
4271 ] + walkopts,
4275 ] + walkopts,
4272 _('[OPTION]... PATTERN [FILE]...'),
4276 _('[OPTION]... PATTERN [FILE]...'),
4273 inferrepo=True)
4277 inferrepo=True)
4274 def grep(ui, repo, pattern, *pats, **opts):
4278 def grep(ui, repo, pattern, *pats, **opts):
4275 """search for a pattern in specified files and revisions
4279 """search for a pattern in specified files and revisions
4276
4280
4277 Search revisions of files for a regular expression.
4281 Search revisions of files for a regular expression.
4278
4282
4279 This command behaves differently than Unix grep. It only accepts
4283 This command behaves differently than Unix grep. It only accepts
4280 Python/Perl regexps. It searches repository history, not the
4284 Python/Perl regexps. It searches repository history, not the
4281 working directory. It always prints the revision number in which a
4285 working directory. It always prints the revision number in which a
4282 match appears.
4286 match appears.
4283
4287
4284 By default, grep only prints output for the first revision of a
4288 By default, grep only prints output for the first revision of a
4285 file in which it finds a match. To get it to print every revision
4289 file in which it finds a match. To get it to print every revision
4286 that contains a change in match status ("-" for a match that
4290 that contains a change in match status ("-" for a match that
4287 becomes a non-match, or "+" for a non-match that becomes a match),
4291 becomes a non-match, or "+" for a non-match that becomes a match),
4288 use the --all flag.
4292 use the --all flag.
4289
4293
4290 Returns 0 if a match is found, 1 otherwise.
4294 Returns 0 if a match is found, 1 otherwise.
4291 """
4295 """
4292 reflags = re.M
4296 reflags = re.M
4293 if opts.get('ignore_case'):
4297 if opts.get('ignore_case'):
4294 reflags |= re.I
4298 reflags |= re.I
4295 try:
4299 try:
4296 regexp = util.re.compile(pattern, reflags)
4300 regexp = util.re.compile(pattern, reflags)
4297 except re.error as inst:
4301 except re.error as inst:
4298 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4302 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4299 return 1
4303 return 1
4300 sep, eol = ':', '\n'
4304 sep, eol = ':', '\n'
4301 if opts.get('print0'):
4305 if opts.get('print0'):
4302 sep = eol = '\0'
4306 sep = eol = '\0'
4303
4307
4304 getfile = util.lrucachefunc(repo.file)
4308 getfile = util.lrucachefunc(repo.file)
4305
4309
4306 def matchlines(body):
4310 def matchlines(body):
4307 begin = 0
4311 begin = 0
4308 linenum = 0
4312 linenum = 0
4309 while begin < len(body):
4313 while begin < len(body):
4310 match = regexp.search(body, begin)
4314 match = regexp.search(body, begin)
4311 if not match:
4315 if not match:
4312 break
4316 break
4313 mstart, mend = match.span()
4317 mstart, mend = match.span()
4314 linenum += body.count('\n', begin, mstart) + 1
4318 linenum += body.count('\n', begin, mstart) + 1
4315 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4319 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4316 begin = body.find('\n', mend) + 1 or len(body) + 1
4320 begin = body.find('\n', mend) + 1 or len(body) + 1
4317 lend = begin - 1
4321 lend = begin - 1
4318 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4322 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4319
4323
4320 class linestate(object):
4324 class linestate(object):
4321 def __init__(self, line, linenum, colstart, colend):
4325 def __init__(self, line, linenum, colstart, colend):
4322 self.line = line
4326 self.line = line
4323 self.linenum = linenum
4327 self.linenum = linenum
4324 self.colstart = colstart
4328 self.colstart = colstart
4325 self.colend = colend
4329 self.colend = colend
4326
4330
4327 def __hash__(self):
4331 def __hash__(self):
4328 return hash((self.linenum, self.line))
4332 return hash((self.linenum, self.line))
4329
4333
4330 def __eq__(self, other):
4334 def __eq__(self, other):
4331 return self.line == other.line
4335 return self.line == other.line
4332
4336
4333 def __iter__(self):
4337 def __iter__(self):
4334 yield (self.line[:self.colstart], '')
4338 yield (self.line[:self.colstart], '')
4335 yield (self.line[self.colstart:self.colend], 'grep.match')
4339 yield (self.line[self.colstart:self.colend], 'grep.match')
4336 rest = self.line[self.colend:]
4340 rest = self.line[self.colend:]
4337 while rest != '':
4341 while rest != '':
4338 match = regexp.search(rest)
4342 match = regexp.search(rest)
4339 if not match:
4343 if not match:
4340 yield (rest, '')
4344 yield (rest, '')
4341 break
4345 break
4342 mstart, mend = match.span()
4346 mstart, mend = match.span()
4343 yield (rest[:mstart], '')
4347 yield (rest[:mstart], '')
4344 yield (rest[mstart:mend], 'grep.match')
4348 yield (rest[mstart:mend], 'grep.match')
4345 rest = rest[mend:]
4349 rest = rest[mend:]
4346
4350
4347 matches = {}
4351 matches = {}
4348 copies = {}
4352 copies = {}
4349 def grepbody(fn, rev, body):
4353 def grepbody(fn, rev, body):
4350 matches[rev].setdefault(fn, [])
4354 matches[rev].setdefault(fn, [])
4351 m = matches[rev][fn]
4355 m = matches[rev][fn]
4352 for lnum, cstart, cend, line in matchlines(body):
4356 for lnum, cstart, cend, line in matchlines(body):
4353 s = linestate(line, lnum, cstart, cend)
4357 s = linestate(line, lnum, cstart, cend)
4354 m.append(s)
4358 m.append(s)
4355
4359
4356 def difflinestates(a, b):
4360 def difflinestates(a, b):
4357 sm = difflib.SequenceMatcher(None, a, b)
4361 sm = difflib.SequenceMatcher(None, a, b)
4358 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4362 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4359 if tag == 'insert':
4363 if tag == 'insert':
4360 for i in xrange(blo, bhi):
4364 for i in xrange(blo, bhi):
4361 yield ('+', b[i])
4365 yield ('+', b[i])
4362 elif tag == 'delete':
4366 elif tag == 'delete':
4363 for i in xrange(alo, ahi):
4367 for i in xrange(alo, ahi):
4364 yield ('-', a[i])
4368 yield ('-', a[i])
4365 elif tag == 'replace':
4369 elif tag == 'replace':
4366 for i in xrange(alo, ahi):
4370 for i in xrange(alo, ahi):
4367 yield ('-', a[i])
4371 yield ('-', a[i])
4368 for i in xrange(blo, bhi):
4372 for i in xrange(blo, bhi):
4369 yield ('+', b[i])
4373 yield ('+', b[i])
4370
4374
4371 def display(fn, ctx, pstates, states):
4375 def display(fn, ctx, pstates, states):
4372 rev = ctx.rev()
4376 rev = ctx.rev()
4373 if ui.quiet:
4377 if ui.quiet:
4374 datefunc = util.shortdate
4378 datefunc = util.shortdate
4375 else:
4379 else:
4376 datefunc = util.datestr
4380 datefunc = util.datestr
4377 found = False
4381 found = False
4378 @util.cachefunc
4382 @util.cachefunc
4379 def binary():
4383 def binary():
4380 flog = getfile(fn)
4384 flog = getfile(fn)
4381 return util.binary(flog.read(ctx.filenode(fn)))
4385 return util.binary(flog.read(ctx.filenode(fn)))
4382
4386
4383 if opts.get('all'):
4387 if opts.get('all'):
4384 iter = difflinestates(pstates, states)
4388 iter = difflinestates(pstates, states)
4385 else:
4389 else:
4386 iter = [('', l) for l in states]
4390 iter = [('', l) for l in states]
4387 for change, l in iter:
4391 for change, l in iter:
4388 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4392 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4389
4393
4390 if opts.get('line_number'):
4394 if opts.get('line_number'):
4391 cols.append((str(l.linenum), 'grep.linenumber'))
4395 cols.append((str(l.linenum), 'grep.linenumber'))
4392 if opts.get('all'):
4396 if opts.get('all'):
4393 cols.append((change, 'grep.change'))
4397 cols.append((change, 'grep.change'))
4394 if opts.get('user'):
4398 if opts.get('user'):
4395 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4399 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4396 if opts.get('date'):
4400 if opts.get('date'):
4397 cols.append((datefunc(ctx.date()), 'grep.date'))
4401 cols.append((datefunc(ctx.date()), 'grep.date'))
4398 for col, label in cols[:-1]:
4402 for col, label in cols[:-1]:
4399 ui.write(col, label=label)
4403 ui.write(col, label=label)
4400 ui.write(sep, label='grep.sep')
4404 ui.write(sep, label='grep.sep')
4401 ui.write(cols[-1][0], label=cols[-1][1])
4405 ui.write(cols[-1][0], label=cols[-1][1])
4402 if not opts.get('files_with_matches'):
4406 if not opts.get('files_with_matches'):
4403 ui.write(sep, label='grep.sep')
4407 ui.write(sep, label='grep.sep')
4404 if not opts.get('text') and binary():
4408 if not opts.get('text') and binary():
4405 ui.write(" Binary file matches")
4409 ui.write(" Binary file matches")
4406 else:
4410 else:
4407 for s, label in l:
4411 for s, label in l:
4408 ui.write(s, label=label)
4412 ui.write(s, label=label)
4409 ui.write(eol)
4413 ui.write(eol)
4410 found = True
4414 found = True
4411 if opts.get('files_with_matches'):
4415 if opts.get('files_with_matches'):
4412 break
4416 break
4413 return found
4417 return found
4414
4418
4415 skip = {}
4419 skip = {}
4416 revfiles = {}
4420 revfiles = {}
4417 matchfn = scmutil.match(repo[None], pats, opts)
4421 matchfn = scmutil.match(repo[None], pats, opts)
4418 found = False
4422 found = False
4419 follow = opts.get('follow')
4423 follow = opts.get('follow')
4420
4424
4421 def prep(ctx, fns):
4425 def prep(ctx, fns):
4422 rev = ctx.rev()
4426 rev = ctx.rev()
4423 pctx = ctx.p1()
4427 pctx = ctx.p1()
4424 parent = pctx.rev()
4428 parent = pctx.rev()
4425 matches.setdefault(rev, {})
4429 matches.setdefault(rev, {})
4426 matches.setdefault(parent, {})
4430 matches.setdefault(parent, {})
4427 files = revfiles.setdefault(rev, [])
4431 files = revfiles.setdefault(rev, [])
4428 for fn in fns:
4432 for fn in fns:
4429 flog = getfile(fn)
4433 flog = getfile(fn)
4430 try:
4434 try:
4431 fnode = ctx.filenode(fn)
4435 fnode = ctx.filenode(fn)
4432 except error.LookupError:
4436 except error.LookupError:
4433 continue
4437 continue
4434
4438
4435 copied = flog.renamed(fnode)
4439 copied = flog.renamed(fnode)
4436 copy = follow and copied and copied[0]
4440 copy = follow and copied and copied[0]
4437 if copy:
4441 if copy:
4438 copies.setdefault(rev, {})[fn] = copy
4442 copies.setdefault(rev, {})[fn] = copy
4439 if fn in skip:
4443 if fn in skip:
4440 if copy:
4444 if copy:
4441 skip[copy] = True
4445 skip[copy] = True
4442 continue
4446 continue
4443 files.append(fn)
4447 files.append(fn)
4444
4448
4445 if fn not in matches[rev]:
4449 if fn not in matches[rev]:
4446 grepbody(fn, rev, flog.read(fnode))
4450 grepbody(fn, rev, flog.read(fnode))
4447
4451
4448 pfn = copy or fn
4452 pfn = copy or fn
4449 if pfn not in matches[parent]:
4453 if pfn not in matches[parent]:
4450 try:
4454 try:
4451 fnode = pctx.filenode(pfn)
4455 fnode = pctx.filenode(pfn)
4452 grepbody(pfn, parent, flog.read(fnode))
4456 grepbody(pfn, parent, flog.read(fnode))
4453 except error.LookupError:
4457 except error.LookupError:
4454 pass
4458 pass
4455
4459
4456 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4460 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4457 rev = ctx.rev()
4461 rev = ctx.rev()
4458 parent = ctx.p1().rev()
4462 parent = ctx.p1().rev()
4459 for fn in sorted(revfiles.get(rev, [])):
4463 for fn in sorted(revfiles.get(rev, [])):
4460 states = matches[rev][fn]
4464 states = matches[rev][fn]
4461 copy = copies.get(rev, {}).get(fn)
4465 copy = copies.get(rev, {}).get(fn)
4462 if fn in skip:
4466 if fn in skip:
4463 if copy:
4467 if copy:
4464 skip[copy] = True
4468 skip[copy] = True
4465 continue
4469 continue
4466 pstates = matches.get(parent, {}).get(copy or fn, [])
4470 pstates = matches.get(parent, {}).get(copy or fn, [])
4467 if pstates or states:
4471 if pstates or states:
4468 r = display(fn, ctx, pstates, states)
4472 r = display(fn, ctx, pstates, states)
4469 found = found or r
4473 found = found or r
4470 if r and not opts.get('all'):
4474 if r and not opts.get('all'):
4471 skip[fn] = True
4475 skip[fn] = True
4472 if copy:
4476 if copy:
4473 skip[copy] = True
4477 skip[copy] = True
4474 del matches[rev]
4478 del matches[rev]
4475 del revfiles[rev]
4479 del revfiles[rev]
4476
4480
4477 return not found
4481 return not found
4478
4482
4479 @command('heads',
4483 @command('heads',
4480 [('r', 'rev', '',
4484 [('r', 'rev', '',
4481 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4485 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4482 ('t', 'topo', False, _('show topological heads only')),
4486 ('t', 'topo', False, _('show topological heads only')),
4483 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4487 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4484 ('c', 'closed', False, _('show normal and closed branch heads')),
4488 ('c', 'closed', False, _('show normal and closed branch heads')),
4485 ] + templateopts,
4489 ] + templateopts,
4486 _('[-ct] [-r STARTREV] [REV]...'))
4490 _('[-ct] [-r STARTREV] [REV]...'))
4487 def heads(ui, repo, *branchrevs, **opts):
4491 def heads(ui, repo, *branchrevs, **opts):
4488 """show branch heads
4492 """show branch heads
4489
4493
4490 With no arguments, show all open branch heads in the repository.
4494 With no arguments, show all open branch heads in the repository.
4491 Branch heads are changesets that have no descendants on the
4495 Branch heads are changesets that have no descendants on the
4492 same branch. They are where development generally takes place and
4496 same branch. They are where development generally takes place and
4493 are the usual targets for update and merge operations.
4497 are the usual targets for update and merge operations.
4494
4498
4495 If one or more REVs are given, only open branch heads on the
4499 If one or more REVs are given, only open branch heads on the
4496 branches associated with the specified changesets are shown. This
4500 branches associated with the specified changesets are shown. This
4497 means that you can use :hg:`heads .` to see the heads on the
4501 means that you can use :hg:`heads .` to see the heads on the
4498 currently checked-out branch.
4502 currently checked-out branch.
4499
4503
4500 If -c/--closed is specified, also show branch heads marked closed
4504 If -c/--closed is specified, also show branch heads marked closed
4501 (see :hg:`commit --close-branch`).
4505 (see :hg:`commit --close-branch`).
4502
4506
4503 If STARTREV is specified, only those heads that are descendants of
4507 If STARTREV is specified, only those heads that are descendants of
4504 STARTREV will be displayed.
4508 STARTREV will be displayed.
4505
4509
4506 If -t/--topo is specified, named branch mechanics will be ignored and only
4510 If -t/--topo is specified, named branch mechanics will be ignored and only
4507 topological heads (changesets with no children) will be shown.
4511 topological heads (changesets with no children) will be shown.
4508
4512
4509 Returns 0 if matching heads are found, 1 if not.
4513 Returns 0 if matching heads are found, 1 if not.
4510 """
4514 """
4511
4515
4512 start = None
4516 start = None
4513 if 'rev' in opts:
4517 if 'rev' in opts:
4514 start = scmutil.revsingle(repo, opts['rev'], None).node()
4518 start = scmutil.revsingle(repo, opts['rev'], None).node()
4515
4519
4516 if opts.get('topo'):
4520 if opts.get('topo'):
4517 heads = [repo[h] for h in repo.heads(start)]
4521 heads = [repo[h] for h in repo.heads(start)]
4518 else:
4522 else:
4519 heads = []
4523 heads = []
4520 for branch in repo.branchmap():
4524 for branch in repo.branchmap():
4521 heads += repo.branchheads(branch, start, opts.get('closed'))
4525 heads += repo.branchheads(branch, start, opts.get('closed'))
4522 heads = [repo[h] for h in heads]
4526 heads = [repo[h] for h in heads]
4523
4527
4524 if branchrevs:
4528 if branchrevs:
4525 branches = set(repo[br].branch() for br in branchrevs)
4529 branches = set(repo[br].branch() for br in branchrevs)
4526 heads = [h for h in heads if h.branch() in branches]
4530 heads = [h for h in heads if h.branch() in branches]
4527
4531
4528 if opts.get('active') and branchrevs:
4532 if opts.get('active') and branchrevs:
4529 dagheads = repo.heads(start)
4533 dagheads = repo.heads(start)
4530 heads = [h for h in heads if h.node() in dagheads]
4534 heads = [h for h in heads if h.node() in dagheads]
4531
4535
4532 if branchrevs:
4536 if branchrevs:
4533 haveheads = set(h.branch() for h in heads)
4537 haveheads = set(h.branch() for h in heads)
4534 if branches - haveheads:
4538 if branches - haveheads:
4535 headless = ', '.join(b for b in branches - haveheads)
4539 headless = ', '.join(b for b in branches - haveheads)
4536 msg = _('no open branch heads found on branches %s')
4540 msg = _('no open branch heads found on branches %s')
4537 if opts.get('rev'):
4541 if opts.get('rev'):
4538 msg += _(' (started at %s)') % opts['rev']
4542 msg += _(' (started at %s)') % opts['rev']
4539 ui.warn((msg + '\n') % headless)
4543 ui.warn((msg + '\n') % headless)
4540
4544
4541 if not heads:
4545 if not heads:
4542 return 1
4546 return 1
4543
4547
4544 heads = sorted(heads, key=lambda x: -x.rev())
4548 heads = sorted(heads, key=lambda x: -x.rev())
4545 displayer = cmdutil.show_changeset(ui, repo, opts)
4549 displayer = cmdutil.show_changeset(ui, repo, opts)
4546 for ctx in heads:
4550 for ctx in heads:
4547 displayer.show(ctx)
4551 displayer.show(ctx)
4548 displayer.close()
4552 displayer.close()
4549
4553
4550 @command('help',
4554 @command('help',
4551 [('e', 'extension', None, _('show only help for extensions')),
4555 [('e', 'extension', None, _('show only help for extensions')),
4552 ('c', 'command', None, _('show only help for commands')),
4556 ('c', 'command', None, _('show only help for commands')),
4553 ('k', 'keyword', None, _('show topics matching keyword')),
4557 ('k', 'keyword', None, _('show topics matching keyword')),
4554 ('s', 'system', [], _('show help for specific platform(s)')),
4558 ('s', 'system', [], _('show help for specific platform(s)')),
4555 ],
4559 ],
4556 _('[-ecks] [TOPIC]'),
4560 _('[-ecks] [TOPIC]'),
4557 norepo=True)
4561 norepo=True)
4558 def help_(ui, name=None, **opts):
4562 def help_(ui, name=None, **opts):
4559 """show help for a given topic or a help overview
4563 """show help for a given topic or a help overview
4560
4564
4561 With no arguments, print a list of commands with short help messages.
4565 With no arguments, print a list of commands with short help messages.
4562
4566
4563 Given a topic, extension, or command name, print help for that
4567 Given a topic, extension, or command name, print help for that
4564 topic.
4568 topic.
4565
4569
4566 Returns 0 if successful.
4570 Returns 0 if successful.
4567 """
4571 """
4568
4572
4569 textwidth = min(ui.termwidth(), 80) - 2
4573 textwidth = min(ui.termwidth(), 80) - 2
4570
4574
4571 keep = opts.get('system') or []
4575 keep = opts.get('system') or []
4572 if len(keep) == 0:
4576 if len(keep) == 0:
4573 if sys.platform.startswith('win'):
4577 if sys.platform.startswith('win'):
4574 keep.append('windows')
4578 keep.append('windows')
4575 elif sys.platform == 'OpenVMS':
4579 elif sys.platform == 'OpenVMS':
4576 keep.append('vms')
4580 keep.append('vms')
4577 elif sys.platform == 'plan9':
4581 elif sys.platform == 'plan9':
4578 keep.append('plan9')
4582 keep.append('plan9')
4579 else:
4583 else:
4580 keep.append('unix')
4584 keep.append('unix')
4581 keep.append(sys.platform.lower())
4585 keep.append(sys.platform.lower())
4582 if ui.verbose:
4586 if ui.verbose:
4583 keep.append('verbose')
4587 keep.append('verbose')
4584
4588
4585 section = None
4589 section = None
4586 subtopic = None
4590 subtopic = None
4587 if name and '.' in name:
4591 if name and '.' in name:
4588 name, section = name.split('.', 1)
4592 name, section = name.split('.', 1)
4589 section = section.lower()
4593 section = section.lower()
4590 if '.' in section:
4594 if '.' in section:
4591 subtopic, section = section.split('.', 1)
4595 subtopic, section = section.split('.', 1)
4592 else:
4596 else:
4593 subtopic = section
4597 subtopic = section
4594
4598
4595 text = help.help_(ui, name, subtopic=subtopic, **opts)
4599 text = help.help_(ui, name, subtopic=subtopic, **opts)
4596
4600
4597 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4601 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4598 section=section)
4602 section=section)
4599
4603
4600 # We could have been given a weird ".foo" section without a name
4604 # We could have been given a weird ".foo" section without a name
4601 # to look for, or we could have simply failed to found "foo.bar"
4605 # to look for, or we could have simply failed to found "foo.bar"
4602 # because bar isn't a section of foo
4606 # because bar isn't a section of foo
4603 if section and not (formatted and name):
4607 if section and not (formatted and name):
4604 raise error.Abort(_("help section not found"))
4608 raise error.Abort(_("help section not found"))
4605
4609
4606 if 'verbose' in pruned:
4610 if 'verbose' in pruned:
4607 keep.append('omitted')
4611 keep.append('omitted')
4608 else:
4612 else:
4609 keep.append('notomitted')
4613 keep.append('notomitted')
4610 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4614 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4611 section=section)
4615 section=section)
4612 ui.write(formatted)
4616 ui.write(formatted)
4613
4617
4614
4618
4615 @command('identify|id',
4619 @command('identify|id',
4616 [('r', 'rev', '',
4620 [('r', 'rev', '',
4617 _('identify the specified revision'), _('REV')),
4621 _('identify the specified revision'), _('REV')),
4618 ('n', 'num', None, _('show local revision number')),
4622 ('n', 'num', None, _('show local revision number')),
4619 ('i', 'id', None, _('show global revision id')),
4623 ('i', 'id', None, _('show global revision id')),
4620 ('b', 'branch', None, _('show branch')),
4624 ('b', 'branch', None, _('show branch')),
4621 ('t', 'tags', None, _('show tags')),
4625 ('t', 'tags', None, _('show tags')),
4622 ('B', 'bookmarks', None, _('show bookmarks')),
4626 ('B', 'bookmarks', None, _('show bookmarks')),
4623 ] + remoteopts,
4627 ] + remoteopts,
4624 _('[-nibtB] [-r REV] [SOURCE]'),
4628 _('[-nibtB] [-r REV] [SOURCE]'),
4625 optionalrepo=True)
4629 optionalrepo=True)
4626 def identify(ui, repo, source=None, rev=None,
4630 def identify(ui, repo, source=None, rev=None,
4627 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4631 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4628 """identify the working directory or specified revision
4632 """identify the working directory or specified revision
4629
4633
4630 Print a summary identifying the repository state at REV using one or
4634 Print a summary identifying the repository state at REV using one or
4631 two parent hash identifiers, followed by a "+" if the working
4635 two parent hash identifiers, followed by a "+" if the working
4632 directory has uncommitted changes, the branch name (if not default),
4636 directory has uncommitted changes, the branch name (if not default),
4633 a list of tags, and a list of bookmarks.
4637 a list of tags, and a list of bookmarks.
4634
4638
4635 When REV is not given, print a summary of the current state of the
4639 When REV is not given, print a summary of the current state of the
4636 repository.
4640 repository.
4637
4641
4638 Specifying a path to a repository root or Mercurial bundle will
4642 Specifying a path to a repository root or Mercurial bundle will
4639 cause lookup to operate on that repository/bundle.
4643 cause lookup to operate on that repository/bundle.
4640
4644
4641 .. container:: verbose
4645 .. container:: verbose
4642
4646
4643 Examples:
4647 Examples:
4644
4648
4645 - generate a build identifier for the working directory::
4649 - generate a build identifier for the working directory::
4646
4650
4647 hg id --id > build-id.dat
4651 hg id --id > build-id.dat
4648
4652
4649 - find the revision corresponding to a tag::
4653 - find the revision corresponding to a tag::
4650
4654
4651 hg id -n -r 1.3
4655 hg id -n -r 1.3
4652
4656
4653 - check the most recent revision of a remote repository::
4657 - check the most recent revision of a remote repository::
4654
4658
4655 hg id -r tip http://selenic.com/hg/
4659 hg id -r tip http://selenic.com/hg/
4656
4660
4657 See :hg:`log` for generating more information about specific revisions,
4661 See :hg:`log` for generating more information about specific revisions,
4658 including full hash identifiers.
4662 including full hash identifiers.
4659
4663
4660 Returns 0 if successful.
4664 Returns 0 if successful.
4661 """
4665 """
4662
4666
4663 if not repo and not source:
4667 if not repo and not source:
4664 raise error.Abort(_("there is no Mercurial repository here "
4668 raise error.Abort(_("there is no Mercurial repository here "
4665 "(.hg not found)"))
4669 "(.hg not found)"))
4666
4670
4667 if ui.debugflag:
4671 if ui.debugflag:
4668 hexfunc = hex
4672 hexfunc = hex
4669 else:
4673 else:
4670 hexfunc = short
4674 hexfunc = short
4671 default = not (num or id or branch or tags or bookmarks)
4675 default = not (num or id or branch or tags or bookmarks)
4672 output = []
4676 output = []
4673 revs = []
4677 revs = []
4674
4678
4675 if source:
4679 if source:
4676 source, branches = hg.parseurl(ui.expandpath(source))
4680 source, branches = hg.parseurl(ui.expandpath(source))
4677 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4681 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4678 repo = peer.local()
4682 repo = peer.local()
4679 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4683 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4680
4684
4681 if not repo:
4685 if not repo:
4682 if num or branch or tags:
4686 if num or branch or tags:
4683 raise error.Abort(
4687 raise error.Abort(
4684 _("can't query remote revision number, branch, or tags"))
4688 _("can't query remote revision number, branch, or tags"))
4685 if not rev and revs:
4689 if not rev and revs:
4686 rev = revs[0]
4690 rev = revs[0]
4687 if not rev:
4691 if not rev:
4688 rev = "tip"
4692 rev = "tip"
4689
4693
4690 remoterev = peer.lookup(rev)
4694 remoterev = peer.lookup(rev)
4691 if default or id:
4695 if default or id:
4692 output = [hexfunc(remoterev)]
4696 output = [hexfunc(remoterev)]
4693
4697
4694 def getbms():
4698 def getbms():
4695 bms = []
4699 bms = []
4696
4700
4697 if 'bookmarks' in peer.listkeys('namespaces'):
4701 if 'bookmarks' in peer.listkeys('namespaces'):
4698 hexremoterev = hex(remoterev)
4702 hexremoterev = hex(remoterev)
4699 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4703 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4700 if bmr == hexremoterev]
4704 if bmr == hexremoterev]
4701
4705
4702 return sorted(bms)
4706 return sorted(bms)
4703
4707
4704 if bookmarks:
4708 if bookmarks:
4705 output.extend(getbms())
4709 output.extend(getbms())
4706 elif default and not ui.quiet:
4710 elif default and not ui.quiet:
4707 # multiple bookmarks for a single parent separated by '/'
4711 # multiple bookmarks for a single parent separated by '/'
4708 bm = '/'.join(getbms())
4712 bm = '/'.join(getbms())
4709 if bm:
4713 if bm:
4710 output.append(bm)
4714 output.append(bm)
4711 else:
4715 else:
4712 ctx = scmutil.revsingle(repo, rev, None)
4716 ctx = scmutil.revsingle(repo, rev, None)
4713
4717
4714 if ctx.rev() is None:
4718 if ctx.rev() is None:
4715 ctx = repo[None]
4719 ctx = repo[None]
4716 parents = ctx.parents()
4720 parents = ctx.parents()
4717 taglist = []
4721 taglist = []
4718 for p in parents:
4722 for p in parents:
4719 taglist.extend(p.tags())
4723 taglist.extend(p.tags())
4720
4724
4721 changed = ""
4725 changed = ""
4722 if default or id or num:
4726 if default or id or num:
4723 if (any(repo.status())
4727 if (any(repo.status())
4724 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4728 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4725 changed = '+'
4729 changed = '+'
4726 if default or id:
4730 if default or id:
4727 output = ["%s%s" %
4731 output = ["%s%s" %
4728 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4732 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4729 if num:
4733 if num:
4730 output.append("%s%s" %
4734 output.append("%s%s" %
4731 ('+'.join([str(p.rev()) for p in parents]), changed))
4735 ('+'.join([str(p.rev()) for p in parents]), changed))
4732 else:
4736 else:
4733 if default or id:
4737 if default or id:
4734 output = [hexfunc(ctx.node())]
4738 output = [hexfunc(ctx.node())]
4735 if num:
4739 if num:
4736 output.append(str(ctx.rev()))
4740 output.append(str(ctx.rev()))
4737 taglist = ctx.tags()
4741 taglist = ctx.tags()
4738
4742
4739 if default and not ui.quiet:
4743 if default and not ui.quiet:
4740 b = ctx.branch()
4744 b = ctx.branch()
4741 if b != 'default':
4745 if b != 'default':
4742 output.append("(%s)" % b)
4746 output.append("(%s)" % b)
4743
4747
4744 # multiple tags for a single parent separated by '/'
4748 # multiple tags for a single parent separated by '/'
4745 t = '/'.join(taglist)
4749 t = '/'.join(taglist)
4746 if t:
4750 if t:
4747 output.append(t)
4751 output.append(t)
4748
4752
4749 # multiple bookmarks for a single parent separated by '/'
4753 # multiple bookmarks for a single parent separated by '/'
4750 bm = '/'.join(ctx.bookmarks())
4754 bm = '/'.join(ctx.bookmarks())
4751 if bm:
4755 if bm:
4752 output.append(bm)
4756 output.append(bm)
4753 else:
4757 else:
4754 if branch:
4758 if branch:
4755 output.append(ctx.branch())
4759 output.append(ctx.branch())
4756
4760
4757 if tags:
4761 if tags:
4758 output.extend(taglist)
4762 output.extend(taglist)
4759
4763
4760 if bookmarks:
4764 if bookmarks:
4761 output.extend(ctx.bookmarks())
4765 output.extend(ctx.bookmarks())
4762
4766
4763 ui.write("%s\n" % ' '.join(output))
4767 ui.write("%s\n" % ' '.join(output))
4764
4768
4765 @command('import|patch',
4769 @command('import|patch',
4766 [('p', 'strip', 1,
4770 [('p', 'strip', 1,
4767 _('directory strip option for patch. This has the same '
4771 _('directory strip option for patch. This has the same '
4768 'meaning as the corresponding patch option'), _('NUM')),
4772 'meaning as the corresponding patch option'), _('NUM')),
4769 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4773 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4770 ('e', 'edit', False, _('invoke editor on commit messages')),
4774 ('e', 'edit', False, _('invoke editor on commit messages')),
4771 ('f', 'force', None,
4775 ('f', 'force', None,
4772 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4776 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4773 ('', 'no-commit', None,
4777 ('', 'no-commit', None,
4774 _("don't commit, just update the working directory")),
4778 _("don't commit, just update the working directory")),
4775 ('', 'bypass', None,
4779 ('', 'bypass', None,
4776 _("apply patch without touching the working directory")),
4780 _("apply patch without touching the working directory")),
4777 ('', 'partial', None,
4781 ('', 'partial', None,
4778 _('commit even if some hunks fail')),
4782 _('commit even if some hunks fail')),
4779 ('', 'exact', None,
4783 ('', 'exact', None,
4780 _('abort if patch would apply lossily')),
4784 _('abort if patch would apply lossily')),
4781 ('', 'prefix', '',
4785 ('', 'prefix', '',
4782 _('apply patch to subdirectory'), _('DIR')),
4786 _('apply patch to subdirectory'), _('DIR')),
4783 ('', 'import-branch', None,
4787 ('', 'import-branch', None,
4784 _('use any branch information in patch (implied by --exact)'))] +
4788 _('use any branch information in patch (implied by --exact)'))] +
4785 commitopts + commitopts2 + similarityopts,
4789 commitopts + commitopts2 + similarityopts,
4786 _('[OPTION]... PATCH...'))
4790 _('[OPTION]... PATCH...'))
4787 def import_(ui, repo, patch1=None, *patches, **opts):
4791 def import_(ui, repo, patch1=None, *patches, **opts):
4788 """import an ordered set of patches
4792 """import an ordered set of patches
4789
4793
4790 Import a list of patches and commit them individually (unless
4794 Import a list of patches and commit them individually (unless
4791 --no-commit is specified).
4795 --no-commit is specified).
4792
4796
4793 To read a patch from standard input, use "-" as the patch name. If
4797 To read a patch from standard input, use "-" as the patch name. If
4794 a URL is specified, the patch will be downloaded from there.
4798 a URL is specified, the patch will be downloaded from there.
4795
4799
4796 Import first applies changes to the working directory (unless
4800 Import first applies changes to the working directory (unless
4797 --bypass is specified), import will abort if there are outstanding
4801 --bypass is specified), import will abort if there are outstanding
4798 changes.
4802 changes.
4799
4803
4800 Use --bypass to apply and commit patches directly to the
4804 Use --bypass to apply and commit patches directly to the
4801 repository, without affecting the working directory. Without
4805 repository, without affecting the working directory. Without
4802 --exact, patches will be applied on top of the working directory
4806 --exact, patches will be applied on top of the working directory
4803 parent revision.
4807 parent revision.
4804
4808
4805 You can import a patch straight from a mail message. Even patches
4809 You can import a patch straight from a mail message. Even patches
4806 as attachments work (to use the body part, it must have type
4810 as attachments work (to use the body part, it must have type
4807 text/plain or text/x-patch). From and Subject headers of email
4811 text/plain or text/x-patch). From and Subject headers of email
4808 message are used as default committer and commit message. All
4812 message are used as default committer and commit message. All
4809 text/plain body parts before first diff are added to the commit
4813 text/plain body parts before first diff are added to the commit
4810 message.
4814 message.
4811
4815
4812 If the imported patch was generated by :hg:`export`, user and
4816 If the imported patch was generated by :hg:`export`, user and
4813 description from patch override values from message headers and
4817 description from patch override values from message headers and
4814 body. Values given on command line with -m/--message and -u/--user
4818 body. Values given on command line with -m/--message and -u/--user
4815 override these.
4819 override these.
4816
4820
4817 If --exact is specified, import will set the working directory to
4821 If --exact is specified, import will set the working directory to
4818 the parent of each patch before applying it, and will abort if the
4822 the parent of each patch before applying it, and will abort if the
4819 resulting changeset has a different ID than the one recorded in
4823 resulting changeset has a different ID than the one recorded in
4820 the patch. This will guard against various ways that portable
4824 the patch. This will guard against various ways that portable
4821 patch formats and mail systems might fail to transfer Mercurial
4825 patch formats and mail systems might fail to transfer Mercurial
4822 data or metadata. See ':hg: bundle' for lossless transmission.
4826 data or metadata. See ':hg: bundle' for lossless transmission.
4823
4827
4824 Use --partial to ensure a changeset will be created from the patch
4828 Use --partial to ensure a changeset will be created from the patch
4825 even if some hunks fail to apply. Hunks that fail to apply will be
4829 even if some hunks fail to apply. Hunks that fail to apply will be
4826 written to a <target-file>.rej file. Conflicts can then be resolved
4830 written to a <target-file>.rej file. Conflicts can then be resolved
4827 by hand before :hg:`commit --amend` is run to update the created
4831 by hand before :hg:`commit --amend` is run to update the created
4828 changeset. This flag exists to let people import patches that
4832 changeset. This flag exists to let people import patches that
4829 partially apply without losing the associated metadata (author,
4833 partially apply without losing the associated metadata (author,
4830 date, description, ...).
4834 date, description, ...).
4831
4835
4832 .. note::
4836 .. note::
4833
4837
4834 When no hunks apply cleanly, :hg:`import --partial` will create
4838 When no hunks apply cleanly, :hg:`import --partial` will create
4835 an empty changeset, importing only the patch metadata.
4839 an empty changeset, importing only the patch metadata.
4836
4840
4837 With -s/--similarity, hg will attempt to discover renames and
4841 With -s/--similarity, hg will attempt to discover renames and
4838 copies in the patch in the same way as :hg:`addremove`.
4842 copies in the patch in the same way as :hg:`addremove`.
4839
4843
4840 It is possible to use external patch programs to perform the patch
4844 It is possible to use external patch programs to perform the patch
4841 by setting the ``ui.patch`` configuration option. For the default
4845 by setting the ``ui.patch`` configuration option. For the default
4842 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4846 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4843 See :hg:`help config` for more information about configuration
4847 See :hg:`help config` for more information about configuration
4844 files and how to use these options.
4848 files and how to use these options.
4845
4849
4846 See :hg:`help dates` for a list of formats valid for -d/--date.
4850 See :hg:`help dates` for a list of formats valid for -d/--date.
4847
4851
4848 .. container:: verbose
4852 .. container:: verbose
4849
4853
4850 Examples:
4854 Examples:
4851
4855
4852 - import a traditional patch from a website and detect renames::
4856 - import a traditional patch from a website and detect renames::
4853
4857
4854 hg import -s 80 http://example.com/bugfix.patch
4858 hg import -s 80 http://example.com/bugfix.patch
4855
4859
4856 - import a changeset from an hgweb server::
4860 - import a changeset from an hgweb server::
4857
4861
4858 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4862 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4859
4863
4860 - import all the patches in an Unix-style mbox::
4864 - import all the patches in an Unix-style mbox::
4861
4865
4862 hg import incoming-patches.mbox
4866 hg import incoming-patches.mbox
4863
4867
4864 - attempt to exactly restore an exported changeset (not always
4868 - attempt to exactly restore an exported changeset (not always
4865 possible)::
4869 possible)::
4866
4870
4867 hg import --exact proposed-fix.patch
4871 hg import --exact proposed-fix.patch
4868
4872
4869 - use an external tool to apply a patch which is too fuzzy for
4873 - use an external tool to apply a patch which is too fuzzy for
4870 the default internal tool.
4874 the default internal tool.
4871
4875
4872 hg import --config ui.patch="patch --merge" fuzzy.patch
4876 hg import --config ui.patch="patch --merge" fuzzy.patch
4873
4877
4874 - change the default fuzzing from 2 to a less strict 7
4878 - change the default fuzzing from 2 to a less strict 7
4875
4879
4876 hg import --config ui.fuzz=7 fuzz.patch
4880 hg import --config ui.fuzz=7 fuzz.patch
4877
4881
4878 Returns 0 on success, 1 on partial success (see --partial).
4882 Returns 0 on success, 1 on partial success (see --partial).
4879 """
4883 """
4880
4884
4881 if not patch1:
4885 if not patch1:
4882 raise error.Abort(_('need at least one patch to import'))
4886 raise error.Abort(_('need at least one patch to import'))
4883
4887
4884 patches = (patch1,) + patches
4888 patches = (patch1,) + patches
4885
4889
4886 date = opts.get('date')
4890 date = opts.get('date')
4887 if date:
4891 if date:
4888 opts['date'] = util.parsedate(date)
4892 opts['date'] = util.parsedate(date)
4889
4893
4890 exact = opts.get('exact')
4894 exact = opts.get('exact')
4891 update = not opts.get('bypass')
4895 update = not opts.get('bypass')
4892 if not update and opts.get('no_commit'):
4896 if not update and opts.get('no_commit'):
4893 raise error.Abort(_('cannot use --no-commit with --bypass'))
4897 raise error.Abort(_('cannot use --no-commit with --bypass'))
4894 try:
4898 try:
4895 sim = float(opts.get('similarity') or 0)
4899 sim = float(opts.get('similarity') or 0)
4896 except ValueError:
4900 except ValueError:
4897 raise error.Abort(_('similarity must be a number'))
4901 raise error.Abort(_('similarity must be a number'))
4898 if sim < 0 or sim > 100:
4902 if sim < 0 or sim > 100:
4899 raise error.Abort(_('similarity must be between 0 and 100'))
4903 raise error.Abort(_('similarity must be between 0 and 100'))
4900 if sim and not update:
4904 if sim and not update:
4901 raise error.Abort(_('cannot use --similarity with --bypass'))
4905 raise error.Abort(_('cannot use --similarity with --bypass'))
4902 if exact:
4906 if exact:
4903 if opts.get('edit'):
4907 if opts.get('edit'):
4904 raise error.Abort(_('cannot use --exact with --edit'))
4908 raise error.Abort(_('cannot use --exact with --edit'))
4905 if opts.get('prefix'):
4909 if opts.get('prefix'):
4906 raise error.Abort(_('cannot use --exact with --prefix'))
4910 raise error.Abort(_('cannot use --exact with --prefix'))
4907
4911
4908 base = opts["base"]
4912 base = opts["base"]
4909 wlock = dsguard = lock = tr = None
4913 wlock = dsguard = lock = tr = None
4910 msgs = []
4914 msgs = []
4911 ret = 0
4915 ret = 0
4912
4916
4913
4917
4914 try:
4918 try:
4915 wlock = repo.wlock()
4919 wlock = repo.wlock()
4916
4920
4917 if update:
4921 if update:
4918 cmdutil.checkunfinished(repo)
4922 cmdutil.checkunfinished(repo)
4919 if (exact or not opts.get('force')):
4923 if (exact or not opts.get('force')):
4920 cmdutil.bailifchanged(repo)
4924 cmdutil.bailifchanged(repo)
4921
4925
4922 if not opts.get('no_commit'):
4926 if not opts.get('no_commit'):
4923 lock = repo.lock()
4927 lock = repo.lock()
4924 tr = repo.transaction('import')
4928 tr = repo.transaction('import')
4925 else:
4929 else:
4926 dsguard = cmdutil.dirstateguard(repo, 'import')
4930 dsguard = cmdutil.dirstateguard(repo, 'import')
4927 parents = repo[None].parents()
4931 parents = repo[None].parents()
4928 for patchurl in patches:
4932 for patchurl in patches:
4929 if patchurl == '-':
4933 if patchurl == '-':
4930 ui.status(_('applying patch from stdin\n'))
4934 ui.status(_('applying patch from stdin\n'))
4931 patchfile = ui.fin
4935 patchfile = ui.fin
4932 patchurl = 'stdin' # for error message
4936 patchurl = 'stdin' # for error message
4933 else:
4937 else:
4934 patchurl = os.path.join(base, patchurl)
4938 patchurl = os.path.join(base, patchurl)
4935 ui.status(_('applying %s\n') % patchurl)
4939 ui.status(_('applying %s\n') % patchurl)
4936 patchfile = hg.openpath(ui, patchurl)
4940 patchfile = hg.openpath(ui, patchurl)
4937
4941
4938 haspatch = False
4942 haspatch = False
4939 for hunk in patch.split(patchfile):
4943 for hunk in patch.split(patchfile):
4940 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4944 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4941 parents, opts,
4945 parents, opts,
4942 msgs, hg.clean)
4946 msgs, hg.clean)
4943 if msg:
4947 if msg:
4944 haspatch = True
4948 haspatch = True
4945 ui.note(msg + '\n')
4949 ui.note(msg + '\n')
4946 if update or exact:
4950 if update or exact:
4947 parents = repo[None].parents()
4951 parents = repo[None].parents()
4948 else:
4952 else:
4949 parents = [repo[node]]
4953 parents = [repo[node]]
4950 if rej:
4954 if rej:
4951 ui.write_err(_("patch applied partially\n"))
4955 ui.write_err(_("patch applied partially\n"))
4952 ui.write_err(_("(fix the .rej files and run "
4956 ui.write_err(_("(fix the .rej files and run "
4953 "`hg commit --amend`)\n"))
4957 "`hg commit --amend`)\n"))
4954 ret = 1
4958 ret = 1
4955 break
4959 break
4956
4960
4957 if not haspatch:
4961 if not haspatch:
4958 raise error.Abort(_('%s: no diffs found') % patchurl)
4962 raise error.Abort(_('%s: no diffs found') % patchurl)
4959
4963
4960 if tr:
4964 if tr:
4961 tr.close()
4965 tr.close()
4962 if msgs:
4966 if msgs:
4963 repo.savecommitmessage('\n* * *\n'.join(msgs))
4967 repo.savecommitmessage('\n* * *\n'.join(msgs))
4964 if dsguard:
4968 if dsguard:
4965 dsguard.close()
4969 dsguard.close()
4966 return ret
4970 return ret
4967 finally:
4971 finally:
4968 if tr:
4972 if tr:
4969 tr.release()
4973 tr.release()
4970 release(lock, dsguard, wlock)
4974 release(lock, dsguard, wlock)
4971
4975
4972 @command('incoming|in',
4976 @command('incoming|in',
4973 [('f', 'force', None,
4977 [('f', 'force', None,
4974 _('run even if remote repository is unrelated')),
4978 _('run even if remote repository is unrelated')),
4975 ('n', 'newest-first', None, _('show newest record first')),
4979 ('n', 'newest-first', None, _('show newest record first')),
4976 ('', 'bundle', '',
4980 ('', 'bundle', '',
4977 _('file to store the bundles into'), _('FILE')),
4981 _('file to store the bundles into'), _('FILE')),
4978 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4982 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4979 ('B', 'bookmarks', False, _("compare bookmarks")),
4983 ('B', 'bookmarks', False, _("compare bookmarks")),
4980 ('b', 'branch', [],
4984 ('b', 'branch', [],
4981 _('a specific branch you would like to pull'), _('BRANCH')),
4985 _('a specific branch you would like to pull'), _('BRANCH')),
4982 ] + logopts + remoteopts + subrepoopts,
4986 ] + logopts + remoteopts + subrepoopts,
4983 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4987 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4984 def incoming(ui, repo, source="default", **opts):
4988 def incoming(ui, repo, source="default", **opts):
4985 """show new changesets found in source
4989 """show new changesets found in source
4986
4990
4987 Show new changesets found in the specified path/URL or the default
4991 Show new changesets found in the specified path/URL or the default
4988 pull location. These are the changesets that would have been pulled
4992 pull location. These are the changesets that would have been pulled
4989 if a pull at the time you issued this command.
4993 if a pull at the time you issued this command.
4990
4994
4991 See pull for valid source format details.
4995 See pull for valid source format details.
4992
4996
4993 .. container:: verbose
4997 .. container:: verbose
4994
4998
4995 With -B/--bookmarks, the result of bookmark comparison between
4999 With -B/--bookmarks, the result of bookmark comparison between
4996 local and remote repositories is displayed. With -v/--verbose,
5000 local and remote repositories is displayed. With -v/--verbose,
4997 status is also displayed for each bookmark like below::
5001 status is also displayed for each bookmark like below::
4998
5002
4999 BM1 01234567890a added
5003 BM1 01234567890a added
5000 BM2 1234567890ab advanced
5004 BM2 1234567890ab advanced
5001 BM3 234567890abc diverged
5005 BM3 234567890abc diverged
5002 BM4 34567890abcd changed
5006 BM4 34567890abcd changed
5003
5007
5004 The action taken locally when pulling depends on the
5008 The action taken locally when pulling depends on the
5005 status of each bookmark:
5009 status of each bookmark:
5006
5010
5007 :``added``: pull will create it
5011 :``added``: pull will create it
5008 :``advanced``: pull will update it
5012 :``advanced``: pull will update it
5009 :``diverged``: pull will create a divergent bookmark
5013 :``diverged``: pull will create a divergent bookmark
5010 :``changed``: result depends on remote changesets
5014 :``changed``: result depends on remote changesets
5011
5015
5012 From the point of view of pulling behavior, bookmark
5016 From the point of view of pulling behavior, bookmark
5013 existing only in the remote repository are treated as ``added``,
5017 existing only in the remote repository are treated as ``added``,
5014 even if it is in fact locally deleted.
5018 even if it is in fact locally deleted.
5015
5019
5016 .. container:: verbose
5020 .. container:: verbose
5017
5021
5018 For remote repository, using --bundle avoids downloading the
5022 For remote repository, using --bundle avoids downloading the
5019 changesets twice if the incoming is followed by a pull.
5023 changesets twice if the incoming is followed by a pull.
5020
5024
5021 Examples:
5025 Examples:
5022
5026
5023 - show incoming changes with patches and full description::
5027 - show incoming changes with patches and full description::
5024
5028
5025 hg incoming -vp
5029 hg incoming -vp
5026
5030
5027 - show incoming changes excluding merges, store a bundle::
5031 - show incoming changes excluding merges, store a bundle::
5028
5032
5029 hg in -vpM --bundle incoming.hg
5033 hg in -vpM --bundle incoming.hg
5030 hg pull incoming.hg
5034 hg pull incoming.hg
5031
5035
5032 - briefly list changes inside a bundle::
5036 - briefly list changes inside a bundle::
5033
5037
5034 hg in changes.hg -T "{desc|firstline}\\n"
5038 hg in changes.hg -T "{desc|firstline}\\n"
5035
5039
5036 Returns 0 if there are incoming changes, 1 otherwise.
5040 Returns 0 if there are incoming changes, 1 otherwise.
5037 """
5041 """
5038 if opts.get('graph'):
5042 if opts.get('graph'):
5039 cmdutil.checkunsupportedgraphflags([], opts)
5043 cmdutil.checkunsupportedgraphflags([], opts)
5040 def display(other, chlist, displayer):
5044 def display(other, chlist, displayer):
5041 revdag = cmdutil.graphrevs(other, chlist, opts)
5045 revdag = cmdutil.graphrevs(other, chlist, opts)
5042 cmdutil.displaygraph(ui, repo, revdag, displayer,
5046 cmdutil.displaygraph(ui, repo, revdag, displayer,
5043 graphmod.asciiedges)
5047 graphmod.asciiedges)
5044
5048
5045 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5049 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5046 return 0
5050 return 0
5047
5051
5048 if opts.get('bundle') and opts.get('subrepos'):
5052 if opts.get('bundle') and opts.get('subrepos'):
5049 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5053 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5050
5054
5051 if opts.get('bookmarks'):
5055 if opts.get('bookmarks'):
5052 source, branches = hg.parseurl(ui.expandpath(source),
5056 source, branches = hg.parseurl(ui.expandpath(source),
5053 opts.get('branch'))
5057 opts.get('branch'))
5054 other = hg.peer(repo, opts, source)
5058 other = hg.peer(repo, opts, source)
5055 if 'bookmarks' not in other.listkeys('namespaces'):
5059 if 'bookmarks' not in other.listkeys('namespaces'):
5056 ui.warn(_("remote doesn't support bookmarks\n"))
5060 ui.warn(_("remote doesn't support bookmarks\n"))
5057 return 0
5061 return 0
5058 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5062 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5059 return bookmarks.incoming(ui, repo, other)
5063 return bookmarks.incoming(ui, repo, other)
5060
5064
5061 repo._subtoppath = ui.expandpath(source)
5065 repo._subtoppath = ui.expandpath(source)
5062 try:
5066 try:
5063 return hg.incoming(ui, repo, source, opts)
5067 return hg.incoming(ui, repo, source, opts)
5064 finally:
5068 finally:
5065 del repo._subtoppath
5069 del repo._subtoppath
5066
5070
5067
5071
5068 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5072 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5069 norepo=True)
5073 norepo=True)
5070 def init(ui, dest=".", **opts):
5074 def init(ui, dest=".", **opts):
5071 """create a new repository in the given directory
5075 """create a new repository in the given directory
5072
5076
5073 Initialize a new repository in the given directory. If the given
5077 Initialize a new repository in the given directory. If the given
5074 directory does not exist, it will be created.
5078 directory does not exist, it will be created.
5075
5079
5076 If no directory is given, the current directory is used.
5080 If no directory is given, the current directory is used.
5077
5081
5078 It is possible to specify an ``ssh://`` URL as the destination.
5082 It is possible to specify an ``ssh://`` URL as the destination.
5079 See :hg:`help urls` for more information.
5083 See :hg:`help urls` for more information.
5080
5084
5081 Returns 0 on success.
5085 Returns 0 on success.
5082 """
5086 """
5083 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5087 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5084
5088
5085 @command('locate',
5089 @command('locate',
5086 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5090 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5087 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5091 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5088 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5092 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5089 ] + walkopts,
5093 ] + walkopts,
5090 _('[OPTION]... [PATTERN]...'))
5094 _('[OPTION]... [PATTERN]...'))
5091 def locate(ui, repo, *pats, **opts):
5095 def locate(ui, repo, *pats, **opts):
5092 """locate files matching specific patterns (DEPRECATED)
5096 """locate files matching specific patterns (DEPRECATED)
5093
5097
5094 Print files under Mercurial control in the working directory whose
5098 Print files under Mercurial control in the working directory whose
5095 names match the given patterns.
5099 names match the given patterns.
5096
5100
5097 By default, this command searches all directories in the working
5101 By default, this command searches all directories in the working
5098 directory. To search just the current directory and its
5102 directory. To search just the current directory and its
5099 subdirectories, use "--include .".
5103 subdirectories, use "--include .".
5100
5104
5101 If no patterns are given to match, this command prints the names
5105 If no patterns are given to match, this command prints the names
5102 of all files under Mercurial control in the working directory.
5106 of all files under Mercurial control in the working directory.
5103
5107
5104 If you want to feed the output of this command into the "xargs"
5108 If you want to feed the output of this command into the "xargs"
5105 command, use the -0 option to both this command and "xargs". This
5109 command, use the -0 option to both this command and "xargs". This
5106 will avoid the problem of "xargs" treating single filenames that
5110 will avoid the problem of "xargs" treating single filenames that
5107 contain whitespace as multiple filenames.
5111 contain whitespace as multiple filenames.
5108
5112
5109 See :hg:`help files` for a more versatile command.
5113 See :hg:`help files` for a more versatile command.
5110
5114
5111 Returns 0 if a match is found, 1 otherwise.
5115 Returns 0 if a match is found, 1 otherwise.
5112 """
5116 """
5113 if opts.get('print0'):
5117 if opts.get('print0'):
5114 end = '\0'
5118 end = '\0'
5115 else:
5119 else:
5116 end = '\n'
5120 end = '\n'
5117 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5121 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5118
5122
5119 ret = 1
5123 ret = 1
5120 ctx = repo[rev]
5124 ctx = repo[rev]
5121 m = scmutil.match(ctx, pats, opts, default='relglob',
5125 m = scmutil.match(ctx, pats, opts, default='relglob',
5122 badfn=lambda x, y: False)
5126 badfn=lambda x, y: False)
5123
5127
5124 for abs in ctx.matches(m):
5128 for abs in ctx.matches(m):
5125 if opts.get('fullpath'):
5129 if opts.get('fullpath'):
5126 ui.write(repo.wjoin(abs), end)
5130 ui.write(repo.wjoin(abs), end)
5127 else:
5131 else:
5128 ui.write(((pats and m.rel(abs)) or abs), end)
5132 ui.write(((pats and m.rel(abs)) or abs), end)
5129 ret = 0
5133 ret = 0
5130
5134
5131 return ret
5135 return ret
5132
5136
5133 @command('^log|history',
5137 @command('^log|history',
5134 [('f', 'follow', None,
5138 [('f', 'follow', None,
5135 _('follow changeset history, or file history across copies and renames')),
5139 _('follow changeset history, or file history across copies and renames')),
5136 ('', 'follow-first', None,
5140 ('', 'follow-first', None,
5137 _('only follow the first parent of merge changesets (DEPRECATED)')),
5141 _('only follow the first parent of merge changesets (DEPRECATED)')),
5138 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5142 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5139 ('C', 'copies', None, _('show copied files')),
5143 ('C', 'copies', None, _('show copied files')),
5140 ('k', 'keyword', [],
5144 ('k', 'keyword', [],
5141 _('do case-insensitive search for a given text'), _('TEXT')),
5145 _('do case-insensitive search for a given text'), _('TEXT')),
5142 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5146 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5143 ('', 'removed', None, _('include revisions where files were removed')),
5147 ('', 'removed', None, _('include revisions where files were removed')),
5144 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5148 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5145 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5149 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5146 ('', 'only-branch', [],
5150 ('', 'only-branch', [],
5147 _('show only changesets within the given named branch (DEPRECATED)'),
5151 _('show only changesets within the given named branch (DEPRECATED)'),
5148 _('BRANCH')),
5152 _('BRANCH')),
5149 ('b', 'branch', [],
5153 ('b', 'branch', [],
5150 _('show changesets within the given named branch'), _('BRANCH')),
5154 _('show changesets within the given named branch'), _('BRANCH')),
5151 ('P', 'prune', [],
5155 ('P', 'prune', [],
5152 _('do not display revision or any of its ancestors'), _('REV')),
5156 _('do not display revision or any of its ancestors'), _('REV')),
5153 ] + logopts + walkopts,
5157 ] + logopts + walkopts,
5154 _('[OPTION]... [FILE]'),
5158 _('[OPTION]... [FILE]'),
5155 inferrepo=True)
5159 inferrepo=True)
5156 def log(ui, repo, *pats, **opts):
5160 def log(ui, repo, *pats, **opts):
5157 """show revision history of entire repository or files
5161 """show revision history of entire repository or files
5158
5162
5159 Print the revision history of the specified files or the entire
5163 Print the revision history of the specified files or the entire
5160 project.
5164 project.
5161
5165
5162 If no revision range is specified, the default is ``tip:0`` unless
5166 If no revision range is specified, the default is ``tip:0`` unless
5163 --follow is set, in which case the working directory parent is
5167 --follow is set, in which case the working directory parent is
5164 used as the starting revision.
5168 used as the starting revision.
5165
5169
5166 File history is shown without following rename or copy history of
5170 File history is shown without following rename or copy history of
5167 files. Use -f/--follow with a filename to follow history across
5171 files. Use -f/--follow with a filename to follow history across
5168 renames and copies. --follow without a filename will only show
5172 renames and copies. --follow without a filename will only show
5169 ancestors or descendants of the starting revision.
5173 ancestors or descendants of the starting revision.
5170
5174
5171 By default this command prints revision number and changeset id,
5175 By default this command prints revision number and changeset id,
5172 tags, non-trivial parents, user, date and time, and a summary for
5176 tags, non-trivial parents, user, date and time, and a summary for
5173 each commit. When the -v/--verbose switch is used, the list of
5177 each commit. When the -v/--verbose switch is used, the list of
5174 changed files and full commit message are shown.
5178 changed files and full commit message are shown.
5175
5179
5176 With --graph the revisions are shown as an ASCII art DAG with the most
5180 With --graph the revisions are shown as an ASCII art DAG with the most
5177 recent changeset at the top.
5181 recent changeset at the top.
5178 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5182 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5179 and '+' represents a fork where the changeset from the lines below is a
5183 and '+' represents a fork where the changeset from the lines below is a
5180 parent of the 'o' merge on the same line.
5184 parent of the 'o' merge on the same line.
5181
5185
5182 .. note::
5186 .. note::
5183
5187
5184 :hg:`log --patch` may generate unexpected diff output for merge
5188 :hg:`log --patch` may generate unexpected diff output for merge
5185 changesets, as it will only compare the merge changeset against
5189 changesets, as it will only compare the merge changeset against
5186 its first parent. Also, only files different from BOTH parents
5190 its first parent. Also, only files different from BOTH parents
5187 will appear in files:.
5191 will appear in files:.
5188
5192
5189 .. note::
5193 .. note::
5190
5194
5191 For performance reasons, :hg:`log FILE` may omit duplicate changes
5195 For performance reasons, :hg:`log FILE` may omit duplicate changes
5192 made on branches and will not show removals or mode changes. To
5196 made on branches and will not show removals or mode changes. To
5193 see all such changes, use the --removed switch.
5197 see all such changes, use the --removed switch.
5194
5198
5195 .. container:: verbose
5199 .. container:: verbose
5196
5200
5197 Some examples:
5201 Some examples:
5198
5202
5199 - changesets with full descriptions and file lists::
5203 - changesets with full descriptions and file lists::
5200
5204
5201 hg log -v
5205 hg log -v
5202
5206
5203 - changesets ancestral to the working directory::
5207 - changesets ancestral to the working directory::
5204
5208
5205 hg log -f
5209 hg log -f
5206
5210
5207 - last 10 commits on the current branch::
5211 - last 10 commits on the current branch::
5208
5212
5209 hg log -l 10 -b .
5213 hg log -l 10 -b .
5210
5214
5211 - changesets showing all modifications of a file, including removals::
5215 - changesets showing all modifications of a file, including removals::
5212
5216
5213 hg log --removed file.c
5217 hg log --removed file.c
5214
5218
5215 - all changesets that touch a directory, with diffs, excluding merges::
5219 - all changesets that touch a directory, with diffs, excluding merges::
5216
5220
5217 hg log -Mp lib/
5221 hg log -Mp lib/
5218
5222
5219 - all revision numbers that match a keyword::
5223 - all revision numbers that match a keyword::
5220
5224
5221 hg log -k bug --template "{rev}\\n"
5225 hg log -k bug --template "{rev}\\n"
5222
5226
5223 - the full hash identifier of the working directory parent::
5227 - the full hash identifier of the working directory parent::
5224
5228
5225 hg log -r . --template "{node}\\n"
5229 hg log -r . --template "{node}\\n"
5226
5230
5227 - list available log templates::
5231 - list available log templates::
5228
5232
5229 hg log -T list
5233 hg log -T list
5230
5234
5231 - check if a given changeset is included in a tagged release::
5235 - check if a given changeset is included in a tagged release::
5232
5236
5233 hg log -r "a21ccf and ancestor(1.9)"
5237 hg log -r "a21ccf and ancestor(1.9)"
5234
5238
5235 - find all changesets by some user in a date range::
5239 - find all changesets by some user in a date range::
5236
5240
5237 hg log -k alice -d "may 2008 to jul 2008"
5241 hg log -k alice -d "may 2008 to jul 2008"
5238
5242
5239 - summary of all changesets after the last tag::
5243 - summary of all changesets after the last tag::
5240
5244
5241 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5245 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5242
5246
5243 See :hg:`help dates` for a list of formats valid for -d/--date.
5247 See :hg:`help dates` for a list of formats valid for -d/--date.
5244
5248
5245 See :hg:`help revisions` and :hg:`help revsets` for more about
5249 See :hg:`help revisions` and :hg:`help revsets` for more about
5246 specifying and ordering revisions.
5250 specifying and ordering revisions.
5247
5251
5248 See :hg:`help templates` for more about pre-packaged styles and
5252 See :hg:`help templates` for more about pre-packaged styles and
5249 specifying custom templates.
5253 specifying custom templates.
5250
5254
5251 Returns 0 on success.
5255 Returns 0 on success.
5252
5256
5253 """
5257 """
5254 if opts.get('follow') and opts.get('rev'):
5258 if opts.get('follow') and opts.get('rev'):
5255 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5259 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5256 del opts['follow']
5260 del opts['follow']
5257
5261
5258 if opts.get('graph'):
5262 if opts.get('graph'):
5259 return cmdutil.graphlog(ui, repo, *pats, **opts)
5263 return cmdutil.graphlog(ui, repo, *pats, **opts)
5260
5264
5261 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5265 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5262 limit = cmdutil.loglimit(opts)
5266 limit = cmdutil.loglimit(opts)
5263 count = 0
5267 count = 0
5264
5268
5265 getrenamed = None
5269 getrenamed = None
5266 if opts.get('copies'):
5270 if opts.get('copies'):
5267 endrev = None
5271 endrev = None
5268 if opts.get('rev'):
5272 if opts.get('rev'):
5269 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5273 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5270 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5274 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5271
5275
5272 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5276 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5273 for rev in revs:
5277 for rev in revs:
5274 if count == limit:
5278 if count == limit:
5275 break
5279 break
5276 ctx = repo[rev]
5280 ctx = repo[rev]
5277 copies = None
5281 copies = None
5278 if getrenamed is not None and rev:
5282 if getrenamed is not None and rev:
5279 copies = []
5283 copies = []
5280 for fn in ctx.files():
5284 for fn in ctx.files():
5281 rename = getrenamed(fn, rev)
5285 rename = getrenamed(fn, rev)
5282 if rename:
5286 if rename:
5283 copies.append((fn, rename[0]))
5287 copies.append((fn, rename[0]))
5284 if filematcher:
5288 if filematcher:
5285 revmatchfn = filematcher(ctx.rev())
5289 revmatchfn = filematcher(ctx.rev())
5286 else:
5290 else:
5287 revmatchfn = None
5291 revmatchfn = None
5288 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5292 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5289 if displayer.flush(ctx):
5293 if displayer.flush(ctx):
5290 count += 1
5294 count += 1
5291
5295
5292 displayer.close()
5296 displayer.close()
5293
5297
5294 @command('manifest',
5298 @command('manifest',
5295 [('r', 'rev', '', _('revision to display'), _('REV')),
5299 [('r', 'rev', '', _('revision to display'), _('REV')),
5296 ('', 'all', False, _("list files from all revisions"))]
5300 ('', 'all', False, _("list files from all revisions"))]
5297 + formatteropts,
5301 + formatteropts,
5298 _('[-r REV]'))
5302 _('[-r REV]'))
5299 def manifest(ui, repo, node=None, rev=None, **opts):
5303 def manifest(ui, repo, node=None, rev=None, **opts):
5300 """output the current or given revision of the project manifest
5304 """output the current or given revision of the project manifest
5301
5305
5302 Print a list of version controlled files for the given revision.
5306 Print a list of version controlled files for the given revision.
5303 If no revision is given, the first parent of the working directory
5307 If no revision is given, the first parent of the working directory
5304 is used, or the null revision if no revision is checked out.
5308 is used, or the null revision if no revision is checked out.
5305
5309
5306 With -v, print file permissions, symlink and executable bits.
5310 With -v, print file permissions, symlink and executable bits.
5307 With --debug, print file revision hashes.
5311 With --debug, print file revision hashes.
5308
5312
5309 If option --all is specified, the list of all files from all revisions
5313 If option --all is specified, the list of all files from all revisions
5310 is printed. This includes deleted and renamed files.
5314 is printed. This includes deleted and renamed files.
5311
5315
5312 Returns 0 on success.
5316 Returns 0 on success.
5313 """
5317 """
5314
5318
5315 fm = ui.formatter('manifest', opts)
5319 fm = ui.formatter('manifest', opts)
5316
5320
5317 if opts.get('all'):
5321 if opts.get('all'):
5318 if rev or node:
5322 if rev or node:
5319 raise error.Abort(_("can't specify a revision with --all"))
5323 raise error.Abort(_("can't specify a revision with --all"))
5320
5324
5321 res = []
5325 res = []
5322 prefix = "data/"
5326 prefix = "data/"
5323 suffix = ".i"
5327 suffix = ".i"
5324 plen = len(prefix)
5328 plen = len(prefix)
5325 slen = len(suffix)
5329 slen = len(suffix)
5326 with repo.lock():
5330 with repo.lock():
5327 for fn, b, size in repo.store.datafiles():
5331 for fn, b, size in repo.store.datafiles():
5328 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5332 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5329 res.append(fn[plen:-slen])
5333 res.append(fn[plen:-slen])
5330 for f in res:
5334 for f in res:
5331 fm.startitem()
5335 fm.startitem()
5332 fm.write("path", '%s\n', f)
5336 fm.write("path", '%s\n', f)
5333 fm.end()
5337 fm.end()
5334 return
5338 return
5335
5339
5336 if rev and node:
5340 if rev and node:
5337 raise error.Abort(_("please specify just one revision"))
5341 raise error.Abort(_("please specify just one revision"))
5338
5342
5339 if not node:
5343 if not node:
5340 node = rev
5344 node = rev
5341
5345
5342 char = {'l': '@', 'x': '*', '': ''}
5346 char = {'l': '@', 'x': '*', '': ''}
5343 mode = {'l': '644', 'x': '755', '': '644'}
5347 mode = {'l': '644', 'x': '755', '': '644'}
5344 ctx = scmutil.revsingle(repo, node)
5348 ctx = scmutil.revsingle(repo, node)
5345 mf = ctx.manifest()
5349 mf = ctx.manifest()
5346 for f in ctx:
5350 for f in ctx:
5347 fm.startitem()
5351 fm.startitem()
5348 fl = ctx[f].flags()
5352 fl = ctx[f].flags()
5349 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5353 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5350 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5354 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5351 fm.write('path', '%s\n', f)
5355 fm.write('path', '%s\n', f)
5352 fm.end()
5356 fm.end()
5353
5357
5354 @command('^merge',
5358 @command('^merge',
5355 [('f', 'force', None,
5359 [('f', 'force', None,
5356 _('force a merge including outstanding changes (DEPRECATED)')),
5360 _('force a merge including outstanding changes (DEPRECATED)')),
5357 ('r', 'rev', '', _('revision to merge'), _('REV')),
5361 ('r', 'rev', '', _('revision to merge'), _('REV')),
5358 ('P', 'preview', None,
5362 ('P', 'preview', None,
5359 _('review revisions to merge (no merge is performed)'))
5363 _('review revisions to merge (no merge is performed)'))
5360 ] + mergetoolopts,
5364 ] + mergetoolopts,
5361 _('[-P] [[-r] REV]'))
5365 _('[-P] [[-r] REV]'))
5362 def merge(ui, repo, node=None, **opts):
5366 def merge(ui, repo, node=None, **opts):
5363 """merge another revision into working directory
5367 """merge another revision into working directory
5364
5368
5365 The current working directory is updated with all changes made in
5369 The current working directory is updated with all changes made in
5366 the requested revision since the last common predecessor revision.
5370 the requested revision since the last common predecessor revision.
5367
5371
5368 Files that changed between either parent are marked as changed for
5372 Files that changed between either parent are marked as changed for
5369 the next commit and a commit must be performed before any further
5373 the next commit and a commit must be performed before any further
5370 updates to the repository are allowed. The next commit will have
5374 updates to the repository are allowed. The next commit will have
5371 two parents.
5375 two parents.
5372
5376
5373 ``--tool`` can be used to specify the merge tool used for file
5377 ``--tool`` can be used to specify the merge tool used for file
5374 merges. It overrides the HGMERGE environment variable and your
5378 merges. It overrides the HGMERGE environment variable and your
5375 configuration files. See :hg:`help merge-tools` for options.
5379 configuration files. See :hg:`help merge-tools` for options.
5376
5380
5377 If no revision is specified, the working directory's parent is a
5381 If no revision is specified, the working directory's parent is a
5378 head revision, and the current branch contains exactly one other
5382 head revision, and the current branch contains exactly one other
5379 head, the other head is merged with by default. Otherwise, an
5383 head, the other head is merged with by default. Otherwise, an
5380 explicit revision with which to merge with must be provided.
5384 explicit revision with which to merge with must be provided.
5381
5385
5382 See :hg:`help resolve` for information on handling file conflicts.
5386 See :hg:`help resolve` for information on handling file conflicts.
5383
5387
5384 To undo an uncommitted merge, use :hg:`update --clean .` which
5388 To undo an uncommitted merge, use :hg:`update --clean .` which
5385 will check out a clean copy of the original merge parent, losing
5389 will check out a clean copy of the original merge parent, losing
5386 all changes.
5390 all changes.
5387
5391
5388 Returns 0 on success, 1 if there are unresolved files.
5392 Returns 0 on success, 1 if there are unresolved files.
5389 """
5393 """
5390
5394
5391 if opts.get('rev') and node:
5395 if opts.get('rev') and node:
5392 raise error.Abort(_("please specify just one revision"))
5396 raise error.Abort(_("please specify just one revision"))
5393 if not node:
5397 if not node:
5394 node = opts.get('rev')
5398 node = opts.get('rev')
5395
5399
5396 if node:
5400 if node:
5397 node = scmutil.revsingle(repo, node).node()
5401 node = scmutil.revsingle(repo, node).node()
5398
5402
5399 if not node:
5403 if not node:
5400 node = repo[destutil.destmerge(repo)].node()
5404 node = repo[destutil.destmerge(repo)].node()
5401
5405
5402 if opts.get('preview'):
5406 if opts.get('preview'):
5403 # find nodes that are ancestors of p2 but not of p1
5407 # find nodes that are ancestors of p2 but not of p1
5404 p1 = repo.lookup('.')
5408 p1 = repo.lookup('.')
5405 p2 = repo.lookup(node)
5409 p2 = repo.lookup(node)
5406 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5410 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5407
5411
5408 displayer = cmdutil.show_changeset(ui, repo, opts)
5412 displayer = cmdutil.show_changeset(ui, repo, opts)
5409 for node in nodes:
5413 for node in nodes:
5410 displayer.show(repo[node])
5414 displayer.show(repo[node])
5411 displayer.close()
5415 displayer.close()
5412 return 0
5416 return 0
5413
5417
5414 try:
5418 try:
5415 # ui.forcemerge is an internal variable, do not document
5419 # ui.forcemerge is an internal variable, do not document
5416 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5420 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5417 force = opts.get('force')
5421 force = opts.get('force')
5418 return hg.merge(repo, node, force=force, mergeforce=force)
5422 return hg.merge(repo, node, force=force, mergeforce=force)
5419 finally:
5423 finally:
5420 ui.setconfig('ui', 'forcemerge', '', 'merge')
5424 ui.setconfig('ui', 'forcemerge', '', 'merge')
5421
5425
5422 @command('outgoing|out',
5426 @command('outgoing|out',
5423 [('f', 'force', None, _('run even when the destination is unrelated')),
5427 [('f', 'force', None, _('run even when the destination is unrelated')),
5424 ('r', 'rev', [],
5428 ('r', 'rev', [],
5425 _('a changeset intended to be included in the destination'), _('REV')),
5429 _('a changeset intended to be included in the destination'), _('REV')),
5426 ('n', 'newest-first', None, _('show newest record first')),
5430 ('n', 'newest-first', None, _('show newest record first')),
5427 ('B', 'bookmarks', False, _('compare bookmarks')),
5431 ('B', 'bookmarks', False, _('compare bookmarks')),
5428 ('b', 'branch', [], _('a specific branch you would like to push'),
5432 ('b', 'branch', [], _('a specific branch you would like to push'),
5429 _('BRANCH')),
5433 _('BRANCH')),
5430 ] + logopts + remoteopts + subrepoopts,
5434 ] + logopts + remoteopts + subrepoopts,
5431 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5435 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5432 def outgoing(ui, repo, dest=None, **opts):
5436 def outgoing(ui, repo, dest=None, **opts):
5433 """show changesets not found in the destination
5437 """show changesets not found in the destination
5434
5438
5435 Show changesets not found in the specified destination repository
5439 Show changesets not found in the specified destination repository
5436 or the default push location. These are the changesets that would
5440 or the default push location. These are the changesets that would
5437 be pushed if a push was requested.
5441 be pushed if a push was requested.
5438
5442
5439 See pull for details of valid destination formats.
5443 See pull for details of valid destination formats.
5440
5444
5441 .. container:: verbose
5445 .. container:: verbose
5442
5446
5443 With -B/--bookmarks, the result of bookmark comparison between
5447 With -B/--bookmarks, the result of bookmark comparison between
5444 local and remote repositories is displayed. With -v/--verbose,
5448 local and remote repositories is displayed. With -v/--verbose,
5445 status is also displayed for each bookmark like below::
5449 status is also displayed for each bookmark like below::
5446
5450
5447 BM1 01234567890a added
5451 BM1 01234567890a added
5448 BM2 deleted
5452 BM2 deleted
5449 BM3 234567890abc advanced
5453 BM3 234567890abc advanced
5450 BM4 34567890abcd diverged
5454 BM4 34567890abcd diverged
5451 BM5 4567890abcde changed
5455 BM5 4567890abcde changed
5452
5456
5453 The action taken when pushing depends on the
5457 The action taken when pushing depends on the
5454 status of each bookmark:
5458 status of each bookmark:
5455
5459
5456 :``added``: push with ``-B`` will create it
5460 :``added``: push with ``-B`` will create it
5457 :``deleted``: push with ``-B`` will delete it
5461 :``deleted``: push with ``-B`` will delete it
5458 :``advanced``: push will update it
5462 :``advanced``: push will update it
5459 :``diverged``: push with ``-B`` will update it
5463 :``diverged``: push with ``-B`` will update it
5460 :``changed``: push with ``-B`` will update it
5464 :``changed``: push with ``-B`` will update it
5461
5465
5462 From the point of view of pushing behavior, bookmarks
5466 From the point of view of pushing behavior, bookmarks
5463 existing only in the remote repository are treated as
5467 existing only in the remote repository are treated as
5464 ``deleted``, even if it is in fact added remotely.
5468 ``deleted``, even if it is in fact added remotely.
5465
5469
5466 Returns 0 if there are outgoing changes, 1 otherwise.
5470 Returns 0 if there are outgoing changes, 1 otherwise.
5467 """
5471 """
5468 if opts.get('graph'):
5472 if opts.get('graph'):
5469 cmdutil.checkunsupportedgraphflags([], opts)
5473 cmdutil.checkunsupportedgraphflags([], opts)
5470 o, other = hg._outgoing(ui, repo, dest, opts)
5474 o, other = hg._outgoing(ui, repo, dest, opts)
5471 if not o:
5475 if not o:
5472 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5476 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5473 return
5477 return
5474
5478
5475 revdag = cmdutil.graphrevs(repo, o, opts)
5479 revdag = cmdutil.graphrevs(repo, o, opts)
5476 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5480 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5477 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5481 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5478 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5482 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5479 return 0
5483 return 0
5480
5484
5481 if opts.get('bookmarks'):
5485 if opts.get('bookmarks'):
5482 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5486 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5483 dest, branches = hg.parseurl(dest, opts.get('branch'))
5487 dest, branches = hg.parseurl(dest, opts.get('branch'))
5484 other = hg.peer(repo, opts, dest)
5488 other = hg.peer(repo, opts, dest)
5485 if 'bookmarks' not in other.listkeys('namespaces'):
5489 if 'bookmarks' not in other.listkeys('namespaces'):
5486 ui.warn(_("remote doesn't support bookmarks\n"))
5490 ui.warn(_("remote doesn't support bookmarks\n"))
5487 return 0
5491 return 0
5488 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5492 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5489 return bookmarks.outgoing(ui, repo, other)
5493 return bookmarks.outgoing(ui, repo, other)
5490
5494
5491 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5495 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5492 try:
5496 try:
5493 return hg.outgoing(ui, repo, dest, opts)
5497 return hg.outgoing(ui, repo, dest, opts)
5494 finally:
5498 finally:
5495 del repo._subtoppath
5499 del repo._subtoppath
5496
5500
5497 @command('parents',
5501 @command('parents',
5498 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5502 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5499 ] + templateopts,
5503 ] + templateopts,
5500 _('[-r REV] [FILE]'),
5504 _('[-r REV] [FILE]'),
5501 inferrepo=True)
5505 inferrepo=True)
5502 def parents(ui, repo, file_=None, **opts):
5506 def parents(ui, repo, file_=None, **opts):
5503 """show the parents of the working directory or revision (DEPRECATED)
5507 """show the parents of the working directory or revision (DEPRECATED)
5504
5508
5505 Print the working directory's parent revisions. If a revision is
5509 Print the working directory's parent revisions. If a revision is
5506 given via -r/--rev, the parent of that revision will be printed.
5510 given via -r/--rev, the parent of that revision will be printed.
5507 If a file argument is given, the revision in which the file was
5511 If a file argument is given, the revision in which the file was
5508 last changed (before the working directory revision or the
5512 last changed (before the working directory revision or the
5509 argument to --rev if given) is printed.
5513 argument to --rev if given) is printed.
5510
5514
5511 This command is equivalent to::
5515 This command is equivalent to::
5512
5516
5513 hg log -r "p1()+p2()" or
5517 hg log -r "p1()+p2()" or
5514 hg log -r "p1(REV)+p2(REV)" or
5518 hg log -r "p1(REV)+p2(REV)" or
5515 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5519 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5516 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5520 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5517
5521
5518 See :hg:`summary` and :hg:`help revsets` for related information.
5522 See :hg:`summary` and :hg:`help revsets` for related information.
5519
5523
5520 Returns 0 on success.
5524 Returns 0 on success.
5521 """
5525 """
5522
5526
5523 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5527 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5524
5528
5525 if file_:
5529 if file_:
5526 m = scmutil.match(ctx, (file_,), opts)
5530 m = scmutil.match(ctx, (file_,), opts)
5527 if m.anypats() or len(m.files()) != 1:
5531 if m.anypats() or len(m.files()) != 1:
5528 raise error.Abort(_('can only specify an explicit filename'))
5532 raise error.Abort(_('can only specify an explicit filename'))
5529 file_ = m.files()[0]
5533 file_ = m.files()[0]
5530 filenodes = []
5534 filenodes = []
5531 for cp in ctx.parents():
5535 for cp in ctx.parents():
5532 if not cp:
5536 if not cp:
5533 continue
5537 continue
5534 try:
5538 try:
5535 filenodes.append(cp.filenode(file_))
5539 filenodes.append(cp.filenode(file_))
5536 except error.LookupError:
5540 except error.LookupError:
5537 pass
5541 pass
5538 if not filenodes:
5542 if not filenodes:
5539 raise error.Abort(_("'%s' not found in manifest!") % file_)
5543 raise error.Abort(_("'%s' not found in manifest!") % file_)
5540 p = []
5544 p = []
5541 for fn in filenodes:
5545 for fn in filenodes:
5542 fctx = repo.filectx(file_, fileid=fn)
5546 fctx = repo.filectx(file_, fileid=fn)
5543 p.append(fctx.node())
5547 p.append(fctx.node())
5544 else:
5548 else:
5545 p = [cp.node() for cp in ctx.parents()]
5549 p = [cp.node() for cp in ctx.parents()]
5546
5550
5547 displayer = cmdutil.show_changeset(ui, repo, opts)
5551 displayer = cmdutil.show_changeset(ui, repo, opts)
5548 for n in p:
5552 for n in p:
5549 if n != nullid:
5553 if n != nullid:
5550 displayer.show(repo[n])
5554 displayer.show(repo[n])
5551 displayer.close()
5555 displayer.close()
5552
5556
5553 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5557 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5554 def paths(ui, repo, search=None, **opts):
5558 def paths(ui, repo, search=None, **opts):
5555 """show aliases for remote repositories
5559 """show aliases for remote repositories
5556
5560
5557 Show definition of symbolic path name NAME. If no name is given,
5561 Show definition of symbolic path name NAME. If no name is given,
5558 show definition of all available names.
5562 show definition of all available names.
5559
5563
5560 Option -q/--quiet suppresses all output when searching for NAME
5564 Option -q/--quiet suppresses all output when searching for NAME
5561 and shows only the path names when listing all definitions.
5565 and shows only the path names when listing all definitions.
5562
5566
5563 Path names are defined in the [paths] section of your
5567 Path names are defined in the [paths] section of your
5564 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5568 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5565 repository, ``.hg/hgrc`` is used, too.
5569 repository, ``.hg/hgrc`` is used, too.
5566
5570
5567 The path names ``default`` and ``default-push`` have a special
5571 The path names ``default`` and ``default-push`` have a special
5568 meaning. When performing a push or pull operation, they are used
5572 meaning. When performing a push or pull operation, they are used
5569 as fallbacks if no location is specified on the command-line.
5573 as fallbacks if no location is specified on the command-line.
5570 When ``default-push`` is set, it will be used for push and
5574 When ``default-push`` is set, it will be used for push and
5571 ``default`` will be used for pull; otherwise ``default`` is used
5575 ``default`` will be used for pull; otherwise ``default`` is used
5572 as the fallback for both. When cloning a repository, the clone
5576 as the fallback for both. When cloning a repository, the clone
5573 source is written as ``default`` in ``.hg/hgrc``.
5577 source is written as ``default`` in ``.hg/hgrc``.
5574
5578
5575 .. note::
5579 .. note::
5576
5580
5577 ``default`` and ``default-push`` apply to all inbound (e.g.
5581 ``default`` and ``default-push`` apply to all inbound (e.g.
5578 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5582 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5579 and :hg:`bundle`) operations.
5583 and :hg:`bundle`) operations.
5580
5584
5581 See :hg:`help urls` for more information.
5585 See :hg:`help urls` for more information.
5582
5586
5583 Returns 0 on success.
5587 Returns 0 on success.
5584 """
5588 """
5585 if search:
5589 if search:
5586 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5590 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5587 if name == search]
5591 if name == search]
5588 else:
5592 else:
5589 pathitems = sorted(ui.paths.iteritems())
5593 pathitems = sorted(ui.paths.iteritems())
5590
5594
5591 fm = ui.formatter('paths', opts)
5595 fm = ui.formatter('paths', opts)
5592 if fm:
5596 if fm:
5593 hidepassword = str
5597 hidepassword = str
5594 else:
5598 else:
5595 hidepassword = util.hidepassword
5599 hidepassword = util.hidepassword
5596 if ui.quiet:
5600 if ui.quiet:
5597 namefmt = '%s\n'
5601 namefmt = '%s\n'
5598 else:
5602 else:
5599 namefmt = '%s = '
5603 namefmt = '%s = '
5600 showsubopts = not search and not ui.quiet
5604 showsubopts = not search and not ui.quiet
5601
5605
5602 for name, path in pathitems:
5606 for name, path in pathitems:
5603 fm.startitem()
5607 fm.startitem()
5604 fm.condwrite(not search, 'name', namefmt, name)
5608 fm.condwrite(not search, 'name', namefmt, name)
5605 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5609 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5606 for subopt, value in sorted(path.suboptions.items()):
5610 for subopt, value in sorted(path.suboptions.items()):
5607 assert subopt not in ('name', 'url')
5611 assert subopt not in ('name', 'url')
5608 if showsubopts:
5612 if showsubopts:
5609 fm.plain('%s:%s = ' % (name, subopt))
5613 fm.plain('%s:%s = ' % (name, subopt))
5610 fm.condwrite(showsubopts, subopt, '%s\n', value)
5614 fm.condwrite(showsubopts, subopt, '%s\n', value)
5611
5615
5612 fm.end()
5616 fm.end()
5613
5617
5614 if search and not pathitems:
5618 if search and not pathitems:
5615 if not ui.quiet:
5619 if not ui.quiet:
5616 ui.warn(_("not found!\n"))
5620 ui.warn(_("not found!\n"))
5617 return 1
5621 return 1
5618 else:
5622 else:
5619 return 0
5623 return 0
5620
5624
5621 @command('phase',
5625 @command('phase',
5622 [('p', 'public', False, _('set changeset phase to public')),
5626 [('p', 'public', False, _('set changeset phase to public')),
5623 ('d', 'draft', False, _('set changeset phase to draft')),
5627 ('d', 'draft', False, _('set changeset phase to draft')),
5624 ('s', 'secret', False, _('set changeset phase to secret')),
5628 ('s', 'secret', False, _('set changeset phase to secret')),
5625 ('f', 'force', False, _('allow to move boundary backward')),
5629 ('f', 'force', False, _('allow to move boundary backward')),
5626 ('r', 'rev', [], _('target revision'), _('REV')),
5630 ('r', 'rev', [], _('target revision'), _('REV')),
5627 ],
5631 ],
5628 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5632 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5629 def phase(ui, repo, *revs, **opts):
5633 def phase(ui, repo, *revs, **opts):
5630 """set or show the current phase name
5634 """set or show the current phase name
5631
5635
5632 With no argument, show the phase name of the current revision(s).
5636 With no argument, show the phase name of the current revision(s).
5633
5637
5634 With one of -p/--public, -d/--draft or -s/--secret, change the
5638 With one of -p/--public, -d/--draft or -s/--secret, change the
5635 phase value of the specified revisions.
5639 phase value of the specified revisions.
5636
5640
5637 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5641 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5638 lower phase to an higher phase. Phases are ordered as follows::
5642 lower phase to an higher phase. Phases are ordered as follows::
5639
5643
5640 public < draft < secret
5644 public < draft < secret
5641
5645
5642 Returns 0 on success, 1 if some phases could not be changed.
5646 Returns 0 on success, 1 if some phases could not be changed.
5643
5647
5644 (For more information about the phases concept, see :hg:`help phases`.)
5648 (For more information about the phases concept, see :hg:`help phases`.)
5645 """
5649 """
5646 # search for a unique phase argument
5650 # search for a unique phase argument
5647 targetphase = None
5651 targetphase = None
5648 for idx, name in enumerate(phases.phasenames):
5652 for idx, name in enumerate(phases.phasenames):
5649 if opts[name]:
5653 if opts[name]:
5650 if targetphase is not None:
5654 if targetphase is not None:
5651 raise error.Abort(_('only one phase can be specified'))
5655 raise error.Abort(_('only one phase can be specified'))
5652 targetphase = idx
5656 targetphase = idx
5653
5657
5654 # look for specified revision
5658 # look for specified revision
5655 revs = list(revs)
5659 revs = list(revs)
5656 revs.extend(opts['rev'])
5660 revs.extend(opts['rev'])
5657 if not revs:
5661 if not revs:
5658 # display both parents as the second parent phase can influence
5662 # display both parents as the second parent phase can influence
5659 # the phase of a merge commit
5663 # the phase of a merge commit
5660 revs = [c.rev() for c in repo[None].parents()]
5664 revs = [c.rev() for c in repo[None].parents()]
5661
5665
5662 revs = scmutil.revrange(repo, revs)
5666 revs = scmutil.revrange(repo, revs)
5663
5667
5664 lock = None
5668 lock = None
5665 ret = 0
5669 ret = 0
5666 if targetphase is None:
5670 if targetphase is None:
5667 # display
5671 # display
5668 for r in revs:
5672 for r in revs:
5669 ctx = repo[r]
5673 ctx = repo[r]
5670 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5674 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5671 else:
5675 else:
5672 tr = None
5676 tr = None
5673 lock = repo.lock()
5677 lock = repo.lock()
5674 try:
5678 try:
5675 tr = repo.transaction("phase")
5679 tr = repo.transaction("phase")
5676 # set phase
5680 # set phase
5677 if not revs:
5681 if not revs:
5678 raise error.Abort(_('empty revision set'))
5682 raise error.Abort(_('empty revision set'))
5679 nodes = [repo[r].node() for r in revs]
5683 nodes = [repo[r].node() for r in revs]
5680 # moving revision from public to draft may hide them
5684 # moving revision from public to draft may hide them
5681 # We have to check result on an unfiltered repository
5685 # We have to check result on an unfiltered repository
5682 unfi = repo.unfiltered()
5686 unfi = repo.unfiltered()
5683 getphase = unfi._phasecache.phase
5687 getphase = unfi._phasecache.phase
5684 olddata = [getphase(unfi, r) for r in unfi]
5688 olddata = [getphase(unfi, r) for r in unfi]
5685 phases.advanceboundary(repo, tr, targetphase, nodes)
5689 phases.advanceboundary(repo, tr, targetphase, nodes)
5686 if opts['force']:
5690 if opts['force']:
5687 phases.retractboundary(repo, tr, targetphase, nodes)
5691 phases.retractboundary(repo, tr, targetphase, nodes)
5688 tr.close()
5692 tr.close()
5689 finally:
5693 finally:
5690 if tr is not None:
5694 if tr is not None:
5691 tr.release()
5695 tr.release()
5692 lock.release()
5696 lock.release()
5693 getphase = unfi._phasecache.phase
5697 getphase = unfi._phasecache.phase
5694 newdata = [getphase(unfi, r) for r in unfi]
5698 newdata = [getphase(unfi, r) for r in unfi]
5695 changes = sum(newdata[r] != olddata[r] for r in unfi)
5699 changes = sum(newdata[r] != olddata[r] for r in unfi)
5696 cl = unfi.changelog
5700 cl = unfi.changelog
5697 rejected = [n for n in nodes
5701 rejected = [n for n in nodes
5698 if newdata[cl.rev(n)] < targetphase]
5702 if newdata[cl.rev(n)] < targetphase]
5699 if rejected:
5703 if rejected:
5700 ui.warn(_('cannot move %i changesets to a higher '
5704 ui.warn(_('cannot move %i changesets to a higher '
5701 'phase, use --force\n') % len(rejected))
5705 'phase, use --force\n') % len(rejected))
5702 ret = 1
5706 ret = 1
5703 if changes:
5707 if changes:
5704 msg = _('phase changed for %i changesets\n') % changes
5708 msg = _('phase changed for %i changesets\n') % changes
5705 if ret:
5709 if ret:
5706 ui.status(msg)
5710 ui.status(msg)
5707 else:
5711 else:
5708 ui.note(msg)
5712 ui.note(msg)
5709 else:
5713 else:
5710 ui.warn(_('no phases changed\n'))
5714 ui.warn(_('no phases changed\n'))
5711 return ret
5715 return ret
5712
5716
5713 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5717 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5714 """Run after a changegroup has been added via pull/unbundle
5718 """Run after a changegroup has been added via pull/unbundle
5715
5719
5716 This takes arguments below:
5720 This takes arguments below:
5717
5721
5718 :modheads: change of heads by pull/unbundle
5722 :modheads: change of heads by pull/unbundle
5719 :optupdate: updating working directory is needed or not
5723 :optupdate: updating working directory is needed or not
5720 :checkout: update destination revision (or None to default destination)
5724 :checkout: update destination revision (or None to default destination)
5721 :brev: a name, which might be a bookmark to be activated after updating
5725 :brev: a name, which might be a bookmark to be activated after updating
5722 """
5726 """
5723 if modheads == 0:
5727 if modheads == 0:
5724 return
5728 return
5725 if optupdate:
5729 if optupdate:
5726 try:
5730 try:
5727 return hg.updatetotally(ui, repo, checkout, brev)
5731 return hg.updatetotally(ui, repo, checkout, brev)
5728 except error.UpdateAbort as inst:
5732 except error.UpdateAbort as inst:
5729 msg = _("not updating: %s") % str(inst)
5733 msg = _("not updating: %s") % str(inst)
5730 hint = inst.hint
5734 hint = inst.hint
5731 raise error.UpdateAbort(msg, hint=hint)
5735 raise error.UpdateAbort(msg, hint=hint)
5732 if modheads > 1:
5736 if modheads > 1:
5733 currentbranchheads = len(repo.branchheads())
5737 currentbranchheads = len(repo.branchheads())
5734 if currentbranchheads == modheads:
5738 if currentbranchheads == modheads:
5735 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5739 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5736 elif currentbranchheads > 1:
5740 elif currentbranchheads > 1:
5737 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5741 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5738 "merge)\n"))
5742 "merge)\n"))
5739 else:
5743 else:
5740 ui.status(_("(run 'hg heads' to see heads)\n"))
5744 ui.status(_("(run 'hg heads' to see heads)\n"))
5741 else:
5745 else:
5742 ui.status(_("(run 'hg update' to get a working copy)\n"))
5746 ui.status(_("(run 'hg update' to get a working copy)\n"))
5743
5747
5744 @command('^pull',
5748 @command('^pull',
5745 [('u', 'update', None,
5749 [('u', 'update', None,
5746 _('update to new branch head if changesets were pulled')),
5750 _('update to new branch head if changesets were pulled')),
5747 ('f', 'force', None, _('run even when remote repository is unrelated')),
5751 ('f', 'force', None, _('run even when remote repository is unrelated')),
5748 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5752 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5749 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5753 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5750 ('b', 'branch', [], _('a specific branch you would like to pull'),
5754 ('b', 'branch', [], _('a specific branch you would like to pull'),
5751 _('BRANCH')),
5755 _('BRANCH')),
5752 ] + remoteopts,
5756 ] + remoteopts,
5753 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5757 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5754 def pull(ui, repo, source="default", **opts):
5758 def pull(ui, repo, source="default", **opts):
5755 """pull changes from the specified source
5759 """pull changes from the specified source
5756
5760
5757 Pull changes from a remote repository to a local one.
5761 Pull changes from a remote repository to a local one.
5758
5762
5759 This finds all changes from the repository at the specified path
5763 This finds all changes from the repository at the specified path
5760 or URL and adds them to a local repository (the current one unless
5764 or URL and adds them to a local repository (the current one unless
5761 -R is specified). By default, this does not update the copy of the
5765 -R is specified). By default, this does not update the copy of the
5762 project in the working directory.
5766 project in the working directory.
5763
5767
5764 Use :hg:`incoming` if you want to see what would have been added
5768 Use :hg:`incoming` if you want to see what would have been added
5765 by a pull at the time you issued this command. If you then decide
5769 by a pull at the time you issued this command. If you then decide
5766 to add those changes to the repository, you should use :hg:`pull
5770 to add those changes to the repository, you should use :hg:`pull
5767 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5771 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5768
5772
5769 If SOURCE is omitted, the 'default' path will be used.
5773 If SOURCE is omitted, the 'default' path will be used.
5770 See :hg:`help urls` for more information.
5774 See :hg:`help urls` for more information.
5771
5775
5772 Returns 0 on success, 1 if an update had unresolved files.
5776 Returns 0 on success, 1 if an update had unresolved files.
5773 """
5777 """
5774 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5778 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5775 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5779 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5776 other = hg.peer(repo, opts, source)
5780 other = hg.peer(repo, opts, source)
5777 try:
5781 try:
5778 revs, checkout = hg.addbranchrevs(repo, other, branches,
5782 revs, checkout = hg.addbranchrevs(repo, other, branches,
5779 opts.get('rev'))
5783 opts.get('rev'))
5780
5784
5781
5785
5782 pullopargs = {}
5786 pullopargs = {}
5783 if opts.get('bookmark'):
5787 if opts.get('bookmark'):
5784 if not revs:
5788 if not revs:
5785 revs = []
5789 revs = []
5786 # The list of bookmark used here is not the one used to actually
5790 # The list of bookmark used here is not the one used to actually
5787 # update the bookmark name. This can result in the revision pulled
5791 # update the bookmark name. This can result in the revision pulled
5788 # not ending up with the name of the bookmark because of a race
5792 # not ending up with the name of the bookmark because of a race
5789 # condition on the server. (See issue 4689 for details)
5793 # condition on the server. (See issue 4689 for details)
5790 remotebookmarks = other.listkeys('bookmarks')
5794 remotebookmarks = other.listkeys('bookmarks')
5791 pullopargs['remotebookmarks'] = remotebookmarks
5795 pullopargs['remotebookmarks'] = remotebookmarks
5792 for b in opts['bookmark']:
5796 for b in opts['bookmark']:
5793 if b not in remotebookmarks:
5797 if b not in remotebookmarks:
5794 raise error.Abort(_('remote bookmark %s not found!') % b)
5798 raise error.Abort(_('remote bookmark %s not found!') % b)
5795 revs.append(remotebookmarks[b])
5799 revs.append(remotebookmarks[b])
5796
5800
5797 if revs:
5801 if revs:
5798 try:
5802 try:
5799 # When 'rev' is a bookmark name, we cannot guarantee that it
5803 # When 'rev' is a bookmark name, we cannot guarantee that it
5800 # will be updated with that name because of a race condition
5804 # will be updated with that name because of a race condition
5801 # server side. (See issue 4689 for details)
5805 # server side. (See issue 4689 for details)
5802 oldrevs = revs
5806 oldrevs = revs
5803 revs = [] # actually, nodes
5807 revs = [] # actually, nodes
5804 for r in oldrevs:
5808 for r in oldrevs:
5805 node = other.lookup(r)
5809 node = other.lookup(r)
5806 revs.append(node)
5810 revs.append(node)
5807 if r == checkout:
5811 if r == checkout:
5808 checkout = node
5812 checkout = node
5809 except error.CapabilityError:
5813 except error.CapabilityError:
5810 err = _("other repository doesn't support revision lookup, "
5814 err = _("other repository doesn't support revision lookup, "
5811 "so a rev cannot be specified.")
5815 "so a rev cannot be specified.")
5812 raise error.Abort(err)
5816 raise error.Abort(err)
5813
5817
5814 pullopargs.update(opts.get('opargs', {}))
5818 pullopargs.update(opts.get('opargs', {}))
5815 modheads = exchange.pull(repo, other, heads=revs,
5819 modheads = exchange.pull(repo, other, heads=revs,
5816 force=opts.get('force'),
5820 force=opts.get('force'),
5817 bookmarks=opts.get('bookmark', ()),
5821 bookmarks=opts.get('bookmark', ()),
5818 opargs=pullopargs).cgresult
5822 opargs=pullopargs).cgresult
5819
5823
5820 # brev is a name, which might be a bookmark to be activated at
5824 # brev is a name, which might be a bookmark to be activated at
5821 # the end of the update. In other words, it is an explicit
5825 # the end of the update. In other words, it is an explicit
5822 # destination of the update
5826 # destination of the update
5823 brev = None
5827 brev = None
5824
5828
5825 if checkout:
5829 if checkout:
5826 checkout = str(repo.changelog.rev(checkout))
5830 checkout = str(repo.changelog.rev(checkout))
5827
5831
5828 # order below depends on implementation of
5832 # order below depends on implementation of
5829 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5833 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5830 # because 'checkout' is determined without it.
5834 # because 'checkout' is determined without it.
5831 if opts.get('rev'):
5835 if opts.get('rev'):
5832 brev = opts['rev'][0]
5836 brev = opts['rev'][0]
5833 elif opts.get('branch'):
5837 elif opts.get('branch'):
5834 brev = opts['branch'][0]
5838 brev = opts['branch'][0]
5835 else:
5839 else:
5836 brev = branches[0]
5840 brev = branches[0]
5837 repo._subtoppath = source
5841 repo._subtoppath = source
5838 try:
5842 try:
5839 ret = postincoming(ui, repo, modheads, opts.get('update'),
5843 ret = postincoming(ui, repo, modheads, opts.get('update'),
5840 checkout, brev)
5844 checkout, brev)
5841
5845
5842 finally:
5846 finally:
5843 del repo._subtoppath
5847 del repo._subtoppath
5844
5848
5845 finally:
5849 finally:
5846 other.close()
5850 other.close()
5847 return ret
5851 return ret
5848
5852
5849 @command('^push',
5853 @command('^push',
5850 [('f', 'force', None, _('force push')),
5854 [('f', 'force', None, _('force push')),
5851 ('r', 'rev', [],
5855 ('r', 'rev', [],
5852 _('a changeset intended to be included in the destination'),
5856 _('a changeset intended to be included in the destination'),
5853 _('REV')),
5857 _('REV')),
5854 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5858 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5855 ('b', 'branch', [],
5859 ('b', 'branch', [],
5856 _('a specific branch you would like to push'), _('BRANCH')),
5860 _('a specific branch you would like to push'), _('BRANCH')),
5857 ('', 'new-branch', False, _('allow pushing a new branch')),
5861 ('', 'new-branch', False, _('allow pushing a new branch')),
5858 ] + remoteopts,
5862 ] + remoteopts,
5859 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5863 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5860 def push(ui, repo, dest=None, **opts):
5864 def push(ui, repo, dest=None, **opts):
5861 """push changes to the specified destination
5865 """push changes to the specified destination
5862
5866
5863 Push changesets from the local repository to the specified
5867 Push changesets from the local repository to the specified
5864 destination.
5868 destination.
5865
5869
5866 This operation is symmetrical to pull: it is identical to a pull
5870 This operation is symmetrical to pull: it is identical to a pull
5867 in the destination repository from the current one.
5871 in the destination repository from the current one.
5868
5872
5869 By default, push will not allow creation of new heads at the
5873 By default, push will not allow creation of new heads at the
5870 destination, since multiple heads would make it unclear which head
5874 destination, since multiple heads would make it unclear which head
5871 to use. In this situation, it is recommended to pull and merge
5875 to use. In this situation, it is recommended to pull and merge
5872 before pushing.
5876 before pushing.
5873
5877
5874 Use --new-branch if you want to allow push to create a new named
5878 Use --new-branch if you want to allow push to create a new named
5875 branch that is not present at the destination. This allows you to
5879 branch that is not present at the destination. This allows you to
5876 only create a new branch without forcing other changes.
5880 only create a new branch without forcing other changes.
5877
5881
5878 .. note::
5882 .. note::
5879
5883
5880 Extra care should be taken with the -f/--force option,
5884 Extra care should be taken with the -f/--force option,
5881 which will push all new heads on all branches, an action which will
5885 which will push all new heads on all branches, an action which will
5882 almost always cause confusion for collaborators.
5886 almost always cause confusion for collaborators.
5883
5887
5884 If -r/--rev is used, the specified revision and all its ancestors
5888 If -r/--rev is used, the specified revision and all its ancestors
5885 will be pushed to the remote repository.
5889 will be pushed to the remote repository.
5886
5890
5887 If -B/--bookmark is used, the specified bookmarked revision, its
5891 If -B/--bookmark is used, the specified bookmarked revision, its
5888 ancestors, and the bookmark will be pushed to the remote
5892 ancestors, and the bookmark will be pushed to the remote
5889 repository. Specifying ``.`` is equivalent to specifying the active
5893 repository. Specifying ``.`` is equivalent to specifying the active
5890 bookmark's name.
5894 bookmark's name.
5891
5895
5892 Please see :hg:`help urls` for important details about ``ssh://``
5896 Please see :hg:`help urls` for important details about ``ssh://``
5893 URLs. If DESTINATION is omitted, a default path will be used.
5897 URLs. If DESTINATION is omitted, a default path will be used.
5894
5898
5895 Returns 0 if push was successful, 1 if nothing to push.
5899 Returns 0 if push was successful, 1 if nothing to push.
5896 """
5900 """
5897
5901
5898 if opts.get('bookmark'):
5902 if opts.get('bookmark'):
5899 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5903 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5900 for b in opts['bookmark']:
5904 for b in opts['bookmark']:
5901 # translate -B options to -r so changesets get pushed
5905 # translate -B options to -r so changesets get pushed
5902 b = repo._bookmarks.expandname(b)
5906 b = repo._bookmarks.expandname(b)
5903 if b in repo._bookmarks:
5907 if b in repo._bookmarks:
5904 opts.setdefault('rev', []).append(b)
5908 opts.setdefault('rev', []).append(b)
5905 else:
5909 else:
5906 # if we try to push a deleted bookmark, translate it to null
5910 # if we try to push a deleted bookmark, translate it to null
5907 # this lets simultaneous -r, -b options continue working
5911 # this lets simultaneous -r, -b options continue working
5908 opts.setdefault('rev', []).append("null")
5912 opts.setdefault('rev', []).append("null")
5909
5913
5910 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5914 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5911 if not path:
5915 if not path:
5912 raise error.Abort(_('default repository not configured!'),
5916 raise error.Abort(_('default repository not configured!'),
5913 hint=_('see the "path" section in "hg help config"'))
5917 hint=_('see the "path" section in "hg help config"'))
5914 dest = path.pushloc or path.loc
5918 dest = path.pushloc or path.loc
5915 branches = (path.branch, opts.get('branch') or [])
5919 branches = (path.branch, opts.get('branch') or [])
5916 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5920 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5917 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5921 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5918 other = hg.peer(repo, opts, dest)
5922 other = hg.peer(repo, opts, dest)
5919
5923
5920 if revs:
5924 if revs:
5921 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5925 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5922 if not revs:
5926 if not revs:
5923 raise error.Abort(_("specified revisions evaluate to an empty set"),
5927 raise error.Abort(_("specified revisions evaluate to an empty set"),
5924 hint=_("use different revision arguments"))
5928 hint=_("use different revision arguments"))
5925
5929
5926 repo._subtoppath = dest
5930 repo._subtoppath = dest
5927 try:
5931 try:
5928 # push subrepos depth-first for coherent ordering
5932 # push subrepos depth-first for coherent ordering
5929 c = repo['']
5933 c = repo['']
5930 subs = c.substate # only repos that are committed
5934 subs = c.substate # only repos that are committed
5931 for s in sorted(subs):
5935 for s in sorted(subs):
5932 result = c.sub(s).push(opts)
5936 result = c.sub(s).push(opts)
5933 if result == 0:
5937 if result == 0:
5934 return not result
5938 return not result
5935 finally:
5939 finally:
5936 del repo._subtoppath
5940 del repo._subtoppath
5937 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5941 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5938 newbranch=opts.get('new_branch'),
5942 newbranch=opts.get('new_branch'),
5939 bookmarks=opts.get('bookmark', ()),
5943 bookmarks=opts.get('bookmark', ()),
5940 opargs=opts.get('opargs'))
5944 opargs=opts.get('opargs'))
5941
5945
5942 result = not pushop.cgresult
5946 result = not pushop.cgresult
5943
5947
5944 if pushop.bkresult is not None:
5948 if pushop.bkresult is not None:
5945 if pushop.bkresult == 2:
5949 if pushop.bkresult == 2:
5946 result = 2
5950 result = 2
5947 elif not result and pushop.bkresult:
5951 elif not result and pushop.bkresult:
5948 result = 2
5952 result = 2
5949
5953
5950 return result
5954 return result
5951
5955
5952 @command('recover', [])
5956 @command('recover', [])
5953 def recover(ui, repo):
5957 def recover(ui, repo):
5954 """roll back an interrupted transaction
5958 """roll back an interrupted transaction
5955
5959
5956 Recover from an interrupted commit or pull.
5960 Recover from an interrupted commit or pull.
5957
5961
5958 This command tries to fix the repository status after an
5962 This command tries to fix the repository status after an
5959 interrupted operation. It should only be necessary when Mercurial
5963 interrupted operation. It should only be necessary when Mercurial
5960 suggests it.
5964 suggests it.
5961
5965
5962 Returns 0 if successful, 1 if nothing to recover or verify fails.
5966 Returns 0 if successful, 1 if nothing to recover or verify fails.
5963 """
5967 """
5964 if repo.recover():
5968 if repo.recover():
5965 return hg.verify(repo)
5969 return hg.verify(repo)
5966 return 1
5970 return 1
5967
5971
5968 @command('^remove|rm',
5972 @command('^remove|rm',
5969 [('A', 'after', None, _('record delete for missing files')),
5973 [('A', 'after', None, _('record delete for missing files')),
5970 ('f', 'force', None,
5974 ('f', 'force', None,
5971 _('forget added files, delete modified files')),
5975 _('forget added files, delete modified files')),
5972 ] + subrepoopts + walkopts,
5976 ] + subrepoopts + walkopts,
5973 _('[OPTION]... FILE...'),
5977 _('[OPTION]... FILE...'),
5974 inferrepo=True)
5978 inferrepo=True)
5975 def remove(ui, repo, *pats, **opts):
5979 def remove(ui, repo, *pats, **opts):
5976 """remove the specified files on the next commit
5980 """remove the specified files on the next commit
5977
5981
5978 Schedule the indicated files for removal from the current branch.
5982 Schedule the indicated files for removal from the current branch.
5979
5983
5980 This command schedules the files to be removed at the next commit.
5984 This command schedules the files to be removed at the next commit.
5981 To undo a remove before that, see :hg:`revert`. To undo added
5985 To undo a remove before that, see :hg:`revert`. To undo added
5982 files, see :hg:`forget`.
5986 files, see :hg:`forget`.
5983
5987
5984 .. container:: verbose
5988 .. container:: verbose
5985
5989
5986 -A/--after can be used to remove only files that have already
5990 -A/--after can be used to remove only files that have already
5987 been deleted, -f/--force can be used to force deletion, and -Af
5991 been deleted, -f/--force can be used to force deletion, and -Af
5988 can be used to remove files from the next revision without
5992 can be used to remove files from the next revision without
5989 deleting them from the working directory.
5993 deleting them from the working directory.
5990
5994
5991 The following table details the behavior of remove for different
5995 The following table details the behavior of remove for different
5992 file states (columns) and option combinations (rows). The file
5996 file states (columns) and option combinations (rows). The file
5993 states are Added [A], Clean [C], Modified [M] and Missing [!]
5997 states are Added [A], Clean [C], Modified [M] and Missing [!]
5994 (as reported by :hg:`status`). The actions are Warn, Remove
5998 (as reported by :hg:`status`). The actions are Warn, Remove
5995 (from branch) and Delete (from disk):
5999 (from branch) and Delete (from disk):
5996
6000
5997 ========= == == == ==
6001 ========= == == == ==
5998 opt/state A C M !
6002 opt/state A C M !
5999 ========= == == == ==
6003 ========= == == == ==
6000 none W RD W R
6004 none W RD W R
6001 -f R RD RD R
6005 -f R RD RD R
6002 -A W W W R
6006 -A W W W R
6003 -Af R R R R
6007 -Af R R R R
6004 ========= == == == ==
6008 ========= == == == ==
6005
6009
6006 .. note::
6010 .. note::
6007
6011
6008 :hg:`remove` never deletes files in Added [A] state from the
6012 :hg:`remove` never deletes files in Added [A] state from the
6009 working directory, not even if ``--force`` is specified.
6013 working directory, not even if ``--force`` is specified.
6010
6014
6011 Returns 0 on success, 1 if any warnings encountered.
6015 Returns 0 on success, 1 if any warnings encountered.
6012 """
6016 """
6013
6017
6014 after, force = opts.get('after'), opts.get('force')
6018 after, force = opts.get('after'), opts.get('force')
6015 if not pats and not after:
6019 if not pats and not after:
6016 raise error.Abort(_('no files specified'))
6020 raise error.Abort(_('no files specified'))
6017
6021
6018 m = scmutil.match(repo[None], pats, opts)
6022 m = scmutil.match(repo[None], pats, opts)
6019 subrepos = opts.get('subrepos')
6023 subrepos = opts.get('subrepos')
6020 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6024 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6021
6025
6022 @command('rename|move|mv',
6026 @command('rename|move|mv',
6023 [('A', 'after', None, _('record a rename that has already occurred')),
6027 [('A', 'after', None, _('record a rename that has already occurred')),
6024 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6028 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6025 ] + walkopts + dryrunopts,
6029 ] + walkopts + dryrunopts,
6026 _('[OPTION]... SOURCE... DEST'))
6030 _('[OPTION]... SOURCE... DEST'))
6027 def rename(ui, repo, *pats, **opts):
6031 def rename(ui, repo, *pats, **opts):
6028 """rename files; equivalent of copy + remove
6032 """rename files; equivalent of copy + remove
6029
6033
6030 Mark dest as copies of sources; mark sources for deletion. If dest
6034 Mark dest as copies of sources; mark sources for deletion. If dest
6031 is a directory, copies are put in that directory. If dest is a
6035 is a directory, copies are put in that directory. If dest is a
6032 file, there can only be one source.
6036 file, there can only be one source.
6033
6037
6034 By default, this command copies the contents of files as they
6038 By default, this command copies the contents of files as they
6035 exist in the working directory. If invoked with -A/--after, the
6039 exist in the working directory. If invoked with -A/--after, the
6036 operation is recorded, but no copying is performed.
6040 operation is recorded, but no copying is performed.
6037
6041
6038 This command takes effect at the next commit. To undo a rename
6042 This command takes effect at the next commit. To undo a rename
6039 before that, see :hg:`revert`.
6043 before that, see :hg:`revert`.
6040
6044
6041 Returns 0 on success, 1 if errors are encountered.
6045 Returns 0 on success, 1 if errors are encountered.
6042 """
6046 """
6043 with repo.wlock(False):
6047 with repo.wlock(False):
6044 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6048 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6045
6049
6046 @command('resolve',
6050 @command('resolve',
6047 [('a', 'all', None, _('select all unresolved files')),
6051 [('a', 'all', None, _('select all unresolved files')),
6048 ('l', 'list', None, _('list state of files needing merge')),
6052 ('l', 'list', None, _('list state of files needing merge')),
6049 ('m', 'mark', None, _('mark files as resolved')),
6053 ('m', 'mark', None, _('mark files as resolved')),
6050 ('u', 'unmark', None, _('mark files as unresolved')),
6054 ('u', 'unmark', None, _('mark files as unresolved')),
6051 ('n', 'no-status', None, _('hide status prefix'))]
6055 ('n', 'no-status', None, _('hide status prefix'))]
6052 + mergetoolopts + walkopts + formatteropts,
6056 + mergetoolopts + walkopts + formatteropts,
6053 _('[OPTION]... [FILE]...'),
6057 _('[OPTION]... [FILE]...'),
6054 inferrepo=True)
6058 inferrepo=True)
6055 def resolve(ui, repo, *pats, **opts):
6059 def resolve(ui, repo, *pats, **opts):
6056 """redo merges or set/view the merge status of files
6060 """redo merges or set/view the merge status of files
6057
6061
6058 Merges with unresolved conflicts are often the result of
6062 Merges with unresolved conflicts are often the result of
6059 non-interactive merging using the ``internal:merge`` configuration
6063 non-interactive merging using the ``internal:merge`` configuration
6060 setting, or a command-line merge tool like ``diff3``. The resolve
6064 setting, or a command-line merge tool like ``diff3``. The resolve
6061 command is used to manage the files involved in a merge, after
6065 command is used to manage the files involved in a merge, after
6062 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6066 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6063 working directory must have two parents). See :hg:`help
6067 working directory must have two parents). See :hg:`help
6064 merge-tools` for information on configuring merge tools.
6068 merge-tools` for information on configuring merge tools.
6065
6069
6066 The resolve command can be used in the following ways:
6070 The resolve command can be used in the following ways:
6067
6071
6068 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6072 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6069 files, discarding any previous merge attempts. Re-merging is not
6073 files, discarding any previous merge attempts. Re-merging is not
6070 performed for files already marked as resolved. Use ``--all/-a``
6074 performed for files already marked as resolved. Use ``--all/-a``
6071 to select all unresolved files. ``--tool`` can be used to specify
6075 to select all unresolved files. ``--tool`` can be used to specify
6072 the merge tool used for the given files. It overrides the HGMERGE
6076 the merge tool used for the given files. It overrides the HGMERGE
6073 environment variable and your configuration files. Previous file
6077 environment variable and your configuration files. Previous file
6074 contents are saved with a ``.orig`` suffix.
6078 contents are saved with a ``.orig`` suffix.
6075
6079
6076 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6080 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6077 (e.g. after having manually fixed-up the files). The default is
6081 (e.g. after having manually fixed-up the files). The default is
6078 to mark all unresolved files.
6082 to mark all unresolved files.
6079
6083
6080 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6084 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6081 default is to mark all resolved files.
6085 default is to mark all resolved files.
6082
6086
6083 - :hg:`resolve -l`: list files which had or still have conflicts.
6087 - :hg:`resolve -l`: list files which had or still have conflicts.
6084 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6088 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6085
6089
6086 .. note::
6090 .. note::
6087
6091
6088 Mercurial will not let you commit files with unresolved merge
6092 Mercurial will not let you commit files with unresolved merge
6089 conflicts. You must use :hg:`resolve -m ...` before you can
6093 conflicts. You must use :hg:`resolve -m ...` before you can
6090 commit after a conflicting merge.
6094 commit after a conflicting merge.
6091
6095
6092 Returns 0 on success, 1 if any files fail a resolve attempt.
6096 Returns 0 on success, 1 if any files fail a resolve attempt.
6093 """
6097 """
6094
6098
6095 flaglist = 'all mark unmark list no_status'.split()
6099 flaglist = 'all mark unmark list no_status'.split()
6096 all, mark, unmark, show, nostatus = \
6100 all, mark, unmark, show, nostatus = \
6097 [opts.get(o) for o in flaglist]
6101 [opts.get(o) for o in flaglist]
6098
6102
6099 if (show and (mark or unmark)) or (mark and unmark):
6103 if (show and (mark or unmark)) or (mark and unmark):
6100 raise error.Abort(_("too many options specified"))
6104 raise error.Abort(_("too many options specified"))
6101 if pats and all:
6105 if pats and all:
6102 raise error.Abort(_("can't specify --all and patterns"))
6106 raise error.Abort(_("can't specify --all and patterns"))
6103 if not (all or pats or show or mark or unmark):
6107 if not (all or pats or show or mark or unmark):
6104 raise error.Abort(_('no files or directories specified'),
6108 raise error.Abort(_('no files or directories specified'),
6105 hint=('use --all to re-merge all unresolved files'))
6109 hint=('use --all to re-merge all unresolved files'))
6106
6110
6107 if show:
6111 if show:
6108 fm = ui.formatter('resolve', opts)
6112 fm = ui.formatter('resolve', opts)
6109 ms = mergemod.mergestate.read(repo)
6113 ms = mergemod.mergestate.read(repo)
6110 m = scmutil.match(repo[None], pats, opts)
6114 m = scmutil.match(repo[None], pats, opts)
6111 for f in ms:
6115 for f in ms:
6112 if not m(f):
6116 if not m(f):
6113 continue
6117 continue
6114 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6118 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6115 'd': 'driverresolved'}[ms[f]]
6119 'd': 'driverresolved'}[ms[f]]
6116 fm.startitem()
6120 fm.startitem()
6117 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6121 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6118 fm.write('path', '%s\n', f, label=l)
6122 fm.write('path', '%s\n', f, label=l)
6119 fm.end()
6123 fm.end()
6120 return 0
6124 return 0
6121
6125
6122 with repo.wlock():
6126 with repo.wlock():
6123 ms = mergemod.mergestate.read(repo)
6127 ms = mergemod.mergestate.read(repo)
6124
6128
6125 if not (ms.active() or repo.dirstate.p2() != nullid):
6129 if not (ms.active() or repo.dirstate.p2() != nullid):
6126 raise error.Abort(
6130 raise error.Abort(
6127 _('resolve command not applicable when not merging'))
6131 _('resolve command not applicable when not merging'))
6128
6132
6129 wctx = repo[None]
6133 wctx = repo[None]
6130
6134
6131 if ms.mergedriver and ms.mdstate() == 'u':
6135 if ms.mergedriver and ms.mdstate() == 'u':
6132 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6136 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6133 ms.commit()
6137 ms.commit()
6134 # allow mark and unmark to go through
6138 # allow mark and unmark to go through
6135 if not mark and not unmark and not proceed:
6139 if not mark and not unmark and not proceed:
6136 return 1
6140 return 1
6137
6141
6138 m = scmutil.match(wctx, pats, opts)
6142 m = scmutil.match(wctx, pats, opts)
6139 ret = 0
6143 ret = 0
6140 didwork = False
6144 didwork = False
6141 runconclude = False
6145 runconclude = False
6142
6146
6143 tocomplete = []
6147 tocomplete = []
6144 for f in ms:
6148 for f in ms:
6145 if not m(f):
6149 if not m(f):
6146 continue
6150 continue
6147
6151
6148 didwork = True
6152 didwork = True
6149
6153
6150 # don't let driver-resolved files be marked, and run the conclude
6154 # don't let driver-resolved files be marked, and run the conclude
6151 # step if asked to resolve
6155 # step if asked to resolve
6152 if ms[f] == "d":
6156 if ms[f] == "d":
6153 exact = m.exact(f)
6157 exact = m.exact(f)
6154 if mark:
6158 if mark:
6155 if exact:
6159 if exact:
6156 ui.warn(_('not marking %s as it is driver-resolved\n')
6160 ui.warn(_('not marking %s as it is driver-resolved\n')
6157 % f)
6161 % f)
6158 elif unmark:
6162 elif unmark:
6159 if exact:
6163 if exact:
6160 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6164 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6161 % f)
6165 % f)
6162 else:
6166 else:
6163 runconclude = True
6167 runconclude = True
6164 continue
6168 continue
6165
6169
6166 if mark:
6170 if mark:
6167 ms.mark(f, "r")
6171 ms.mark(f, "r")
6168 elif unmark:
6172 elif unmark:
6169 ms.mark(f, "u")
6173 ms.mark(f, "u")
6170 else:
6174 else:
6171 # backup pre-resolve (merge uses .orig for its own purposes)
6175 # backup pre-resolve (merge uses .orig for its own purposes)
6172 a = repo.wjoin(f)
6176 a = repo.wjoin(f)
6173 try:
6177 try:
6174 util.copyfile(a, a + ".resolve")
6178 util.copyfile(a, a + ".resolve")
6175 except (IOError, OSError) as inst:
6179 except (IOError, OSError) as inst:
6176 if inst.errno != errno.ENOENT:
6180 if inst.errno != errno.ENOENT:
6177 raise
6181 raise
6178
6182
6179 try:
6183 try:
6180 # preresolve file
6184 # preresolve file
6181 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6185 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6182 'resolve')
6186 'resolve')
6183 complete, r = ms.preresolve(f, wctx)
6187 complete, r = ms.preresolve(f, wctx)
6184 if not complete:
6188 if not complete:
6185 tocomplete.append(f)
6189 tocomplete.append(f)
6186 elif r:
6190 elif r:
6187 ret = 1
6191 ret = 1
6188 finally:
6192 finally:
6189 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6193 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6190 ms.commit()
6194 ms.commit()
6191
6195
6192 # replace filemerge's .orig file with our resolve file, but only
6196 # replace filemerge's .orig file with our resolve file, but only
6193 # for merges that are complete
6197 # for merges that are complete
6194 if complete:
6198 if complete:
6195 try:
6199 try:
6196 util.rename(a + ".resolve",
6200 util.rename(a + ".resolve",
6197 scmutil.origpath(ui, repo, a))
6201 scmutil.origpath(ui, repo, a))
6198 except OSError as inst:
6202 except OSError as inst:
6199 if inst.errno != errno.ENOENT:
6203 if inst.errno != errno.ENOENT:
6200 raise
6204 raise
6201
6205
6202 for f in tocomplete:
6206 for f in tocomplete:
6203 try:
6207 try:
6204 # resolve file
6208 # resolve file
6205 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6209 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6206 'resolve')
6210 'resolve')
6207 r = ms.resolve(f, wctx)
6211 r = ms.resolve(f, wctx)
6208 if r:
6212 if r:
6209 ret = 1
6213 ret = 1
6210 finally:
6214 finally:
6211 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6215 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6212 ms.commit()
6216 ms.commit()
6213
6217
6214 # replace filemerge's .orig file with our resolve file
6218 # replace filemerge's .orig file with our resolve file
6215 a = repo.wjoin(f)
6219 a = repo.wjoin(f)
6216 try:
6220 try:
6217 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6221 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6218 except OSError as inst:
6222 except OSError as inst:
6219 if inst.errno != errno.ENOENT:
6223 if inst.errno != errno.ENOENT:
6220 raise
6224 raise
6221
6225
6222 ms.commit()
6226 ms.commit()
6223 ms.recordactions()
6227 ms.recordactions()
6224
6228
6225 if not didwork and pats:
6229 if not didwork and pats:
6226 hint = None
6230 hint = None
6227 if not any([p for p in pats if p.find(':') >= 0]):
6231 if not any([p for p in pats if p.find(':') >= 0]):
6228 pats = ['path:%s' % p for p in pats]
6232 pats = ['path:%s' % p for p in pats]
6229 m = scmutil.match(wctx, pats, opts)
6233 m = scmutil.match(wctx, pats, opts)
6230 for f in ms:
6234 for f in ms:
6231 if not m(f):
6235 if not m(f):
6232 continue
6236 continue
6233 flags = ''.join(['-%s ' % o[0] for o in flaglist
6237 flags = ''.join(['-%s ' % o[0] for o in flaglist
6234 if opts.get(o)])
6238 if opts.get(o)])
6235 hint = _("(try: hg resolve %s%s)\n") % (
6239 hint = _("(try: hg resolve %s%s)\n") % (
6236 flags,
6240 flags,
6237 ' '.join(pats))
6241 ' '.join(pats))
6238 break
6242 break
6239 ui.warn(_("arguments do not match paths that need resolving\n"))
6243 ui.warn(_("arguments do not match paths that need resolving\n"))
6240 if hint:
6244 if hint:
6241 ui.warn(hint)
6245 ui.warn(hint)
6242 elif ms.mergedriver and ms.mdstate() != 's':
6246 elif ms.mergedriver and ms.mdstate() != 's':
6243 # run conclude step when either a driver-resolved file is requested
6247 # run conclude step when either a driver-resolved file is requested
6244 # or there are no driver-resolved files
6248 # or there are no driver-resolved files
6245 # we can't use 'ret' to determine whether any files are unresolved
6249 # we can't use 'ret' to determine whether any files are unresolved
6246 # because we might not have tried to resolve some
6250 # because we might not have tried to resolve some
6247 if ((runconclude or not list(ms.driverresolved()))
6251 if ((runconclude or not list(ms.driverresolved()))
6248 and not list(ms.unresolved())):
6252 and not list(ms.unresolved())):
6249 proceed = mergemod.driverconclude(repo, ms, wctx)
6253 proceed = mergemod.driverconclude(repo, ms, wctx)
6250 ms.commit()
6254 ms.commit()
6251 if not proceed:
6255 if not proceed:
6252 return 1
6256 return 1
6253
6257
6254 # Nudge users into finishing an unfinished operation
6258 # Nudge users into finishing an unfinished operation
6255 unresolvedf = list(ms.unresolved())
6259 unresolvedf = list(ms.unresolved())
6256 driverresolvedf = list(ms.driverresolved())
6260 driverresolvedf = list(ms.driverresolved())
6257 if not unresolvedf and not driverresolvedf:
6261 if not unresolvedf and not driverresolvedf:
6258 ui.status(_('(no more unresolved files)\n'))
6262 ui.status(_('(no more unresolved files)\n'))
6259 cmdutil.checkafterresolved(repo)
6263 cmdutil.checkafterresolved(repo)
6260 elif not unresolvedf:
6264 elif not unresolvedf:
6261 ui.status(_('(no more unresolved files -- '
6265 ui.status(_('(no more unresolved files -- '
6262 'run "hg resolve --all" to conclude)\n'))
6266 'run "hg resolve --all" to conclude)\n'))
6263
6267
6264 return ret
6268 return ret
6265
6269
6266 @command('revert',
6270 @command('revert',
6267 [('a', 'all', None, _('revert all changes when no arguments given')),
6271 [('a', 'all', None, _('revert all changes when no arguments given')),
6268 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6272 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6269 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6273 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6270 ('C', 'no-backup', None, _('do not save backup copies of files')),
6274 ('C', 'no-backup', None, _('do not save backup copies of files')),
6271 ('i', 'interactive', None,
6275 ('i', 'interactive', None,
6272 _('interactively select the changes (EXPERIMENTAL)')),
6276 _('interactively select the changes (EXPERIMENTAL)')),
6273 ] + walkopts + dryrunopts,
6277 ] + walkopts + dryrunopts,
6274 _('[OPTION]... [-r REV] [NAME]...'))
6278 _('[OPTION]... [-r REV] [NAME]...'))
6275 def revert(ui, repo, *pats, **opts):
6279 def revert(ui, repo, *pats, **opts):
6276 """restore files to their checkout state
6280 """restore files to their checkout state
6277
6281
6278 .. note::
6282 .. note::
6279
6283
6280 To check out earlier revisions, you should use :hg:`update REV`.
6284 To check out earlier revisions, you should use :hg:`update REV`.
6281 To cancel an uncommitted merge (and lose your changes),
6285 To cancel an uncommitted merge (and lose your changes),
6282 use :hg:`update --clean .`.
6286 use :hg:`update --clean .`.
6283
6287
6284 With no revision specified, revert the specified files or directories
6288 With no revision specified, revert the specified files or directories
6285 to the contents they had in the parent of the working directory.
6289 to the contents they had in the parent of the working directory.
6286 This restores the contents of files to an unmodified
6290 This restores the contents of files to an unmodified
6287 state and unschedules adds, removes, copies, and renames. If the
6291 state and unschedules adds, removes, copies, and renames. If the
6288 working directory has two parents, you must explicitly specify a
6292 working directory has two parents, you must explicitly specify a
6289 revision.
6293 revision.
6290
6294
6291 Using the -r/--rev or -d/--date options, revert the given files or
6295 Using the -r/--rev or -d/--date options, revert the given files or
6292 directories to their states as of a specific revision. Because
6296 directories to their states as of a specific revision. Because
6293 revert does not change the working directory parents, this will
6297 revert does not change the working directory parents, this will
6294 cause these files to appear modified. This can be helpful to "back
6298 cause these files to appear modified. This can be helpful to "back
6295 out" some or all of an earlier change. See :hg:`backout` for a
6299 out" some or all of an earlier change. See :hg:`backout` for a
6296 related method.
6300 related method.
6297
6301
6298 Modified files are saved with a .orig suffix before reverting.
6302 Modified files are saved with a .orig suffix before reverting.
6299 To disable these backups, use --no-backup.
6303 To disable these backups, use --no-backup.
6300
6304
6301 See :hg:`help dates` for a list of formats valid for -d/--date.
6305 See :hg:`help dates` for a list of formats valid for -d/--date.
6302
6306
6303 See :hg:`help backout` for a way to reverse the effect of an
6307 See :hg:`help backout` for a way to reverse the effect of an
6304 earlier changeset.
6308 earlier changeset.
6305
6309
6306 Returns 0 on success.
6310 Returns 0 on success.
6307 """
6311 """
6308
6312
6309 if opts.get("date"):
6313 if opts.get("date"):
6310 if opts.get("rev"):
6314 if opts.get("rev"):
6311 raise error.Abort(_("you can't specify a revision and a date"))
6315 raise error.Abort(_("you can't specify a revision and a date"))
6312 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6316 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6313
6317
6314 parent, p2 = repo.dirstate.parents()
6318 parent, p2 = repo.dirstate.parents()
6315 if not opts.get('rev') and p2 != nullid:
6319 if not opts.get('rev') and p2 != nullid:
6316 # revert after merge is a trap for new users (issue2915)
6320 # revert after merge is a trap for new users (issue2915)
6317 raise error.Abort(_('uncommitted merge with no revision specified'),
6321 raise error.Abort(_('uncommitted merge with no revision specified'),
6318 hint=_('use "hg update" or see "hg help revert"'))
6322 hint=_('use "hg update" or see "hg help revert"'))
6319
6323
6320 ctx = scmutil.revsingle(repo, opts.get('rev'))
6324 ctx = scmutil.revsingle(repo, opts.get('rev'))
6321
6325
6322 if (not (pats or opts.get('include') or opts.get('exclude') or
6326 if (not (pats or opts.get('include') or opts.get('exclude') or
6323 opts.get('all') or opts.get('interactive'))):
6327 opts.get('all') or opts.get('interactive'))):
6324 msg = _("no files or directories specified")
6328 msg = _("no files or directories specified")
6325 if p2 != nullid:
6329 if p2 != nullid:
6326 hint = _("uncommitted merge, use --all to discard all changes,"
6330 hint = _("uncommitted merge, use --all to discard all changes,"
6327 " or 'hg update -C .' to abort the merge")
6331 " or 'hg update -C .' to abort the merge")
6328 raise error.Abort(msg, hint=hint)
6332 raise error.Abort(msg, hint=hint)
6329 dirty = any(repo.status())
6333 dirty = any(repo.status())
6330 node = ctx.node()
6334 node = ctx.node()
6331 if node != parent:
6335 if node != parent:
6332 if dirty:
6336 if dirty:
6333 hint = _("uncommitted changes, use --all to discard all"
6337 hint = _("uncommitted changes, use --all to discard all"
6334 " changes, or 'hg update %s' to update") % ctx.rev()
6338 " changes, or 'hg update %s' to update") % ctx.rev()
6335 else:
6339 else:
6336 hint = _("use --all to revert all files,"
6340 hint = _("use --all to revert all files,"
6337 " or 'hg update %s' to update") % ctx.rev()
6341 " or 'hg update %s' to update") % ctx.rev()
6338 elif dirty:
6342 elif dirty:
6339 hint = _("uncommitted changes, use --all to discard all changes")
6343 hint = _("uncommitted changes, use --all to discard all changes")
6340 else:
6344 else:
6341 hint = _("use --all to revert all files")
6345 hint = _("use --all to revert all files")
6342 raise error.Abort(msg, hint=hint)
6346 raise error.Abort(msg, hint=hint)
6343
6347
6344 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6348 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6345
6349
6346 @command('rollback', dryrunopts +
6350 @command('rollback', dryrunopts +
6347 [('f', 'force', False, _('ignore safety measures'))])
6351 [('f', 'force', False, _('ignore safety measures'))])
6348 def rollback(ui, repo, **opts):
6352 def rollback(ui, repo, **opts):
6349 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6353 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6350
6354
6351 Please use :hg:`commit --amend` instead of rollback to correct
6355 Please use :hg:`commit --amend` instead of rollback to correct
6352 mistakes in the last commit.
6356 mistakes in the last commit.
6353
6357
6354 This command should be used with care. There is only one level of
6358 This command should be used with care. There is only one level of
6355 rollback, and there is no way to undo a rollback. It will also
6359 rollback, and there is no way to undo a rollback. It will also
6356 restore the dirstate at the time of the last transaction, losing
6360 restore the dirstate at the time of the last transaction, losing
6357 any dirstate changes since that time. This command does not alter
6361 any dirstate changes since that time. This command does not alter
6358 the working directory.
6362 the working directory.
6359
6363
6360 Transactions are used to encapsulate the effects of all commands
6364 Transactions are used to encapsulate the effects of all commands
6361 that create new changesets or propagate existing changesets into a
6365 that create new changesets or propagate existing changesets into a
6362 repository.
6366 repository.
6363
6367
6364 .. container:: verbose
6368 .. container:: verbose
6365
6369
6366 For example, the following commands are transactional, and their
6370 For example, the following commands are transactional, and their
6367 effects can be rolled back:
6371 effects can be rolled back:
6368
6372
6369 - commit
6373 - commit
6370 - import
6374 - import
6371 - pull
6375 - pull
6372 - push (with this repository as the destination)
6376 - push (with this repository as the destination)
6373 - unbundle
6377 - unbundle
6374
6378
6375 To avoid permanent data loss, rollback will refuse to rollback a
6379 To avoid permanent data loss, rollback will refuse to rollback a
6376 commit transaction if it isn't checked out. Use --force to
6380 commit transaction if it isn't checked out. Use --force to
6377 override this protection.
6381 override this protection.
6378
6382
6379 This command is not intended for use on public repositories. Once
6383 This command is not intended for use on public repositories. Once
6380 changes are visible for pull by other users, rolling a transaction
6384 changes are visible for pull by other users, rolling a transaction
6381 back locally is ineffective (someone else may already have pulled
6385 back locally is ineffective (someone else may already have pulled
6382 the changes). Furthermore, a race is possible with readers of the
6386 the changes). Furthermore, a race is possible with readers of the
6383 repository; for example an in-progress pull from the repository
6387 repository; for example an in-progress pull from the repository
6384 may fail if a rollback is performed.
6388 may fail if a rollback is performed.
6385
6389
6386 Returns 0 on success, 1 if no rollback data is available.
6390 Returns 0 on success, 1 if no rollback data is available.
6387 """
6391 """
6388 return repo.rollback(dryrun=opts.get('dry_run'),
6392 return repo.rollback(dryrun=opts.get('dry_run'),
6389 force=opts.get('force'))
6393 force=opts.get('force'))
6390
6394
6391 @command('root', [])
6395 @command('root', [])
6392 def root(ui, repo):
6396 def root(ui, repo):
6393 """print the root (top) of the current working directory
6397 """print the root (top) of the current working directory
6394
6398
6395 Print the root directory of the current repository.
6399 Print the root directory of the current repository.
6396
6400
6397 Returns 0 on success.
6401 Returns 0 on success.
6398 """
6402 """
6399 ui.write(repo.root + "\n")
6403 ui.write(repo.root + "\n")
6400
6404
6401 @command('^serve',
6405 @command('^serve',
6402 [('A', 'accesslog', '', _('name of access log file to write to'),
6406 [('A', 'accesslog', '', _('name of access log file to write to'),
6403 _('FILE')),
6407 _('FILE')),
6404 ('d', 'daemon', None, _('run server in background')),
6408 ('d', 'daemon', None, _('run server in background')),
6405 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6409 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6406 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6410 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6407 # use string type, then we can check if something was passed
6411 # use string type, then we can check if something was passed
6408 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6412 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6409 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6413 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6410 _('ADDR')),
6414 _('ADDR')),
6411 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6415 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6412 _('PREFIX')),
6416 _('PREFIX')),
6413 ('n', 'name', '',
6417 ('n', 'name', '',
6414 _('name to show in web pages (default: working directory)'), _('NAME')),
6418 _('name to show in web pages (default: working directory)'), _('NAME')),
6415 ('', 'web-conf', '',
6419 ('', 'web-conf', '',
6416 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6420 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6417 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6421 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6418 _('FILE')),
6422 _('FILE')),
6419 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6423 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6420 ('', 'stdio', None, _('for remote clients')),
6424 ('', 'stdio', None, _('for remote clients')),
6421 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6425 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6422 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6426 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6423 ('', 'style', '', _('template style to use'), _('STYLE')),
6427 ('', 'style', '', _('template style to use'), _('STYLE')),
6424 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6428 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6425 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6429 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6426 _('[OPTION]...'),
6430 _('[OPTION]...'),
6427 optionalrepo=True)
6431 optionalrepo=True)
6428 def serve(ui, repo, **opts):
6432 def serve(ui, repo, **opts):
6429 """start stand-alone webserver
6433 """start stand-alone webserver
6430
6434
6431 Start a local HTTP repository browser and pull server. You can use
6435 Start a local HTTP repository browser and pull server. You can use
6432 this for ad-hoc sharing and browsing of repositories. It is
6436 this for ad-hoc sharing and browsing of repositories. It is
6433 recommended to use a real web server to serve a repository for
6437 recommended to use a real web server to serve a repository for
6434 longer periods of time.
6438 longer periods of time.
6435
6439
6436 Please note that the server does not implement access control.
6440 Please note that the server does not implement access control.
6437 This means that, by default, anybody can read from the server and
6441 This means that, by default, anybody can read from the server and
6438 nobody can write to it by default. Set the ``web.allow_push``
6442 nobody can write to it by default. Set the ``web.allow_push``
6439 option to ``*`` to allow everybody to push to the server. You
6443 option to ``*`` to allow everybody to push to the server. You
6440 should use a real web server if you need to authenticate users.
6444 should use a real web server if you need to authenticate users.
6441
6445
6442 By default, the server logs accesses to stdout and errors to
6446 By default, the server logs accesses to stdout and errors to
6443 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6447 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6444 files.
6448 files.
6445
6449
6446 To have the server choose a free port number to listen on, specify
6450 To have the server choose a free port number to listen on, specify
6447 a port number of 0; in this case, the server will print the port
6451 a port number of 0; in this case, the server will print the port
6448 number it uses.
6452 number it uses.
6449
6453
6450 Returns 0 on success.
6454 Returns 0 on success.
6451 """
6455 """
6452
6456
6453 if opts["stdio"] and opts["cmdserver"]:
6457 if opts["stdio"] and opts["cmdserver"]:
6454 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6458 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6455
6459
6456 if opts["stdio"]:
6460 if opts["stdio"]:
6457 if repo is None:
6461 if repo is None:
6458 raise error.RepoError(_("there is no Mercurial repository here"
6462 raise error.RepoError(_("there is no Mercurial repository here"
6459 " (.hg not found)"))
6463 " (.hg not found)"))
6460 s = sshserver.sshserver(ui, repo)
6464 s = sshserver.sshserver(ui, repo)
6461 s.serve_forever()
6465 s.serve_forever()
6462
6466
6463 if opts["cmdserver"]:
6467 if opts["cmdserver"]:
6464 service = commandserver.createservice(ui, repo, opts)
6468 service = commandserver.createservice(ui, repo, opts)
6465 else:
6469 else:
6466 service = hgweb.createservice(ui, repo, opts)
6470 service = hgweb.createservice(ui, repo, opts)
6467 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6471 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6468
6472
6469 @command('^status|st',
6473 @command('^status|st',
6470 [('A', 'all', None, _('show status of all files')),
6474 [('A', 'all', None, _('show status of all files')),
6471 ('m', 'modified', None, _('show only modified files')),
6475 ('m', 'modified', None, _('show only modified files')),
6472 ('a', 'added', None, _('show only added files')),
6476 ('a', 'added', None, _('show only added files')),
6473 ('r', 'removed', None, _('show only removed files')),
6477 ('r', 'removed', None, _('show only removed files')),
6474 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6478 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6475 ('c', 'clean', None, _('show only files without changes')),
6479 ('c', 'clean', None, _('show only files without changes')),
6476 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6480 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6477 ('i', 'ignored', None, _('show only ignored files')),
6481 ('i', 'ignored', None, _('show only ignored files')),
6478 ('n', 'no-status', None, _('hide status prefix')),
6482 ('n', 'no-status', None, _('hide status prefix')),
6479 ('C', 'copies', None, _('show source of copied files')),
6483 ('C', 'copies', None, _('show source of copied files')),
6480 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6484 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6481 ('', 'rev', [], _('show difference from revision'), _('REV')),
6485 ('', 'rev', [], _('show difference from revision'), _('REV')),
6482 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6486 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6483 ] + walkopts + subrepoopts + formatteropts,
6487 ] + walkopts + subrepoopts + formatteropts,
6484 _('[OPTION]... [FILE]...'),
6488 _('[OPTION]... [FILE]...'),
6485 inferrepo=True)
6489 inferrepo=True)
6486 def status(ui, repo, *pats, **opts):
6490 def status(ui, repo, *pats, **opts):
6487 """show changed files in the working directory
6491 """show changed files in the working directory
6488
6492
6489 Show status of files in the repository. If names are given, only
6493 Show status of files in the repository. If names are given, only
6490 files that match are shown. Files that are clean or ignored or
6494 files that match are shown. Files that are clean or ignored or
6491 the source of a copy/move operation, are not listed unless
6495 the source of a copy/move operation, are not listed unless
6492 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6496 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6493 Unless options described with "show only ..." are given, the
6497 Unless options described with "show only ..." are given, the
6494 options -mardu are used.
6498 options -mardu are used.
6495
6499
6496 Option -q/--quiet hides untracked (unknown and ignored) files
6500 Option -q/--quiet hides untracked (unknown and ignored) files
6497 unless explicitly requested with -u/--unknown or -i/--ignored.
6501 unless explicitly requested with -u/--unknown or -i/--ignored.
6498
6502
6499 .. note::
6503 .. note::
6500
6504
6501 :hg:`status` may appear to disagree with diff if permissions have
6505 :hg:`status` may appear to disagree with diff if permissions have
6502 changed or a merge has occurred. The standard diff format does
6506 changed or a merge has occurred. The standard diff format does
6503 not report permission changes and diff only reports changes
6507 not report permission changes and diff only reports changes
6504 relative to one merge parent.
6508 relative to one merge parent.
6505
6509
6506 If one revision is given, it is used as the base revision.
6510 If one revision is given, it is used as the base revision.
6507 If two revisions are given, the differences between them are
6511 If two revisions are given, the differences between them are
6508 shown. The --change option can also be used as a shortcut to list
6512 shown. The --change option can also be used as a shortcut to list
6509 the changed files of a revision from its first parent.
6513 the changed files of a revision from its first parent.
6510
6514
6511 The codes used to show the status of files are::
6515 The codes used to show the status of files are::
6512
6516
6513 M = modified
6517 M = modified
6514 A = added
6518 A = added
6515 R = removed
6519 R = removed
6516 C = clean
6520 C = clean
6517 ! = missing (deleted by non-hg command, but still tracked)
6521 ! = missing (deleted by non-hg command, but still tracked)
6518 ? = not tracked
6522 ? = not tracked
6519 I = ignored
6523 I = ignored
6520 = origin of the previous file (with --copies)
6524 = origin of the previous file (with --copies)
6521
6525
6522 .. container:: verbose
6526 .. container:: verbose
6523
6527
6524 Examples:
6528 Examples:
6525
6529
6526 - show changes in the working directory relative to a
6530 - show changes in the working directory relative to a
6527 changeset::
6531 changeset::
6528
6532
6529 hg status --rev 9353
6533 hg status --rev 9353
6530
6534
6531 - show changes in the working directory relative to the
6535 - show changes in the working directory relative to the
6532 current directory (see :hg:`help patterns` for more information)::
6536 current directory (see :hg:`help patterns` for more information)::
6533
6537
6534 hg status re:
6538 hg status re:
6535
6539
6536 - show all changes including copies in an existing changeset::
6540 - show all changes including copies in an existing changeset::
6537
6541
6538 hg status --copies --change 9353
6542 hg status --copies --change 9353
6539
6543
6540 - get a NUL separated list of added files, suitable for xargs::
6544 - get a NUL separated list of added files, suitable for xargs::
6541
6545
6542 hg status -an0
6546 hg status -an0
6543
6547
6544 Returns 0 on success.
6548 Returns 0 on success.
6545 """
6549 """
6546
6550
6547 revs = opts.get('rev')
6551 revs = opts.get('rev')
6548 change = opts.get('change')
6552 change = opts.get('change')
6549
6553
6550 if revs and change:
6554 if revs and change:
6551 msg = _('cannot specify --rev and --change at the same time')
6555 msg = _('cannot specify --rev and --change at the same time')
6552 raise error.Abort(msg)
6556 raise error.Abort(msg)
6553 elif change:
6557 elif change:
6554 node2 = scmutil.revsingle(repo, change, None).node()
6558 node2 = scmutil.revsingle(repo, change, None).node()
6555 node1 = repo[node2].p1().node()
6559 node1 = repo[node2].p1().node()
6556 else:
6560 else:
6557 node1, node2 = scmutil.revpair(repo, revs)
6561 node1, node2 = scmutil.revpair(repo, revs)
6558
6562
6559 if pats:
6563 if pats:
6560 cwd = repo.getcwd()
6564 cwd = repo.getcwd()
6561 else:
6565 else:
6562 cwd = ''
6566 cwd = ''
6563
6567
6564 if opts.get('print0'):
6568 if opts.get('print0'):
6565 end = '\0'
6569 end = '\0'
6566 else:
6570 else:
6567 end = '\n'
6571 end = '\n'
6568 copy = {}
6572 copy = {}
6569 states = 'modified added removed deleted unknown ignored clean'.split()
6573 states = 'modified added removed deleted unknown ignored clean'.split()
6570 show = [k for k in states if opts.get(k)]
6574 show = [k for k in states if opts.get(k)]
6571 if opts.get('all'):
6575 if opts.get('all'):
6572 show += ui.quiet and (states[:4] + ['clean']) or states
6576 show += ui.quiet and (states[:4] + ['clean']) or states
6573 if not show:
6577 if not show:
6574 if ui.quiet:
6578 if ui.quiet:
6575 show = states[:4]
6579 show = states[:4]
6576 else:
6580 else:
6577 show = states[:5]
6581 show = states[:5]
6578
6582
6579 m = scmutil.match(repo[node2], pats, opts)
6583 m = scmutil.match(repo[node2], pats, opts)
6580 stat = repo.status(node1, node2, m,
6584 stat = repo.status(node1, node2, m,
6581 'ignored' in show, 'clean' in show, 'unknown' in show,
6585 'ignored' in show, 'clean' in show, 'unknown' in show,
6582 opts.get('subrepos'))
6586 opts.get('subrepos'))
6583 changestates = zip(states, 'MAR!?IC', stat)
6587 changestates = zip(states, 'MAR!?IC', stat)
6584
6588
6585 if (opts.get('all') or opts.get('copies')
6589 if (opts.get('all') or opts.get('copies')
6586 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6590 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6587 copy = copies.pathcopies(repo[node1], repo[node2], m)
6591 copy = copies.pathcopies(repo[node1], repo[node2], m)
6588
6592
6589 fm = ui.formatter('status', opts)
6593 fm = ui.formatter('status', opts)
6590 fmt = '%s' + end
6594 fmt = '%s' + end
6591 showchar = not opts.get('no_status')
6595 showchar = not opts.get('no_status')
6592
6596
6593 for state, char, files in changestates:
6597 for state, char, files in changestates:
6594 if state in show:
6598 if state in show:
6595 label = 'status.' + state
6599 label = 'status.' + state
6596 for f in files:
6600 for f in files:
6597 fm.startitem()
6601 fm.startitem()
6598 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6602 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6599 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6603 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6600 if f in copy:
6604 if f in copy:
6601 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6605 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6602 label='status.copied')
6606 label='status.copied')
6603 fm.end()
6607 fm.end()
6604
6608
6605 @command('^summary|sum',
6609 @command('^summary|sum',
6606 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6610 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6607 def summary(ui, repo, **opts):
6611 def summary(ui, repo, **opts):
6608 """summarize working directory state
6612 """summarize working directory state
6609
6613
6610 This generates a brief summary of the working directory state,
6614 This generates a brief summary of the working directory state,
6611 including parents, branch, commit status, phase and available updates.
6615 including parents, branch, commit status, phase and available updates.
6612
6616
6613 With the --remote option, this will check the default paths for
6617 With the --remote option, this will check the default paths for
6614 incoming and outgoing changes. This can be time-consuming.
6618 incoming and outgoing changes. This can be time-consuming.
6615
6619
6616 Returns 0 on success.
6620 Returns 0 on success.
6617 """
6621 """
6618
6622
6619 ctx = repo[None]
6623 ctx = repo[None]
6620 parents = ctx.parents()
6624 parents = ctx.parents()
6621 pnode = parents[0].node()
6625 pnode = parents[0].node()
6622 marks = []
6626 marks = []
6623
6627
6624 ms = None
6628 ms = None
6625 try:
6629 try:
6626 ms = mergemod.mergestate.read(repo)
6630 ms = mergemod.mergestate.read(repo)
6627 except error.UnsupportedMergeRecords as e:
6631 except error.UnsupportedMergeRecords as e:
6628 s = ' '.join(e.recordtypes)
6632 s = ' '.join(e.recordtypes)
6629 ui.warn(
6633 ui.warn(
6630 _('warning: merge state has unsupported record types: %s\n') % s)
6634 _('warning: merge state has unsupported record types: %s\n') % s)
6631 unresolved = 0
6635 unresolved = 0
6632 else:
6636 else:
6633 unresolved = [f for f in ms if ms[f] == 'u']
6637 unresolved = [f for f in ms if ms[f] == 'u']
6634
6638
6635 for p in parents:
6639 for p in parents:
6636 # label with log.changeset (instead of log.parent) since this
6640 # label with log.changeset (instead of log.parent) since this
6637 # shows a working directory parent *changeset*:
6641 # shows a working directory parent *changeset*:
6638 # i18n: column positioning for "hg summary"
6642 # i18n: column positioning for "hg summary"
6639 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6643 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6640 label='log.changeset changeset.%s' % p.phasestr())
6644 label='log.changeset changeset.%s' % p.phasestr())
6641 ui.write(' '.join(p.tags()), label='log.tag')
6645 ui.write(' '.join(p.tags()), label='log.tag')
6642 if p.bookmarks():
6646 if p.bookmarks():
6643 marks.extend(p.bookmarks())
6647 marks.extend(p.bookmarks())
6644 if p.rev() == -1:
6648 if p.rev() == -1:
6645 if not len(repo):
6649 if not len(repo):
6646 ui.write(_(' (empty repository)'))
6650 ui.write(_(' (empty repository)'))
6647 else:
6651 else:
6648 ui.write(_(' (no revision checked out)'))
6652 ui.write(_(' (no revision checked out)'))
6649 ui.write('\n')
6653 ui.write('\n')
6650 if p.description():
6654 if p.description():
6651 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6655 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6652 label='log.summary')
6656 label='log.summary')
6653
6657
6654 branch = ctx.branch()
6658 branch = ctx.branch()
6655 bheads = repo.branchheads(branch)
6659 bheads = repo.branchheads(branch)
6656 # i18n: column positioning for "hg summary"
6660 # i18n: column positioning for "hg summary"
6657 m = _('branch: %s\n') % branch
6661 m = _('branch: %s\n') % branch
6658 if branch != 'default':
6662 if branch != 'default':
6659 ui.write(m, label='log.branch')
6663 ui.write(m, label='log.branch')
6660 else:
6664 else:
6661 ui.status(m, label='log.branch')
6665 ui.status(m, label='log.branch')
6662
6666
6663 if marks:
6667 if marks:
6664 active = repo._activebookmark
6668 active = repo._activebookmark
6665 # i18n: column positioning for "hg summary"
6669 # i18n: column positioning for "hg summary"
6666 ui.write(_('bookmarks:'), label='log.bookmark')
6670 ui.write(_('bookmarks:'), label='log.bookmark')
6667 if active is not None:
6671 if active is not None:
6668 if active in marks:
6672 if active in marks:
6669 ui.write(' *' + active, label=activebookmarklabel)
6673 ui.write(' *' + active, label=activebookmarklabel)
6670 marks.remove(active)
6674 marks.remove(active)
6671 else:
6675 else:
6672 ui.write(' [%s]' % active, label=activebookmarklabel)
6676 ui.write(' [%s]' % active, label=activebookmarklabel)
6673 for m in marks:
6677 for m in marks:
6674 ui.write(' ' + m, label='log.bookmark')
6678 ui.write(' ' + m, label='log.bookmark')
6675 ui.write('\n', label='log.bookmark')
6679 ui.write('\n', label='log.bookmark')
6676
6680
6677 status = repo.status(unknown=True)
6681 status = repo.status(unknown=True)
6678
6682
6679 c = repo.dirstate.copies()
6683 c = repo.dirstate.copies()
6680 copied, renamed = [], []
6684 copied, renamed = [], []
6681 for d, s in c.iteritems():
6685 for d, s in c.iteritems():
6682 if s in status.removed:
6686 if s in status.removed:
6683 status.removed.remove(s)
6687 status.removed.remove(s)
6684 renamed.append(d)
6688 renamed.append(d)
6685 else:
6689 else:
6686 copied.append(d)
6690 copied.append(d)
6687 if d in status.added:
6691 if d in status.added:
6688 status.added.remove(d)
6692 status.added.remove(d)
6689
6693
6690 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6694 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6691
6695
6692 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6696 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6693 (ui.label(_('%d added'), 'status.added'), status.added),
6697 (ui.label(_('%d added'), 'status.added'), status.added),
6694 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6698 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6695 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6699 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6696 (ui.label(_('%d copied'), 'status.copied'), copied),
6700 (ui.label(_('%d copied'), 'status.copied'), copied),
6697 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6701 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6698 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6702 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6699 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6703 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6700 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6704 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6701 t = []
6705 t = []
6702 for l, s in labels:
6706 for l, s in labels:
6703 if s:
6707 if s:
6704 t.append(l % len(s))
6708 t.append(l % len(s))
6705
6709
6706 t = ', '.join(t)
6710 t = ', '.join(t)
6707 cleanworkdir = False
6711 cleanworkdir = False
6708
6712
6709 if repo.vfs.exists('graftstate'):
6713 if repo.vfs.exists('graftstate'):
6710 t += _(' (graft in progress)')
6714 t += _(' (graft in progress)')
6711 if repo.vfs.exists('updatestate'):
6715 if repo.vfs.exists('updatestate'):
6712 t += _(' (interrupted update)')
6716 t += _(' (interrupted update)')
6713 elif len(parents) > 1:
6717 elif len(parents) > 1:
6714 t += _(' (merge)')
6718 t += _(' (merge)')
6715 elif branch != parents[0].branch():
6719 elif branch != parents[0].branch():
6716 t += _(' (new branch)')
6720 t += _(' (new branch)')
6717 elif (parents[0].closesbranch() and
6721 elif (parents[0].closesbranch() and
6718 pnode in repo.branchheads(branch, closed=True)):
6722 pnode in repo.branchheads(branch, closed=True)):
6719 t += _(' (head closed)')
6723 t += _(' (head closed)')
6720 elif not (status.modified or status.added or status.removed or renamed or
6724 elif not (status.modified or status.added or status.removed or renamed or
6721 copied or subs):
6725 copied or subs):
6722 t += _(' (clean)')
6726 t += _(' (clean)')
6723 cleanworkdir = True
6727 cleanworkdir = True
6724 elif pnode not in bheads:
6728 elif pnode not in bheads:
6725 t += _(' (new branch head)')
6729 t += _(' (new branch head)')
6726
6730
6727 if parents:
6731 if parents:
6728 pendingphase = max(p.phase() for p in parents)
6732 pendingphase = max(p.phase() for p in parents)
6729 else:
6733 else:
6730 pendingphase = phases.public
6734 pendingphase = phases.public
6731
6735
6732 if pendingphase > phases.newcommitphase(ui):
6736 if pendingphase > phases.newcommitphase(ui):
6733 t += ' (%s)' % phases.phasenames[pendingphase]
6737 t += ' (%s)' % phases.phasenames[pendingphase]
6734
6738
6735 if cleanworkdir:
6739 if cleanworkdir:
6736 # i18n: column positioning for "hg summary"
6740 # i18n: column positioning for "hg summary"
6737 ui.status(_('commit: %s\n') % t.strip())
6741 ui.status(_('commit: %s\n') % t.strip())
6738 else:
6742 else:
6739 # i18n: column positioning for "hg summary"
6743 # i18n: column positioning for "hg summary"
6740 ui.write(_('commit: %s\n') % t.strip())
6744 ui.write(_('commit: %s\n') % t.strip())
6741
6745
6742 # all ancestors of branch heads - all ancestors of parent = new csets
6746 # all ancestors of branch heads - all ancestors of parent = new csets
6743 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6747 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6744 bheads))
6748 bheads))
6745
6749
6746 if new == 0:
6750 if new == 0:
6747 # i18n: column positioning for "hg summary"
6751 # i18n: column positioning for "hg summary"
6748 ui.status(_('update: (current)\n'))
6752 ui.status(_('update: (current)\n'))
6749 elif pnode not in bheads:
6753 elif pnode not in bheads:
6750 # i18n: column positioning for "hg summary"
6754 # i18n: column positioning for "hg summary"
6751 ui.write(_('update: %d new changesets (update)\n') % new)
6755 ui.write(_('update: %d new changesets (update)\n') % new)
6752 else:
6756 else:
6753 # i18n: column positioning for "hg summary"
6757 # i18n: column positioning for "hg summary"
6754 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6758 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6755 (new, len(bheads)))
6759 (new, len(bheads)))
6756
6760
6757 t = []
6761 t = []
6758 draft = len(repo.revs('draft()'))
6762 draft = len(repo.revs('draft()'))
6759 if draft:
6763 if draft:
6760 t.append(_('%d draft') % draft)
6764 t.append(_('%d draft') % draft)
6761 secret = len(repo.revs('secret()'))
6765 secret = len(repo.revs('secret()'))
6762 if secret:
6766 if secret:
6763 t.append(_('%d secret') % secret)
6767 t.append(_('%d secret') % secret)
6764
6768
6765 if draft or secret:
6769 if draft or secret:
6766 ui.status(_('phases: %s\n') % ', '.join(t))
6770 ui.status(_('phases: %s\n') % ', '.join(t))
6767
6771
6768 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6772 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6769 for trouble in ("unstable", "divergent", "bumped"):
6773 for trouble in ("unstable", "divergent", "bumped"):
6770 numtrouble = len(repo.revs(trouble + "()"))
6774 numtrouble = len(repo.revs(trouble + "()"))
6771 # We write all the possibilities to ease translation
6775 # We write all the possibilities to ease translation
6772 troublemsg = {
6776 troublemsg = {
6773 "unstable": _("unstable: %d changesets"),
6777 "unstable": _("unstable: %d changesets"),
6774 "divergent": _("divergent: %d changesets"),
6778 "divergent": _("divergent: %d changesets"),
6775 "bumped": _("bumped: %d changesets"),
6779 "bumped": _("bumped: %d changesets"),
6776 }
6780 }
6777 if numtrouble > 0:
6781 if numtrouble > 0:
6778 ui.status(troublemsg[trouble] % numtrouble + "\n")
6782 ui.status(troublemsg[trouble] % numtrouble + "\n")
6779
6783
6780 cmdutil.summaryhooks(ui, repo)
6784 cmdutil.summaryhooks(ui, repo)
6781
6785
6782 if opts.get('remote'):
6786 if opts.get('remote'):
6783 needsincoming, needsoutgoing = True, True
6787 needsincoming, needsoutgoing = True, True
6784 else:
6788 else:
6785 needsincoming, needsoutgoing = False, False
6789 needsincoming, needsoutgoing = False, False
6786 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6790 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6787 if i:
6791 if i:
6788 needsincoming = True
6792 needsincoming = True
6789 if o:
6793 if o:
6790 needsoutgoing = True
6794 needsoutgoing = True
6791 if not needsincoming and not needsoutgoing:
6795 if not needsincoming and not needsoutgoing:
6792 return
6796 return
6793
6797
6794 def getincoming():
6798 def getincoming():
6795 source, branches = hg.parseurl(ui.expandpath('default'))
6799 source, branches = hg.parseurl(ui.expandpath('default'))
6796 sbranch = branches[0]
6800 sbranch = branches[0]
6797 try:
6801 try:
6798 other = hg.peer(repo, {}, source)
6802 other = hg.peer(repo, {}, source)
6799 except error.RepoError:
6803 except error.RepoError:
6800 if opts.get('remote'):
6804 if opts.get('remote'):
6801 raise
6805 raise
6802 return source, sbranch, None, None, None
6806 return source, sbranch, None, None, None
6803 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6807 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6804 if revs:
6808 if revs:
6805 revs = [other.lookup(rev) for rev in revs]
6809 revs = [other.lookup(rev) for rev in revs]
6806 ui.debug('comparing with %s\n' % util.hidepassword(source))
6810 ui.debug('comparing with %s\n' % util.hidepassword(source))
6807 repo.ui.pushbuffer()
6811 repo.ui.pushbuffer()
6808 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6812 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6809 repo.ui.popbuffer()
6813 repo.ui.popbuffer()
6810 return source, sbranch, other, commoninc, commoninc[1]
6814 return source, sbranch, other, commoninc, commoninc[1]
6811
6815
6812 if needsincoming:
6816 if needsincoming:
6813 source, sbranch, sother, commoninc, incoming = getincoming()
6817 source, sbranch, sother, commoninc, incoming = getincoming()
6814 else:
6818 else:
6815 source = sbranch = sother = commoninc = incoming = None
6819 source = sbranch = sother = commoninc = incoming = None
6816
6820
6817 def getoutgoing():
6821 def getoutgoing():
6818 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6822 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6819 dbranch = branches[0]
6823 dbranch = branches[0]
6820 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6824 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6821 if source != dest:
6825 if source != dest:
6822 try:
6826 try:
6823 dother = hg.peer(repo, {}, dest)
6827 dother = hg.peer(repo, {}, dest)
6824 except error.RepoError:
6828 except error.RepoError:
6825 if opts.get('remote'):
6829 if opts.get('remote'):
6826 raise
6830 raise
6827 return dest, dbranch, None, None
6831 return dest, dbranch, None, None
6828 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6832 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6829 elif sother is None:
6833 elif sother is None:
6830 # there is no explicit destination peer, but source one is invalid
6834 # there is no explicit destination peer, but source one is invalid
6831 return dest, dbranch, None, None
6835 return dest, dbranch, None, None
6832 else:
6836 else:
6833 dother = sother
6837 dother = sother
6834 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6838 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6835 common = None
6839 common = None
6836 else:
6840 else:
6837 common = commoninc
6841 common = commoninc
6838 if revs:
6842 if revs:
6839 revs = [repo.lookup(rev) for rev in revs]
6843 revs = [repo.lookup(rev) for rev in revs]
6840 repo.ui.pushbuffer()
6844 repo.ui.pushbuffer()
6841 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6845 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6842 commoninc=common)
6846 commoninc=common)
6843 repo.ui.popbuffer()
6847 repo.ui.popbuffer()
6844 return dest, dbranch, dother, outgoing
6848 return dest, dbranch, dother, outgoing
6845
6849
6846 if needsoutgoing:
6850 if needsoutgoing:
6847 dest, dbranch, dother, outgoing = getoutgoing()
6851 dest, dbranch, dother, outgoing = getoutgoing()
6848 else:
6852 else:
6849 dest = dbranch = dother = outgoing = None
6853 dest = dbranch = dother = outgoing = None
6850
6854
6851 if opts.get('remote'):
6855 if opts.get('remote'):
6852 t = []
6856 t = []
6853 if incoming:
6857 if incoming:
6854 t.append(_('1 or more incoming'))
6858 t.append(_('1 or more incoming'))
6855 o = outgoing.missing
6859 o = outgoing.missing
6856 if o:
6860 if o:
6857 t.append(_('%d outgoing') % len(o))
6861 t.append(_('%d outgoing') % len(o))
6858 other = dother or sother
6862 other = dother or sother
6859 if 'bookmarks' in other.listkeys('namespaces'):
6863 if 'bookmarks' in other.listkeys('namespaces'):
6860 counts = bookmarks.summary(repo, other)
6864 counts = bookmarks.summary(repo, other)
6861 if counts[0] > 0:
6865 if counts[0] > 0:
6862 t.append(_('%d incoming bookmarks') % counts[0])
6866 t.append(_('%d incoming bookmarks') % counts[0])
6863 if counts[1] > 0:
6867 if counts[1] > 0:
6864 t.append(_('%d outgoing bookmarks') % counts[1])
6868 t.append(_('%d outgoing bookmarks') % counts[1])
6865
6869
6866 if t:
6870 if t:
6867 # i18n: column positioning for "hg summary"
6871 # i18n: column positioning for "hg summary"
6868 ui.write(_('remote: %s\n') % (', '.join(t)))
6872 ui.write(_('remote: %s\n') % (', '.join(t)))
6869 else:
6873 else:
6870 # i18n: column positioning for "hg summary"
6874 # i18n: column positioning for "hg summary"
6871 ui.status(_('remote: (synced)\n'))
6875 ui.status(_('remote: (synced)\n'))
6872
6876
6873 cmdutil.summaryremotehooks(ui, repo, opts,
6877 cmdutil.summaryremotehooks(ui, repo, opts,
6874 ((source, sbranch, sother, commoninc),
6878 ((source, sbranch, sother, commoninc),
6875 (dest, dbranch, dother, outgoing)))
6879 (dest, dbranch, dother, outgoing)))
6876
6880
6877 @command('tag',
6881 @command('tag',
6878 [('f', 'force', None, _('force tag')),
6882 [('f', 'force', None, _('force tag')),
6879 ('l', 'local', None, _('make the tag local')),
6883 ('l', 'local', None, _('make the tag local')),
6880 ('r', 'rev', '', _('revision to tag'), _('REV')),
6884 ('r', 'rev', '', _('revision to tag'), _('REV')),
6881 ('', 'remove', None, _('remove a tag')),
6885 ('', 'remove', None, _('remove a tag')),
6882 # -l/--local is already there, commitopts cannot be used
6886 # -l/--local is already there, commitopts cannot be used
6883 ('e', 'edit', None, _('invoke editor on commit messages')),
6887 ('e', 'edit', None, _('invoke editor on commit messages')),
6884 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6888 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6885 ] + commitopts2,
6889 ] + commitopts2,
6886 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6890 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6887 def tag(ui, repo, name1, *names, **opts):
6891 def tag(ui, repo, name1, *names, **opts):
6888 """add one or more tags for the current or given revision
6892 """add one or more tags for the current or given revision
6889
6893
6890 Name a particular revision using <name>.
6894 Name a particular revision using <name>.
6891
6895
6892 Tags are used to name particular revisions of the repository and are
6896 Tags are used to name particular revisions of the repository and are
6893 very useful to compare different revisions, to go back to significant
6897 very useful to compare different revisions, to go back to significant
6894 earlier versions or to mark branch points as releases, etc. Changing
6898 earlier versions or to mark branch points as releases, etc. Changing
6895 an existing tag is normally disallowed; use -f/--force to override.
6899 an existing tag is normally disallowed; use -f/--force to override.
6896
6900
6897 If no revision is given, the parent of the working directory is
6901 If no revision is given, the parent of the working directory is
6898 used.
6902 used.
6899
6903
6900 To facilitate version control, distribution, and merging of tags,
6904 To facilitate version control, distribution, and merging of tags,
6901 they are stored as a file named ".hgtags" which is managed similarly
6905 they are stored as a file named ".hgtags" which is managed similarly
6902 to other project files and can be hand-edited if necessary. This
6906 to other project files and can be hand-edited if necessary. This
6903 also means that tagging creates a new commit. The file
6907 also means that tagging creates a new commit. The file
6904 ".hg/localtags" is used for local tags (not shared among
6908 ".hg/localtags" is used for local tags (not shared among
6905 repositories).
6909 repositories).
6906
6910
6907 Tag commits are usually made at the head of a branch. If the parent
6911 Tag commits are usually made at the head of a branch. If the parent
6908 of the working directory is not a branch head, :hg:`tag` aborts; use
6912 of the working directory is not a branch head, :hg:`tag` aborts; use
6909 -f/--force to force the tag commit to be based on a non-head
6913 -f/--force to force the tag commit to be based on a non-head
6910 changeset.
6914 changeset.
6911
6915
6912 See :hg:`help dates` for a list of formats valid for -d/--date.
6916 See :hg:`help dates` for a list of formats valid for -d/--date.
6913
6917
6914 Since tag names have priority over branch names during revision
6918 Since tag names have priority over branch names during revision
6915 lookup, using an existing branch name as a tag name is discouraged.
6919 lookup, using an existing branch name as a tag name is discouraged.
6916
6920
6917 Returns 0 on success.
6921 Returns 0 on success.
6918 """
6922 """
6919 wlock = lock = None
6923 wlock = lock = None
6920 try:
6924 try:
6921 wlock = repo.wlock()
6925 wlock = repo.wlock()
6922 lock = repo.lock()
6926 lock = repo.lock()
6923 rev_ = "."
6927 rev_ = "."
6924 names = [t.strip() for t in (name1,) + names]
6928 names = [t.strip() for t in (name1,) + names]
6925 if len(names) != len(set(names)):
6929 if len(names) != len(set(names)):
6926 raise error.Abort(_('tag names must be unique'))
6930 raise error.Abort(_('tag names must be unique'))
6927 for n in names:
6931 for n in names:
6928 scmutil.checknewlabel(repo, n, 'tag')
6932 scmutil.checknewlabel(repo, n, 'tag')
6929 if not n:
6933 if not n:
6930 raise error.Abort(_('tag names cannot consist entirely of '
6934 raise error.Abort(_('tag names cannot consist entirely of '
6931 'whitespace'))
6935 'whitespace'))
6932 if opts.get('rev') and opts.get('remove'):
6936 if opts.get('rev') and opts.get('remove'):
6933 raise error.Abort(_("--rev and --remove are incompatible"))
6937 raise error.Abort(_("--rev and --remove are incompatible"))
6934 if opts.get('rev'):
6938 if opts.get('rev'):
6935 rev_ = opts['rev']
6939 rev_ = opts['rev']
6936 message = opts.get('message')
6940 message = opts.get('message')
6937 if opts.get('remove'):
6941 if opts.get('remove'):
6938 if opts.get('local'):
6942 if opts.get('local'):
6939 expectedtype = 'local'
6943 expectedtype = 'local'
6940 else:
6944 else:
6941 expectedtype = 'global'
6945 expectedtype = 'global'
6942
6946
6943 for n in names:
6947 for n in names:
6944 if not repo.tagtype(n):
6948 if not repo.tagtype(n):
6945 raise error.Abort(_("tag '%s' does not exist") % n)
6949 raise error.Abort(_("tag '%s' does not exist") % n)
6946 if repo.tagtype(n) != expectedtype:
6950 if repo.tagtype(n) != expectedtype:
6947 if expectedtype == 'global':
6951 if expectedtype == 'global':
6948 raise error.Abort(_("tag '%s' is not a global tag") % n)
6952 raise error.Abort(_("tag '%s' is not a global tag") % n)
6949 else:
6953 else:
6950 raise error.Abort(_("tag '%s' is not a local tag") % n)
6954 raise error.Abort(_("tag '%s' is not a local tag") % n)
6951 rev_ = 'null'
6955 rev_ = 'null'
6952 if not message:
6956 if not message:
6953 # we don't translate commit messages
6957 # we don't translate commit messages
6954 message = 'Removed tag %s' % ', '.join(names)
6958 message = 'Removed tag %s' % ', '.join(names)
6955 elif not opts.get('force'):
6959 elif not opts.get('force'):
6956 for n in names:
6960 for n in names:
6957 if n in repo.tags():
6961 if n in repo.tags():
6958 raise error.Abort(_("tag '%s' already exists "
6962 raise error.Abort(_("tag '%s' already exists "
6959 "(use -f to force)") % n)
6963 "(use -f to force)") % n)
6960 if not opts.get('local'):
6964 if not opts.get('local'):
6961 p1, p2 = repo.dirstate.parents()
6965 p1, p2 = repo.dirstate.parents()
6962 if p2 != nullid:
6966 if p2 != nullid:
6963 raise error.Abort(_('uncommitted merge'))
6967 raise error.Abort(_('uncommitted merge'))
6964 bheads = repo.branchheads()
6968 bheads = repo.branchheads()
6965 if not opts.get('force') and bheads and p1 not in bheads:
6969 if not opts.get('force') and bheads and p1 not in bheads:
6966 raise error.Abort(_('not at a branch head (use -f to force)'))
6970 raise error.Abort(_('not at a branch head (use -f to force)'))
6967 r = scmutil.revsingle(repo, rev_).node()
6971 r = scmutil.revsingle(repo, rev_).node()
6968
6972
6969 if not message:
6973 if not message:
6970 # we don't translate commit messages
6974 # we don't translate commit messages
6971 message = ('Added tag %s for changeset %s' %
6975 message = ('Added tag %s for changeset %s' %
6972 (', '.join(names), short(r)))
6976 (', '.join(names), short(r)))
6973
6977
6974 date = opts.get('date')
6978 date = opts.get('date')
6975 if date:
6979 if date:
6976 date = util.parsedate(date)
6980 date = util.parsedate(date)
6977
6981
6978 if opts.get('remove'):
6982 if opts.get('remove'):
6979 editform = 'tag.remove'
6983 editform = 'tag.remove'
6980 else:
6984 else:
6981 editform = 'tag.add'
6985 editform = 'tag.add'
6982 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6986 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6983
6987
6984 # don't allow tagging the null rev
6988 # don't allow tagging the null rev
6985 if (not opts.get('remove') and
6989 if (not opts.get('remove') and
6986 scmutil.revsingle(repo, rev_).rev() == nullrev):
6990 scmutil.revsingle(repo, rev_).rev() == nullrev):
6987 raise error.Abort(_("cannot tag null revision"))
6991 raise error.Abort(_("cannot tag null revision"))
6988
6992
6989 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6993 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6990 editor=editor)
6994 editor=editor)
6991 finally:
6995 finally:
6992 release(lock, wlock)
6996 release(lock, wlock)
6993
6997
6994 @command('tags', formatteropts, '')
6998 @command('tags', formatteropts, '')
6995 def tags(ui, repo, **opts):
6999 def tags(ui, repo, **opts):
6996 """list repository tags
7000 """list repository tags
6997
7001
6998 This lists both regular and local tags. When the -v/--verbose
7002 This lists both regular and local tags. When the -v/--verbose
6999 switch is used, a third column "local" is printed for local tags.
7003 switch is used, a third column "local" is printed for local tags.
7000 When the -q/--quiet switch is used, only the tag name is printed.
7004 When the -q/--quiet switch is used, only the tag name is printed.
7001
7005
7002 Returns 0 on success.
7006 Returns 0 on success.
7003 """
7007 """
7004
7008
7005 fm = ui.formatter('tags', opts)
7009 fm = ui.formatter('tags', opts)
7006 hexfunc = fm.hexfunc
7010 hexfunc = fm.hexfunc
7007 tagtype = ""
7011 tagtype = ""
7008
7012
7009 for t, n in reversed(repo.tagslist()):
7013 for t, n in reversed(repo.tagslist()):
7010 hn = hexfunc(n)
7014 hn = hexfunc(n)
7011 label = 'tags.normal'
7015 label = 'tags.normal'
7012 tagtype = ''
7016 tagtype = ''
7013 if repo.tagtype(t) == 'local':
7017 if repo.tagtype(t) == 'local':
7014 label = 'tags.local'
7018 label = 'tags.local'
7015 tagtype = 'local'
7019 tagtype = 'local'
7016
7020
7017 fm.startitem()
7021 fm.startitem()
7018 fm.write('tag', '%s', t, label=label)
7022 fm.write('tag', '%s', t, label=label)
7019 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7023 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7020 fm.condwrite(not ui.quiet, 'rev node', fmt,
7024 fm.condwrite(not ui.quiet, 'rev node', fmt,
7021 repo.changelog.rev(n), hn, label=label)
7025 repo.changelog.rev(n), hn, label=label)
7022 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7026 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7023 tagtype, label=label)
7027 tagtype, label=label)
7024 fm.plain('\n')
7028 fm.plain('\n')
7025 fm.end()
7029 fm.end()
7026
7030
7027 @command('tip',
7031 @command('tip',
7028 [('p', 'patch', None, _('show patch')),
7032 [('p', 'patch', None, _('show patch')),
7029 ('g', 'git', None, _('use git extended diff format')),
7033 ('g', 'git', None, _('use git extended diff format')),
7030 ] + templateopts,
7034 ] + templateopts,
7031 _('[-p] [-g]'))
7035 _('[-p] [-g]'))
7032 def tip(ui, repo, **opts):
7036 def tip(ui, repo, **opts):
7033 """show the tip revision (DEPRECATED)
7037 """show the tip revision (DEPRECATED)
7034
7038
7035 The tip revision (usually just called the tip) is the changeset
7039 The tip revision (usually just called the tip) is the changeset
7036 most recently added to the repository (and therefore the most
7040 most recently added to the repository (and therefore the most
7037 recently changed head).
7041 recently changed head).
7038
7042
7039 If you have just made a commit, that commit will be the tip. If
7043 If you have just made a commit, that commit will be the tip. If
7040 you have just pulled changes from another repository, the tip of
7044 you have just pulled changes from another repository, the tip of
7041 that repository becomes the current tip. The "tip" tag is special
7045 that repository becomes the current tip. The "tip" tag is special
7042 and cannot be renamed or assigned to a different changeset.
7046 and cannot be renamed or assigned to a different changeset.
7043
7047
7044 This command is deprecated, please use :hg:`heads` instead.
7048 This command is deprecated, please use :hg:`heads` instead.
7045
7049
7046 Returns 0 on success.
7050 Returns 0 on success.
7047 """
7051 """
7048 displayer = cmdutil.show_changeset(ui, repo, opts)
7052 displayer = cmdutil.show_changeset(ui, repo, opts)
7049 displayer.show(repo['tip'])
7053 displayer.show(repo['tip'])
7050 displayer.close()
7054 displayer.close()
7051
7055
7052 @command('unbundle',
7056 @command('unbundle',
7053 [('u', 'update', None,
7057 [('u', 'update', None,
7054 _('update to new branch head if changesets were unbundled'))],
7058 _('update to new branch head if changesets were unbundled'))],
7055 _('[-u] FILE...'))
7059 _('[-u] FILE...'))
7056 def unbundle(ui, repo, fname1, *fnames, **opts):
7060 def unbundle(ui, repo, fname1, *fnames, **opts):
7057 """apply one or more changegroup files
7061 """apply one or more changegroup files
7058
7062
7059 Apply one or more compressed changegroup files generated by the
7063 Apply one or more compressed changegroup files generated by the
7060 bundle command.
7064 bundle command.
7061
7065
7062 Returns 0 on success, 1 if an update has unresolved files.
7066 Returns 0 on success, 1 if an update has unresolved files.
7063 """
7067 """
7064 fnames = (fname1,) + fnames
7068 fnames = (fname1,) + fnames
7065
7069
7066 with repo.lock():
7070 with repo.lock():
7067 for fname in fnames:
7071 for fname in fnames:
7068 f = hg.openpath(ui, fname)
7072 f = hg.openpath(ui, fname)
7069 gen = exchange.readbundle(ui, f, fname)
7073 gen = exchange.readbundle(ui, f, fname)
7070 if isinstance(gen, bundle2.unbundle20):
7074 if isinstance(gen, bundle2.unbundle20):
7071 tr = repo.transaction('unbundle')
7075 tr = repo.transaction('unbundle')
7072 try:
7076 try:
7073 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7077 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7074 url='bundle:' + fname)
7078 url='bundle:' + fname)
7075 tr.close()
7079 tr.close()
7076 except error.BundleUnknownFeatureError as exc:
7080 except error.BundleUnknownFeatureError as exc:
7077 raise error.Abort(_('%s: unknown bundle feature, %s')
7081 raise error.Abort(_('%s: unknown bundle feature, %s')
7078 % (fname, exc),
7082 % (fname, exc),
7079 hint=_("see https://mercurial-scm.org/"
7083 hint=_("see https://mercurial-scm.org/"
7080 "wiki/BundleFeature for more "
7084 "wiki/BundleFeature for more "
7081 "information"))
7085 "information"))
7082 finally:
7086 finally:
7083 if tr:
7087 if tr:
7084 tr.release()
7088 tr.release()
7085 changes = [r.get('return', 0)
7089 changes = [r.get('return', 0)
7086 for r in op.records['changegroup']]
7090 for r in op.records['changegroup']]
7087 modheads = changegroup.combineresults(changes)
7091 modheads = changegroup.combineresults(changes)
7088 elif isinstance(gen, streamclone.streamcloneapplier):
7092 elif isinstance(gen, streamclone.streamcloneapplier):
7089 raise error.Abort(
7093 raise error.Abort(
7090 _('packed bundles cannot be applied with '
7094 _('packed bundles cannot be applied with '
7091 '"hg unbundle"'),
7095 '"hg unbundle"'),
7092 hint=_('use "hg debugapplystreamclonebundle"'))
7096 hint=_('use "hg debugapplystreamclonebundle"'))
7093 else:
7097 else:
7094 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7098 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7095
7099
7096 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7100 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7097
7101
7098 @command('^update|up|checkout|co',
7102 @command('^update|up|checkout|co',
7099 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7103 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7100 ('c', 'check', None,
7104 ('c', 'check', None,
7101 _('update across branches if no uncommitted changes')),
7105 _('update across branches if no uncommitted changes')),
7102 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7106 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7103 ('r', 'rev', '', _('revision'), _('REV'))
7107 ('r', 'rev', '', _('revision'), _('REV'))
7104 ] + mergetoolopts,
7108 ] + mergetoolopts,
7105 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7109 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7106 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7110 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7107 tool=None):
7111 tool=None):
7108 """update working directory (or switch revisions)
7112 """update working directory (or switch revisions)
7109
7113
7110 Update the repository's working directory to the specified
7114 Update the repository's working directory to the specified
7111 changeset. If no changeset is specified, update to the tip of the
7115 changeset. If no changeset is specified, update to the tip of the
7112 current named branch and move the active bookmark (see :hg:`help
7116 current named branch and move the active bookmark (see :hg:`help
7113 bookmarks`).
7117 bookmarks`).
7114
7118
7115 Update sets the working directory's parent revision to the specified
7119 Update sets the working directory's parent revision to the specified
7116 changeset (see :hg:`help parents`).
7120 changeset (see :hg:`help parents`).
7117
7121
7118 If the changeset is not a descendant or ancestor of the working
7122 If the changeset is not a descendant or ancestor of the working
7119 directory's parent, the update is aborted. With the -c/--check
7123 directory's parent, the update is aborted. With the -c/--check
7120 option, the working directory is checked for uncommitted changes; if
7124 option, the working directory is checked for uncommitted changes; if
7121 none are found, the working directory is updated to the specified
7125 none are found, the working directory is updated to the specified
7122 changeset.
7126 changeset.
7123
7127
7124 .. container:: verbose
7128 .. container:: verbose
7125
7129
7126 The following rules apply when the working directory contains
7130 The following rules apply when the working directory contains
7127 uncommitted changes:
7131 uncommitted changes:
7128
7132
7129 1. If neither -c/--check nor -C/--clean is specified, and if
7133 1. If neither -c/--check nor -C/--clean is specified, and if
7130 the requested changeset is an ancestor or descendant of
7134 the requested changeset is an ancestor or descendant of
7131 the working directory's parent, the uncommitted changes
7135 the working directory's parent, the uncommitted changes
7132 are merged into the requested changeset and the merged
7136 are merged into the requested changeset and the merged
7133 result is left uncommitted. If the requested changeset is
7137 result is left uncommitted. If the requested changeset is
7134 not an ancestor or descendant (that is, it is on another
7138 not an ancestor or descendant (that is, it is on another
7135 branch), the update is aborted and the uncommitted changes
7139 branch), the update is aborted and the uncommitted changes
7136 are preserved.
7140 are preserved.
7137
7141
7138 2. With the -c/--check option, the update is aborted and the
7142 2. With the -c/--check option, the update is aborted and the
7139 uncommitted changes are preserved.
7143 uncommitted changes are preserved.
7140
7144
7141 3. With the -C/--clean option, uncommitted changes are discarded and
7145 3. With the -C/--clean option, uncommitted changes are discarded and
7142 the working directory is updated to the requested changeset.
7146 the working directory is updated to the requested changeset.
7143
7147
7144 To cancel an uncommitted merge (and lose your changes), use
7148 To cancel an uncommitted merge (and lose your changes), use
7145 :hg:`update --clean .`.
7149 :hg:`update --clean .`.
7146
7150
7147 Use null as the changeset to remove the working directory (like
7151 Use null as the changeset to remove the working directory (like
7148 :hg:`clone -U`).
7152 :hg:`clone -U`).
7149
7153
7150 If you want to revert just one file to an older revision, use
7154 If you want to revert just one file to an older revision, use
7151 :hg:`revert [-r REV] NAME`.
7155 :hg:`revert [-r REV] NAME`.
7152
7156
7153 See :hg:`help dates` for a list of formats valid for -d/--date.
7157 See :hg:`help dates` for a list of formats valid for -d/--date.
7154
7158
7155 Returns 0 on success, 1 if there are unresolved files.
7159 Returns 0 on success, 1 if there are unresolved files.
7156 """
7160 """
7157 if rev and node:
7161 if rev and node:
7158 raise error.Abort(_("please specify just one revision"))
7162 raise error.Abort(_("please specify just one revision"))
7159
7163
7160 if rev is None or rev == '':
7164 if rev is None or rev == '':
7161 rev = node
7165 rev = node
7162
7166
7163 if date and rev is not None:
7167 if date and rev is not None:
7164 raise error.Abort(_("you can't specify a revision and a date"))
7168 raise error.Abort(_("you can't specify a revision and a date"))
7165
7169
7166 if check and clean:
7170 if check and clean:
7167 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7171 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7168
7172
7169 with repo.wlock():
7173 with repo.wlock():
7170 cmdutil.clearunfinished(repo)
7174 cmdutil.clearunfinished(repo)
7171
7175
7172 if date:
7176 if date:
7173 rev = cmdutil.finddate(ui, repo, date)
7177 rev = cmdutil.finddate(ui, repo, date)
7174
7178
7175 # if we defined a bookmark, we have to remember the original name
7179 # if we defined a bookmark, we have to remember the original name
7176 brev = rev
7180 brev = rev
7177 rev = scmutil.revsingle(repo, rev, rev).rev()
7181 rev = scmutil.revsingle(repo, rev, rev).rev()
7178
7182
7179 if check:
7183 if check:
7180 cmdutil.bailifchanged(repo, merge=False)
7184 cmdutil.bailifchanged(repo, merge=False)
7181
7185
7182 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7186 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7183
7187
7184 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7188 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7185
7189
7186 @command('verify', [])
7190 @command('verify', [])
7187 def verify(ui, repo):
7191 def verify(ui, repo):
7188 """verify the integrity of the repository
7192 """verify the integrity of the repository
7189
7193
7190 Verify the integrity of the current repository.
7194 Verify the integrity of the current repository.
7191
7195
7192 This will perform an extensive check of the repository's
7196 This will perform an extensive check of the repository's
7193 integrity, validating the hashes and checksums of each entry in
7197 integrity, validating the hashes and checksums of each entry in
7194 the changelog, manifest, and tracked files, as well as the
7198 the changelog, manifest, and tracked files, as well as the
7195 integrity of their crosslinks and indices.
7199 integrity of their crosslinks and indices.
7196
7200
7197 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7201 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7198 for more information about recovery from corruption of the
7202 for more information about recovery from corruption of the
7199 repository.
7203 repository.
7200
7204
7201 Returns 0 on success, 1 if errors are encountered.
7205 Returns 0 on success, 1 if errors are encountered.
7202 """
7206 """
7203 return hg.verify(repo)
7207 return hg.verify(repo)
7204
7208
7205 @command('version', [], norepo=True)
7209 @command('version', [], norepo=True)
7206 def version_(ui):
7210 def version_(ui):
7207 """output version and copyright information"""
7211 """output version and copyright information"""
7208 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7212 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7209 % util.version())
7213 % util.version())
7210 ui.status(_(
7214 ui.status(_(
7211 "(see https://mercurial-scm.org for more information)\n"
7215 "(see https://mercurial-scm.org for more information)\n"
7212 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7216 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7213 "This is free software; see the source for copying conditions. "
7217 "This is free software; see the source for copying conditions. "
7214 "There is NO\nwarranty; "
7218 "There is NO\nwarranty; "
7215 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7219 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7216 ))
7220 ))
7217
7221
7218 ui.note(_("\nEnabled extensions:\n\n"))
7222 ui.note(_("\nEnabled extensions:\n\n"))
7219 if ui.verbose:
7223 if ui.verbose:
7220 # format names and versions into columns
7224 # format names and versions into columns
7221 names = []
7225 names = []
7222 vers = []
7226 vers = []
7223 place = []
7227 place = []
7224 for name, module in extensions.extensions():
7228 for name, module in extensions.extensions():
7225 names.append(name)
7229 names.append(name)
7226 vers.append(extensions.moduleversion(module))
7230 vers.append(extensions.moduleversion(module))
7227 if extensions.ismoduleinternal(module):
7231 if extensions.ismoduleinternal(module):
7228 place.append(_("internal"))
7232 place.append(_("internal"))
7229 else:
7233 else:
7230 place.append(_("external"))
7234 place.append(_("external"))
7231 if names:
7235 if names:
7232 maxnamelen = max(len(n) for n in names)
7236 maxnamelen = max(len(n) for n in names)
7233 for i, name in enumerate(names):
7237 for i, name in enumerate(names):
7234 ui.write(" %-*s %s %s\n" %
7238 ui.write(" %-*s %s %s\n" %
7235 (maxnamelen, name, place[i], vers[i]))
7239 (maxnamelen, name, place[i], vers[i]))
7236
7240
7237 def loadcmdtable(ui, name, cmdtable):
7241 def loadcmdtable(ui, name, cmdtable):
7238 """Load command functions from specified cmdtable
7242 """Load command functions from specified cmdtable
7239 """
7243 """
7240 overrides = [cmd for cmd in cmdtable if cmd in table]
7244 overrides = [cmd for cmd in cmdtable if cmd in table]
7241 if overrides:
7245 if overrides:
7242 ui.warn(_("extension '%s' overrides commands: %s\n")
7246 ui.warn(_("extension '%s' overrides commands: %s\n")
7243 % (name, " ".join(overrides)))
7247 % (name, " ".join(overrides)))
7244 table.update(cmdtable)
7248 table.update(cmdtable)
@@ -1,1109 +1,1128
1 # templater.py - template expansion for output
1 # templater.py - template expansion for output
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 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 os
10 import os
11 import re
11 import re
12 import types
12 import types
13
13
14 from .i18n import _
14 from .i18n import _
15 from . import (
15 from . import (
16 config,
16 config,
17 error,
17 error,
18 minirst,
18 minirst,
19 parser,
19 parser,
20 registrar,
20 registrar,
21 revset as revsetmod,
21 revset as revsetmod,
22 templatefilters,
22 templatefilters,
23 templatekw,
23 templatekw,
24 util,
24 util,
25 )
25 )
26
26
27 # template parsing
27 # template parsing
28
28
29 elements = {
29 elements = {
30 # token-type: binding-strength, primary, prefix, infix, suffix
30 # token-type: binding-strength, primary, prefix, infix, suffix
31 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
31 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
32 ",": (2, None, None, ("list", 2), None),
32 ",": (2, None, None, ("list", 2), None),
33 "|": (5, None, None, ("|", 5), None),
33 "|": (5, None, None, ("|", 5), None),
34 "%": (6, None, None, ("%", 6), None),
34 "%": (6, None, None, ("%", 6), None),
35 ")": (0, None, None, None, None),
35 ")": (0, None, None, None, None),
36 "integer": (0, "integer", None, None, None),
36 "integer": (0, "integer", None, None, None),
37 "symbol": (0, "symbol", None, None, None),
37 "symbol": (0, "symbol", None, None, None),
38 "string": (0, "string", None, None, None),
38 "string": (0, "string", None, None, None),
39 "template": (0, "template", None, None, None),
39 "template": (0, "template", None, None, None),
40 "end": (0, None, None, None, None),
40 "end": (0, None, None, None, None),
41 }
41 }
42
42
43 def tokenize(program, start, end, term=None):
43 def tokenize(program, start, end, term=None):
44 """Parse a template expression into a stream of tokens, which must end
44 """Parse a template expression into a stream of tokens, which must end
45 with term if specified"""
45 with term if specified"""
46 pos = start
46 pos = start
47 while pos < end:
47 while pos < end:
48 c = program[pos]
48 c = program[pos]
49 if c.isspace(): # skip inter-token whitespace
49 if c.isspace(): # skip inter-token whitespace
50 pass
50 pass
51 elif c in "(,)%|": # handle simple operators
51 elif c in "(,)%|": # handle simple operators
52 yield (c, None, pos)
52 yield (c, None, pos)
53 elif c in '"\'': # handle quoted templates
53 elif c in '"\'': # handle quoted templates
54 s = pos + 1
54 s = pos + 1
55 data, pos = _parsetemplate(program, s, end, c)
55 data, pos = _parsetemplate(program, s, end, c)
56 yield ('template', data, s)
56 yield ('template', data, s)
57 pos -= 1
57 pos -= 1
58 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
58 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
59 # handle quoted strings
59 # handle quoted strings
60 c = program[pos + 1]
60 c = program[pos + 1]
61 s = pos = pos + 2
61 s = pos = pos + 2
62 while pos < end: # find closing quote
62 while pos < end: # find closing quote
63 d = program[pos]
63 d = program[pos]
64 if d == '\\': # skip over escaped characters
64 if d == '\\': # skip over escaped characters
65 pos += 2
65 pos += 2
66 continue
66 continue
67 if d == c:
67 if d == c:
68 yield ('string', program[s:pos], s)
68 yield ('string', program[s:pos], s)
69 break
69 break
70 pos += 1
70 pos += 1
71 else:
71 else:
72 raise error.ParseError(_("unterminated string"), s)
72 raise error.ParseError(_("unterminated string"), s)
73 elif c.isdigit() or c == '-':
73 elif c.isdigit() or c == '-':
74 s = pos
74 s = pos
75 if c == '-': # simply take negate operator as part of integer
75 if c == '-': # simply take negate operator as part of integer
76 pos += 1
76 pos += 1
77 if pos >= end or not program[pos].isdigit():
77 if pos >= end or not program[pos].isdigit():
78 raise error.ParseError(_("integer literal without digits"), s)
78 raise error.ParseError(_("integer literal without digits"), s)
79 pos += 1
79 pos += 1
80 while pos < end:
80 while pos < end:
81 d = program[pos]
81 d = program[pos]
82 if not d.isdigit():
82 if not d.isdigit():
83 break
83 break
84 pos += 1
84 pos += 1
85 yield ('integer', program[s:pos], s)
85 yield ('integer', program[s:pos], s)
86 pos -= 1
86 pos -= 1
87 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
87 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
88 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
88 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
89 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
89 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
90 # where some of nested templates were preprocessed as strings and
90 # where some of nested templates were preprocessed as strings and
91 # then compiled. therefore, \"...\" was allowed. (issue4733)
91 # then compiled. therefore, \"...\" was allowed. (issue4733)
92 #
92 #
93 # processing flow of _evalifliteral() at 5ab28a2e9962:
93 # processing flow of _evalifliteral() at 5ab28a2e9962:
94 # outer template string -> stringify() -> compiletemplate()
94 # outer template string -> stringify() -> compiletemplate()
95 # ------------------------ ------------ ------------------
95 # ------------------------ ------------ ------------------
96 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
96 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
97 # ~~~~~~~~
97 # ~~~~~~~~
98 # escaped quoted string
98 # escaped quoted string
99 if c == 'r':
99 if c == 'r':
100 pos += 1
100 pos += 1
101 token = 'string'
101 token = 'string'
102 else:
102 else:
103 token = 'template'
103 token = 'template'
104 quote = program[pos:pos + 2]
104 quote = program[pos:pos + 2]
105 s = pos = pos + 2
105 s = pos = pos + 2
106 while pos < end: # find closing escaped quote
106 while pos < end: # find closing escaped quote
107 if program.startswith('\\\\\\', pos, end):
107 if program.startswith('\\\\\\', pos, end):
108 pos += 4 # skip over double escaped characters
108 pos += 4 # skip over double escaped characters
109 continue
109 continue
110 if program.startswith(quote, pos, end):
110 if program.startswith(quote, pos, end):
111 # interpret as if it were a part of an outer string
111 # interpret as if it were a part of an outer string
112 data = parser.unescapestr(program[s:pos])
112 data = parser.unescapestr(program[s:pos])
113 if token == 'template':
113 if token == 'template':
114 data = _parsetemplate(data, 0, len(data))[0]
114 data = _parsetemplate(data, 0, len(data))[0]
115 yield (token, data, s)
115 yield (token, data, s)
116 pos += 1
116 pos += 1
117 break
117 break
118 pos += 1
118 pos += 1
119 else:
119 else:
120 raise error.ParseError(_("unterminated string"), s)
120 raise error.ParseError(_("unterminated string"), s)
121 elif c.isalnum() or c in '_':
121 elif c.isalnum() or c in '_':
122 s = pos
122 s = pos
123 pos += 1
123 pos += 1
124 while pos < end: # find end of symbol
124 while pos < end: # find end of symbol
125 d = program[pos]
125 d = program[pos]
126 if not (d.isalnum() or d == "_"):
126 if not (d.isalnum() or d == "_"):
127 break
127 break
128 pos += 1
128 pos += 1
129 sym = program[s:pos]
129 sym = program[s:pos]
130 yield ('symbol', sym, s)
130 yield ('symbol', sym, s)
131 pos -= 1
131 pos -= 1
132 elif c == term:
132 elif c == term:
133 yield ('end', None, pos + 1)
133 yield ('end', None, pos + 1)
134 return
134 return
135 else:
135 else:
136 raise error.ParseError(_("syntax error"), pos)
136 raise error.ParseError(_("syntax error"), pos)
137 pos += 1
137 pos += 1
138 if term:
138 if term:
139 raise error.ParseError(_("unterminated template expansion"), start)
139 raise error.ParseError(_("unterminated template expansion"), start)
140 yield ('end', None, pos)
140 yield ('end', None, pos)
141
141
142 def _parsetemplate(tmpl, start, stop, quote=''):
142 def _parsetemplate(tmpl, start, stop, quote=''):
143 r"""
143 r"""
144 >>> _parsetemplate('foo{bar}"baz', 0, 12)
144 >>> _parsetemplate('foo{bar}"baz', 0, 12)
145 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
145 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
146 >>> _parsetemplate('foo{bar}"baz', 0, 12, quote='"')
146 >>> _parsetemplate('foo{bar}"baz', 0, 12, quote='"')
147 ([('string', 'foo'), ('symbol', 'bar')], 9)
147 ([('string', 'foo'), ('symbol', 'bar')], 9)
148 >>> _parsetemplate('foo"{bar}', 0, 9, quote='"')
148 >>> _parsetemplate('foo"{bar}', 0, 9, quote='"')
149 ([('string', 'foo')], 4)
149 ([('string', 'foo')], 4)
150 >>> _parsetemplate(r'foo\"bar"baz', 0, 12, quote='"')
150 >>> _parsetemplate(r'foo\"bar"baz', 0, 12, quote='"')
151 ([('string', 'foo"'), ('string', 'bar')], 9)
151 ([('string', 'foo"'), ('string', 'bar')], 9)
152 >>> _parsetemplate(r'foo\\"bar', 0, 10, quote='"')
152 >>> _parsetemplate(r'foo\\"bar', 0, 10, quote='"')
153 ([('string', 'foo\\')], 6)
153 ([('string', 'foo\\')], 6)
154 """
154 """
155 parsed = []
155 parsed = []
156 sepchars = '{' + quote
156 sepchars = '{' + quote
157 pos = start
157 pos = start
158 p = parser.parser(elements)
158 p = parser.parser(elements)
159 while pos < stop:
159 while pos < stop:
160 n = min((tmpl.find(c, pos, stop) for c in sepchars),
160 n = min((tmpl.find(c, pos, stop) for c in sepchars),
161 key=lambda n: (n < 0, n))
161 key=lambda n: (n < 0, n))
162 if n < 0:
162 if n < 0:
163 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
163 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
164 pos = stop
164 pos = stop
165 break
165 break
166 c = tmpl[n]
166 c = tmpl[n]
167 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
167 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
168 if bs % 2 == 1:
168 if bs % 2 == 1:
169 # escaped (e.g. '\{', '\\\{', but not '\\{')
169 # escaped (e.g. '\{', '\\\{', but not '\\{')
170 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
170 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
171 pos = n + 1
171 pos = n + 1
172 continue
172 continue
173 if n > pos:
173 if n > pos:
174 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
174 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
175 if c == quote:
175 if c == quote:
176 return parsed, n + 1
176 return parsed, n + 1
177
177
178 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
178 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
179 parsed.append(parseres)
179 parsed.append(parseres)
180
180
181 if quote:
181 if quote:
182 raise error.ParseError(_("unterminated string"), start)
182 raise error.ParseError(_("unterminated string"), start)
183 return parsed, pos
183 return parsed, pos
184
184
185 def _unnesttemplatelist(tree):
185 def _unnesttemplatelist(tree):
186 """Expand list of templates to node tuple
186 """Expand list of templates to node tuple
187
187
188 >>> def f(tree):
188 >>> def f(tree):
189 ... print prettyformat(_unnesttemplatelist(tree))
189 ... print prettyformat(_unnesttemplatelist(tree))
190 >>> f(('template', []))
190 >>> f(('template', []))
191 ('string', '')
191 ('string', '')
192 >>> f(('template', [('string', 'foo')]))
192 >>> f(('template', [('string', 'foo')]))
193 ('string', 'foo')
193 ('string', 'foo')
194 >>> f(('template', [('string', 'foo'), ('symbol', 'rev')]))
194 >>> f(('template', [('string', 'foo'), ('symbol', 'rev')]))
195 (template
195 (template
196 ('string', 'foo')
196 ('string', 'foo')
197 ('symbol', 'rev'))
197 ('symbol', 'rev'))
198 >>> f(('template', [('symbol', 'rev')])) # template(rev) -> str
198 >>> f(('template', [('symbol', 'rev')])) # template(rev) -> str
199 (template
199 (template
200 ('symbol', 'rev'))
200 ('symbol', 'rev'))
201 >>> f(('template', [('template', [('string', 'foo')])]))
201 >>> f(('template', [('template', [('string', 'foo')])]))
202 ('string', 'foo')
202 ('string', 'foo')
203 """
203 """
204 if not isinstance(tree, tuple):
204 if not isinstance(tree, tuple):
205 return tree
205 return tree
206 op = tree[0]
206 op = tree[0]
207 if op != 'template':
207 if op != 'template':
208 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
208 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:])
209
209
210 assert len(tree) == 2
210 assert len(tree) == 2
211 xs = tuple(_unnesttemplatelist(x) for x in tree[1])
211 xs = tuple(_unnesttemplatelist(x) for x in tree[1])
212 if not xs:
212 if not xs:
213 return ('string', '') # empty template ""
213 return ('string', '') # empty template ""
214 elif len(xs) == 1 and xs[0][0] == 'string':
214 elif len(xs) == 1 and xs[0][0] == 'string':
215 return xs[0] # fast path for string with no template fragment "x"
215 return xs[0] # fast path for string with no template fragment "x"
216 else:
216 else:
217 return (op,) + xs
217 return (op,) + xs
218
218
219 def parse(tmpl):
219 def parse(tmpl):
220 """Parse template string into tree"""
220 """Parse template string into tree"""
221 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
221 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
222 assert pos == len(tmpl), 'unquoted template should be consumed'
222 assert pos == len(tmpl), 'unquoted template should be consumed'
223 return _unnesttemplatelist(('template', parsed))
223 return _unnesttemplatelist(('template', parsed))
224
224
225 def _parseexpr(expr):
225 def _parseexpr(expr):
226 """Parse a template expression into tree
226 """Parse a template expression into tree
227
227
228 >>> _parseexpr('"foo"')
228 >>> _parseexpr('"foo"')
229 ('string', 'foo')
229 ('string', 'foo')
230 >>> _parseexpr('foo(bar)')
230 >>> _parseexpr('foo(bar)')
231 ('func', ('symbol', 'foo'), ('symbol', 'bar'))
231 ('func', ('symbol', 'foo'), ('symbol', 'bar'))
232 >>> _parseexpr('foo(')
232 >>> _parseexpr('foo(')
233 Traceback (most recent call last):
233 Traceback (most recent call last):
234 ...
234 ...
235 ParseError: ('not a prefix: end', 4)
235 ParseError: ('not a prefix: end', 4)
236 >>> _parseexpr('"foo" "bar"')
236 >>> _parseexpr('"foo" "bar"')
237 Traceback (most recent call last):
237 Traceback (most recent call last):
238 ...
238 ...
239 ParseError: ('invalid token', 7)
239 ParseError: ('invalid token', 7)
240 """
240 """
241 p = parser.parser(elements)
241 p = parser.parser(elements)
242 tree, pos = p.parse(tokenize(expr, 0, len(expr)))
242 tree, pos = p.parse(tokenize(expr, 0, len(expr)))
243 if pos != len(expr):
243 if pos != len(expr):
244 raise error.ParseError(_('invalid token'), pos)
244 raise error.ParseError(_('invalid token'), pos)
245 return _unnesttemplatelist(tree)
245 return _unnesttemplatelist(tree)
246
246
247 def prettyformat(tree):
247 def prettyformat(tree):
248 return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
248 return parser.prettyformat(tree, ('integer', 'string', 'symbol'))
249
249
250 def compiletemplate(tmpl, context):
250 def compiletemplate(tmpl, context):
251 """Parse and compile template string to (func, data) pair"""
251 """Parse and compile template string to (func, data) pair"""
252 return compileexp(parse(tmpl), context, methods)
252 return compileexp(parse(tmpl), context, methods)
253
253
254 def compileexp(exp, context, curmethods):
254 def compileexp(exp, context, curmethods):
255 t = exp[0]
255 t = exp[0]
256 if t in curmethods:
256 if t in curmethods:
257 return curmethods[t](exp, context)
257 return curmethods[t](exp, context)
258 raise error.ParseError(_("unknown method '%s'") % t)
258 raise error.ParseError(_("unknown method '%s'") % t)
259
259
260 # template evaluation
260 # template evaluation
261
261
262 def getsymbol(exp):
262 def getsymbol(exp):
263 if exp[0] == 'symbol':
263 if exp[0] == 'symbol':
264 return exp[1]
264 return exp[1]
265 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
265 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
266
266
267 def getlist(x):
267 def getlist(x):
268 if not x:
268 if not x:
269 return []
269 return []
270 if x[0] == 'list':
270 if x[0] == 'list':
271 return getlist(x[1]) + [x[2]]
271 return getlist(x[1]) + [x[2]]
272 return [x]
272 return [x]
273
273
274 def gettemplate(exp, context):
274 def gettemplate(exp, context):
275 """Compile given template tree or load named template from map file;
275 """Compile given template tree or load named template from map file;
276 returns (func, data) pair"""
276 returns (func, data) pair"""
277 if exp[0] in ('template', 'string'):
277 if exp[0] in ('template', 'string'):
278 return compileexp(exp, context, methods)
278 return compileexp(exp, context, methods)
279 if exp[0] == 'symbol':
279 if exp[0] == 'symbol':
280 # unlike runsymbol(), here 'symbol' is always taken as template name
280 # unlike runsymbol(), here 'symbol' is always taken as template name
281 # even if it exists in mapping. this allows us to override mapping
281 # even if it exists in mapping. this allows us to override mapping
282 # by web templates, e.g. 'changelogtag' is redefined in map file.
282 # by web templates, e.g. 'changelogtag' is redefined in map file.
283 return context._load(exp[1])
283 return context._load(exp[1])
284 raise error.ParseError(_("expected template specifier"))
284 raise error.ParseError(_("expected template specifier"))
285
285
286 def evalfuncarg(context, mapping, arg):
286 def evalfuncarg(context, mapping, arg):
287 func, data = arg
287 func, data = arg
288 # func() may return string, generator of strings or arbitrary object such
288 # func() may return string, generator of strings or arbitrary object such
289 # as date tuple, but filter does not want generator.
289 # as date tuple, but filter does not want generator.
290 thing = func(context, mapping, data)
290 thing = func(context, mapping, data)
291 if isinstance(thing, types.GeneratorType):
291 if isinstance(thing, types.GeneratorType):
292 thing = stringify(thing)
292 thing = stringify(thing)
293 return thing
293 return thing
294
294
295 def evalinteger(context, mapping, arg, err):
295 def evalinteger(context, mapping, arg, err):
296 v = evalfuncarg(context, mapping, arg)
296 v = evalfuncarg(context, mapping, arg)
297 try:
297 try:
298 return int(v)
298 return int(v)
299 except (TypeError, ValueError):
299 except (TypeError, ValueError):
300 raise error.ParseError(err)
300 raise error.ParseError(err)
301
301
302 def evalstring(context, mapping, arg):
302 def evalstring(context, mapping, arg):
303 func, data = arg
303 func, data = arg
304 return stringify(func(context, mapping, data))
304 return stringify(func(context, mapping, data))
305
305
306 def evalstringliteral(context, mapping, arg):
306 def evalstringliteral(context, mapping, arg):
307 """Evaluate given argument as string template, but returns symbol name
307 """Evaluate given argument as string template, but returns symbol name
308 if it is unknown"""
308 if it is unknown"""
309 func, data = arg
309 func, data = arg
310 if func is runsymbol:
310 if func is runsymbol:
311 thing = func(context, mapping, data, default=data)
311 thing = func(context, mapping, data, default=data)
312 else:
312 else:
313 thing = func(context, mapping, data)
313 thing = func(context, mapping, data)
314 return stringify(thing)
314 return stringify(thing)
315
315
316 def runinteger(context, mapping, data):
316 def runinteger(context, mapping, data):
317 return int(data)
317 return int(data)
318
318
319 def runstring(context, mapping, data):
319 def runstring(context, mapping, data):
320 return data
320 return data
321
321
322 def _recursivesymbolblocker(key):
322 def _recursivesymbolblocker(key):
323 def showrecursion(**args):
323 def showrecursion(**args):
324 raise error.Abort(_("recursive reference '%s' in template") % key)
324 raise error.Abort(_("recursive reference '%s' in template") % key)
325 return showrecursion
325 return showrecursion
326
326
327 def _runrecursivesymbol(context, mapping, key):
327 def _runrecursivesymbol(context, mapping, key):
328 raise error.Abort(_("recursive reference '%s' in template") % key)
328 raise error.Abort(_("recursive reference '%s' in template") % key)
329
329
330 def runsymbol(context, mapping, key, default=''):
330 def runsymbol(context, mapping, key, default=''):
331 v = mapping.get(key)
331 v = mapping.get(key)
332 if v is None:
332 if v is None:
333 v = context._defaults.get(key)
333 v = context._defaults.get(key)
334 if v is None:
334 if v is None:
335 # put poison to cut recursion. we can't move this to parsing phase
335 # put poison to cut recursion. we can't move this to parsing phase
336 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
336 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
337 safemapping = mapping.copy()
337 safemapping = mapping.copy()
338 safemapping[key] = _recursivesymbolblocker(key)
338 safemapping[key] = _recursivesymbolblocker(key)
339 try:
339 try:
340 v = context.process(key, safemapping)
340 v = context.process(key, safemapping)
341 except TemplateNotFound:
341 except TemplateNotFound:
342 v = default
342 v = default
343 if callable(v):
343 if callable(v):
344 return v(**mapping)
344 return v(**mapping)
345 return v
345 return v
346
346
347 def buildtemplate(exp, context):
347 def buildtemplate(exp, context):
348 ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
348 ctmpl = [compileexp(e, context, methods) for e in exp[1:]]
349 return (runtemplate, ctmpl)
349 return (runtemplate, ctmpl)
350
350
351 def runtemplate(context, mapping, template):
351 def runtemplate(context, mapping, template):
352 for func, data in template:
352 for func, data in template:
353 yield func(context, mapping, data)
353 yield func(context, mapping, data)
354
354
355 def buildfilter(exp, context):
355 def buildfilter(exp, context):
356 arg = compileexp(exp[1], context, methods)
356 arg = compileexp(exp[1], context, methods)
357 n = getsymbol(exp[2])
357 n = getsymbol(exp[2])
358 if n in context._filters:
358 if n in context._filters:
359 filt = context._filters[n]
359 filt = context._filters[n]
360 return (runfilter, (arg, filt))
360 return (runfilter, (arg, filt))
361 if n in funcs:
361 if n in funcs:
362 f = funcs[n]
362 f = funcs[n]
363 return (f, [arg])
363 return (f, [arg])
364 raise error.ParseError(_("unknown function '%s'") % n)
364 raise error.ParseError(_("unknown function '%s'") % n)
365
365
366 def runfilter(context, mapping, data):
366 def runfilter(context, mapping, data):
367 arg, filt = data
367 arg, filt = data
368 thing = evalfuncarg(context, mapping, arg)
368 thing = evalfuncarg(context, mapping, arg)
369 try:
369 try:
370 return filt(thing)
370 return filt(thing)
371 except (ValueError, AttributeError, TypeError):
371 except (ValueError, AttributeError, TypeError):
372 if isinstance(arg[1], tuple):
372 if isinstance(arg[1], tuple):
373 dt = arg[1][1]
373 dt = arg[1][1]
374 else:
374 else:
375 dt = arg[1]
375 dt = arg[1]
376 raise error.Abort(_("template filter '%s' is not compatible with "
376 raise error.Abort(_("template filter '%s' is not compatible with "
377 "keyword '%s'") % (filt.func_name, dt))
377 "keyword '%s'") % (filt.func_name, dt))
378
378
379 def buildmap(exp, context):
379 def buildmap(exp, context):
380 func, data = compileexp(exp[1], context, methods)
380 func, data = compileexp(exp[1], context, methods)
381 tfunc, tdata = gettemplate(exp[2], context)
381 tfunc, tdata = gettemplate(exp[2], context)
382 return (runmap, (func, data, tfunc, tdata))
382 return (runmap, (func, data, tfunc, tdata))
383
383
384 def runmap(context, mapping, data):
384 def runmap(context, mapping, data):
385 func, data, tfunc, tdata = data
385 func, data, tfunc, tdata = data
386 d = func(context, mapping, data)
386 d = func(context, mapping, data)
387 if util.safehasattr(d, 'itermaps'):
387 if util.safehasattr(d, 'itermaps'):
388 diter = d.itermaps()
388 diter = d.itermaps()
389 else:
389 else:
390 try:
390 try:
391 diter = iter(d)
391 diter = iter(d)
392 except TypeError:
392 except TypeError:
393 if func is runsymbol:
393 if func is runsymbol:
394 raise error.ParseError(_("keyword '%s' is not iterable") % data)
394 raise error.ParseError(_("keyword '%s' is not iterable") % data)
395 else:
395 else:
396 raise error.ParseError(_("%r is not iterable") % d)
396 raise error.ParseError(_("%r is not iterable") % d)
397
397
398 for i in diter:
398 for i in diter:
399 lm = mapping.copy()
399 lm = mapping.copy()
400 if isinstance(i, dict):
400 if isinstance(i, dict):
401 lm.update(i)
401 lm.update(i)
402 lm['originalnode'] = mapping.get('node')
402 lm['originalnode'] = mapping.get('node')
403 yield tfunc(context, lm, tdata)
403 yield tfunc(context, lm, tdata)
404 else:
404 else:
405 # v is not an iterable of dicts, this happen when 'key'
405 # v is not an iterable of dicts, this happen when 'key'
406 # has been fully expanded already and format is useless.
406 # has been fully expanded already and format is useless.
407 # If so, return the expanded value.
407 # If so, return the expanded value.
408 yield i
408 yield i
409
409
410 def buildfunc(exp, context):
410 def buildfunc(exp, context):
411 n = getsymbol(exp[1])
411 n = getsymbol(exp[1])
412 args = [compileexp(x, context, exprmethods) for x in getlist(exp[2])]
412 args = [compileexp(x, context, exprmethods) for x in getlist(exp[2])]
413 if n in funcs:
413 if n in funcs:
414 f = funcs[n]
414 f = funcs[n]
415 return (f, args)
415 return (f, args)
416 if n in context._filters:
416 if n in context._filters:
417 if len(args) != 1:
417 if len(args) != 1:
418 raise error.ParseError(_("filter %s expects one argument") % n)
418 raise error.ParseError(_("filter %s expects one argument") % n)
419 f = context._filters[n]
419 f = context._filters[n]
420 return (runfilter, (args[0], f))
420 return (runfilter, (args[0], f))
421 raise error.ParseError(_("unknown function '%s'") % n)
421 raise error.ParseError(_("unknown function '%s'") % n)
422
422
423 # dict of template built-in functions
423 # dict of template built-in functions
424 funcs = {}
424 funcs = {}
425
425
426 templatefunc = registrar.templatefunc(funcs)
426 templatefunc = registrar.templatefunc(funcs)
427
427
428 @templatefunc('date(date[, fmt])')
428 @templatefunc('date(date[, fmt])')
429 def date(context, mapping, args):
429 def date(context, mapping, args):
430 """Format a date. See :hg:`help dates` for formatting
430 """Format a date. See :hg:`help dates` for formatting
431 strings. The default is a Unix date format, including the timezone:
431 strings. The default is a Unix date format, including the timezone:
432 "Mon Sep 04 15:13:13 2006 0700"."""
432 "Mon Sep 04 15:13:13 2006 0700"."""
433 if not (1 <= len(args) <= 2):
433 if not (1 <= len(args) <= 2):
434 # i18n: "date" is a keyword
434 # i18n: "date" is a keyword
435 raise error.ParseError(_("date expects one or two arguments"))
435 raise error.ParseError(_("date expects one or two arguments"))
436
436
437 date = evalfuncarg(context, mapping, args[0])
437 date = evalfuncarg(context, mapping, args[0])
438 fmt = None
438 fmt = None
439 if len(args) == 2:
439 if len(args) == 2:
440 fmt = evalstring(context, mapping, args[1])
440 fmt = evalstring(context, mapping, args[1])
441 try:
441 try:
442 if fmt is None:
442 if fmt is None:
443 return util.datestr(date)
443 return util.datestr(date)
444 else:
444 else:
445 return util.datestr(date, fmt)
445 return util.datestr(date, fmt)
446 except (TypeError, ValueError):
446 except (TypeError, ValueError):
447 # i18n: "date" is a keyword
447 # i18n: "date" is a keyword
448 raise error.ParseError(_("date expects a date information"))
448 raise error.ParseError(_("date expects a date information"))
449
449
450 @templatefunc('diff([includepattern [, excludepattern]])')
450 @templatefunc('diff([includepattern [, excludepattern]])')
451 def diff(context, mapping, args):
451 def diff(context, mapping, args):
452 """Show a diff, optionally
452 """Show a diff, optionally
453 specifying files to include or exclude."""
453 specifying files to include or exclude."""
454 if len(args) > 2:
454 if len(args) > 2:
455 # i18n: "diff" is a keyword
455 # i18n: "diff" is a keyword
456 raise error.ParseError(_("diff expects zero, one, or two arguments"))
456 raise error.ParseError(_("diff expects zero, one, or two arguments"))
457
457
458 def getpatterns(i):
458 def getpatterns(i):
459 if i < len(args):
459 if i < len(args):
460 s = evalstring(context, mapping, args[i]).strip()
460 s = evalstring(context, mapping, args[i]).strip()
461 if s:
461 if s:
462 return [s]
462 return [s]
463 return []
463 return []
464
464
465 ctx = mapping['ctx']
465 ctx = mapping['ctx']
466 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
466 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
467
467
468 return ''.join(chunks)
468 return ''.join(chunks)
469
469
470 @templatefunc('fill(text[, width[, initialident[, hangindent]]])')
470 @templatefunc('fill(text[, width[, initialident[, hangindent]]])')
471 def fill(context, mapping, args):
471 def fill(context, mapping, args):
472 """Fill many
472 """Fill many
473 paragraphs with optional indentation. See the "fill" filter."""
473 paragraphs with optional indentation. See the "fill" filter."""
474 if not (1 <= len(args) <= 4):
474 if not (1 <= len(args) <= 4):
475 # i18n: "fill" is a keyword
475 # i18n: "fill" is a keyword
476 raise error.ParseError(_("fill expects one to four arguments"))
476 raise error.ParseError(_("fill expects one to four arguments"))
477
477
478 text = evalstring(context, mapping, args[0])
478 text = evalstring(context, mapping, args[0])
479 width = 76
479 width = 76
480 initindent = ''
480 initindent = ''
481 hangindent = ''
481 hangindent = ''
482 if 2 <= len(args) <= 4:
482 if 2 <= len(args) <= 4:
483 width = evalinteger(context, mapping, args[1],
483 width = evalinteger(context, mapping, args[1],
484 # i18n: "fill" is a keyword
484 # i18n: "fill" is a keyword
485 _("fill expects an integer width"))
485 _("fill expects an integer width"))
486 try:
486 try:
487 initindent = evalstring(context, mapping, args[2])
487 initindent = evalstring(context, mapping, args[2])
488 hangindent = evalstring(context, mapping, args[3])
488 hangindent = evalstring(context, mapping, args[3])
489 except IndexError:
489 except IndexError:
490 pass
490 pass
491
491
492 return templatefilters.fill(text, width, initindent, hangindent)
492 return templatefilters.fill(text, width, initindent, hangindent)
493
493
494 @templatefunc('pad(text, width[, fillchar=\' \'[, right=False]])')
494 @templatefunc('pad(text, width[, fillchar=\' \'[, right=False]])')
495 def pad(context, mapping, args):
495 def pad(context, mapping, args):
496 """Pad text with a
496 """Pad text with a
497 fill character."""
497 fill character."""
498 if not (2 <= len(args) <= 4):
498 if not (2 <= len(args) <= 4):
499 # i18n: "pad" is a keyword
499 # i18n: "pad" is a keyword
500 raise error.ParseError(_("pad() expects two to four arguments"))
500 raise error.ParseError(_("pad() expects two to four arguments"))
501
501
502 width = evalinteger(context, mapping, args[1],
502 width = evalinteger(context, mapping, args[1],
503 # i18n: "pad" is a keyword
503 # i18n: "pad" is a keyword
504 _("pad() expects an integer width"))
504 _("pad() expects an integer width"))
505
505
506 text = evalstring(context, mapping, args[0])
506 text = evalstring(context, mapping, args[0])
507
507
508 right = False
508 right = False
509 fillchar = ' '
509 fillchar = ' '
510 if len(args) > 2:
510 if len(args) > 2:
511 fillchar = evalstring(context, mapping, args[2])
511 fillchar = evalstring(context, mapping, args[2])
512 if len(args) > 3:
512 if len(args) > 3:
513 right = util.parsebool(args[3][1])
513 right = util.parsebool(args[3][1])
514
514
515 if right:
515 if right:
516 return text.rjust(width, fillchar)
516 return text.rjust(width, fillchar)
517 else:
517 else:
518 return text.ljust(width, fillchar)
518 return text.ljust(width, fillchar)
519
519
520 @templatefunc('indent(text, indentchars[, firstline])')
520 @templatefunc('indent(text, indentchars[, firstline])')
521 def indent(context, mapping, args):
521 def indent(context, mapping, args):
522 """Indents all non-empty lines
522 """Indents all non-empty lines
523 with the characters given in the indentchars string. An optional
523 with the characters given in the indentchars string. An optional
524 third parameter will override the indent for the first line only
524 third parameter will override the indent for the first line only
525 if present."""
525 if present."""
526 if not (2 <= len(args) <= 3):
526 if not (2 <= len(args) <= 3):
527 # i18n: "indent" is a keyword
527 # i18n: "indent" is a keyword
528 raise error.ParseError(_("indent() expects two or three arguments"))
528 raise error.ParseError(_("indent() expects two or three arguments"))
529
529
530 text = evalstring(context, mapping, args[0])
530 text = evalstring(context, mapping, args[0])
531 indent = evalstring(context, mapping, args[1])
531 indent = evalstring(context, mapping, args[1])
532
532
533 if len(args) == 3:
533 if len(args) == 3:
534 firstline = evalstring(context, mapping, args[2])
534 firstline = evalstring(context, mapping, args[2])
535 else:
535 else:
536 firstline = indent
536 firstline = indent
537
537
538 # the indent function doesn't indent the first line, so we do it here
538 # the indent function doesn't indent the first line, so we do it here
539 return templatefilters.indent(firstline + text, indent)
539 return templatefilters.indent(firstline + text, indent)
540
540
541 @templatefunc('get(dict, key)')
541 @templatefunc('get(dict, key)')
542 def get(context, mapping, args):
542 def get(context, mapping, args):
543 """Get an attribute/key from an object. Some keywords
543 """Get an attribute/key from an object. Some keywords
544 are complex types. This function allows you to obtain the value of an
544 are complex types. This function allows you to obtain the value of an
545 attribute on these types."""
545 attribute on these types."""
546 if len(args) != 2:
546 if len(args) != 2:
547 # i18n: "get" is a keyword
547 # i18n: "get" is a keyword
548 raise error.ParseError(_("get() expects two arguments"))
548 raise error.ParseError(_("get() expects two arguments"))
549
549
550 dictarg = evalfuncarg(context, mapping, args[0])
550 dictarg = evalfuncarg(context, mapping, args[0])
551 if not util.safehasattr(dictarg, 'get'):
551 if not util.safehasattr(dictarg, 'get'):
552 # i18n: "get" is a keyword
552 # i18n: "get" is a keyword
553 raise error.ParseError(_("get() expects a dict as first argument"))
553 raise error.ParseError(_("get() expects a dict as first argument"))
554
554
555 key = evalfuncarg(context, mapping, args[1])
555 key = evalfuncarg(context, mapping, args[1])
556 return dictarg.get(key)
556 return dictarg.get(key)
557
557
558 @templatefunc('if(expr, then[, else])')
558 @templatefunc('if(expr, then[, else])')
559 def if_(context, mapping, args):
559 def if_(context, mapping, args):
560 """Conditionally execute based on the result of
560 """Conditionally execute based on the result of
561 an expression."""
561 an expression."""
562 if not (2 <= len(args) <= 3):
562 if not (2 <= len(args) <= 3):
563 # i18n: "if" is a keyword
563 # i18n: "if" is a keyword
564 raise error.ParseError(_("if expects two or three arguments"))
564 raise error.ParseError(_("if expects two or three arguments"))
565
565
566 test = evalstring(context, mapping, args[0])
566 test = evalstring(context, mapping, args[0])
567 if test:
567 if test:
568 yield args[1][0](context, mapping, args[1][1])
568 yield args[1][0](context, mapping, args[1][1])
569 elif len(args) == 3:
569 elif len(args) == 3:
570 yield args[2][0](context, mapping, args[2][1])
570 yield args[2][0](context, mapping, args[2][1])
571
571
572 @templatefunc('ifcontains(search, thing, then[, else])')
572 @templatefunc('ifcontains(search, thing, then[, else])')
573 def ifcontains(context, mapping, args):
573 def ifcontains(context, mapping, args):
574 """Conditionally execute based
574 """Conditionally execute based
575 on whether the item "search" is in "thing"."""
575 on whether the item "search" is in "thing"."""
576 if not (3 <= len(args) <= 4):
576 if not (3 <= len(args) <= 4):
577 # i18n: "ifcontains" is a keyword
577 # i18n: "ifcontains" is a keyword
578 raise error.ParseError(_("ifcontains expects three or four arguments"))
578 raise error.ParseError(_("ifcontains expects three or four arguments"))
579
579
580 item = evalstring(context, mapping, args[0])
580 item = evalstring(context, mapping, args[0])
581 items = evalfuncarg(context, mapping, args[1])
581 items = evalfuncarg(context, mapping, args[1])
582
582
583 if item in items:
583 if item in items:
584 yield args[2][0](context, mapping, args[2][1])
584 yield args[2][0](context, mapping, args[2][1])
585 elif len(args) == 4:
585 elif len(args) == 4:
586 yield args[3][0](context, mapping, args[3][1])
586 yield args[3][0](context, mapping, args[3][1])
587
587
588 @templatefunc('ifeq(expr1, expr2, then[, else])')
588 @templatefunc('ifeq(expr1, expr2, then[, else])')
589 def ifeq(context, mapping, args):
589 def ifeq(context, mapping, args):
590 """Conditionally execute based on
590 """Conditionally execute based on
591 whether 2 items are equivalent."""
591 whether 2 items are equivalent."""
592 if not (3 <= len(args) <= 4):
592 if not (3 <= len(args) <= 4):
593 # i18n: "ifeq" is a keyword
593 # i18n: "ifeq" is a keyword
594 raise error.ParseError(_("ifeq expects three or four arguments"))
594 raise error.ParseError(_("ifeq expects three or four arguments"))
595
595
596 test = evalstring(context, mapping, args[0])
596 test = evalstring(context, mapping, args[0])
597 match = evalstring(context, mapping, args[1])
597 match = evalstring(context, mapping, args[1])
598 if test == match:
598 if test == match:
599 yield args[2][0](context, mapping, args[2][1])
599 yield args[2][0](context, mapping, args[2][1])
600 elif len(args) == 4:
600 elif len(args) == 4:
601 yield args[3][0](context, mapping, args[3][1])
601 yield args[3][0](context, mapping, args[3][1])
602
602
603 @templatefunc('join(list, sep)')
603 @templatefunc('join(list, sep)')
604 def join(context, mapping, args):
604 def join(context, mapping, args):
605 """Join items in a list with a delimiter."""
605 """Join items in a list with a delimiter."""
606 if not (1 <= len(args) <= 2):
606 if not (1 <= len(args) <= 2):
607 # i18n: "join" is a keyword
607 # i18n: "join" is a keyword
608 raise error.ParseError(_("join expects one or two arguments"))
608 raise error.ParseError(_("join expects one or two arguments"))
609
609
610 joinset = args[0][0](context, mapping, args[0][1])
610 joinset = args[0][0](context, mapping, args[0][1])
611 if util.safehasattr(joinset, 'itermaps'):
611 if util.safehasattr(joinset, 'itermaps'):
612 jf = joinset.joinfmt
612 jf = joinset.joinfmt
613 joinset = [jf(x) for x in joinset.itermaps()]
613 joinset = [jf(x) for x in joinset.itermaps()]
614
614
615 joiner = " "
615 joiner = " "
616 if len(args) > 1:
616 if len(args) > 1:
617 joiner = evalstring(context, mapping, args[1])
617 joiner = evalstring(context, mapping, args[1])
618
618
619 first = True
619 first = True
620 for x in joinset:
620 for x in joinset:
621 if first:
621 if first:
622 first = False
622 first = False
623 else:
623 else:
624 yield joiner
624 yield joiner
625 yield x
625 yield x
626
626
627 @templatefunc('label(label, expr)')
627 @templatefunc('label(label, expr)')
628 def label(context, mapping, args):
628 def label(context, mapping, args):
629 """Apply a label to generated content. Content with
629 """Apply a label to generated content. Content with
630 a label applied can result in additional post-processing, such as
630 a label applied can result in additional post-processing, such as
631 automatic colorization."""
631 automatic colorization."""
632 if len(args) != 2:
632 if len(args) != 2:
633 # i18n: "label" is a keyword
633 # i18n: "label" is a keyword
634 raise error.ParseError(_("label expects two arguments"))
634 raise error.ParseError(_("label expects two arguments"))
635
635
636 ui = mapping['ui']
636 ui = mapping['ui']
637 thing = evalstring(context, mapping, args[1])
637 thing = evalstring(context, mapping, args[1])
638 # preserve unknown symbol as literal so effects like 'red', 'bold',
638 # preserve unknown symbol as literal so effects like 'red', 'bold',
639 # etc. don't need to be quoted
639 # etc. don't need to be quoted
640 label = evalstringliteral(context, mapping, args[0])
640 label = evalstringliteral(context, mapping, args[0])
641
641
642 return ui.label(thing, label)
642 return ui.label(thing, label)
643
643
644 @templatefunc('latesttag([pattern])')
644 @templatefunc('latesttag([pattern])')
645 def latesttag(context, mapping, args):
645 def latesttag(context, mapping, args):
646 """The global tags matching the given pattern on the
646 """The global tags matching the given pattern on the
647 most recent globally tagged ancestor of this changeset."""
647 most recent globally tagged ancestor of this changeset."""
648 if len(args) > 1:
648 if len(args) > 1:
649 # i18n: "latesttag" is a keyword
649 # i18n: "latesttag" is a keyword
650 raise error.ParseError(_("latesttag expects at most one argument"))
650 raise error.ParseError(_("latesttag expects at most one argument"))
651
651
652 pattern = None
652 pattern = None
653 if len(args) == 1:
653 if len(args) == 1:
654 pattern = evalstring(context, mapping, args[0])
654 pattern = evalstring(context, mapping, args[0])
655
655
656 return templatekw.showlatesttags(pattern, **mapping)
656 return templatekw.showlatesttags(pattern, **mapping)
657
657
658 @templatefunc('localdate(date[, tz])')
658 @templatefunc('localdate(date[, tz])')
659 def localdate(context, mapping, args):
659 def localdate(context, mapping, args):
660 """Converts a date to the specified timezone.
660 """Converts a date to the specified timezone.
661 The default is local date."""
661 The default is local date."""
662 if not (1 <= len(args) <= 2):
662 if not (1 <= len(args) <= 2):
663 # i18n: "localdate" is a keyword
663 # i18n: "localdate" is a keyword
664 raise error.ParseError(_("localdate expects one or two arguments"))
664 raise error.ParseError(_("localdate expects one or two arguments"))
665
665
666 date = evalfuncarg(context, mapping, args[0])
666 date = evalfuncarg(context, mapping, args[0])
667 try:
667 try:
668 date = util.parsedate(date)
668 date = util.parsedate(date)
669 except AttributeError: # not str nor date tuple
669 except AttributeError: # not str nor date tuple
670 # i18n: "localdate" is a keyword
670 # i18n: "localdate" is a keyword
671 raise error.ParseError(_("localdate expects a date information"))
671 raise error.ParseError(_("localdate expects a date information"))
672 if len(args) >= 2:
672 if len(args) >= 2:
673 tzoffset = None
673 tzoffset = None
674 tz = evalfuncarg(context, mapping, args[1])
674 tz = evalfuncarg(context, mapping, args[1])
675 if isinstance(tz, str):
675 if isinstance(tz, str):
676 tzoffset = util.parsetimezone(tz)
676 tzoffset = util.parsetimezone(tz)
677 if tzoffset is None:
677 if tzoffset is None:
678 try:
678 try:
679 tzoffset = int(tz)
679 tzoffset = int(tz)
680 except (TypeError, ValueError):
680 except (TypeError, ValueError):
681 # i18n: "localdate" is a keyword
681 # i18n: "localdate" is a keyword
682 raise error.ParseError(_("localdate expects a timezone"))
682 raise error.ParseError(_("localdate expects a timezone"))
683 else:
683 else:
684 tzoffset = util.makedate()[1]
684 tzoffset = util.makedate()[1]
685 return (date[0], tzoffset)
685 return (date[0], tzoffset)
686
686
687 @templatefunc('revset(query[, formatargs...])')
687 @templatefunc('revset(query[, formatargs...])')
688 def revset(context, mapping, args):
688 def revset(context, mapping, args):
689 """Execute a revision set query. See
689 """Execute a revision set query. See
690 :hg:`help revset`."""
690 :hg:`help revset`."""
691 if not len(args) > 0:
691 if not len(args) > 0:
692 # i18n: "revset" is a keyword
692 # i18n: "revset" is a keyword
693 raise error.ParseError(_("revset expects one or more arguments"))
693 raise error.ParseError(_("revset expects one or more arguments"))
694
694
695 raw = evalstring(context, mapping, args[0])
695 raw = evalstring(context, mapping, args[0])
696 ctx = mapping['ctx']
696 ctx = mapping['ctx']
697 repo = ctx.repo()
697 repo = ctx.repo()
698
698
699 def query(expr):
699 def query(expr):
700 m = revsetmod.match(repo.ui, expr)
700 m = revsetmod.match(repo.ui, expr)
701 return m(repo)
701 return m(repo)
702
702
703 if len(args) > 1:
703 if len(args) > 1:
704 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
704 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
705 revs = query(revsetmod.formatspec(raw, *formatargs))
705 revs = query(revsetmod.formatspec(raw, *formatargs))
706 revs = list(revs)
706 revs = list(revs)
707 else:
707 else:
708 revsetcache = mapping['cache'].setdefault("revsetcache", {})
708 revsetcache = mapping['cache'].setdefault("revsetcache", {})
709 if raw in revsetcache:
709 if raw in revsetcache:
710 revs = revsetcache[raw]
710 revs = revsetcache[raw]
711 else:
711 else:
712 revs = query(raw)
712 revs = query(raw)
713 revs = list(revs)
713 revs = list(revs)
714 revsetcache[raw] = revs
714 revsetcache[raw] = revs
715
715
716 return templatekw.showrevslist("revision", revs, **mapping)
716 return templatekw.showrevslist("revision", revs, **mapping)
717
717
718 @templatefunc('rstdoc(text, style)')
718 @templatefunc('rstdoc(text, style)')
719 def rstdoc(context, mapping, args):
719 def rstdoc(context, mapping, args):
720 """Format ReStructuredText."""
720 """Format ReStructuredText."""
721 if len(args) != 2:
721 if len(args) != 2:
722 # i18n: "rstdoc" is a keyword
722 # i18n: "rstdoc" is a keyword
723 raise error.ParseError(_("rstdoc expects two arguments"))
723 raise error.ParseError(_("rstdoc expects two arguments"))
724
724
725 text = evalstring(context, mapping, args[0])
725 text = evalstring(context, mapping, args[0])
726 style = evalstring(context, mapping, args[1])
726 style = evalstring(context, mapping, args[1])
727
727
728 return minirst.format(text, style=style, keep=['verbose'])
728 return minirst.format(text, style=style, keep=['verbose'])
729
729
730 @templatefunc('shortest(node, minlength=4)')
730 @templatefunc('shortest(node, minlength=4)')
731 def shortest(context, mapping, args):
731 def shortest(context, mapping, args):
732 """Obtain the shortest representation of
732 """Obtain the shortest representation of
733 a node."""
733 a node."""
734 if not (1 <= len(args) <= 2):
734 if not (1 <= len(args) <= 2):
735 # i18n: "shortest" is a keyword
735 # i18n: "shortest" is a keyword
736 raise error.ParseError(_("shortest() expects one or two arguments"))
736 raise error.ParseError(_("shortest() expects one or two arguments"))
737
737
738 node = evalstring(context, mapping, args[0])
738 node = evalstring(context, mapping, args[0])
739
739
740 minlength = 4
740 minlength = 4
741 if len(args) > 1:
741 if len(args) > 1:
742 minlength = evalinteger(context, mapping, args[1],
742 minlength = evalinteger(context, mapping, args[1],
743 # i18n: "shortest" is a keyword
743 # i18n: "shortest" is a keyword
744 _("shortest() expects an integer minlength"))
744 _("shortest() expects an integer minlength"))
745
745
746 cl = mapping['ctx']._repo.changelog
746 cl = mapping['ctx']._repo.changelog
747 def isvalid(test):
747 def isvalid(test):
748 try:
748 try:
749 try:
749 try:
750 cl.index.partialmatch(test)
750 cl.index.partialmatch(test)
751 except AttributeError:
751 except AttributeError:
752 # Pure mercurial doesn't support partialmatch on the index.
752 # Pure mercurial doesn't support partialmatch on the index.
753 # Fallback to the slow way.
753 # Fallback to the slow way.
754 if cl._partialmatch(test) is None:
754 if cl._partialmatch(test) is None:
755 return False
755 return False
756
756
757 try:
757 try:
758 i = int(test)
758 i = int(test)
759 # if we are a pure int, then starting with zero will not be
759 # if we are a pure int, then starting with zero will not be
760 # confused as a rev; or, obviously, if the int is larger than
760 # confused as a rev; or, obviously, if the int is larger than
761 # the value of the tip rev
761 # the value of the tip rev
762 if test[0] == '0' or i > len(cl):
762 if test[0] == '0' or i > len(cl):
763 return True
763 return True
764 return False
764 return False
765 except ValueError:
765 except ValueError:
766 return True
766 return True
767 except error.RevlogError:
767 except error.RevlogError:
768 return False
768 return False
769
769
770 shortest = node
770 shortest = node
771 startlength = max(6, minlength)
771 startlength = max(6, minlength)
772 length = startlength
772 length = startlength
773 while True:
773 while True:
774 test = node[:length]
774 test = node[:length]
775 if isvalid(test):
775 if isvalid(test):
776 shortest = test
776 shortest = test
777 if length == minlength or length > startlength:
777 if length == minlength or length > startlength:
778 return shortest
778 return shortest
779 length -= 1
779 length -= 1
780 else:
780 else:
781 length += 1
781 length += 1
782 if len(shortest) <= length:
782 if len(shortest) <= length:
783 return shortest
783 return shortest
784
784
785 @templatefunc('strip(text[, chars])')
785 @templatefunc('strip(text[, chars])')
786 def strip(context, mapping, args):
786 def strip(context, mapping, args):
787 """Strip characters from a string. By default,
787 """Strip characters from a string. By default,
788 strips all leading and trailing whitespace."""
788 strips all leading and trailing whitespace."""
789 if not (1 <= len(args) <= 2):
789 if not (1 <= len(args) <= 2):
790 # i18n: "strip" is a keyword
790 # i18n: "strip" is a keyword
791 raise error.ParseError(_("strip expects one or two arguments"))
791 raise error.ParseError(_("strip expects one or two arguments"))
792
792
793 text = evalstring(context, mapping, args[0])
793 text = evalstring(context, mapping, args[0])
794 if len(args) == 2:
794 if len(args) == 2:
795 chars = evalstring(context, mapping, args[1])
795 chars = evalstring(context, mapping, args[1])
796 return text.strip(chars)
796 return text.strip(chars)
797 return text.strip()
797 return text.strip()
798
798
799 @templatefunc('sub(pattern, replacement, expression)')
799 @templatefunc('sub(pattern, replacement, expression)')
800 def sub(context, mapping, args):
800 def sub(context, mapping, args):
801 """Perform text substitution
801 """Perform text substitution
802 using regular expressions."""
802 using regular expressions."""
803 if len(args) != 3:
803 if len(args) != 3:
804 # i18n: "sub" is a keyword
804 # i18n: "sub" is a keyword
805 raise error.ParseError(_("sub expects three arguments"))
805 raise error.ParseError(_("sub expects three arguments"))
806
806
807 pat = evalstring(context, mapping, args[0])
807 pat = evalstring(context, mapping, args[0])
808 rpl = evalstring(context, mapping, args[1])
808 rpl = evalstring(context, mapping, args[1])
809 src = evalstring(context, mapping, args[2])
809 src = evalstring(context, mapping, args[2])
810 try:
810 try:
811 patre = re.compile(pat)
811 patre = re.compile(pat)
812 except re.error:
812 except re.error:
813 # i18n: "sub" is a keyword
813 # i18n: "sub" is a keyword
814 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
814 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
815 try:
815 try:
816 yield patre.sub(rpl, src)
816 yield patre.sub(rpl, src)
817 except re.error:
817 except re.error:
818 # i18n: "sub" is a keyword
818 # i18n: "sub" is a keyword
819 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
819 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
820
820
821 @templatefunc('startswith(pattern, text)')
821 @templatefunc('startswith(pattern, text)')
822 def startswith(context, mapping, args):
822 def startswith(context, mapping, args):
823 """Returns the value from the "text" argument
823 """Returns the value from the "text" argument
824 if it begins with the content from the "pattern" argument."""
824 if it begins with the content from the "pattern" argument."""
825 if len(args) != 2:
825 if len(args) != 2:
826 # i18n: "startswith" is a keyword
826 # i18n: "startswith" is a keyword
827 raise error.ParseError(_("startswith expects two arguments"))
827 raise error.ParseError(_("startswith expects two arguments"))
828
828
829 patn = evalstring(context, mapping, args[0])
829 patn = evalstring(context, mapping, args[0])
830 text = evalstring(context, mapping, args[1])
830 text = evalstring(context, mapping, args[1])
831 if text.startswith(patn):
831 if text.startswith(patn):
832 return text
832 return text
833 return ''
833 return ''
834
834
835 @templatefunc('word(number, text[, separator])')
835 @templatefunc('word(number, text[, separator])')
836 def word(context, mapping, args):
836 def word(context, mapping, args):
837 """Return the nth word from a string."""
837 """Return the nth word from a string."""
838 if not (2 <= len(args) <= 3):
838 if not (2 <= len(args) <= 3):
839 # i18n: "word" is a keyword
839 # i18n: "word" is a keyword
840 raise error.ParseError(_("word expects two or three arguments, got %d")
840 raise error.ParseError(_("word expects two or three arguments, got %d")
841 % len(args))
841 % len(args))
842
842
843 num = evalinteger(context, mapping, args[0],
843 num = evalinteger(context, mapping, args[0],
844 # i18n: "word" is a keyword
844 # i18n: "word" is a keyword
845 _("word expects an integer index"))
845 _("word expects an integer index"))
846 text = evalstring(context, mapping, args[1])
846 text = evalstring(context, mapping, args[1])
847 if len(args) == 3:
847 if len(args) == 3:
848 splitter = evalstring(context, mapping, args[2])
848 splitter = evalstring(context, mapping, args[2])
849 else:
849 else:
850 splitter = None
850 splitter = None
851
851
852 tokens = text.split(splitter)
852 tokens = text.split(splitter)
853 if num >= len(tokens) or num < -len(tokens):
853 if num >= len(tokens) or num < -len(tokens):
854 return ''
854 return ''
855 else:
855 else:
856 return tokens[num]
856 return tokens[num]
857
857
858 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
858 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
859 exprmethods = {
859 exprmethods = {
860 "integer": lambda e, c: (runinteger, e[1]),
860 "integer": lambda e, c: (runinteger, e[1]),
861 "string": lambda e, c: (runstring, e[1]),
861 "string": lambda e, c: (runstring, e[1]),
862 "symbol": lambda e, c: (runsymbol, e[1]),
862 "symbol": lambda e, c: (runsymbol, e[1]),
863 "template": buildtemplate,
863 "template": buildtemplate,
864 "group": lambda e, c: compileexp(e[1], c, exprmethods),
864 "group": lambda e, c: compileexp(e[1], c, exprmethods),
865 # ".": buildmember,
865 # ".": buildmember,
866 "|": buildfilter,
866 "|": buildfilter,
867 "%": buildmap,
867 "%": buildmap,
868 "func": buildfunc,
868 "func": buildfunc,
869 }
869 }
870
870
871 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
871 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
872 methods = exprmethods.copy()
872 methods = exprmethods.copy()
873 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
873 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
874
874
875 class _aliasrules(parser.basealiasrules):
876 """Parsing and expansion rule set of template aliases"""
877 _section = _('template alias')
878 _parse = staticmethod(_parseexpr)
879
880 @staticmethod
881 def _trygetfunc(tree):
882 """Return (name, args) if tree is func(...) or ...|filter; otherwise
883 None"""
884 if tree[0] == 'func' and tree[1][0] == 'symbol':
885 return tree[1][1], getlist(tree[2])
886 if tree[0] == '|' and tree[2][0] == 'symbol':
887 return tree[2][1], [tree[1]]
888
889 def expandaliases(tree, aliases):
890 """Return new tree of aliases are expanded"""
891 aliasmap = _aliasrules.buildmap(aliases)
892 return _aliasrules.expand(aliasmap, tree)
893
875 # template engine
894 # template engine
876
895
877 stringify = templatefilters.stringify
896 stringify = templatefilters.stringify
878
897
879 def _flatten(thing):
898 def _flatten(thing):
880 '''yield a single stream from a possibly nested set of iterators'''
899 '''yield a single stream from a possibly nested set of iterators'''
881 if isinstance(thing, str):
900 if isinstance(thing, str):
882 yield thing
901 yield thing
883 elif not util.safehasattr(thing, '__iter__'):
902 elif not util.safehasattr(thing, '__iter__'):
884 if thing is not None:
903 if thing is not None:
885 yield str(thing)
904 yield str(thing)
886 else:
905 else:
887 for i in thing:
906 for i in thing:
888 if isinstance(i, str):
907 if isinstance(i, str):
889 yield i
908 yield i
890 elif not util.safehasattr(i, '__iter__'):
909 elif not util.safehasattr(i, '__iter__'):
891 if i is not None:
910 if i is not None:
892 yield str(i)
911 yield str(i)
893 elif i is not None:
912 elif i is not None:
894 for j in _flatten(i):
913 for j in _flatten(i):
895 yield j
914 yield j
896
915
897 def unquotestring(s):
916 def unquotestring(s):
898 '''unwrap quotes if any; otherwise returns unmodified string'''
917 '''unwrap quotes if any; otherwise returns unmodified string'''
899 if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
918 if len(s) < 2 or s[0] not in "'\"" or s[0] != s[-1]:
900 return s
919 return s
901 return s[1:-1]
920 return s[1:-1]
902
921
903 class engine(object):
922 class engine(object):
904 '''template expansion engine.
923 '''template expansion engine.
905
924
906 template expansion works like this. a map file contains key=value
925 template expansion works like this. a map file contains key=value
907 pairs. if value is quoted, it is treated as string. otherwise, it
926 pairs. if value is quoted, it is treated as string. otherwise, it
908 is treated as name of template file.
927 is treated as name of template file.
909
928
910 templater is asked to expand a key in map. it looks up key, and
929 templater is asked to expand a key in map. it looks up key, and
911 looks for strings like this: {foo}. it expands {foo} by looking up
930 looks for strings like this: {foo}. it expands {foo} by looking up
912 foo in map, and substituting it. expansion is recursive: it stops
931 foo in map, and substituting it. expansion is recursive: it stops
913 when there is no more {foo} to replace.
932 when there is no more {foo} to replace.
914
933
915 expansion also allows formatting and filtering.
934 expansion also allows formatting and filtering.
916
935
917 format uses key to expand each item in list. syntax is
936 format uses key to expand each item in list. syntax is
918 {key%format}.
937 {key%format}.
919
938
920 filter uses function to transform value. syntax is
939 filter uses function to transform value. syntax is
921 {key|filter1|filter2|...}.'''
940 {key|filter1|filter2|...}.'''
922
941
923 def __init__(self, loader, filters=None, defaults=None):
942 def __init__(self, loader, filters=None, defaults=None):
924 self._loader = loader
943 self._loader = loader
925 if filters is None:
944 if filters is None:
926 filters = {}
945 filters = {}
927 self._filters = filters
946 self._filters = filters
928 if defaults is None:
947 if defaults is None:
929 defaults = {}
948 defaults = {}
930 self._defaults = defaults
949 self._defaults = defaults
931 self._cache = {} # key: (func, data)
950 self._cache = {} # key: (func, data)
932
951
933 def _load(self, t):
952 def _load(self, t):
934 '''load, parse, and cache a template'''
953 '''load, parse, and cache a template'''
935 if t not in self._cache:
954 if t not in self._cache:
936 # put poison to cut recursion while compiling 't'
955 # put poison to cut recursion while compiling 't'
937 self._cache[t] = (_runrecursivesymbol, t)
956 self._cache[t] = (_runrecursivesymbol, t)
938 try:
957 try:
939 self._cache[t] = compiletemplate(self._loader(t), self)
958 self._cache[t] = compiletemplate(self._loader(t), self)
940 except: # re-raises
959 except: # re-raises
941 del self._cache[t]
960 del self._cache[t]
942 raise
961 raise
943 return self._cache[t]
962 return self._cache[t]
944
963
945 def process(self, t, mapping):
964 def process(self, t, mapping):
946 '''Perform expansion. t is name of map element to expand.
965 '''Perform expansion. t is name of map element to expand.
947 mapping contains added elements for use during expansion. Is a
966 mapping contains added elements for use during expansion. Is a
948 generator.'''
967 generator.'''
949 func, data = self._load(t)
968 func, data = self._load(t)
950 return _flatten(func(self, mapping, data))
969 return _flatten(func(self, mapping, data))
951
970
952 engines = {'default': engine}
971 engines = {'default': engine}
953
972
954 def stylelist():
973 def stylelist():
955 paths = templatepaths()
974 paths = templatepaths()
956 if not paths:
975 if not paths:
957 return _('no templates found, try `hg debuginstall` for more info')
976 return _('no templates found, try `hg debuginstall` for more info')
958 dirlist = os.listdir(paths[0])
977 dirlist = os.listdir(paths[0])
959 stylelist = []
978 stylelist = []
960 for file in dirlist:
979 for file in dirlist:
961 split = file.split(".")
980 split = file.split(".")
962 if split[-1] in ('orig', 'rej'):
981 if split[-1] in ('orig', 'rej'):
963 continue
982 continue
964 if split[0] == "map-cmdline":
983 if split[0] == "map-cmdline":
965 stylelist.append(split[1])
984 stylelist.append(split[1])
966 return ", ".join(sorted(stylelist))
985 return ", ".join(sorted(stylelist))
967
986
968 class TemplateNotFound(error.Abort):
987 class TemplateNotFound(error.Abort):
969 pass
988 pass
970
989
971 class templater(object):
990 class templater(object):
972
991
973 def __init__(self, mapfile, filters=None, defaults=None, cache=None,
992 def __init__(self, mapfile, filters=None, defaults=None, cache=None,
974 minchunk=1024, maxchunk=65536):
993 minchunk=1024, maxchunk=65536):
975 '''set up template engine.
994 '''set up template engine.
976 mapfile is name of file to read map definitions from.
995 mapfile is name of file to read map definitions from.
977 filters is dict of functions. each transforms a value into another.
996 filters is dict of functions. each transforms a value into another.
978 defaults is dict of default map definitions.'''
997 defaults is dict of default map definitions.'''
979 if filters is None:
998 if filters is None:
980 filters = {}
999 filters = {}
981 if defaults is None:
1000 if defaults is None:
982 defaults = {}
1001 defaults = {}
983 if cache is None:
1002 if cache is None:
984 cache = {}
1003 cache = {}
985 self.cache = cache.copy()
1004 self.cache = cache.copy()
986 self.map = {}
1005 self.map = {}
987 if mapfile:
1006 if mapfile:
988 self.base = os.path.dirname(mapfile)
1007 self.base = os.path.dirname(mapfile)
989 else:
1008 else:
990 self.base = ''
1009 self.base = ''
991 self.filters = templatefilters.filters.copy()
1010 self.filters = templatefilters.filters.copy()
992 self.filters.update(filters)
1011 self.filters.update(filters)
993 self.defaults = defaults
1012 self.defaults = defaults
994 self.minchunk, self.maxchunk = minchunk, maxchunk
1013 self.minchunk, self.maxchunk = minchunk, maxchunk
995 self.ecache = {}
1014 self.ecache = {}
996
1015
997 if not mapfile:
1016 if not mapfile:
998 return
1017 return
999 if not os.path.exists(mapfile):
1018 if not os.path.exists(mapfile):
1000 raise error.Abort(_("style '%s' not found") % mapfile,
1019 raise error.Abort(_("style '%s' not found") % mapfile,
1001 hint=_("available styles: %s") % stylelist())
1020 hint=_("available styles: %s") % stylelist())
1002
1021
1003 conf = config.config(includepaths=templatepaths())
1022 conf = config.config(includepaths=templatepaths())
1004 conf.read(mapfile)
1023 conf.read(mapfile)
1005
1024
1006 for key, val in conf[''].items():
1025 for key, val in conf[''].items():
1007 if not val:
1026 if not val:
1008 raise error.ParseError(_('missing value'), conf.source('', key))
1027 raise error.ParseError(_('missing value'), conf.source('', key))
1009 if val[0] in "'\"":
1028 if val[0] in "'\"":
1010 if val[0] != val[-1]:
1029 if val[0] != val[-1]:
1011 raise error.ParseError(_('unmatched quotes'),
1030 raise error.ParseError(_('unmatched quotes'),
1012 conf.source('', key))
1031 conf.source('', key))
1013 self.cache[key] = unquotestring(val)
1032 self.cache[key] = unquotestring(val)
1014 else:
1033 else:
1015 val = 'default', val
1034 val = 'default', val
1016 if ':' in val[1]:
1035 if ':' in val[1]:
1017 val = val[1].split(':', 1)
1036 val = val[1].split(':', 1)
1018 self.map[key] = val[0], os.path.join(self.base, val[1])
1037 self.map[key] = val[0], os.path.join(self.base, val[1])
1019
1038
1020 def __contains__(self, key):
1039 def __contains__(self, key):
1021 return key in self.cache or key in self.map
1040 return key in self.cache or key in self.map
1022
1041
1023 def load(self, t):
1042 def load(self, t):
1024 '''Get the template for the given template name. Use a local cache.'''
1043 '''Get the template for the given template name. Use a local cache.'''
1025 if t not in self.cache:
1044 if t not in self.cache:
1026 try:
1045 try:
1027 self.cache[t] = util.readfile(self.map[t][1])
1046 self.cache[t] = util.readfile(self.map[t][1])
1028 except KeyError as inst:
1047 except KeyError as inst:
1029 raise TemplateNotFound(_('"%s" not in template map') %
1048 raise TemplateNotFound(_('"%s" not in template map') %
1030 inst.args[0])
1049 inst.args[0])
1031 except IOError as inst:
1050 except IOError as inst:
1032 raise IOError(inst.args[0], _('template file %s: %s') %
1051 raise IOError(inst.args[0], _('template file %s: %s') %
1033 (self.map[t][1], inst.args[1]))
1052 (self.map[t][1], inst.args[1]))
1034 return self.cache[t]
1053 return self.cache[t]
1035
1054
1036 def __call__(self, t, **mapping):
1055 def __call__(self, t, **mapping):
1037 ttype = t in self.map and self.map[t][0] or 'default'
1056 ttype = t in self.map and self.map[t][0] or 'default'
1038 if ttype not in self.ecache:
1057 if ttype not in self.ecache:
1039 try:
1058 try:
1040 ecls = engines[ttype]
1059 ecls = engines[ttype]
1041 except KeyError:
1060 except KeyError:
1042 raise error.Abort(_('invalid template engine: %s') % ttype)
1061 raise error.Abort(_('invalid template engine: %s') % ttype)
1043 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults)
1062 self.ecache[ttype] = ecls(self.load, self.filters, self.defaults)
1044 proc = self.ecache[ttype]
1063 proc = self.ecache[ttype]
1045
1064
1046 stream = proc.process(t, mapping)
1065 stream = proc.process(t, mapping)
1047 if self.minchunk:
1066 if self.minchunk:
1048 stream = util.increasingchunks(stream, min=self.minchunk,
1067 stream = util.increasingchunks(stream, min=self.minchunk,
1049 max=self.maxchunk)
1068 max=self.maxchunk)
1050 return stream
1069 return stream
1051
1070
1052 def templatepaths():
1071 def templatepaths():
1053 '''return locations used for template files.'''
1072 '''return locations used for template files.'''
1054 pathsrel = ['templates']
1073 pathsrel = ['templates']
1055 paths = [os.path.normpath(os.path.join(util.datapath, f))
1074 paths = [os.path.normpath(os.path.join(util.datapath, f))
1056 for f in pathsrel]
1075 for f in pathsrel]
1057 return [p for p in paths if os.path.isdir(p)]
1076 return [p for p in paths if os.path.isdir(p)]
1058
1077
1059 def templatepath(name):
1078 def templatepath(name):
1060 '''return location of template file. returns None if not found.'''
1079 '''return location of template file. returns None if not found.'''
1061 for p in templatepaths():
1080 for p in templatepaths():
1062 f = os.path.join(p, name)
1081 f = os.path.join(p, name)
1063 if os.path.exists(f):
1082 if os.path.exists(f):
1064 return f
1083 return f
1065 return None
1084 return None
1066
1085
1067 def stylemap(styles, paths=None):
1086 def stylemap(styles, paths=None):
1068 """Return path to mapfile for a given style.
1087 """Return path to mapfile for a given style.
1069
1088
1070 Searches mapfile in the following locations:
1089 Searches mapfile in the following locations:
1071 1. templatepath/style/map
1090 1. templatepath/style/map
1072 2. templatepath/map-style
1091 2. templatepath/map-style
1073 3. templatepath/map
1092 3. templatepath/map
1074 """
1093 """
1075
1094
1076 if paths is None:
1095 if paths is None:
1077 paths = templatepaths()
1096 paths = templatepaths()
1078 elif isinstance(paths, str):
1097 elif isinstance(paths, str):
1079 paths = [paths]
1098 paths = [paths]
1080
1099
1081 if isinstance(styles, str):
1100 if isinstance(styles, str):
1082 styles = [styles]
1101 styles = [styles]
1083
1102
1084 for style in styles:
1103 for style in styles:
1085 # only plain name is allowed to honor template paths
1104 # only plain name is allowed to honor template paths
1086 if (not style
1105 if (not style
1087 or style in (os.curdir, os.pardir)
1106 or style in (os.curdir, os.pardir)
1088 or os.sep in style
1107 or os.sep in style
1089 or os.altsep and os.altsep in style):
1108 or os.altsep and os.altsep in style):
1090 continue
1109 continue
1091 locations = [os.path.join(style, 'map'), 'map-' + style]
1110 locations = [os.path.join(style, 'map'), 'map-' + style]
1092 locations.append('map')
1111 locations.append('map')
1093
1112
1094 for path in paths:
1113 for path in paths:
1095 for location in locations:
1114 for location in locations:
1096 mapfile = os.path.join(path, location)
1115 mapfile = os.path.join(path, location)
1097 if os.path.isfile(mapfile):
1116 if os.path.isfile(mapfile):
1098 return style, mapfile
1117 return style, mapfile
1099
1118
1100 raise RuntimeError("No hgweb templates found in %r" % paths)
1119 raise RuntimeError("No hgweb templates found in %r" % paths)
1101
1120
1102 def loadfunction(ui, extname, registrarobj):
1121 def loadfunction(ui, extname, registrarobj):
1103 """Load template function from specified registrarobj
1122 """Load template function from specified registrarobj
1104 """
1123 """
1105 for name, func in registrarobj._table.iteritems():
1124 for name, func in registrarobj._table.iteritems():
1106 funcs[name] = func
1125 funcs[name] = func
1107
1126
1108 # tell hggettext to extract docstrings from these functions:
1127 # tell hggettext to extract docstrings from these functions:
1109 i18nfunctions = funcs.values()
1128 i18nfunctions = funcs.values()
@@ -1,3718 +1,3812
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3 $ echo a > a
3 $ echo a > a
4 $ hg add a
4 $ hg add a
5 $ echo line 1 > b
5 $ echo line 1 > b
6 $ echo line 2 >> b
6 $ echo line 2 >> b
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
8
8
9 $ hg add b
9 $ hg add b
10 $ echo other 1 > c
10 $ echo other 1 > c
11 $ echo other 2 >> c
11 $ echo other 2 >> c
12 $ echo >> c
12 $ echo >> c
13 $ echo other 3 >> c
13 $ echo other 3 >> c
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
15
15
16 $ hg add c
16 $ hg add c
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
18 $ echo c >> c
18 $ echo c >> c
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
20
20
21 $ echo foo > .hg/branch
21 $ echo foo > .hg/branch
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
23
23
24 $ hg co -q 3
24 $ hg co -q 3
25 $ echo other 4 >> d
25 $ echo other 4 >> d
26 $ hg add d
26 $ hg add d
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
28
28
29 $ hg merge -q foo
29 $ hg merge -q foo
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
31
31
32 Second branch starting at nullrev:
32 Second branch starting at nullrev:
33
33
34 $ hg update null
34 $ hg update null
35 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
35 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
36 $ echo second > second
36 $ echo second > second
37 $ hg add second
37 $ hg add second
38 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
38 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
39 created new head
39 created new head
40
40
41 $ echo third > third
41 $ echo third > third
42 $ hg add third
42 $ hg add third
43 $ hg mv second fourth
43 $ hg mv second fourth
44 $ hg commit -m third -d "2020-01-01 10:01"
44 $ hg commit -m third -d "2020-01-01 10:01"
45
45
46 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
46 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
47 fourth (second)
47 fourth (second)
48 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
48 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
49 second -> fourth
49 second -> fourth
50 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
50 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
51 8 t
51 8 t
52 7 f
52 7 f
53
53
54 Working-directory revision has special identifiers, though they are still
54 Working-directory revision has special identifiers, though they are still
55 experimental:
55 experimental:
56
56
57 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
57 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
58 2147483647:ffffffffffffffffffffffffffffffffffffffff
58 2147483647:ffffffffffffffffffffffffffffffffffffffff
59
59
60 Some keywords are invalid for working-directory revision, but they should
60 Some keywords are invalid for working-directory revision, but they should
61 never cause crash:
61 never cause crash:
62
62
63 $ hg log -r 'wdir()' -T '{manifest}\n'
63 $ hg log -r 'wdir()' -T '{manifest}\n'
64
64
65
65
66 Quoting for ui.logtemplate
66 Quoting for ui.logtemplate
67
67
68 $ hg tip --config "ui.logtemplate={rev}\n"
68 $ hg tip --config "ui.logtemplate={rev}\n"
69 8
69 8
70 $ hg tip --config "ui.logtemplate='{rev}\n'"
70 $ hg tip --config "ui.logtemplate='{rev}\n'"
71 8
71 8
72 $ hg tip --config 'ui.logtemplate="{rev}\n"'
72 $ hg tip --config 'ui.logtemplate="{rev}\n"'
73 8
73 8
74 $ hg tip --config 'ui.logtemplate=n{rev}\n'
74 $ hg tip --config 'ui.logtemplate=n{rev}\n'
75 n8
75 n8
76
76
77 Make sure user/global hgrc does not affect tests
77 Make sure user/global hgrc does not affect tests
78
78
79 $ echo '[ui]' > .hg/hgrc
79 $ echo '[ui]' > .hg/hgrc
80 $ echo 'logtemplate =' >> .hg/hgrc
80 $ echo 'logtemplate =' >> .hg/hgrc
81 $ echo 'style =' >> .hg/hgrc
81 $ echo 'style =' >> .hg/hgrc
82
82
83 Add some simple styles to settings
83 Add some simple styles to settings
84
84
85 $ echo '[templates]' >> .hg/hgrc
85 $ echo '[templates]' >> .hg/hgrc
86 $ printf 'simple = "{rev}\\n"\n' >> .hg/hgrc
86 $ printf 'simple = "{rev}\\n"\n' >> .hg/hgrc
87 $ printf 'simple2 = {rev}\\n\n' >> .hg/hgrc
87 $ printf 'simple2 = {rev}\\n\n' >> .hg/hgrc
88
88
89 $ hg log -l1 -Tsimple
89 $ hg log -l1 -Tsimple
90 8
90 8
91 $ hg log -l1 -Tsimple2
91 $ hg log -l1 -Tsimple2
92 8
92 8
93
93
94 Test templates and style maps in files:
94 Test templates and style maps in files:
95
95
96 $ echo "{rev}" > tmpl
96 $ echo "{rev}" > tmpl
97 $ hg log -l1 -T./tmpl
97 $ hg log -l1 -T./tmpl
98 8
98 8
99 $ hg log -l1 -Tblah/blah
99 $ hg log -l1 -Tblah/blah
100 blah/blah (no-eol)
100 blah/blah (no-eol)
101
101
102 $ printf 'changeset = "{rev}\\n"\n' > map-simple
102 $ printf 'changeset = "{rev}\\n"\n' > map-simple
103 $ hg log -l1 -T./map-simple
103 $ hg log -l1 -T./map-simple
104 8
104 8
105
105
106 Template should precede style option
106 Template should precede style option
107
107
108 $ hg log -l1 --style default -T '{rev}\n'
108 $ hg log -l1 --style default -T '{rev}\n'
109 8
109 8
110
110
111 Add a commit with empty description, to ensure that the templates
111 Add a commit with empty description, to ensure that the templates
112 below will omit the description line.
112 below will omit the description line.
113
113
114 $ echo c >> c
114 $ echo c >> c
115 $ hg add c
115 $ hg add c
116 $ hg commit -qm ' '
116 $ hg commit -qm ' '
117
117
118 Default style is like normal output. Phases style should be the same
118 Default style is like normal output. Phases style should be the same
119 as default style, except for extra phase lines.
119 as default style, except for extra phase lines.
120
120
121 $ hg log > log.out
121 $ hg log > log.out
122 $ hg log --style default > style.out
122 $ hg log --style default > style.out
123 $ cmp log.out style.out || diff -u log.out style.out
123 $ cmp log.out style.out || diff -u log.out style.out
124 $ hg log -T phases > phases.out
124 $ hg log -T phases > phases.out
125 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
125 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
126 +phase: draft
126 +phase: draft
127 +phase: draft
127 +phase: draft
128 +phase: draft
128 +phase: draft
129 +phase: draft
129 +phase: draft
130 +phase: draft
130 +phase: draft
131 +phase: draft
131 +phase: draft
132 +phase: draft
132 +phase: draft
133 +phase: draft
133 +phase: draft
134 +phase: draft
134 +phase: draft
135 +phase: draft
135 +phase: draft
136
136
137 $ hg log -v > log.out
137 $ hg log -v > log.out
138 $ hg log -v --style default > style.out
138 $ hg log -v --style default > style.out
139 $ cmp log.out style.out || diff -u log.out style.out
139 $ cmp log.out style.out || diff -u log.out style.out
140 $ hg log -v -T phases > phases.out
140 $ hg log -v -T phases > phases.out
141 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
141 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
142 +phase: draft
142 +phase: draft
143 +phase: draft
143 +phase: draft
144 +phase: draft
144 +phase: draft
145 +phase: draft
145 +phase: draft
146 +phase: draft
146 +phase: draft
147 +phase: draft
147 +phase: draft
148 +phase: draft
148 +phase: draft
149 +phase: draft
149 +phase: draft
150 +phase: draft
150 +phase: draft
151 +phase: draft
151 +phase: draft
152
152
153 $ hg log -q > log.out
153 $ hg log -q > log.out
154 $ hg log -q --style default > style.out
154 $ hg log -q --style default > style.out
155 $ cmp log.out style.out || diff -u log.out style.out
155 $ cmp log.out style.out || diff -u log.out style.out
156 $ hg log -q -T phases > phases.out
156 $ hg log -q -T phases > phases.out
157 $ cmp log.out phases.out || diff -u log.out phases.out
157 $ cmp log.out phases.out || diff -u log.out phases.out
158
158
159 $ hg log --debug > log.out
159 $ hg log --debug > log.out
160 $ hg log --debug --style default > style.out
160 $ hg log --debug --style default > style.out
161 $ cmp log.out style.out || diff -u log.out style.out
161 $ cmp log.out style.out || diff -u log.out style.out
162 $ hg log --debug -T phases > phases.out
162 $ hg log --debug -T phases > phases.out
163 $ cmp log.out phases.out || diff -u log.out phases.out
163 $ cmp log.out phases.out || diff -u log.out phases.out
164
164
165 Default style of working-directory revision should also be the same (but
165 Default style of working-directory revision should also be the same (but
166 date may change while running tests):
166 date may change while running tests):
167
167
168 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
168 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
169 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
169 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
170 $ cmp log.out style.out || diff -u log.out style.out
170 $ cmp log.out style.out || diff -u log.out style.out
171
171
172 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
172 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
173 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
173 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
174 $ cmp log.out style.out || diff -u log.out style.out
174 $ cmp log.out style.out || diff -u log.out style.out
175
175
176 $ hg log -r 'wdir()' -q > log.out
176 $ hg log -r 'wdir()' -q > log.out
177 $ hg log -r 'wdir()' -q --style default > style.out
177 $ hg log -r 'wdir()' -q --style default > style.out
178 $ cmp log.out style.out || diff -u log.out style.out
178 $ cmp log.out style.out || diff -u log.out style.out
179
179
180 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
180 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
181 $ hg log -r 'wdir()' --debug --style default \
181 $ hg log -r 'wdir()' --debug --style default \
182 > | sed 's|^date:.*|date:|' > style.out
182 > | sed 's|^date:.*|date:|' > style.out
183 $ cmp log.out style.out || diff -u log.out style.out
183 $ cmp log.out style.out || diff -u log.out style.out
184
184
185 Default style should also preserve color information (issue2866):
185 Default style should also preserve color information (issue2866):
186
186
187 $ cp $HGRCPATH $HGRCPATH-bak
187 $ cp $HGRCPATH $HGRCPATH-bak
188 $ cat <<EOF >> $HGRCPATH
188 $ cat <<EOF >> $HGRCPATH
189 > [extensions]
189 > [extensions]
190 > color=
190 > color=
191 > EOF
191 > EOF
192
192
193 $ hg --color=debug log > log.out
193 $ hg --color=debug log > log.out
194 $ hg --color=debug log --style default > style.out
194 $ hg --color=debug log --style default > style.out
195 $ cmp log.out style.out || diff -u log.out style.out
195 $ cmp log.out style.out || diff -u log.out style.out
196 $ hg --color=debug log -T phases > phases.out
196 $ hg --color=debug log -T phases > phases.out
197 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
197 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
198 +[log.phase|phase: draft]
198 +[log.phase|phase: draft]
199 +[log.phase|phase: draft]
199 +[log.phase|phase: draft]
200 +[log.phase|phase: draft]
200 +[log.phase|phase: draft]
201 +[log.phase|phase: draft]
201 +[log.phase|phase: draft]
202 +[log.phase|phase: draft]
202 +[log.phase|phase: draft]
203 +[log.phase|phase: draft]
203 +[log.phase|phase: draft]
204 +[log.phase|phase: draft]
204 +[log.phase|phase: draft]
205 +[log.phase|phase: draft]
205 +[log.phase|phase: draft]
206 +[log.phase|phase: draft]
206 +[log.phase|phase: draft]
207 +[log.phase|phase: draft]
207 +[log.phase|phase: draft]
208
208
209 $ hg --color=debug -v log > log.out
209 $ hg --color=debug -v log > log.out
210 $ hg --color=debug -v log --style default > style.out
210 $ hg --color=debug -v log --style default > style.out
211 $ cmp log.out style.out || diff -u log.out style.out
211 $ cmp log.out style.out || diff -u log.out style.out
212 $ hg --color=debug -v log -T phases > phases.out
212 $ hg --color=debug -v log -T phases > phases.out
213 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
213 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
214 +[log.phase|phase: draft]
214 +[log.phase|phase: draft]
215 +[log.phase|phase: draft]
215 +[log.phase|phase: draft]
216 +[log.phase|phase: draft]
216 +[log.phase|phase: draft]
217 +[log.phase|phase: draft]
217 +[log.phase|phase: draft]
218 +[log.phase|phase: draft]
218 +[log.phase|phase: draft]
219 +[log.phase|phase: draft]
219 +[log.phase|phase: draft]
220 +[log.phase|phase: draft]
220 +[log.phase|phase: draft]
221 +[log.phase|phase: draft]
221 +[log.phase|phase: draft]
222 +[log.phase|phase: draft]
222 +[log.phase|phase: draft]
223 +[log.phase|phase: draft]
223 +[log.phase|phase: draft]
224
224
225 $ hg --color=debug -q log > log.out
225 $ hg --color=debug -q log > log.out
226 $ hg --color=debug -q log --style default > style.out
226 $ hg --color=debug -q log --style default > style.out
227 $ cmp log.out style.out || diff -u log.out style.out
227 $ cmp log.out style.out || diff -u log.out style.out
228 $ hg --color=debug -q log -T phases > phases.out
228 $ hg --color=debug -q log -T phases > phases.out
229 $ cmp log.out phases.out || diff -u log.out phases.out
229 $ cmp log.out phases.out || diff -u log.out phases.out
230
230
231 $ hg --color=debug --debug log > log.out
231 $ hg --color=debug --debug log > log.out
232 $ hg --color=debug --debug log --style default > style.out
232 $ hg --color=debug --debug log --style default > style.out
233 $ cmp log.out style.out || diff -u log.out style.out
233 $ cmp log.out style.out || diff -u log.out style.out
234 $ hg --color=debug --debug log -T phases > phases.out
234 $ hg --color=debug --debug log -T phases > phases.out
235 $ cmp log.out phases.out || diff -u log.out phases.out
235 $ cmp log.out phases.out || diff -u log.out phases.out
236
236
237 $ mv $HGRCPATH-bak $HGRCPATH
237 $ mv $HGRCPATH-bak $HGRCPATH
238
238
239 Remove commit with empty commit message, so as to not pollute further
239 Remove commit with empty commit message, so as to not pollute further
240 tests.
240 tests.
241
241
242 $ hg --config extensions.strip= strip -q .
242 $ hg --config extensions.strip= strip -q .
243
243
244 Revision with no copies (used to print a traceback):
244 Revision with no copies (used to print a traceback):
245
245
246 $ hg tip -v --template '\n'
246 $ hg tip -v --template '\n'
247
247
248
248
249 Compact style works:
249 Compact style works:
250
250
251 $ hg log -Tcompact
251 $ hg log -Tcompact
252 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
252 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
253 third
253 third
254
254
255 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
255 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
256 second
256 second
257
257
258 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
258 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
259 merge
259 merge
260
260
261 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
261 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
262 new head
262 new head
263
263
264 4 bbe44766e73d 1970-01-17 04:53 +0000 person
264 4 bbe44766e73d 1970-01-17 04:53 +0000 person
265 new branch
265 new branch
266
266
267 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
267 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
268 no user, no domain
268 no user, no domain
269
269
270 2 97054abb4ab8 1970-01-14 21:20 +0000 other
270 2 97054abb4ab8 1970-01-14 21:20 +0000 other
271 no person
271 no person
272
272
273 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
273 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
274 other 1
274 other 1
275
275
276 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
276 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
277 line 1
277 line 1
278
278
279
279
280 $ hg log -v --style compact
280 $ hg log -v --style compact
281 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
281 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
282 third
282 third
283
283
284 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
284 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
285 second
285 second
286
286
287 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
287 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
288 merge
288 merge
289
289
290 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
290 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
291 new head
291 new head
292
292
293 4 bbe44766e73d 1970-01-17 04:53 +0000 person
293 4 bbe44766e73d 1970-01-17 04:53 +0000 person
294 new branch
294 new branch
295
295
296 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
296 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
297 no user, no domain
297 no user, no domain
298
298
299 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
299 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
300 no person
300 no person
301
301
302 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
302 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
303 other 1
303 other 1
304 other 2
304 other 2
305
305
306 other 3
306 other 3
307
307
308 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
308 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
309 line 1
309 line 1
310 line 2
310 line 2
311
311
312
312
313 $ hg log --debug --style compact
313 $ hg log --debug --style compact
314 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
314 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
315 third
315 third
316
316
317 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
317 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
318 second
318 second
319
319
320 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
320 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
321 merge
321 merge
322
322
323 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
323 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
324 new head
324 new head
325
325
326 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
326 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
327 new branch
327 new branch
328
328
329 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
329 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
330 no user, no domain
330 no user, no domain
331
331
332 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
332 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
333 no person
333 no person
334
334
335 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
335 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
336 other 1
336 other 1
337 other 2
337 other 2
338
338
339 other 3
339 other 3
340
340
341 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
341 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
342 line 1
342 line 1
343 line 2
343 line 2
344
344
345
345
346 Test xml styles:
346 Test xml styles:
347
347
348 $ hg log --style xml -r 'not all()'
348 $ hg log --style xml -r 'not all()'
349 <?xml version="1.0"?>
349 <?xml version="1.0"?>
350 <log>
350 <log>
351 </log>
351 </log>
352
352
353 $ hg log --style xml
353 $ hg log --style xml
354 <?xml version="1.0"?>
354 <?xml version="1.0"?>
355 <log>
355 <log>
356 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
356 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
357 <tag>tip</tag>
357 <tag>tip</tag>
358 <author email="test">test</author>
358 <author email="test">test</author>
359 <date>2020-01-01T10:01:00+00:00</date>
359 <date>2020-01-01T10:01:00+00:00</date>
360 <msg xml:space="preserve">third</msg>
360 <msg xml:space="preserve">third</msg>
361 </logentry>
361 </logentry>
362 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
362 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
363 <parent revision="-1" node="0000000000000000000000000000000000000000" />
363 <parent revision="-1" node="0000000000000000000000000000000000000000" />
364 <author email="user@hostname">User Name</author>
364 <author email="user@hostname">User Name</author>
365 <date>1970-01-12T13:46:40+00:00</date>
365 <date>1970-01-12T13:46:40+00:00</date>
366 <msg xml:space="preserve">second</msg>
366 <msg xml:space="preserve">second</msg>
367 </logentry>
367 </logentry>
368 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
368 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
369 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
369 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
370 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
370 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
371 <author email="person">person</author>
371 <author email="person">person</author>
372 <date>1970-01-18T08:40:01+00:00</date>
372 <date>1970-01-18T08:40:01+00:00</date>
373 <msg xml:space="preserve">merge</msg>
373 <msg xml:space="preserve">merge</msg>
374 </logentry>
374 </logentry>
375 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
375 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
376 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
376 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
377 <author email="person">person</author>
377 <author email="person">person</author>
378 <date>1970-01-18T08:40:00+00:00</date>
378 <date>1970-01-18T08:40:00+00:00</date>
379 <msg xml:space="preserve">new head</msg>
379 <msg xml:space="preserve">new head</msg>
380 </logentry>
380 </logentry>
381 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
381 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
382 <branch>foo</branch>
382 <branch>foo</branch>
383 <author email="person">person</author>
383 <author email="person">person</author>
384 <date>1970-01-17T04:53:20+00:00</date>
384 <date>1970-01-17T04:53:20+00:00</date>
385 <msg xml:space="preserve">new branch</msg>
385 <msg xml:space="preserve">new branch</msg>
386 </logentry>
386 </logentry>
387 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
387 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
388 <author email="person">person</author>
388 <author email="person">person</author>
389 <date>1970-01-16T01:06:40+00:00</date>
389 <date>1970-01-16T01:06:40+00:00</date>
390 <msg xml:space="preserve">no user, no domain</msg>
390 <msg xml:space="preserve">no user, no domain</msg>
391 </logentry>
391 </logentry>
392 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
392 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
393 <author email="other@place">other</author>
393 <author email="other@place">other</author>
394 <date>1970-01-14T21:20:00+00:00</date>
394 <date>1970-01-14T21:20:00+00:00</date>
395 <msg xml:space="preserve">no person</msg>
395 <msg xml:space="preserve">no person</msg>
396 </logentry>
396 </logentry>
397 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
397 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
398 <author email="other@place">A. N. Other</author>
398 <author email="other@place">A. N. Other</author>
399 <date>1970-01-13T17:33:20+00:00</date>
399 <date>1970-01-13T17:33:20+00:00</date>
400 <msg xml:space="preserve">other 1
400 <msg xml:space="preserve">other 1
401 other 2
401 other 2
402
402
403 other 3</msg>
403 other 3</msg>
404 </logentry>
404 </logentry>
405 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
405 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
406 <author email="user@hostname">User Name</author>
406 <author email="user@hostname">User Name</author>
407 <date>1970-01-12T13:46:40+00:00</date>
407 <date>1970-01-12T13:46:40+00:00</date>
408 <msg xml:space="preserve">line 1
408 <msg xml:space="preserve">line 1
409 line 2</msg>
409 line 2</msg>
410 </logentry>
410 </logentry>
411 </log>
411 </log>
412
412
413 $ hg log -v --style xml
413 $ hg log -v --style xml
414 <?xml version="1.0"?>
414 <?xml version="1.0"?>
415 <log>
415 <log>
416 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
416 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
417 <tag>tip</tag>
417 <tag>tip</tag>
418 <author email="test">test</author>
418 <author email="test">test</author>
419 <date>2020-01-01T10:01:00+00:00</date>
419 <date>2020-01-01T10:01:00+00:00</date>
420 <msg xml:space="preserve">third</msg>
420 <msg xml:space="preserve">third</msg>
421 <paths>
421 <paths>
422 <path action="A">fourth</path>
422 <path action="A">fourth</path>
423 <path action="A">third</path>
423 <path action="A">third</path>
424 <path action="R">second</path>
424 <path action="R">second</path>
425 </paths>
425 </paths>
426 <copies>
426 <copies>
427 <copy source="second">fourth</copy>
427 <copy source="second">fourth</copy>
428 </copies>
428 </copies>
429 </logentry>
429 </logentry>
430 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
430 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
431 <parent revision="-1" node="0000000000000000000000000000000000000000" />
431 <parent revision="-1" node="0000000000000000000000000000000000000000" />
432 <author email="user@hostname">User Name</author>
432 <author email="user@hostname">User Name</author>
433 <date>1970-01-12T13:46:40+00:00</date>
433 <date>1970-01-12T13:46:40+00:00</date>
434 <msg xml:space="preserve">second</msg>
434 <msg xml:space="preserve">second</msg>
435 <paths>
435 <paths>
436 <path action="A">second</path>
436 <path action="A">second</path>
437 </paths>
437 </paths>
438 </logentry>
438 </logentry>
439 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
439 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
440 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
440 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
441 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
441 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
442 <author email="person">person</author>
442 <author email="person">person</author>
443 <date>1970-01-18T08:40:01+00:00</date>
443 <date>1970-01-18T08:40:01+00:00</date>
444 <msg xml:space="preserve">merge</msg>
444 <msg xml:space="preserve">merge</msg>
445 <paths>
445 <paths>
446 </paths>
446 </paths>
447 </logentry>
447 </logentry>
448 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
448 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
449 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
449 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
450 <author email="person">person</author>
450 <author email="person">person</author>
451 <date>1970-01-18T08:40:00+00:00</date>
451 <date>1970-01-18T08:40:00+00:00</date>
452 <msg xml:space="preserve">new head</msg>
452 <msg xml:space="preserve">new head</msg>
453 <paths>
453 <paths>
454 <path action="A">d</path>
454 <path action="A">d</path>
455 </paths>
455 </paths>
456 </logentry>
456 </logentry>
457 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
457 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
458 <branch>foo</branch>
458 <branch>foo</branch>
459 <author email="person">person</author>
459 <author email="person">person</author>
460 <date>1970-01-17T04:53:20+00:00</date>
460 <date>1970-01-17T04:53:20+00:00</date>
461 <msg xml:space="preserve">new branch</msg>
461 <msg xml:space="preserve">new branch</msg>
462 <paths>
462 <paths>
463 </paths>
463 </paths>
464 </logentry>
464 </logentry>
465 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
465 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
466 <author email="person">person</author>
466 <author email="person">person</author>
467 <date>1970-01-16T01:06:40+00:00</date>
467 <date>1970-01-16T01:06:40+00:00</date>
468 <msg xml:space="preserve">no user, no domain</msg>
468 <msg xml:space="preserve">no user, no domain</msg>
469 <paths>
469 <paths>
470 <path action="M">c</path>
470 <path action="M">c</path>
471 </paths>
471 </paths>
472 </logentry>
472 </logentry>
473 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
473 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
474 <author email="other@place">other</author>
474 <author email="other@place">other</author>
475 <date>1970-01-14T21:20:00+00:00</date>
475 <date>1970-01-14T21:20:00+00:00</date>
476 <msg xml:space="preserve">no person</msg>
476 <msg xml:space="preserve">no person</msg>
477 <paths>
477 <paths>
478 <path action="A">c</path>
478 <path action="A">c</path>
479 </paths>
479 </paths>
480 </logentry>
480 </logentry>
481 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
481 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
482 <author email="other@place">A. N. Other</author>
482 <author email="other@place">A. N. Other</author>
483 <date>1970-01-13T17:33:20+00:00</date>
483 <date>1970-01-13T17:33:20+00:00</date>
484 <msg xml:space="preserve">other 1
484 <msg xml:space="preserve">other 1
485 other 2
485 other 2
486
486
487 other 3</msg>
487 other 3</msg>
488 <paths>
488 <paths>
489 <path action="A">b</path>
489 <path action="A">b</path>
490 </paths>
490 </paths>
491 </logentry>
491 </logentry>
492 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
492 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
493 <author email="user@hostname">User Name</author>
493 <author email="user@hostname">User Name</author>
494 <date>1970-01-12T13:46:40+00:00</date>
494 <date>1970-01-12T13:46:40+00:00</date>
495 <msg xml:space="preserve">line 1
495 <msg xml:space="preserve">line 1
496 line 2</msg>
496 line 2</msg>
497 <paths>
497 <paths>
498 <path action="A">a</path>
498 <path action="A">a</path>
499 </paths>
499 </paths>
500 </logentry>
500 </logentry>
501 </log>
501 </log>
502
502
503 $ hg log --debug --style xml
503 $ hg log --debug --style xml
504 <?xml version="1.0"?>
504 <?xml version="1.0"?>
505 <log>
505 <log>
506 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
506 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
507 <tag>tip</tag>
507 <tag>tip</tag>
508 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
508 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
509 <parent revision="-1" node="0000000000000000000000000000000000000000" />
509 <parent revision="-1" node="0000000000000000000000000000000000000000" />
510 <author email="test">test</author>
510 <author email="test">test</author>
511 <date>2020-01-01T10:01:00+00:00</date>
511 <date>2020-01-01T10:01:00+00:00</date>
512 <msg xml:space="preserve">third</msg>
512 <msg xml:space="preserve">third</msg>
513 <paths>
513 <paths>
514 <path action="A">fourth</path>
514 <path action="A">fourth</path>
515 <path action="A">third</path>
515 <path action="A">third</path>
516 <path action="R">second</path>
516 <path action="R">second</path>
517 </paths>
517 </paths>
518 <copies>
518 <copies>
519 <copy source="second">fourth</copy>
519 <copy source="second">fourth</copy>
520 </copies>
520 </copies>
521 <extra key="branch">default</extra>
521 <extra key="branch">default</extra>
522 </logentry>
522 </logentry>
523 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
523 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
524 <parent revision="-1" node="0000000000000000000000000000000000000000" />
524 <parent revision="-1" node="0000000000000000000000000000000000000000" />
525 <parent revision="-1" node="0000000000000000000000000000000000000000" />
525 <parent revision="-1" node="0000000000000000000000000000000000000000" />
526 <author email="user@hostname">User Name</author>
526 <author email="user@hostname">User Name</author>
527 <date>1970-01-12T13:46:40+00:00</date>
527 <date>1970-01-12T13:46:40+00:00</date>
528 <msg xml:space="preserve">second</msg>
528 <msg xml:space="preserve">second</msg>
529 <paths>
529 <paths>
530 <path action="A">second</path>
530 <path action="A">second</path>
531 </paths>
531 </paths>
532 <extra key="branch">default</extra>
532 <extra key="branch">default</extra>
533 </logentry>
533 </logentry>
534 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
534 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
535 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
535 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
536 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
536 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
537 <author email="person">person</author>
537 <author email="person">person</author>
538 <date>1970-01-18T08:40:01+00:00</date>
538 <date>1970-01-18T08:40:01+00:00</date>
539 <msg xml:space="preserve">merge</msg>
539 <msg xml:space="preserve">merge</msg>
540 <paths>
540 <paths>
541 </paths>
541 </paths>
542 <extra key="branch">default</extra>
542 <extra key="branch">default</extra>
543 </logentry>
543 </logentry>
544 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
544 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
545 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
545 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
546 <parent revision="-1" node="0000000000000000000000000000000000000000" />
546 <parent revision="-1" node="0000000000000000000000000000000000000000" />
547 <author email="person">person</author>
547 <author email="person">person</author>
548 <date>1970-01-18T08:40:00+00:00</date>
548 <date>1970-01-18T08:40:00+00:00</date>
549 <msg xml:space="preserve">new head</msg>
549 <msg xml:space="preserve">new head</msg>
550 <paths>
550 <paths>
551 <path action="A">d</path>
551 <path action="A">d</path>
552 </paths>
552 </paths>
553 <extra key="branch">default</extra>
553 <extra key="branch">default</extra>
554 </logentry>
554 </logentry>
555 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
555 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
556 <branch>foo</branch>
556 <branch>foo</branch>
557 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
557 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
558 <parent revision="-1" node="0000000000000000000000000000000000000000" />
558 <parent revision="-1" node="0000000000000000000000000000000000000000" />
559 <author email="person">person</author>
559 <author email="person">person</author>
560 <date>1970-01-17T04:53:20+00:00</date>
560 <date>1970-01-17T04:53:20+00:00</date>
561 <msg xml:space="preserve">new branch</msg>
561 <msg xml:space="preserve">new branch</msg>
562 <paths>
562 <paths>
563 </paths>
563 </paths>
564 <extra key="branch">foo</extra>
564 <extra key="branch">foo</extra>
565 </logentry>
565 </logentry>
566 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
566 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
567 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
567 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
568 <parent revision="-1" node="0000000000000000000000000000000000000000" />
568 <parent revision="-1" node="0000000000000000000000000000000000000000" />
569 <author email="person">person</author>
569 <author email="person">person</author>
570 <date>1970-01-16T01:06:40+00:00</date>
570 <date>1970-01-16T01:06:40+00:00</date>
571 <msg xml:space="preserve">no user, no domain</msg>
571 <msg xml:space="preserve">no user, no domain</msg>
572 <paths>
572 <paths>
573 <path action="M">c</path>
573 <path action="M">c</path>
574 </paths>
574 </paths>
575 <extra key="branch">default</extra>
575 <extra key="branch">default</extra>
576 </logentry>
576 </logentry>
577 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
577 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
578 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
578 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
579 <parent revision="-1" node="0000000000000000000000000000000000000000" />
579 <parent revision="-1" node="0000000000000000000000000000000000000000" />
580 <author email="other@place">other</author>
580 <author email="other@place">other</author>
581 <date>1970-01-14T21:20:00+00:00</date>
581 <date>1970-01-14T21:20:00+00:00</date>
582 <msg xml:space="preserve">no person</msg>
582 <msg xml:space="preserve">no person</msg>
583 <paths>
583 <paths>
584 <path action="A">c</path>
584 <path action="A">c</path>
585 </paths>
585 </paths>
586 <extra key="branch">default</extra>
586 <extra key="branch">default</extra>
587 </logentry>
587 </logentry>
588 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
588 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
589 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
589 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
590 <parent revision="-1" node="0000000000000000000000000000000000000000" />
590 <parent revision="-1" node="0000000000000000000000000000000000000000" />
591 <author email="other@place">A. N. Other</author>
591 <author email="other@place">A. N. Other</author>
592 <date>1970-01-13T17:33:20+00:00</date>
592 <date>1970-01-13T17:33:20+00:00</date>
593 <msg xml:space="preserve">other 1
593 <msg xml:space="preserve">other 1
594 other 2
594 other 2
595
595
596 other 3</msg>
596 other 3</msg>
597 <paths>
597 <paths>
598 <path action="A">b</path>
598 <path action="A">b</path>
599 </paths>
599 </paths>
600 <extra key="branch">default</extra>
600 <extra key="branch">default</extra>
601 </logentry>
601 </logentry>
602 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
602 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
603 <parent revision="-1" node="0000000000000000000000000000000000000000" />
603 <parent revision="-1" node="0000000000000000000000000000000000000000" />
604 <parent revision="-1" node="0000000000000000000000000000000000000000" />
604 <parent revision="-1" node="0000000000000000000000000000000000000000" />
605 <author email="user@hostname">User Name</author>
605 <author email="user@hostname">User Name</author>
606 <date>1970-01-12T13:46:40+00:00</date>
606 <date>1970-01-12T13:46:40+00:00</date>
607 <msg xml:space="preserve">line 1
607 <msg xml:space="preserve">line 1
608 line 2</msg>
608 line 2</msg>
609 <paths>
609 <paths>
610 <path action="A">a</path>
610 <path action="A">a</path>
611 </paths>
611 </paths>
612 <extra key="branch">default</extra>
612 <extra key="branch">default</extra>
613 </logentry>
613 </logentry>
614 </log>
614 </log>
615
615
616
616
617 Test JSON style:
617 Test JSON style:
618
618
619 $ hg log -k nosuch -Tjson
619 $ hg log -k nosuch -Tjson
620 []
620 []
621
621
622 $ hg log -qr . -Tjson
622 $ hg log -qr . -Tjson
623 [
623 [
624 {
624 {
625 "rev": 8,
625 "rev": 8,
626 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
626 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
627 }
627 }
628 ]
628 ]
629
629
630 $ hg log -vpr . -Tjson --stat
630 $ hg log -vpr . -Tjson --stat
631 [
631 [
632 {
632 {
633 "rev": 8,
633 "rev": 8,
634 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
634 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
635 "branch": "default",
635 "branch": "default",
636 "phase": "draft",
636 "phase": "draft",
637 "user": "test",
637 "user": "test",
638 "date": [1577872860, 0],
638 "date": [1577872860, 0],
639 "desc": "third",
639 "desc": "third",
640 "bookmarks": [],
640 "bookmarks": [],
641 "tags": ["tip"],
641 "tags": ["tip"],
642 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
642 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
643 "files": ["fourth", "second", "third"],
643 "files": ["fourth", "second", "third"],
644 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
644 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
645 "diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n"
645 "diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n"
646 }
646 }
647 ]
647 ]
648
648
649 honor --git but not format-breaking diffopts
649 honor --git but not format-breaking diffopts
650 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
650 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
651 [
651 [
652 {
652 {
653 "rev": 8,
653 "rev": 8,
654 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
654 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
655 "branch": "default",
655 "branch": "default",
656 "phase": "draft",
656 "phase": "draft",
657 "user": "test",
657 "user": "test",
658 "date": [1577872860, 0],
658 "date": [1577872860, 0],
659 "desc": "third",
659 "desc": "third",
660 "bookmarks": [],
660 "bookmarks": [],
661 "tags": ["tip"],
661 "tags": ["tip"],
662 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
662 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
663 "files": ["fourth", "second", "third"],
663 "files": ["fourth", "second", "third"],
664 "diff": "diff --git a/second b/fourth\nrename from second\nrename to fourth\ndiff --git a/third b/third\nnew file mode 100644\n--- /dev/null\n+++ b/third\n@@ -0,0 +1,1 @@\n+third\n"
664 "diff": "diff --git a/second b/fourth\nrename from second\nrename to fourth\ndiff --git a/third b/third\nnew file mode 100644\n--- /dev/null\n+++ b/third\n@@ -0,0 +1,1 @@\n+third\n"
665 }
665 }
666 ]
666 ]
667
667
668 $ hg log -T json
668 $ hg log -T json
669 [
669 [
670 {
670 {
671 "rev": 8,
671 "rev": 8,
672 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
672 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
673 "branch": "default",
673 "branch": "default",
674 "phase": "draft",
674 "phase": "draft",
675 "user": "test",
675 "user": "test",
676 "date": [1577872860, 0],
676 "date": [1577872860, 0],
677 "desc": "third",
677 "desc": "third",
678 "bookmarks": [],
678 "bookmarks": [],
679 "tags": ["tip"],
679 "tags": ["tip"],
680 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
680 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
681 },
681 },
682 {
682 {
683 "rev": 7,
683 "rev": 7,
684 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
684 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
685 "branch": "default",
685 "branch": "default",
686 "phase": "draft",
686 "phase": "draft",
687 "user": "User Name <user@hostname>",
687 "user": "User Name <user@hostname>",
688 "date": [1000000, 0],
688 "date": [1000000, 0],
689 "desc": "second",
689 "desc": "second",
690 "bookmarks": [],
690 "bookmarks": [],
691 "tags": [],
691 "tags": [],
692 "parents": ["0000000000000000000000000000000000000000"]
692 "parents": ["0000000000000000000000000000000000000000"]
693 },
693 },
694 {
694 {
695 "rev": 6,
695 "rev": 6,
696 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
696 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
697 "branch": "default",
697 "branch": "default",
698 "phase": "draft",
698 "phase": "draft",
699 "user": "person",
699 "user": "person",
700 "date": [1500001, 0],
700 "date": [1500001, 0],
701 "desc": "merge",
701 "desc": "merge",
702 "bookmarks": [],
702 "bookmarks": [],
703 "tags": [],
703 "tags": [],
704 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
704 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
705 },
705 },
706 {
706 {
707 "rev": 5,
707 "rev": 5,
708 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
708 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
709 "branch": "default",
709 "branch": "default",
710 "phase": "draft",
710 "phase": "draft",
711 "user": "person",
711 "user": "person",
712 "date": [1500000, 0],
712 "date": [1500000, 0],
713 "desc": "new head",
713 "desc": "new head",
714 "bookmarks": [],
714 "bookmarks": [],
715 "tags": [],
715 "tags": [],
716 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
716 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
717 },
717 },
718 {
718 {
719 "rev": 4,
719 "rev": 4,
720 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
720 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
721 "branch": "foo",
721 "branch": "foo",
722 "phase": "draft",
722 "phase": "draft",
723 "user": "person",
723 "user": "person",
724 "date": [1400000, 0],
724 "date": [1400000, 0],
725 "desc": "new branch",
725 "desc": "new branch",
726 "bookmarks": [],
726 "bookmarks": [],
727 "tags": [],
727 "tags": [],
728 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
728 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
729 },
729 },
730 {
730 {
731 "rev": 3,
731 "rev": 3,
732 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
732 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
733 "branch": "default",
733 "branch": "default",
734 "phase": "draft",
734 "phase": "draft",
735 "user": "person",
735 "user": "person",
736 "date": [1300000, 0],
736 "date": [1300000, 0],
737 "desc": "no user, no domain",
737 "desc": "no user, no domain",
738 "bookmarks": [],
738 "bookmarks": [],
739 "tags": [],
739 "tags": [],
740 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
740 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
741 },
741 },
742 {
742 {
743 "rev": 2,
743 "rev": 2,
744 "node": "97054abb4ab824450e9164180baf491ae0078465",
744 "node": "97054abb4ab824450e9164180baf491ae0078465",
745 "branch": "default",
745 "branch": "default",
746 "phase": "draft",
746 "phase": "draft",
747 "user": "other@place",
747 "user": "other@place",
748 "date": [1200000, 0],
748 "date": [1200000, 0],
749 "desc": "no person",
749 "desc": "no person",
750 "bookmarks": [],
750 "bookmarks": [],
751 "tags": [],
751 "tags": [],
752 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
752 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
753 },
753 },
754 {
754 {
755 "rev": 1,
755 "rev": 1,
756 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
756 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
757 "branch": "default",
757 "branch": "default",
758 "phase": "draft",
758 "phase": "draft",
759 "user": "A. N. Other <other@place>",
759 "user": "A. N. Other <other@place>",
760 "date": [1100000, 0],
760 "date": [1100000, 0],
761 "desc": "other 1\nother 2\n\nother 3",
761 "desc": "other 1\nother 2\n\nother 3",
762 "bookmarks": [],
762 "bookmarks": [],
763 "tags": [],
763 "tags": [],
764 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
764 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
765 },
765 },
766 {
766 {
767 "rev": 0,
767 "rev": 0,
768 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
768 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
769 "branch": "default",
769 "branch": "default",
770 "phase": "draft",
770 "phase": "draft",
771 "user": "User Name <user@hostname>",
771 "user": "User Name <user@hostname>",
772 "date": [1000000, 0],
772 "date": [1000000, 0],
773 "desc": "line 1\nline 2",
773 "desc": "line 1\nline 2",
774 "bookmarks": [],
774 "bookmarks": [],
775 "tags": [],
775 "tags": [],
776 "parents": ["0000000000000000000000000000000000000000"]
776 "parents": ["0000000000000000000000000000000000000000"]
777 }
777 }
778 ]
778 ]
779
779
780 $ hg heads -v -Tjson
780 $ hg heads -v -Tjson
781 [
781 [
782 {
782 {
783 "rev": 8,
783 "rev": 8,
784 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
784 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
785 "branch": "default",
785 "branch": "default",
786 "phase": "draft",
786 "phase": "draft",
787 "user": "test",
787 "user": "test",
788 "date": [1577872860, 0],
788 "date": [1577872860, 0],
789 "desc": "third",
789 "desc": "third",
790 "bookmarks": [],
790 "bookmarks": [],
791 "tags": ["tip"],
791 "tags": ["tip"],
792 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
792 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
793 "files": ["fourth", "second", "third"]
793 "files": ["fourth", "second", "third"]
794 },
794 },
795 {
795 {
796 "rev": 6,
796 "rev": 6,
797 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
797 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
798 "branch": "default",
798 "branch": "default",
799 "phase": "draft",
799 "phase": "draft",
800 "user": "person",
800 "user": "person",
801 "date": [1500001, 0],
801 "date": [1500001, 0],
802 "desc": "merge",
802 "desc": "merge",
803 "bookmarks": [],
803 "bookmarks": [],
804 "tags": [],
804 "tags": [],
805 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
805 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
806 "files": []
806 "files": []
807 },
807 },
808 {
808 {
809 "rev": 4,
809 "rev": 4,
810 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
810 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
811 "branch": "foo",
811 "branch": "foo",
812 "phase": "draft",
812 "phase": "draft",
813 "user": "person",
813 "user": "person",
814 "date": [1400000, 0],
814 "date": [1400000, 0],
815 "desc": "new branch",
815 "desc": "new branch",
816 "bookmarks": [],
816 "bookmarks": [],
817 "tags": [],
817 "tags": [],
818 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
818 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
819 "files": []
819 "files": []
820 }
820 }
821 ]
821 ]
822
822
823 $ hg log --debug -Tjson
823 $ hg log --debug -Tjson
824 [
824 [
825 {
825 {
826 "rev": 8,
826 "rev": 8,
827 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
827 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
828 "branch": "default",
828 "branch": "default",
829 "phase": "draft",
829 "phase": "draft",
830 "user": "test",
830 "user": "test",
831 "date": [1577872860, 0],
831 "date": [1577872860, 0],
832 "desc": "third",
832 "desc": "third",
833 "bookmarks": [],
833 "bookmarks": [],
834 "tags": ["tip"],
834 "tags": ["tip"],
835 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
835 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
836 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
836 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
837 "extra": {"branch": "default"},
837 "extra": {"branch": "default"},
838 "modified": [],
838 "modified": [],
839 "added": ["fourth", "third"],
839 "added": ["fourth", "third"],
840 "removed": ["second"]
840 "removed": ["second"]
841 },
841 },
842 {
842 {
843 "rev": 7,
843 "rev": 7,
844 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
844 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
845 "branch": "default",
845 "branch": "default",
846 "phase": "draft",
846 "phase": "draft",
847 "user": "User Name <user@hostname>",
847 "user": "User Name <user@hostname>",
848 "date": [1000000, 0],
848 "date": [1000000, 0],
849 "desc": "second",
849 "desc": "second",
850 "bookmarks": [],
850 "bookmarks": [],
851 "tags": [],
851 "tags": [],
852 "parents": ["0000000000000000000000000000000000000000"],
852 "parents": ["0000000000000000000000000000000000000000"],
853 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
853 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
854 "extra": {"branch": "default"},
854 "extra": {"branch": "default"},
855 "modified": [],
855 "modified": [],
856 "added": ["second"],
856 "added": ["second"],
857 "removed": []
857 "removed": []
858 },
858 },
859 {
859 {
860 "rev": 6,
860 "rev": 6,
861 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
861 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
862 "branch": "default",
862 "branch": "default",
863 "phase": "draft",
863 "phase": "draft",
864 "user": "person",
864 "user": "person",
865 "date": [1500001, 0],
865 "date": [1500001, 0],
866 "desc": "merge",
866 "desc": "merge",
867 "bookmarks": [],
867 "bookmarks": [],
868 "tags": [],
868 "tags": [],
869 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
869 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
870 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
870 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
871 "extra": {"branch": "default"},
871 "extra": {"branch": "default"},
872 "modified": [],
872 "modified": [],
873 "added": [],
873 "added": [],
874 "removed": []
874 "removed": []
875 },
875 },
876 {
876 {
877 "rev": 5,
877 "rev": 5,
878 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
878 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
879 "branch": "default",
879 "branch": "default",
880 "phase": "draft",
880 "phase": "draft",
881 "user": "person",
881 "user": "person",
882 "date": [1500000, 0],
882 "date": [1500000, 0],
883 "desc": "new head",
883 "desc": "new head",
884 "bookmarks": [],
884 "bookmarks": [],
885 "tags": [],
885 "tags": [],
886 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
886 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
887 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
887 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
888 "extra": {"branch": "default"},
888 "extra": {"branch": "default"},
889 "modified": [],
889 "modified": [],
890 "added": ["d"],
890 "added": ["d"],
891 "removed": []
891 "removed": []
892 },
892 },
893 {
893 {
894 "rev": 4,
894 "rev": 4,
895 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
895 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
896 "branch": "foo",
896 "branch": "foo",
897 "phase": "draft",
897 "phase": "draft",
898 "user": "person",
898 "user": "person",
899 "date": [1400000, 0],
899 "date": [1400000, 0],
900 "desc": "new branch",
900 "desc": "new branch",
901 "bookmarks": [],
901 "bookmarks": [],
902 "tags": [],
902 "tags": [],
903 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
903 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
904 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
904 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
905 "extra": {"branch": "foo"},
905 "extra": {"branch": "foo"},
906 "modified": [],
906 "modified": [],
907 "added": [],
907 "added": [],
908 "removed": []
908 "removed": []
909 },
909 },
910 {
910 {
911 "rev": 3,
911 "rev": 3,
912 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
912 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
913 "branch": "default",
913 "branch": "default",
914 "phase": "draft",
914 "phase": "draft",
915 "user": "person",
915 "user": "person",
916 "date": [1300000, 0],
916 "date": [1300000, 0],
917 "desc": "no user, no domain",
917 "desc": "no user, no domain",
918 "bookmarks": [],
918 "bookmarks": [],
919 "tags": [],
919 "tags": [],
920 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
920 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
921 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
921 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
922 "extra": {"branch": "default"},
922 "extra": {"branch": "default"},
923 "modified": ["c"],
923 "modified": ["c"],
924 "added": [],
924 "added": [],
925 "removed": []
925 "removed": []
926 },
926 },
927 {
927 {
928 "rev": 2,
928 "rev": 2,
929 "node": "97054abb4ab824450e9164180baf491ae0078465",
929 "node": "97054abb4ab824450e9164180baf491ae0078465",
930 "branch": "default",
930 "branch": "default",
931 "phase": "draft",
931 "phase": "draft",
932 "user": "other@place",
932 "user": "other@place",
933 "date": [1200000, 0],
933 "date": [1200000, 0],
934 "desc": "no person",
934 "desc": "no person",
935 "bookmarks": [],
935 "bookmarks": [],
936 "tags": [],
936 "tags": [],
937 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
937 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
938 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
938 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
939 "extra": {"branch": "default"},
939 "extra": {"branch": "default"},
940 "modified": [],
940 "modified": [],
941 "added": ["c"],
941 "added": ["c"],
942 "removed": []
942 "removed": []
943 },
943 },
944 {
944 {
945 "rev": 1,
945 "rev": 1,
946 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
946 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
947 "branch": "default",
947 "branch": "default",
948 "phase": "draft",
948 "phase": "draft",
949 "user": "A. N. Other <other@place>",
949 "user": "A. N. Other <other@place>",
950 "date": [1100000, 0],
950 "date": [1100000, 0],
951 "desc": "other 1\nother 2\n\nother 3",
951 "desc": "other 1\nother 2\n\nother 3",
952 "bookmarks": [],
952 "bookmarks": [],
953 "tags": [],
953 "tags": [],
954 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
954 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
955 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
955 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
956 "extra": {"branch": "default"},
956 "extra": {"branch": "default"},
957 "modified": [],
957 "modified": [],
958 "added": ["b"],
958 "added": ["b"],
959 "removed": []
959 "removed": []
960 },
960 },
961 {
961 {
962 "rev": 0,
962 "rev": 0,
963 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
963 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
964 "branch": "default",
964 "branch": "default",
965 "phase": "draft",
965 "phase": "draft",
966 "user": "User Name <user@hostname>",
966 "user": "User Name <user@hostname>",
967 "date": [1000000, 0],
967 "date": [1000000, 0],
968 "desc": "line 1\nline 2",
968 "desc": "line 1\nline 2",
969 "bookmarks": [],
969 "bookmarks": [],
970 "tags": [],
970 "tags": [],
971 "parents": ["0000000000000000000000000000000000000000"],
971 "parents": ["0000000000000000000000000000000000000000"],
972 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
972 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
973 "extra": {"branch": "default"},
973 "extra": {"branch": "default"},
974 "modified": [],
974 "modified": [],
975 "added": ["a"],
975 "added": ["a"],
976 "removed": []
976 "removed": []
977 }
977 }
978 ]
978 ]
979
979
980 Error if style not readable:
980 Error if style not readable:
981
981
982 #if unix-permissions no-root
982 #if unix-permissions no-root
983 $ touch q
983 $ touch q
984 $ chmod 0 q
984 $ chmod 0 q
985 $ hg log --style ./q
985 $ hg log --style ./q
986 abort: Permission denied: ./q
986 abort: Permission denied: ./q
987 [255]
987 [255]
988 #endif
988 #endif
989
989
990 Error if no style:
990 Error if no style:
991
991
992 $ hg log --style notexist
992 $ hg log --style notexist
993 abort: style 'notexist' not found
993 abort: style 'notexist' not found
994 (available styles: bisect, changelog, compact, default, phases, status, xml)
994 (available styles: bisect, changelog, compact, default, phases, status, xml)
995 [255]
995 [255]
996
996
997 $ hg log -T list
997 $ hg log -T list
998 available styles: bisect, changelog, compact, default, phases, status, xml
998 available styles: bisect, changelog, compact, default, phases, status, xml
999 abort: specify a template
999 abort: specify a template
1000 [255]
1000 [255]
1001
1001
1002 Error if style missing key:
1002 Error if style missing key:
1003
1003
1004 $ echo 'q = q' > t
1004 $ echo 'q = q' > t
1005 $ hg log --style ./t
1005 $ hg log --style ./t
1006 abort: "changeset" not in template map
1006 abort: "changeset" not in template map
1007 [255]
1007 [255]
1008
1008
1009 Error if style missing value:
1009 Error if style missing value:
1010
1010
1011 $ echo 'changeset =' > t
1011 $ echo 'changeset =' > t
1012 $ hg log --style t
1012 $ hg log --style t
1013 hg: parse error at t:1: missing value
1013 hg: parse error at t:1: missing value
1014 [255]
1014 [255]
1015
1015
1016 Error if include fails:
1016 Error if include fails:
1017
1017
1018 $ echo 'changeset = q' >> t
1018 $ echo 'changeset = q' >> t
1019 #if unix-permissions no-root
1019 #if unix-permissions no-root
1020 $ hg log --style ./t
1020 $ hg log --style ./t
1021 abort: template file ./q: Permission denied
1021 abort: template file ./q: Permission denied
1022 [255]
1022 [255]
1023 $ rm -f q
1023 $ rm -f q
1024 #endif
1024 #endif
1025
1025
1026 Include works:
1026 Include works:
1027
1027
1028 $ echo '{rev}' > q
1028 $ echo '{rev}' > q
1029 $ hg log --style ./t
1029 $ hg log --style ./t
1030 8
1030 8
1031 7
1031 7
1032 6
1032 6
1033 5
1033 5
1034 4
1034 4
1035 3
1035 3
1036 2
1036 2
1037 1
1037 1
1038 0
1038 0
1039
1039
1040 Check that recursive reference does not fall into RuntimeError (issue4758):
1040 Check that recursive reference does not fall into RuntimeError (issue4758):
1041
1041
1042 common mistake:
1042 common mistake:
1043
1043
1044 $ hg log -T '{changeset}\n'
1044 $ hg log -T '{changeset}\n'
1045 abort: recursive reference 'changeset' in template
1045 abort: recursive reference 'changeset' in template
1046 [255]
1046 [255]
1047
1047
1048 circular reference:
1048 circular reference:
1049
1049
1050 $ cat << EOF > issue4758
1050 $ cat << EOF > issue4758
1051 > changeset = '{foo}'
1051 > changeset = '{foo}'
1052 > foo = '{changeset}'
1052 > foo = '{changeset}'
1053 > EOF
1053 > EOF
1054 $ hg log --style ./issue4758
1054 $ hg log --style ./issue4758
1055 abort: recursive reference 'foo' in template
1055 abort: recursive reference 'foo' in template
1056 [255]
1056 [255]
1057
1057
1058 buildmap() -> gettemplate(), where no thunk was made:
1058 buildmap() -> gettemplate(), where no thunk was made:
1059
1059
1060 $ hg log -T '{files % changeset}\n'
1060 $ hg log -T '{files % changeset}\n'
1061 abort: recursive reference 'changeset' in template
1061 abort: recursive reference 'changeset' in template
1062 [255]
1062 [255]
1063
1063
1064 not a recursion if a keyword of the same name exists:
1064 not a recursion if a keyword of the same name exists:
1065
1065
1066 $ cat << EOF > issue4758
1066 $ cat << EOF > issue4758
1067 > changeset = '{tags % rev}'
1067 > changeset = '{tags % rev}'
1068 > rev = '{rev} {tag}\n'
1068 > rev = '{rev} {tag}\n'
1069 > EOF
1069 > EOF
1070 $ hg log --style ./issue4758 -r tip
1070 $ hg log --style ./issue4758 -r tip
1071 8 tip
1071 8 tip
1072
1072
1073 Check that {phase} works correctly on parents:
1073 Check that {phase} works correctly on parents:
1074
1074
1075 $ cat << EOF > parentphase
1075 $ cat << EOF > parentphase
1076 > changeset_debug = '{rev} ({phase}):{parents}\n'
1076 > changeset_debug = '{rev} ({phase}):{parents}\n'
1077 > parent = ' {rev} ({phase})'
1077 > parent = ' {rev} ({phase})'
1078 > EOF
1078 > EOF
1079 $ hg phase -r 5 --public
1079 $ hg phase -r 5 --public
1080 $ hg phase -r 7 --secret --force
1080 $ hg phase -r 7 --secret --force
1081 $ hg log --debug -G --style ./parentphase
1081 $ hg log --debug -G --style ./parentphase
1082 @ 8 (secret): 7 (secret) -1 (public)
1082 @ 8 (secret): 7 (secret) -1 (public)
1083 |
1083 |
1084 o 7 (secret): -1 (public) -1 (public)
1084 o 7 (secret): -1 (public) -1 (public)
1085
1085
1086 o 6 (draft): 5 (public) 4 (draft)
1086 o 6 (draft): 5 (public) 4 (draft)
1087 |\
1087 |\
1088 | o 5 (public): 3 (public) -1 (public)
1088 | o 5 (public): 3 (public) -1 (public)
1089 | |
1089 | |
1090 o | 4 (draft): 3 (public) -1 (public)
1090 o | 4 (draft): 3 (public) -1 (public)
1091 |/
1091 |/
1092 o 3 (public): 2 (public) -1 (public)
1092 o 3 (public): 2 (public) -1 (public)
1093 |
1093 |
1094 o 2 (public): 1 (public) -1 (public)
1094 o 2 (public): 1 (public) -1 (public)
1095 |
1095 |
1096 o 1 (public): 0 (public) -1 (public)
1096 o 1 (public): 0 (public) -1 (public)
1097 |
1097 |
1098 o 0 (public): -1 (public) -1 (public)
1098 o 0 (public): -1 (public) -1 (public)
1099
1099
1100
1100
1101 Missing non-standard names give no error (backward compatibility):
1101 Missing non-standard names give no error (backward compatibility):
1102
1102
1103 $ echo "changeset = '{c}'" > t
1103 $ echo "changeset = '{c}'" > t
1104 $ hg log --style ./t
1104 $ hg log --style ./t
1105
1105
1106 Defining non-standard name works:
1106 Defining non-standard name works:
1107
1107
1108 $ cat <<EOF > t
1108 $ cat <<EOF > t
1109 > changeset = '{c}'
1109 > changeset = '{c}'
1110 > c = q
1110 > c = q
1111 > EOF
1111 > EOF
1112 $ hg log --style ./t
1112 $ hg log --style ./t
1113 8
1113 8
1114 7
1114 7
1115 6
1115 6
1116 5
1116 5
1117 4
1117 4
1118 3
1118 3
1119 2
1119 2
1120 1
1120 1
1121 0
1121 0
1122
1122
1123 ui.style works:
1123 ui.style works:
1124
1124
1125 $ echo '[ui]' > .hg/hgrc
1125 $ echo '[ui]' > .hg/hgrc
1126 $ echo 'style = t' >> .hg/hgrc
1126 $ echo 'style = t' >> .hg/hgrc
1127 $ hg log
1127 $ hg log
1128 8
1128 8
1129 7
1129 7
1130 6
1130 6
1131 5
1131 5
1132 4
1132 4
1133 3
1133 3
1134 2
1134 2
1135 1
1135 1
1136 0
1136 0
1137
1137
1138
1138
1139 Issue338:
1139 Issue338:
1140
1140
1141 $ hg log --style=changelog > changelog
1141 $ hg log --style=changelog > changelog
1142
1142
1143 $ cat changelog
1143 $ cat changelog
1144 2020-01-01 test <test>
1144 2020-01-01 test <test>
1145
1145
1146 * fourth, second, third:
1146 * fourth, second, third:
1147 third
1147 third
1148 [95c24699272e] [tip]
1148 [95c24699272e] [tip]
1149
1149
1150 1970-01-12 User Name <user@hostname>
1150 1970-01-12 User Name <user@hostname>
1151
1151
1152 * second:
1152 * second:
1153 second
1153 second
1154 [29114dbae42b]
1154 [29114dbae42b]
1155
1155
1156 1970-01-18 person <person>
1156 1970-01-18 person <person>
1157
1157
1158 * merge
1158 * merge
1159 [d41e714fe50d]
1159 [d41e714fe50d]
1160
1160
1161 * d:
1161 * d:
1162 new head
1162 new head
1163 [13207e5a10d9]
1163 [13207e5a10d9]
1164
1164
1165 1970-01-17 person <person>
1165 1970-01-17 person <person>
1166
1166
1167 * new branch
1167 * new branch
1168 [bbe44766e73d] <foo>
1168 [bbe44766e73d] <foo>
1169
1169
1170 1970-01-16 person <person>
1170 1970-01-16 person <person>
1171
1171
1172 * c:
1172 * c:
1173 no user, no domain
1173 no user, no domain
1174 [10e46f2dcbf4]
1174 [10e46f2dcbf4]
1175
1175
1176 1970-01-14 other <other@place>
1176 1970-01-14 other <other@place>
1177
1177
1178 * c:
1178 * c:
1179 no person
1179 no person
1180 [97054abb4ab8]
1180 [97054abb4ab8]
1181
1181
1182 1970-01-13 A. N. Other <other@place>
1182 1970-01-13 A. N. Other <other@place>
1183
1183
1184 * b:
1184 * b:
1185 other 1 other 2
1185 other 1 other 2
1186
1186
1187 other 3
1187 other 3
1188 [b608e9d1a3f0]
1188 [b608e9d1a3f0]
1189
1189
1190 1970-01-12 User Name <user@hostname>
1190 1970-01-12 User Name <user@hostname>
1191
1191
1192 * a:
1192 * a:
1193 line 1 line 2
1193 line 1 line 2
1194 [1e4e1b8f71e0]
1194 [1e4e1b8f71e0]
1195
1195
1196
1196
1197 Issue2130: xml output for 'hg heads' is malformed
1197 Issue2130: xml output for 'hg heads' is malformed
1198
1198
1199 $ hg heads --style changelog
1199 $ hg heads --style changelog
1200 2020-01-01 test <test>
1200 2020-01-01 test <test>
1201
1201
1202 * fourth, second, third:
1202 * fourth, second, third:
1203 third
1203 third
1204 [95c24699272e] [tip]
1204 [95c24699272e] [tip]
1205
1205
1206 1970-01-18 person <person>
1206 1970-01-18 person <person>
1207
1207
1208 * merge
1208 * merge
1209 [d41e714fe50d]
1209 [d41e714fe50d]
1210
1210
1211 1970-01-17 person <person>
1211 1970-01-17 person <person>
1212
1212
1213 * new branch
1213 * new branch
1214 [bbe44766e73d] <foo>
1214 [bbe44766e73d] <foo>
1215
1215
1216
1216
1217 Keys work:
1217 Keys work:
1218
1218
1219 $ for key in author branch branches date desc file_adds file_dels file_mods \
1219 $ for key in author branch branches date desc file_adds file_dels file_mods \
1220 > file_copies file_copies_switch files \
1220 > file_copies file_copies_switch files \
1221 > manifest node parents rev tags diffstat extras \
1221 > manifest node parents rev tags diffstat extras \
1222 > p1rev p2rev p1node p2node; do
1222 > p1rev p2rev p1node p2node; do
1223 > for mode in '' --verbose --debug; do
1223 > for mode in '' --verbose --debug; do
1224 > hg log $mode --template "$key$mode: {$key}\n"
1224 > hg log $mode --template "$key$mode: {$key}\n"
1225 > done
1225 > done
1226 > done
1226 > done
1227 author: test
1227 author: test
1228 author: User Name <user@hostname>
1228 author: User Name <user@hostname>
1229 author: person
1229 author: person
1230 author: person
1230 author: person
1231 author: person
1231 author: person
1232 author: person
1232 author: person
1233 author: other@place
1233 author: other@place
1234 author: A. N. Other <other@place>
1234 author: A. N. Other <other@place>
1235 author: User Name <user@hostname>
1235 author: User Name <user@hostname>
1236 author--verbose: test
1236 author--verbose: test
1237 author--verbose: User Name <user@hostname>
1237 author--verbose: User Name <user@hostname>
1238 author--verbose: person
1238 author--verbose: person
1239 author--verbose: person
1239 author--verbose: person
1240 author--verbose: person
1240 author--verbose: person
1241 author--verbose: person
1241 author--verbose: person
1242 author--verbose: other@place
1242 author--verbose: other@place
1243 author--verbose: A. N. Other <other@place>
1243 author--verbose: A. N. Other <other@place>
1244 author--verbose: User Name <user@hostname>
1244 author--verbose: User Name <user@hostname>
1245 author--debug: test
1245 author--debug: test
1246 author--debug: User Name <user@hostname>
1246 author--debug: User Name <user@hostname>
1247 author--debug: person
1247 author--debug: person
1248 author--debug: person
1248 author--debug: person
1249 author--debug: person
1249 author--debug: person
1250 author--debug: person
1250 author--debug: person
1251 author--debug: other@place
1251 author--debug: other@place
1252 author--debug: A. N. Other <other@place>
1252 author--debug: A. N. Other <other@place>
1253 author--debug: User Name <user@hostname>
1253 author--debug: User Name <user@hostname>
1254 branch: default
1254 branch: default
1255 branch: default
1255 branch: default
1256 branch: default
1256 branch: default
1257 branch: default
1257 branch: default
1258 branch: foo
1258 branch: foo
1259 branch: default
1259 branch: default
1260 branch: default
1260 branch: default
1261 branch: default
1261 branch: default
1262 branch: default
1262 branch: default
1263 branch--verbose: default
1263 branch--verbose: default
1264 branch--verbose: default
1264 branch--verbose: default
1265 branch--verbose: default
1265 branch--verbose: default
1266 branch--verbose: default
1266 branch--verbose: default
1267 branch--verbose: foo
1267 branch--verbose: foo
1268 branch--verbose: default
1268 branch--verbose: default
1269 branch--verbose: default
1269 branch--verbose: default
1270 branch--verbose: default
1270 branch--verbose: default
1271 branch--verbose: default
1271 branch--verbose: default
1272 branch--debug: default
1272 branch--debug: default
1273 branch--debug: default
1273 branch--debug: default
1274 branch--debug: default
1274 branch--debug: default
1275 branch--debug: default
1275 branch--debug: default
1276 branch--debug: foo
1276 branch--debug: foo
1277 branch--debug: default
1277 branch--debug: default
1278 branch--debug: default
1278 branch--debug: default
1279 branch--debug: default
1279 branch--debug: default
1280 branch--debug: default
1280 branch--debug: default
1281 branches:
1281 branches:
1282 branches:
1282 branches:
1283 branches:
1283 branches:
1284 branches:
1284 branches:
1285 branches: foo
1285 branches: foo
1286 branches:
1286 branches:
1287 branches:
1287 branches:
1288 branches:
1288 branches:
1289 branches:
1289 branches:
1290 branches--verbose:
1290 branches--verbose:
1291 branches--verbose:
1291 branches--verbose:
1292 branches--verbose:
1292 branches--verbose:
1293 branches--verbose:
1293 branches--verbose:
1294 branches--verbose: foo
1294 branches--verbose: foo
1295 branches--verbose:
1295 branches--verbose:
1296 branches--verbose:
1296 branches--verbose:
1297 branches--verbose:
1297 branches--verbose:
1298 branches--verbose:
1298 branches--verbose:
1299 branches--debug:
1299 branches--debug:
1300 branches--debug:
1300 branches--debug:
1301 branches--debug:
1301 branches--debug:
1302 branches--debug:
1302 branches--debug:
1303 branches--debug: foo
1303 branches--debug: foo
1304 branches--debug:
1304 branches--debug:
1305 branches--debug:
1305 branches--debug:
1306 branches--debug:
1306 branches--debug:
1307 branches--debug:
1307 branches--debug:
1308 date: 1577872860.00
1308 date: 1577872860.00
1309 date: 1000000.00
1309 date: 1000000.00
1310 date: 1500001.00
1310 date: 1500001.00
1311 date: 1500000.00
1311 date: 1500000.00
1312 date: 1400000.00
1312 date: 1400000.00
1313 date: 1300000.00
1313 date: 1300000.00
1314 date: 1200000.00
1314 date: 1200000.00
1315 date: 1100000.00
1315 date: 1100000.00
1316 date: 1000000.00
1316 date: 1000000.00
1317 date--verbose: 1577872860.00
1317 date--verbose: 1577872860.00
1318 date--verbose: 1000000.00
1318 date--verbose: 1000000.00
1319 date--verbose: 1500001.00
1319 date--verbose: 1500001.00
1320 date--verbose: 1500000.00
1320 date--verbose: 1500000.00
1321 date--verbose: 1400000.00
1321 date--verbose: 1400000.00
1322 date--verbose: 1300000.00
1322 date--verbose: 1300000.00
1323 date--verbose: 1200000.00
1323 date--verbose: 1200000.00
1324 date--verbose: 1100000.00
1324 date--verbose: 1100000.00
1325 date--verbose: 1000000.00
1325 date--verbose: 1000000.00
1326 date--debug: 1577872860.00
1326 date--debug: 1577872860.00
1327 date--debug: 1000000.00
1327 date--debug: 1000000.00
1328 date--debug: 1500001.00
1328 date--debug: 1500001.00
1329 date--debug: 1500000.00
1329 date--debug: 1500000.00
1330 date--debug: 1400000.00
1330 date--debug: 1400000.00
1331 date--debug: 1300000.00
1331 date--debug: 1300000.00
1332 date--debug: 1200000.00
1332 date--debug: 1200000.00
1333 date--debug: 1100000.00
1333 date--debug: 1100000.00
1334 date--debug: 1000000.00
1334 date--debug: 1000000.00
1335 desc: third
1335 desc: third
1336 desc: second
1336 desc: second
1337 desc: merge
1337 desc: merge
1338 desc: new head
1338 desc: new head
1339 desc: new branch
1339 desc: new branch
1340 desc: no user, no domain
1340 desc: no user, no domain
1341 desc: no person
1341 desc: no person
1342 desc: other 1
1342 desc: other 1
1343 other 2
1343 other 2
1344
1344
1345 other 3
1345 other 3
1346 desc: line 1
1346 desc: line 1
1347 line 2
1347 line 2
1348 desc--verbose: third
1348 desc--verbose: third
1349 desc--verbose: second
1349 desc--verbose: second
1350 desc--verbose: merge
1350 desc--verbose: merge
1351 desc--verbose: new head
1351 desc--verbose: new head
1352 desc--verbose: new branch
1352 desc--verbose: new branch
1353 desc--verbose: no user, no domain
1353 desc--verbose: no user, no domain
1354 desc--verbose: no person
1354 desc--verbose: no person
1355 desc--verbose: other 1
1355 desc--verbose: other 1
1356 other 2
1356 other 2
1357
1357
1358 other 3
1358 other 3
1359 desc--verbose: line 1
1359 desc--verbose: line 1
1360 line 2
1360 line 2
1361 desc--debug: third
1361 desc--debug: third
1362 desc--debug: second
1362 desc--debug: second
1363 desc--debug: merge
1363 desc--debug: merge
1364 desc--debug: new head
1364 desc--debug: new head
1365 desc--debug: new branch
1365 desc--debug: new branch
1366 desc--debug: no user, no domain
1366 desc--debug: no user, no domain
1367 desc--debug: no person
1367 desc--debug: no person
1368 desc--debug: other 1
1368 desc--debug: other 1
1369 other 2
1369 other 2
1370
1370
1371 other 3
1371 other 3
1372 desc--debug: line 1
1372 desc--debug: line 1
1373 line 2
1373 line 2
1374 file_adds: fourth third
1374 file_adds: fourth third
1375 file_adds: second
1375 file_adds: second
1376 file_adds:
1376 file_adds:
1377 file_adds: d
1377 file_adds: d
1378 file_adds:
1378 file_adds:
1379 file_adds:
1379 file_adds:
1380 file_adds: c
1380 file_adds: c
1381 file_adds: b
1381 file_adds: b
1382 file_adds: a
1382 file_adds: a
1383 file_adds--verbose: fourth third
1383 file_adds--verbose: fourth third
1384 file_adds--verbose: second
1384 file_adds--verbose: second
1385 file_adds--verbose:
1385 file_adds--verbose:
1386 file_adds--verbose: d
1386 file_adds--verbose: d
1387 file_adds--verbose:
1387 file_adds--verbose:
1388 file_adds--verbose:
1388 file_adds--verbose:
1389 file_adds--verbose: c
1389 file_adds--verbose: c
1390 file_adds--verbose: b
1390 file_adds--verbose: b
1391 file_adds--verbose: a
1391 file_adds--verbose: a
1392 file_adds--debug: fourth third
1392 file_adds--debug: fourth third
1393 file_adds--debug: second
1393 file_adds--debug: second
1394 file_adds--debug:
1394 file_adds--debug:
1395 file_adds--debug: d
1395 file_adds--debug: d
1396 file_adds--debug:
1396 file_adds--debug:
1397 file_adds--debug:
1397 file_adds--debug:
1398 file_adds--debug: c
1398 file_adds--debug: c
1399 file_adds--debug: b
1399 file_adds--debug: b
1400 file_adds--debug: a
1400 file_adds--debug: a
1401 file_dels: second
1401 file_dels: second
1402 file_dels:
1402 file_dels:
1403 file_dels:
1403 file_dels:
1404 file_dels:
1404 file_dels:
1405 file_dels:
1405 file_dels:
1406 file_dels:
1406 file_dels:
1407 file_dels:
1407 file_dels:
1408 file_dels:
1408 file_dels:
1409 file_dels:
1409 file_dels:
1410 file_dels--verbose: second
1410 file_dels--verbose: second
1411 file_dels--verbose:
1411 file_dels--verbose:
1412 file_dels--verbose:
1412 file_dels--verbose:
1413 file_dels--verbose:
1413 file_dels--verbose:
1414 file_dels--verbose:
1414 file_dels--verbose:
1415 file_dels--verbose:
1415 file_dels--verbose:
1416 file_dels--verbose:
1416 file_dels--verbose:
1417 file_dels--verbose:
1417 file_dels--verbose:
1418 file_dels--verbose:
1418 file_dels--verbose:
1419 file_dels--debug: second
1419 file_dels--debug: second
1420 file_dels--debug:
1420 file_dels--debug:
1421 file_dels--debug:
1421 file_dels--debug:
1422 file_dels--debug:
1422 file_dels--debug:
1423 file_dels--debug:
1423 file_dels--debug:
1424 file_dels--debug:
1424 file_dels--debug:
1425 file_dels--debug:
1425 file_dels--debug:
1426 file_dels--debug:
1426 file_dels--debug:
1427 file_dels--debug:
1427 file_dels--debug:
1428 file_mods:
1428 file_mods:
1429 file_mods:
1429 file_mods:
1430 file_mods:
1430 file_mods:
1431 file_mods:
1431 file_mods:
1432 file_mods:
1432 file_mods:
1433 file_mods: c
1433 file_mods: c
1434 file_mods:
1434 file_mods:
1435 file_mods:
1435 file_mods:
1436 file_mods:
1436 file_mods:
1437 file_mods--verbose:
1437 file_mods--verbose:
1438 file_mods--verbose:
1438 file_mods--verbose:
1439 file_mods--verbose:
1439 file_mods--verbose:
1440 file_mods--verbose:
1440 file_mods--verbose:
1441 file_mods--verbose:
1441 file_mods--verbose:
1442 file_mods--verbose: c
1442 file_mods--verbose: c
1443 file_mods--verbose:
1443 file_mods--verbose:
1444 file_mods--verbose:
1444 file_mods--verbose:
1445 file_mods--verbose:
1445 file_mods--verbose:
1446 file_mods--debug:
1446 file_mods--debug:
1447 file_mods--debug:
1447 file_mods--debug:
1448 file_mods--debug:
1448 file_mods--debug:
1449 file_mods--debug:
1449 file_mods--debug:
1450 file_mods--debug:
1450 file_mods--debug:
1451 file_mods--debug: c
1451 file_mods--debug: c
1452 file_mods--debug:
1452 file_mods--debug:
1453 file_mods--debug:
1453 file_mods--debug:
1454 file_mods--debug:
1454 file_mods--debug:
1455 file_copies: fourth (second)
1455 file_copies: fourth (second)
1456 file_copies:
1456 file_copies:
1457 file_copies:
1457 file_copies:
1458 file_copies:
1458 file_copies:
1459 file_copies:
1459 file_copies:
1460 file_copies:
1460 file_copies:
1461 file_copies:
1461 file_copies:
1462 file_copies:
1462 file_copies:
1463 file_copies:
1463 file_copies:
1464 file_copies--verbose: fourth (second)
1464 file_copies--verbose: fourth (second)
1465 file_copies--verbose:
1465 file_copies--verbose:
1466 file_copies--verbose:
1466 file_copies--verbose:
1467 file_copies--verbose:
1467 file_copies--verbose:
1468 file_copies--verbose:
1468 file_copies--verbose:
1469 file_copies--verbose:
1469 file_copies--verbose:
1470 file_copies--verbose:
1470 file_copies--verbose:
1471 file_copies--verbose:
1471 file_copies--verbose:
1472 file_copies--verbose:
1472 file_copies--verbose:
1473 file_copies--debug: fourth (second)
1473 file_copies--debug: fourth (second)
1474 file_copies--debug:
1474 file_copies--debug:
1475 file_copies--debug:
1475 file_copies--debug:
1476 file_copies--debug:
1476 file_copies--debug:
1477 file_copies--debug:
1477 file_copies--debug:
1478 file_copies--debug:
1478 file_copies--debug:
1479 file_copies--debug:
1479 file_copies--debug:
1480 file_copies--debug:
1480 file_copies--debug:
1481 file_copies--debug:
1481 file_copies--debug:
1482 file_copies_switch:
1482 file_copies_switch:
1483 file_copies_switch:
1483 file_copies_switch:
1484 file_copies_switch:
1484 file_copies_switch:
1485 file_copies_switch:
1485 file_copies_switch:
1486 file_copies_switch:
1486 file_copies_switch:
1487 file_copies_switch:
1487 file_copies_switch:
1488 file_copies_switch:
1488 file_copies_switch:
1489 file_copies_switch:
1489 file_copies_switch:
1490 file_copies_switch:
1490 file_copies_switch:
1491 file_copies_switch--verbose:
1491 file_copies_switch--verbose:
1492 file_copies_switch--verbose:
1492 file_copies_switch--verbose:
1493 file_copies_switch--verbose:
1493 file_copies_switch--verbose:
1494 file_copies_switch--verbose:
1494 file_copies_switch--verbose:
1495 file_copies_switch--verbose:
1495 file_copies_switch--verbose:
1496 file_copies_switch--verbose:
1496 file_copies_switch--verbose:
1497 file_copies_switch--verbose:
1497 file_copies_switch--verbose:
1498 file_copies_switch--verbose:
1498 file_copies_switch--verbose:
1499 file_copies_switch--verbose:
1499 file_copies_switch--verbose:
1500 file_copies_switch--debug:
1500 file_copies_switch--debug:
1501 file_copies_switch--debug:
1501 file_copies_switch--debug:
1502 file_copies_switch--debug:
1502 file_copies_switch--debug:
1503 file_copies_switch--debug:
1503 file_copies_switch--debug:
1504 file_copies_switch--debug:
1504 file_copies_switch--debug:
1505 file_copies_switch--debug:
1505 file_copies_switch--debug:
1506 file_copies_switch--debug:
1506 file_copies_switch--debug:
1507 file_copies_switch--debug:
1507 file_copies_switch--debug:
1508 file_copies_switch--debug:
1508 file_copies_switch--debug:
1509 files: fourth second third
1509 files: fourth second third
1510 files: second
1510 files: second
1511 files:
1511 files:
1512 files: d
1512 files: d
1513 files:
1513 files:
1514 files: c
1514 files: c
1515 files: c
1515 files: c
1516 files: b
1516 files: b
1517 files: a
1517 files: a
1518 files--verbose: fourth second third
1518 files--verbose: fourth second third
1519 files--verbose: second
1519 files--verbose: second
1520 files--verbose:
1520 files--verbose:
1521 files--verbose: d
1521 files--verbose: d
1522 files--verbose:
1522 files--verbose:
1523 files--verbose: c
1523 files--verbose: c
1524 files--verbose: c
1524 files--verbose: c
1525 files--verbose: b
1525 files--verbose: b
1526 files--verbose: a
1526 files--verbose: a
1527 files--debug: fourth second third
1527 files--debug: fourth second third
1528 files--debug: second
1528 files--debug: second
1529 files--debug:
1529 files--debug:
1530 files--debug: d
1530 files--debug: d
1531 files--debug:
1531 files--debug:
1532 files--debug: c
1532 files--debug: c
1533 files--debug: c
1533 files--debug: c
1534 files--debug: b
1534 files--debug: b
1535 files--debug: a
1535 files--debug: a
1536 manifest: 6:94961b75a2da
1536 manifest: 6:94961b75a2da
1537 manifest: 5:f2dbc354b94e
1537 manifest: 5:f2dbc354b94e
1538 manifest: 4:4dc3def4f9b4
1538 manifest: 4:4dc3def4f9b4
1539 manifest: 4:4dc3def4f9b4
1539 manifest: 4:4dc3def4f9b4
1540 manifest: 3:cb5a1327723b
1540 manifest: 3:cb5a1327723b
1541 manifest: 3:cb5a1327723b
1541 manifest: 3:cb5a1327723b
1542 manifest: 2:6e0e82995c35
1542 manifest: 2:6e0e82995c35
1543 manifest: 1:4e8d705b1e53
1543 manifest: 1:4e8d705b1e53
1544 manifest: 0:a0c8bcbbb45c
1544 manifest: 0:a0c8bcbbb45c
1545 manifest--verbose: 6:94961b75a2da
1545 manifest--verbose: 6:94961b75a2da
1546 manifest--verbose: 5:f2dbc354b94e
1546 manifest--verbose: 5:f2dbc354b94e
1547 manifest--verbose: 4:4dc3def4f9b4
1547 manifest--verbose: 4:4dc3def4f9b4
1548 manifest--verbose: 4:4dc3def4f9b4
1548 manifest--verbose: 4:4dc3def4f9b4
1549 manifest--verbose: 3:cb5a1327723b
1549 manifest--verbose: 3:cb5a1327723b
1550 manifest--verbose: 3:cb5a1327723b
1550 manifest--verbose: 3:cb5a1327723b
1551 manifest--verbose: 2:6e0e82995c35
1551 manifest--verbose: 2:6e0e82995c35
1552 manifest--verbose: 1:4e8d705b1e53
1552 manifest--verbose: 1:4e8d705b1e53
1553 manifest--verbose: 0:a0c8bcbbb45c
1553 manifest--verbose: 0:a0c8bcbbb45c
1554 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1554 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1555 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1555 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1556 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1556 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1557 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1557 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1558 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1558 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1559 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1559 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1560 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1560 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1561 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1561 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1562 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1562 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1563 node: 95c24699272ef57d062b8bccc32c878bf841784a
1563 node: 95c24699272ef57d062b8bccc32c878bf841784a
1564 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1564 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1565 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1565 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1566 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1566 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1567 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1567 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1568 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1568 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1569 node: 97054abb4ab824450e9164180baf491ae0078465
1569 node: 97054abb4ab824450e9164180baf491ae0078465
1570 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1570 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1571 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1571 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1572 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1572 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1573 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1573 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1574 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1574 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1575 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1575 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1576 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1576 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1577 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1577 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1578 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1578 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1579 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1579 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1580 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1580 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1581 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1581 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1582 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1582 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1583 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1583 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1584 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1584 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1585 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1585 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1586 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1586 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1587 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1587 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1588 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1588 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1589 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1589 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1590 parents:
1590 parents:
1591 parents: -1:000000000000
1591 parents: -1:000000000000
1592 parents: 5:13207e5a10d9 4:bbe44766e73d
1592 parents: 5:13207e5a10d9 4:bbe44766e73d
1593 parents: 3:10e46f2dcbf4
1593 parents: 3:10e46f2dcbf4
1594 parents:
1594 parents:
1595 parents:
1595 parents:
1596 parents:
1596 parents:
1597 parents:
1597 parents:
1598 parents:
1598 parents:
1599 parents--verbose:
1599 parents--verbose:
1600 parents--verbose: -1:000000000000
1600 parents--verbose: -1:000000000000
1601 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1601 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1602 parents--verbose: 3:10e46f2dcbf4
1602 parents--verbose: 3:10e46f2dcbf4
1603 parents--verbose:
1603 parents--verbose:
1604 parents--verbose:
1604 parents--verbose:
1605 parents--verbose:
1605 parents--verbose:
1606 parents--verbose:
1606 parents--verbose:
1607 parents--verbose:
1607 parents--verbose:
1608 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1608 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1609 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1609 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1610 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1610 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1611 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1611 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1612 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1612 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1613 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1613 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1614 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1614 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1615 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1615 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1616 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1616 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1617 rev: 8
1617 rev: 8
1618 rev: 7
1618 rev: 7
1619 rev: 6
1619 rev: 6
1620 rev: 5
1620 rev: 5
1621 rev: 4
1621 rev: 4
1622 rev: 3
1622 rev: 3
1623 rev: 2
1623 rev: 2
1624 rev: 1
1624 rev: 1
1625 rev: 0
1625 rev: 0
1626 rev--verbose: 8
1626 rev--verbose: 8
1627 rev--verbose: 7
1627 rev--verbose: 7
1628 rev--verbose: 6
1628 rev--verbose: 6
1629 rev--verbose: 5
1629 rev--verbose: 5
1630 rev--verbose: 4
1630 rev--verbose: 4
1631 rev--verbose: 3
1631 rev--verbose: 3
1632 rev--verbose: 2
1632 rev--verbose: 2
1633 rev--verbose: 1
1633 rev--verbose: 1
1634 rev--verbose: 0
1634 rev--verbose: 0
1635 rev--debug: 8
1635 rev--debug: 8
1636 rev--debug: 7
1636 rev--debug: 7
1637 rev--debug: 6
1637 rev--debug: 6
1638 rev--debug: 5
1638 rev--debug: 5
1639 rev--debug: 4
1639 rev--debug: 4
1640 rev--debug: 3
1640 rev--debug: 3
1641 rev--debug: 2
1641 rev--debug: 2
1642 rev--debug: 1
1642 rev--debug: 1
1643 rev--debug: 0
1643 rev--debug: 0
1644 tags: tip
1644 tags: tip
1645 tags:
1645 tags:
1646 tags:
1646 tags:
1647 tags:
1647 tags:
1648 tags:
1648 tags:
1649 tags:
1649 tags:
1650 tags:
1650 tags:
1651 tags:
1651 tags:
1652 tags:
1652 tags:
1653 tags--verbose: tip
1653 tags--verbose: tip
1654 tags--verbose:
1654 tags--verbose:
1655 tags--verbose:
1655 tags--verbose:
1656 tags--verbose:
1656 tags--verbose:
1657 tags--verbose:
1657 tags--verbose:
1658 tags--verbose:
1658 tags--verbose:
1659 tags--verbose:
1659 tags--verbose:
1660 tags--verbose:
1660 tags--verbose:
1661 tags--verbose:
1661 tags--verbose:
1662 tags--debug: tip
1662 tags--debug: tip
1663 tags--debug:
1663 tags--debug:
1664 tags--debug:
1664 tags--debug:
1665 tags--debug:
1665 tags--debug:
1666 tags--debug:
1666 tags--debug:
1667 tags--debug:
1667 tags--debug:
1668 tags--debug:
1668 tags--debug:
1669 tags--debug:
1669 tags--debug:
1670 tags--debug:
1670 tags--debug:
1671 diffstat: 3: +2/-1
1671 diffstat: 3: +2/-1
1672 diffstat: 1: +1/-0
1672 diffstat: 1: +1/-0
1673 diffstat: 0: +0/-0
1673 diffstat: 0: +0/-0
1674 diffstat: 1: +1/-0
1674 diffstat: 1: +1/-0
1675 diffstat: 0: +0/-0
1675 diffstat: 0: +0/-0
1676 diffstat: 1: +1/-0
1676 diffstat: 1: +1/-0
1677 diffstat: 1: +4/-0
1677 diffstat: 1: +4/-0
1678 diffstat: 1: +2/-0
1678 diffstat: 1: +2/-0
1679 diffstat: 1: +1/-0
1679 diffstat: 1: +1/-0
1680 diffstat--verbose: 3: +2/-1
1680 diffstat--verbose: 3: +2/-1
1681 diffstat--verbose: 1: +1/-0
1681 diffstat--verbose: 1: +1/-0
1682 diffstat--verbose: 0: +0/-0
1682 diffstat--verbose: 0: +0/-0
1683 diffstat--verbose: 1: +1/-0
1683 diffstat--verbose: 1: +1/-0
1684 diffstat--verbose: 0: +0/-0
1684 diffstat--verbose: 0: +0/-0
1685 diffstat--verbose: 1: +1/-0
1685 diffstat--verbose: 1: +1/-0
1686 diffstat--verbose: 1: +4/-0
1686 diffstat--verbose: 1: +4/-0
1687 diffstat--verbose: 1: +2/-0
1687 diffstat--verbose: 1: +2/-0
1688 diffstat--verbose: 1: +1/-0
1688 diffstat--verbose: 1: +1/-0
1689 diffstat--debug: 3: +2/-1
1689 diffstat--debug: 3: +2/-1
1690 diffstat--debug: 1: +1/-0
1690 diffstat--debug: 1: +1/-0
1691 diffstat--debug: 0: +0/-0
1691 diffstat--debug: 0: +0/-0
1692 diffstat--debug: 1: +1/-0
1692 diffstat--debug: 1: +1/-0
1693 diffstat--debug: 0: +0/-0
1693 diffstat--debug: 0: +0/-0
1694 diffstat--debug: 1: +1/-0
1694 diffstat--debug: 1: +1/-0
1695 diffstat--debug: 1: +4/-0
1695 diffstat--debug: 1: +4/-0
1696 diffstat--debug: 1: +2/-0
1696 diffstat--debug: 1: +2/-0
1697 diffstat--debug: 1: +1/-0
1697 diffstat--debug: 1: +1/-0
1698 extras: branch=default
1698 extras: branch=default
1699 extras: branch=default
1699 extras: branch=default
1700 extras: branch=default
1700 extras: branch=default
1701 extras: branch=default
1701 extras: branch=default
1702 extras: branch=foo
1702 extras: branch=foo
1703 extras: branch=default
1703 extras: branch=default
1704 extras: branch=default
1704 extras: branch=default
1705 extras: branch=default
1705 extras: branch=default
1706 extras: branch=default
1706 extras: branch=default
1707 extras--verbose: branch=default
1707 extras--verbose: branch=default
1708 extras--verbose: branch=default
1708 extras--verbose: branch=default
1709 extras--verbose: branch=default
1709 extras--verbose: branch=default
1710 extras--verbose: branch=default
1710 extras--verbose: branch=default
1711 extras--verbose: branch=foo
1711 extras--verbose: branch=foo
1712 extras--verbose: branch=default
1712 extras--verbose: branch=default
1713 extras--verbose: branch=default
1713 extras--verbose: branch=default
1714 extras--verbose: branch=default
1714 extras--verbose: branch=default
1715 extras--verbose: branch=default
1715 extras--verbose: branch=default
1716 extras--debug: branch=default
1716 extras--debug: branch=default
1717 extras--debug: branch=default
1717 extras--debug: branch=default
1718 extras--debug: branch=default
1718 extras--debug: branch=default
1719 extras--debug: branch=default
1719 extras--debug: branch=default
1720 extras--debug: branch=foo
1720 extras--debug: branch=foo
1721 extras--debug: branch=default
1721 extras--debug: branch=default
1722 extras--debug: branch=default
1722 extras--debug: branch=default
1723 extras--debug: branch=default
1723 extras--debug: branch=default
1724 extras--debug: branch=default
1724 extras--debug: branch=default
1725 p1rev: 7
1725 p1rev: 7
1726 p1rev: -1
1726 p1rev: -1
1727 p1rev: 5
1727 p1rev: 5
1728 p1rev: 3
1728 p1rev: 3
1729 p1rev: 3
1729 p1rev: 3
1730 p1rev: 2
1730 p1rev: 2
1731 p1rev: 1
1731 p1rev: 1
1732 p1rev: 0
1732 p1rev: 0
1733 p1rev: -1
1733 p1rev: -1
1734 p1rev--verbose: 7
1734 p1rev--verbose: 7
1735 p1rev--verbose: -1
1735 p1rev--verbose: -1
1736 p1rev--verbose: 5
1736 p1rev--verbose: 5
1737 p1rev--verbose: 3
1737 p1rev--verbose: 3
1738 p1rev--verbose: 3
1738 p1rev--verbose: 3
1739 p1rev--verbose: 2
1739 p1rev--verbose: 2
1740 p1rev--verbose: 1
1740 p1rev--verbose: 1
1741 p1rev--verbose: 0
1741 p1rev--verbose: 0
1742 p1rev--verbose: -1
1742 p1rev--verbose: -1
1743 p1rev--debug: 7
1743 p1rev--debug: 7
1744 p1rev--debug: -1
1744 p1rev--debug: -1
1745 p1rev--debug: 5
1745 p1rev--debug: 5
1746 p1rev--debug: 3
1746 p1rev--debug: 3
1747 p1rev--debug: 3
1747 p1rev--debug: 3
1748 p1rev--debug: 2
1748 p1rev--debug: 2
1749 p1rev--debug: 1
1749 p1rev--debug: 1
1750 p1rev--debug: 0
1750 p1rev--debug: 0
1751 p1rev--debug: -1
1751 p1rev--debug: -1
1752 p2rev: -1
1752 p2rev: -1
1753 p2rev: -1
1753 p2rev: -1
1754 p2rev: 4
1754 p2rev: 4
1755 p2rev: -1
1755 p2rev: -1
1756 p2rev: -1
1756 p2rev: -1
1757 p2rev: -1
1757 p2rev: -1
1758 p2rev: -1
1758 p2rev: -1
1759 p2rev: -1
1759 p2rev: -1
1760 p2rev: -1
1760 p2rev: -1
1761 p2rev--verbose: -1
1761 p2rev--verbose: -1
1762 p2rev--verbose: -1
1762 p2rev--verbose: -1
1763 p2rev--verbose: 4
1763 p2rev--verbose: 4
1764 p2rev--verbose: -1
1764 p2rev--verbose: -1
1765 p2rev--verbose: -1
1765 p2rev--verbose: -1
1766 p2rev--verbose: -1
1766 p2rev--verbose: -1
1767 p2rev--verbose: -1
1767 p2rev--verbose: -1
1768 p2rev--verbose: -1
1768 p2rev--verbose: -1
1769 p2rev--verbose: -1
1769 p2rev--verbose: -1
1770 p2rev--debug: -1
1770 p2rev--debug: -1
1771 p2rev--debug: -1
1771 p2rev--debug: -1
1772 p2rev--debug: 4
1772 p2rev--debug: 4
1773 p2rev--debug: -1
1773 p2rev--debug: -1
1774 p2rev--debug: -1
1774 p2rev--debug: -1
1775 p2rev--debug: -1
1775 p2rev--debug: -1
1776 p2rev--debug: -1
1776 p2rev--debug: -1
1777 p2rev--debug: -1
1777 p2rev--debug: -1
1778 p2rev--debug: -1
1778 p2rev--debug: -1
1779 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1779 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1780 p1node: 0000000000000000000000000000000000000000
1780 p1node: 0000000000000000000000000000000000000000
1781 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1781 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1782 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1782 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1783 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1783 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1784 p1node: 97054abb4ab824450e9164180baf491ae0078465
1784 p1node: 97054abb4ab824450e9164180baf491ae0078465
1785 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1785 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1786 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1786 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1787 p1node: 0000000000000000000000000000000000000000
1787 p1node: 0000000000000000000000000000000000000000
1788 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1788 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1789 p1node--verbose: 0000000000000000000000000000000000000000
1789 p1node--verbose: 0000000000000000000000000000000000000000
1790 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1790 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1791 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1791 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1792 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1792 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1793 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1793 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1794 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1794 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1795 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1795 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1796 p1node--verbose: 0000000000000000000000000000000000000000
1796 p1node--verbose: 0000000000000000000000000000000000000000
1797 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1797 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1798 p1node--debug: 0000000000000000000000000000000000000000
1798 p1node--debug: 0000000000000000000000000000000000000000
1799 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1799 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1800 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1800 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1801 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1801 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1802 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1802 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1803 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1803 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1804 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1804 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1805 p1node--debug: 0000000000000000000000000000000000000000
1805 p1node--debug: 0000000000000000000000000000000000000000
1806 p2node: 0000000000000000000000000000000000000000
1806 p2node: 0000000000000000000000000000000000000000
1807 p2node: 0000000000000000000000000000000000000000
1807 p2node: 0000000000000000000000000000000000000000
1808 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1808 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1809 p2node: 0000000000000000000000000000000000000000
1809 p2node: 0000000000000000000000000000000000000000
1810 p2node: 0000000000000000000000000000000000000000
1810 p2node: 0000000000000000000000000000000000000000
1811 p2node: 0000000000000000000000000000000000000000
1811 p2node: 0000000000000000000000000000000000000000
1812 p2node: 0000000000000000000000000000000000000000
1812 p2node: 0000000000000000000000000000000000000000
1813 p2node: 0000000000000000000000000000000000000000
1813 p2node: 0000000000000000000000000000000000000000
1814 p2node: 0000000000000000000000000000000000000000
1814 p2node: 0000000000000000000000000000000000000000
1815 p2node--verbose: 0000000000000000000000000000000000000000
1815 p2node--verbose: 0000000000000000000000000000000000000000
1816 p2node--verbose: 0000000000000000000000000000000000000000
1816 p2node--verbose: 0000000000000000000000000000000000000000
1817 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1817 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1818 p2node--verbose: 0000000000000000000000000000000000000000
1818 p2node--verbose: 0000000000000000000000000000000000000000
1819 p2node--verbose: 0000000000000000000000000000000000000000
1819 p2node--verbose: 0000000000000000000000000000000000000000
1820 p2node--verbose: 0000000000000000000000000000000000000000
1820 p2node--verbose: 0000000000000000000000000000000000000000
1821 p2node--verbose: 0000000000000000000000000000000000000000
1821 p2node--verbose: 0000000000000000000000000000000000000000
1822 p2node--verbose: 0000000000000000000000000000000000000000
1822 p2node--verbose: 0000000000000000000000000000000000000000
1823 p2node--verbose: 0000000000000000000000000000000000000000
1823 p2node--verbose: 0000000000000000000000000000000000000000
1824 p2node--debug: 0000000000000000000000000000000000000000
1824 p2node--debug: 0000000000000000000000000000000000000000
1825 p2node--debug: 0000000000000000000000000000000000000000
1825 p2node--debug: 0000000000000000000000000000000000000000
1826 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1826 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1827 p2node--debug: 0000000000000000000000000000000000000000
1827 p2node--debug: 0000000000000000000000000000000000000000
1828 p2node--debug: 0000000000000000000000000000000000000000
1828 p2node--debug: 0000000000000000000000000000000000000000
1829 p2node--debug: 0000000000000000000000000000000000000000
1829 p2node--debug: 0000000000000000000000000000000000000000
1830 p2node--debug: 0000000000000000000000000000000000000000
1830 p2node--debug: 0000000000000000000000000000000000000000
1831 p2node--debug: 0000000000000000000000000000000000000000
1831 p2node--debug: 0000000000000000000000000000000000000000
1832 p2node--debug: 0000000000000000000000000000000000000000
1832 p2node--debug: 0000000000000000000000000000000000000000
1833
1833
1834 Filters work:
1834 Filters work:
1835
1835
1836 $ hg log --template '{author|domain}\n'
1836 $ hg log --template '{author|domain}\n'
1837
1837
1838 hostname
1838 hostname
1839
1839
1840
1840
1841
1841
1842
1842
1843 place
1843 place
1844 place
1844 place
1845 hostname
1845 hostname
1846
1846
1847 $ hg log --template '{author|person}\n'
1847 $ hg log --template '{author|person}\n'
1848 test
1848 test
1849 User Name
1849 User Name
1850 person
1850 person
1851 person
1851 person
1852 person
1852 person
1853 person
1853 person
1854 other
1854 other
1855 A. N. Other
1855 A. N. Other
1856 User Name
1856 User Name
1857
1857
1858 $ hg log --template '{author|user}\n'
1858 $ hg log --template '{author|user}\n'
1859 test
1859 test
1860 user
1860 user
1861 person
1861 person
1862 person
1862 person
1863 person
1863 person
1864 person
1864 person
1865 other
1865 other
1866 other
1866 other
1867 user
1867 user
1868
1868
1869 $ hg log --template '{date|date}\n'
1869 $ hg log --template '{date|date}\n'
1870 Wed Jan 01 10:01:00 2020 +0000
1870 Wed Jan 01 10:01:00 2020 +0000
1871 Mon Jan 12 13:46:40 1970 +0000
1871 Mon Jan 12 13:46:40 1970 +0000
1872 Sun Jan 18 08:40:01 1970 +0000
1872 Sun Jan 18 08:40:01 1970 +0000
1873 Sun Jan 18 08:40:00 1970 +0000
1873 Sun Jan 18 08:40:00 1970 +0000
1874 Sat Jan 17 04:53:20 1970 +0000
1874 Sat Jan 17 04:53:20 1970 +0000
1875 Fri Jan 16 01:06:40 1970 +0000
1875 Fri Jan 16 01:06:40 1970 +0000
1876 Wed Jan 14 21:20:00 1970 +0000
1876 Wed Jan 14 21:20:00 1970 +0000
1877 Tue Jan 13 17:33:20 1970 +0000
1877 Tue Jan 13 17:33:20 1970 +0000
1878 Mon Jan 12 13:46:40 1970 +0000
1878 Mon Jan 12 13:46:40 1970 +0000
1879
1879
1880 $ hg log --template '{date|isodate}\n'
1880 $ hg log --template '{date|isodate}\n'
1881 2020-01-01 10:01 +0000
1881 2020-01-01 10:01 +0000
1882 1970-01-12 13:46 +0000
1882 1970-01-12 13:46 +0000
1883 1970-01-18 08:40 +0000
1883 1970-01-18 08:40 +0000
1884 1970-01-18 08:40 +0000
1884 1970-01-18 08:40 +0000
1885 1970-01-17 04:53 +0000
1885 1970-01-17 04:53 +0000
1886 1970-01-16 01:06 +0000
1886 1970-01-16 01:06 +0000
1887 1970-01-14 21:20 +0000
1887 1970-01-14 21:20 +0000
1888 1970-01-13 17:33 +0000
1888 1970-01-13 17:33 +0000
1889 1970-01-12 13:46 +0000
1889 1970-01-12 13:46 +0000
1890
1890
1891 $ hg log --template '{date|isodatesec}\n'
1891 $ hg log --template '{date|isodatesec}\n'
1892 2020-01-01 10:01:00 +0000
1892 2020-01-01 10:01:00 +0000
1893 1970-01-12 13:46:40 +0000
1893 1970-01-12 13:46:40 +0000
1894 1970-01-18 08:40:01 +0000
1894 1970-01-18 08:40:01 +0000
1895 1970-01-18 08:40:00 +0000
1895 1970-01-18 08:40:00 +0000
1896 1970-01-17 04:53:20 +0000
1896 1970-01-17 04:53:20 +0000
1897 1970-01-16 01:06:40 +0000
1897 1970-01-16 01:06:40 +0000
1898 1970-01-14 21:20:00 +0000
1898 1970-01-14 21:20:00 +0000
1899 1970-01-13 17:33:20 +0000
1899 1970-01-13 17:33:20 +0000
1900 1970-01-12 13:46:40 +0000
1900 1970-01-12 13:46:40 +0000
1901
1901
1902 $ hg log --template '{date|rfc822date}\n'
1902 $ hg log --template '{date|rfc822date}\n'
1903 Wed, 01 Jan 2020 10:01:00 +0000
1903 Wed, 01 Jan 2020 10:01:00 +0000
1904 Mon, 12 Jan 1970 13:46:40 +0000
1904 Mon, 12 Jan 1970 13:46:40 +0000
1905 Sun, 18 Jan 1970 08:40:01 +0000
1905 Sun, 18 Jan 1970 08:40:01 +0000
1906 Sun, 18 Jan 1970 08:40:00 +0000
1906 Sun, 18 Jan 1970 08:40:00 +0000
1907 Sat, 17 Jan 1970 04:53:20 +0000
1907 Sat, 17 Jan 1970 04:53:20 +0000
1908 Fri, 16 Jan 1970 01:06:40 +0000
1908 Fri, 16 Jan 1970 01:06:40 +0000
1909 Wed, 14 Jan 1970 21:20:00 +0000
1909 Wed, 14 Jan 1970 21:20:00 +0000
1910 Tue, 13 Jan 1970 17:33:20 +0000
1910 Tue, 13 Jan 1970 17:33:20 +0000
1911 Mon, 12 Jan 1970 13:46:40 +0000
1911 Mon, 12 Jan 1970 13:46:40 +0000
1912
1912
1913 $ hg log --template '{desc|firstline}\n'
1913 $ hg log --template '{desc|firstline}\n'
1914 third
1914 third
1915 second
1915 second
1916 merge
1916 merge
1917 new head
1917 new head
1918 new branch
1918 new branch
1919 no user, no domain
1919 no user, no domain
1920 no person
1920 no person
1921 other 1
1921 other 1
1922 line 1
1922 line 1
1923
1923
1924 $ hg log --template '{node|short}\n'
1924 $ hg log --template '{node|short}\n'
1925 95c24699272e
1925 95c24699272e
1926 29114dbae42b
1926 29114dbae42b
1927 d41e714fe50d
1927 d41e714fe50d
1928 13207e5a10d9
1928 13207e5a10d9
1929 bbe44766e73d
1929 bbe44766e73d
1930 10e46f2dcbf4
1930 10e46f2dcbf4
1931 97054abb4ab8
1931 97054abb4ab8
1932 b608e9d1a3f0
1932 b608e9d1a3f0
1933 1e4e1b8f71e0
1933 1e4e1b8f71e0
1934
1934
1935 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
1935 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
1936 <changeset author="test"/>
1936 <changeset author="test"/>
1937 <changeset author="User Name &lt;user@hostname&gt;"/>
1937 <changeset author="User Name &lt;user@hostname&gt;"/>
1938 <changeset author="person"/>
1938 <changeset author="person"/>
1939 <changeset author="person"/>
1939 <changeset author="person"/>
1940 <changeset author="person"/>
1940 <changeset author="person"/>
1941 <changeset author="person"/>
1941 <changeset author="person"/>
1942 <changeset author="other@place"/>
1942 <changeset author="other@place"/>
1943 <changeset author="A. N. Other &lt;other@place&gt;"/>
1943 <changeset author="A. N. Other &lt;other@place&gt;"/>
1944 <changeset author="User Name &lt;user@hostname&gt;"/>
1944 <changeset author="User Name &lt;user@hostname&gt;"/>
1945
1945
1946 $ hg log --template '{rev}: {children}\n'
1946 $ hg log --template '{rev}: {children}\n'
1947 8:
1947 8:
1948 7: 8:95c24699272e
1948 7: 8:95c24699272e
1949 6:
1949 6:
1950 5: 6:d41e714fe50d
1950 5: 6:d41e714fe50d
1951 4: 6:d41e714fe50d
1951 4: 6:d41e714fe50d
1952 3: 4:bbe44766e73d 5:13207e5a10d9
1952 3: 4:bbe44766e73d 5:13207e5a10d9
1953 2: 3:10e46f2dcbf4
1953 2: 3:10e46f2dcbf4
1954 1: 2:97054abb4ab8
1954 1: 2:97054abb4ab8
1955 0: 1:b608e9d1a3f0
1955 0: 1:b608e9d1a3f0
1956
1956
1957 Formatnode filter works:
1957 Formatnode filter works:
1958
1958
1959 $ hg -q log -r 0 --template '{node|formatnode}\n'
1959 $ hg -q log -r 0 --template '{node|formatnode}\n'
1960 1e4e1b8f71e0
1960 1e4e1b8f71e0
1961
1961
1962 $ hg log -r 0 --template '{node|formatnode}\n'
1962 $ hg log -r 0 --template '{node|formatnode}\n'
1963 1e4e1b8f71e0
1963 1e4e1b8f71e0
1964
1964
1965 $ hg -v log -r 0 --template '{node|formatnode}\n'
1965 $ hg -v log -r 0 --template '{node|formatnode}\n'
1966 1e4e1b8f71e0
1966 1e4e1b8f71e0
1967
1967
1968 $ hg --debug log -r 0 --template '{node|formatnode}\n'
1968 $ hg --debug log -r 0 --template '{node|formatnode}\n'
1969 1e4e1b8f71e05681d422154f5421e385fec3454f
1969 1e4e1b8f71e05681d422154f5421e385fec3454f
1970
1970
1971 Age filter:
1971 Age filter:
1972
1972
1973 $ hg init unstable-hash
1973 $ hg init unstable-hash
1974 $ cd unstable-hash
1974 $ cd unstable-hash
1975 $ hg log --template '{date|age}\n' > /dev/null || exit 1
1975 $ hg log --template '{date|age}\n' > /dev/null || exit 1
1976
1976
1977 >>> from datetime import datetime, timedelta
1977 >>> from datetime import datetime, timedelta
1978 >>> fp = open('a', 'w')
1978 >>> fp = open('a', 'w')
1979 >>> n = datetime.now() + timedelta(366 * 7)
1979 >>> n = datetime.now() + timedelta(366 * 7)
1980 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
1980 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
1981 >>> fp.close()
1981 >>> fp.close()
1982 $ hg add a
1982 $ hg add a
1983 $ hg commit -m future -d "`cat a`"
1983 $ hg commit -m future -d "`cat a`"
1984
1984
1985 $ hg log -l1 --template '{date|age}\n'
1985 $ hg log -l1 --template '{date|age}\n'
1986 7 years from now
1986 7 years from now
1987
1987
1988 $ cd ..
1988 $ cd ..
1989 $ rm -rf unstable-hash
1989 $ rm -rf unstable-hash
1990
1990
1991 Add a dummy commit to make up for the instability of the above:
1991 Add a dummy commit to make up for the instability of the above:
1992
1992
1993 $ echo a > a
1993 $ echo a > a
1994 $ hg add a
1994 $ hg add a
1995 $ hg ci -m future
1995 $ hg ci -m future
1996
1996
1997 Count filter:
1997 Count filter:
1998
1998
1999 $ hg log -l1 --template '{node|count} {node|short|count}\n'
1999 $ hg log -l1 --template '{node|count} {node|short|count}\n'
2000 40 12
2000 40 12
2001
2001
2002 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2002 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2003 0 1 4
2003 0 1 4
2004
2004
2005 $ hg log -G --template '{rev}: children: {children|count}, \
2005 $ hg log -G --template '{rev}: children: {children|count}, \
2006 > tags: {tags|count}, file_adds: {file_adds|count}, \
2006 > tags: {tags|count}, file_adds: {file_adds|count}, \
2007 > ancestors: {revset("ancestors(%s)", rev)|count}'
2007 > ancestors: {revset("ancestors(%s)", rev)|count}'
2008 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2008 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2009 |
2009 |
2010 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2010 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2011 |
2011 |
2012 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2012 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2013
2013
2014 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2014 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2015 |\
2015 |\
2016 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2016 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2017 | |
2017 | |
2018 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2018 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2019 |/
2019 |/
2020 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2020 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2021 |
2021 |
2022 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2022 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2023 |
2023 |
2024 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2024 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2025 |
2025 |
2026 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2026 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2027
2027
2028
2028
2029 Upper/lower filters:
2029 Upper/lower filters:
2030
2030
2031 $ hg log -r0 --template '{branch|upper}\n'
2031 $ hg log -r0 --template '{branch|upper}\n'
2032 DEFAULT
2032 DEFAULT
2033 $ hg log -r0 --template '{author|lower}\n'
2033 $ hg log -r0 --template '{author|lower}\n'
2034 user name <user@hostname>
2034 user name <user@hostname>
2035 $ hg log -r0 --template '{date|upper}\n'
2035 $ hg log -r0 --template '{date|upper}\n'
2036 abort: template filter 'upper' is not compatible with keyword 'date'
2036 abort: template filter 'upper' is not compatible with keyword 'date'
2037 [255]
2037 [255]
2038
2038
2039 Add a commit that does all possible modifications at once
2039 Add a commit that does all possible modifications at once
2040
2040
2041 $ echo modify >> third
2041 $ echo modify >> third
2042 $ touch b
2042 $ touch b
2043 $ hg add b
2043 $ hg add b
2044 $ hg mv fourth fifth
2044 $ hg mv fourth fifth
2045 $ hg rm a
2045 $ hg rm a
2046 $ hg ci -m "Modify, add, remove, rename"
2046 $ hg ci -m "Modify, add, remove, rename"
2047
2047
2048 Check the status template
2048 Check the status template
2049
2049
2050 $ cat <<EOF >> $HGRCPATH
2050 $ cat <<EOF >> $HGRCPATH
2051 > [extensions]
2051 > [extensions]
2052 > color=
2052 > color=
2053 > EOF
2053 > EOF
2054
2054
2055 $ hg log -T status -r 10
2055 $ hg log -T status -r 10
2056 changeset: 10:0f9759ec227a
2056 changeset: 10:0f9759ec227a
2057 tag: tip
2057 tag: tip
2058 user: test
2058 user: test
2059 date: Thu Jan 01 00:00:00 1970 +0000
2059 date: Thu Jan 01 00:00:00 1970 +0000
2060 summary: Modify, add, remove, rename
2060 summary: Modify, add, remove, rename
2061 files:
2061 files:
2062 M third
2062 M third
2063 A b
2063 A b
2064 A fifth
2064 A fifth
2065 R a
2065 R a
2066 R fourth
2066 R fourth
2067
2067
2068 $ hg log -T status -C -r 10
2068 $ hg log -T status -C -r 10
2069 changeset: 10:0f9759ec227a
2069 changeset: 10:0f9759ec227a
2070 tag: tip
2070 tag: tip
2071 user: test
2071 user: test
2072 date: Thu Jan 01 00:00:00 1970 +0000
2072 date: Thu Jan 01 00:00:00 1970 +0000
2073 summary: Modify, add, remove, rename
2073 summary: Modify, add, remove, rename
2074 files:
2074 files:
2075 M third
2075 M third
2076 A b
2076 A b
2077 A fifth
2077 A fifth
2078 fourth
2078 fourth
2079 R a
2079 R a
2080 R fourth
2080 R fourth
2081
2081
2082 $ hg log -T status -C -r 10 -v
2082 $ hg log -T status -C -r 10 -v
2083 changeset: 10:0f9759ec227a
2083 changeset: 10:0f9759ec227a
2084 tag: tip
2084 tag: tip
2085 user: test
2085 user: test
2086 date: Thu Jan 01 00:00:00 1970 +0000
2086 date: Thu Jan 01 00:00:00 1970 +0000
2087 description:
2087 description:
2088 Modify, add, remove, rename
2088 Modify, add, remove, rename
2089
2089
2090 files:
2090 files:
2091 M third
2091 M third
2092 A b
2092 A b
2093 A fifth
2093 A fifth
2094 fourth
2094 fourth
2095 R a
2095 R a
2096 R fourth
2096 R fourth
2097
2097
2098 $ hg log -T status -C -r 10 --debug
2098 $ hg log -T status -C -r 10 --debug
2099 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2099 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2100 tag: tip
2100 tag: tip
2101 phase: secret
2101 phase: secret
2102 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2102 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2103 parent: -1:0000000000000000000000000000000000000000
2103 parent: -1:0000000000000000000000000000000000000000
2104 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2104 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2105 user: test
2105 user: test
2106 date: Thu Jan 01 00:00:00 1970 +0000
2106 date: Thu Jan 01 00:00:00 1970 +0000
2107 extra: branch=default
2107 extra: branch=default
2108 description:
2108 description:
2109 Modify, add, remove, rename
2109 Modify, add, remove, rename
2110
2110
2111 files:
2111 files:
2112 M third
2112 M third
2113 A b
2113 A b
2114 A fifth
2114 A fifth
2115 fourth
2115 fourth
2116 R a
2116 R a
2117 R fourth
2117 R fourth
2118
2118
2119 $ hg log -T status -C -r 10 --quiet
2119 $ hg log -T status -C -r 10 --quiet
2120 10:0f9759ec227a
2120 10:0f9759ec227a
2121 $ hg --color=debug log -T status -r 10
2121 $ hg --color=debug log -T status -r 10
2122 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2122 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2123 [log.tag|tag: tip]
2123 [log.tag|tag: tip]
2124 [log.user|user: test]
2124 [log.user|user: test]
2125 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2125 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2126 [log.summary|summary: Modify, add, remove, rename]
2126 [log.summary|summary: Modify, add, remove, rename]
2127 [ui.note log.files|files:]
2127 [ui.note log.files|files:]
2128 [status.modified|M third]
2128 [status.modified|M third]
2129 [status.added|A b]
2129 [status.added|A b]
2130 [status.added|A fifth]
2130 [status.added|A fifth]
2131 [status.removed|R a]
2131 [status.removed|R a]
2132 [status.removed|R fourth]
2132 [status.removed|R fourth]
2133
2133
2134 $ hg --color=debug log -T status -C -r 10
2134 $ hg --color=debug log -T status -C -r 10
2135 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2135 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2136 [log.tag|tag: tip]
2136 [log.tag|tag: tip]
2137 [log.user|user: test]
2137 [log.user|user: test]
2138 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2138 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2139 [log.summary|summary: Modify, add, remove, rename]
2139 [log.summary|summary: Modify, add, remove, rename]
2140 [ui.note log.files|files:]
2140 [ui.note log.files|files:]
2141 [status.modified|M third]
2141 [status.modified|M third]
2142 [status.added|A b]
2142 [status.added|A b]
2143 [status.added|A fifth]
2143 [status.added|A fifth]
2144 [status.copied| fourth]
2144 [status.copied| fourth]
2145 [status.removed|R a]
2145 [status.removed|R a]
2146 [status.removed|R fourth]
2146 [status.removed|R fourth]
2147
2147
2148 $ hg --color=debug log -T status -C -r 10 -v
2148 $ hg --color=debug log -T status -C -r 10 -v
2149 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2149 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2150 [log.tag|tag: tip]
2150 [log.tag|tag: tip]
2151 [log.user|user: test]
2151 [log.user|user: test]
2152 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2152 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2153 [ui.note log.description|description:]
2153 [ui.note log.description|description:]
2154 [ui.note log.description|Modify, add, remove, rename]
2154 [ui.note log.description|Modify, add, remove, rename]
2155
2155
2156 [ui.note log.files|files:]
2156 [ui.note log.files|files:]
2157 [status.modified|M third]
2157 [status.modified|M third]
2158 [status.added|A b]
2158 [status.added|A b]
2159 [status.added|A fifth]
2159 [status.added|A fifth]
2160 [status.copied| fourth]
2160 [status.copied| fourth]
2161 [status.removed|R a]
2161 [status.removed|R a]
2162 [status.removed|R fourth]
2162 [status.removed|R fourth]
2163
2163
2164 $ hg --color=debug log -T status -C -r 10 --debug
2164 $ hg --color=debug log -T status -C -r 10 --debug
2165 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2165 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2166 [log.tag|tag: tip]
2166 [log.tag|tag: tip]
2167 [log.phase|phase: secret]
2167 [log.phase|phase: secret]
2168 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2168 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2169 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2169 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2170 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2170 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2171 [log.user|user: test]
2171 [log.user|user: test]
2172 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2172 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2173 [ui.debug log.extra|extra: branch=default]
2173 [ui.debug log.extra|extra: branch=default]
2174 [ui.note log.description|description:]
2174 [ui.note log.description|description:]
2175 [ui.note log.description|Modify, add, remove, rename]
2175 [ui.note log.description|Modify, add, remove, rename]
2176
2176
2177 [ui.note log.files|files:]
2177 [ui.note log.files|files:]
2178 [status.modified|M third]
2178 [status.modified|M third]
2179 [status.added|A b]
2179 [status.added|A b]
2180 [status.added|A fifth]
2180 [status.added|A fifth]
2181 [status.copied| fourth]
2181 [status.copied| fourth]
2182 [status.removed|R a]
2182 [status.removed|R a]
2183 [status.removed|R fourth]
2183 [status.removed|R fourth]
2184
2184
2185 $ hg --color=debug log -T status -C -r 10 --quiet
2185 $ hg --color=debug log -T status -C -r 10 --quiet
2186 [log.node|10:0f9759ec227a]
2186 [log.node|10:0f9759ec227a]
2187
2187
2188 Check the bisect template
2188 Check the bisect template
2189
2189
2190 $ hg bisect -g 1
2190 $ hg bisect -g 1
2191 $ hg bisect -b 3 --noupdate
2191 $ hg bisect -b 3 --noupdate
2192 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2192 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2193 $ hg log -T bisect -r 0:4
2193 $ hg log -T bisect -r 0:4
2194 changeset: 0:1e4e1b8f71e0
2194 changeset: 0:1e4e1b8f71e0
2195 bisect: good (implicit)
2195 bisect: good (implicit)
2196 user: User Name <user@hostname>
2196 user: User Name <user@hostname>
2197 date: Mon Jan 12 13:46:40 1970 +0000
2197 date: Mon Jan 12 13:46:40 1970 +0000
2198 summary: line 1
2198 summary: line 1
2199
2199
2200 changeset: 1:b608e9d1a3f0
2200 changeset: 1:b608e9d1a3f0
2201 bisect: good
2201 bisect: good
2202 user: A. N. Other <other@place>
2202 user: A. N. Other <other@place>
2203 date: Tue Jan 13 17:33:20 1970 +0000
2203 date: Tue Jan 13 17:33:20 1970 +0000
2204 summary: other 1
2204 summary: other 1
2205
2205
2206 changeset: 2:97054abb4ab8
2206 changeset: 2:97054abb4ab8
2207 bisect: untested
2207 bisect: untested
2208 user: other@place
2208 user: other@place
2209 date: Wed Jan 14 21:20:00 1970 +0000
2209 date: Wed Jan 14 21:20:00 1970 +0000
2210 summary: no person
2210 summary: no person
2211
2211
2212 changeset: 3:10e46f2dcbf4
2212 changeset: 3:10e46f2dcbf4
2213 bisect: bad
2213 bisect: bad
2214 user: person
2214 user: person
2215 date: Fri Jan 16 01:06:40 1970 +0000
2215 date: Fri Jan 16 01:06:40 1970 +0000
2216 summary: no user, no domain
2216 summary: no user, no domain
2217
2217
2218 changeset: 4:bbe44766e73d
2218 changeset: 4:bbe44766e73d
2219 bisect: bad (implicit)
2219 bisect: bad (implicit)
2220 branch: foo
2220 branch: foo
2221 user: person
2221 user: person
2222 date: Sat Jan 17 04:53:20 1970 +0000
2222 date: Sat Jan 17 04:53:20 1970 +0000
2223 summary: new branch
2223 summary: new branch
2224
2224
2225 $ hg log --debug -T bisect -r 0:4
2225 $ hg log --debug -T bisect -r 0:4
2226 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2226 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2227 bisect: good (implicit)
2227 bisect: good (implicit)
2228 phase: public
2228 phase: public
2229 parent: -1:0000000000000000000000000000000000000000
2229 parent: -1:0000000000000000000000000000000000000000
2230 parent: -1:0000000000000000000000000000000000000000
2230 parent: -1:0000000000000000000000000000000000000000
2231 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2231 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2232 user: User Name <user@hostname>
2232 user: User Name <user@hostname>
2233 date: Mon Jan 12 13:46:40 1970 +0000
2233 date: Mon Jan 12 13:46:40 1970 +0000
2234 files+: a
2234 files+: a
2235 extra: branch=default
2235 extra: branch=default
2236 description:
2236 description:
2237 line 1
2237 line 1
2238 line 2
2238 line 2
2239
2239
2240
2240
2241 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2241 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2242 bisect: good
2242 bisect: good
2243 phase: public
2243 phase: public
2244 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2244 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2245 parent: -1:0000000000000000000000000000000000000000
2245 parent: -1:0000000000000000000000000000000000000000
2246 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2246 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2247 user: A. N. Other <other@place>
2247 user: A. N. Other <other@place>
2248 date: Tue Jan 13 17:33:20 1970 +0000
2248 date: Tue Jan 13 17:33:20 1970 +0000
2249 files+: b
2249 files+: b
2250 extra: branch=default
2250 extra: branch=default
2251 description:
2251 description:
2252 other 1
2252 other 1
2253 other 2
2253 other 2
2254
2254
2255 other 3
2255 other 3
2256
2256
2257
2257
2258 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2258 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2259 bisect: untested
2259 bisect: untested
2260 phase: public
2260 phase: public
2261 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2261 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2262 parent: -1:0000000000000000000000000000000000000000
2262 parent: -1:0000000000000000000000000000000000000000
2263 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2263 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2264 user: other@place
2264 user: other@place
2265 date: Wed Jan 14 21:20:00 1970 +0000
2265 date: Wed Jan 14 21:20:00 1970 +0000
2266 files+: c
2266 files+: c
2267 extra: branch=default
2267 extra: branch=default
2268 description:
2268 description:
2269 no person
2269 no person
2270
2270
2271
2271
2272 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2272 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2273 bisect: bad
2273 bisect: bad
2274 phase: public
2274 phase: public
2275 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2275 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2276 parent: -1:0000000000000000000000000000000000000000
2276 parent: -1:0000000000000000000000000000000000000000
2277 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2277 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2278 user: person
2278 user: person
2279 date: Fri Jan 16 01:06:40 1970 +0000
2279 date: Fri Jan 16 01:06:40 1970 +0000
2280 files: c
2280 files: c
2281 extra: branch=default
2281 extra: branch=default
2282 description:
2282 description:
2283 no user, no domain
2283 no user, no domain
2284
2284
2285
2285
2286 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2286 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2287 bisect: bad (implicit)
2287 bisect: bad (implicit)
2288 branch: foo
2288 branch: foo
2289 phase: draft
2289 phase: draft
2290 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2290 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2291 parent: -1:0000000000000000000000000000000000000000
2291 parent: -1:0000000000000000000000000000000000000000
2292 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2292 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2293 user: person
2293 user: person
2294 date: Sat Jan 17 04:53:20 1970 +0000
2294 date: Sat Jan 17 04:53:20 1970 +0000
2295 extra: branch=foo
2295 extra: branch=foo
2296 description:
2296 description:
2297 new branch
2297 new branch
2298
2298
2299
2299
2300 $ hg log -v -T bisect -r 0:4
2300 $ hg log -v -T bisect -r 0:4
2301 changeset: 0:1e4e1b8f71e0
2301 changeset: 0:1e4e1b8f71e0
2302 bisect: good (implicit)
2302 bisect: good (implicit)
2303 user: User Name <user@hostname>
2303 user: User Name <user@hostname>
2304 date: Mon Jan 12 13:46:40 1970 +0000
2304 date: Mon Jan 12 13:46:40 1970 +0000
2305 files: a
2305 files: a
2306 description:
2306 description:
2307 line 1
2307 line 1
2308 line 2
2308 line 2
2309
2309
2310
2310
2311 changeset: 1:b608e9d1a3f0
2311 changeset: 1:b608e9d1a3f0
2312 bisect: good
2312 bisect: good
2313 user: A. N. Other <other@place>
2313 user: A. N. Other <other@place>
2314 date: Tue Jan 13 17:33:20 1970 +0000
2314 date: Tue Jan 13 17:33:20 1970 +0000
2315 files: b
2315 files: b
2316 description:
2316 description:
2317 other 1
2317 other 1
2318 other 2
2318 other 2
2319
2319
2320 other 3
2320 other 3
2321
2321
2322
2322
2323 changeset: 2:97054abb4ab8
2323 changeset: 2:97054abb4ab8
2324 bisect: untested
2324 bisect: untested
2325 user: other@place
2325 user: other@place
2326 date: Wed Jan 14 21:20:00 1970 +0000
2326 date: Wed Jan 14 21:20:00 1970 +0000
2327 files: c
2327 files: c
2328 description:
2328 description:
2329 no person
2329 no person
2330
2330
2331
2331
2332 changeset: 3:10e46f2dcbf4
2332 changeset: 3:10e46f2dcbf4
2333 bisect: bad
2333 bisect: bad
2334 user: person
2334 user: person
2335 date: Fri Jan 16 01:06:40 1970 +0000
2335 date: Fri Jan 16 01:06:40 1970 +0000
2336 files: c
2336 files: c
2337 description:
2337 description:
2338 no user, no domain
2338 no user, no domain
2339
2339
2340
2340
2341 changeset: 4:bbe44766e73d
2341 changeset: 4:bbe44766e73d
2342 bisect: bad (implicit)
2342 bisect: bad (implicit)
2343 branch: foo
2343 branch: foo
2344 user: person
2344 user: person
2345 date: Sat Jan 17 04:53:20 1970 +0000
2345 date: Sat Jan 17 04:53:20 1970 +0000
2346 description:
2346 description:
2347 new branch
2347 new branch
2348
2348
2349
2349
2350 $ hg --color=debug log -T bisect -r 0:4
2350 $ hg --color=debug log -T bisect -r 0:4
2351 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2351 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2352 [log.bisect bisect.good|bisect: good (implicit)]
2352 [log.bisect bisect.good|bisect: good (implicit)]
2353 [log.user|user: User Name <user@hostname>]
2353 [log.user|user: User Name <user@hostname>]
2354 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2354 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2355 [log.summary|summary: line 1]
2355 [log.summary|summary: line 1]
2356
2356
2357 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2357 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2358 [log.bisect bisect.good|bisect: good]
2358 [log.bisect bisect.good|bisect: good]
2359 [log.user|user: A. N. Other <other@place>]
2359 [log.user|user: A. N. Other <other@place>]
2360 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2360 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2361 [log.summary|summary: other 1]
2361 [log.summary|summary: other 1]
2362
2362
2363 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2363 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2364 [log.bisect bisect.untested|bisect: untested]
2364 [log.bisect bisect.untested|bisect: untested]
2365 [log.user|user: other@place]
2365 [log.user|user: other@place]
2366 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2366 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2367 [log.summary|summary: no person]
2367 [log.summary|summary: no person]
2368
2368
2369 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2369 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2370 [log.bisect bisect.bad|bisect: bad]
2370 [log.bisect bisect.bad|bisect: bad]
2371 [log.user|user: person]
2371 [log.user|user: person]
2372 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2372 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2373 [log.summary|summary: no user, no domain]
2373 [log.summary|summary: no user, no domain]
2374
2374
2375 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2375 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2376 [log.bisect bisect.bad|bisect: bad (implicit)]
2376 [log.bisect bisect.bad|bisect: bad (implicit)]
2377 [log.branch|branch: foo]
2377 [log.branch|branch: foo]
2378 [log.user|user: person]
2378 [log.user|user: person]
2379 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2379 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2380 [log.summary|summary: new branch]
2380 [log.summary|summary: new branch]
2381
2381
2382 $ hg --color=debug log --debug -T bisect -r 0:4
2382 $ hg --color=debug log --debug -T bisect -r 0:4
2383 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2383 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2384 [log.bisect bisect.good|bisect: good (implicit)]
2384 [log.bisect bisect.good|bisect: good (implicit)]
2385 [log.phase|phase: public]
2385 [log.phase|phase: public]
2386 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2386 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2387 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2387 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2388 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2388 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2389 [log.user|user: User Name <user@hostname>]
2389 [log.user|user: User Name <user@hostname>]
2390 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2390 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2391 [ui.debug log.files|files+: a]
2391 [ui.debug log.files|files+: a]
2392 [ui.debug log.extra|extra: branch=default]
2392 [ui.debug log.extra|extra: branch=default]
2393 [ui.note log.description|description:]
2393 [ui.note log.description|description:]
2394 [ui.note log.description|line 1
2394 [ui.note log.description|line 1
2395 line 2]
2395 line 2]
2396
2396
2397
2397
2398 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2398 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2399 [log.bisect bisect.good|bisect: good]
2399 [log.bisect bisect.good|bisect: good]
2400 [log.phase|phase: public]
2400 [log.phase|phase: public]
2401 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2401 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2402 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2402 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2403 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2403 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2404 [log.user|user: A. N. Other <other@place>]
2404 [log.user|user: A. N. Other <other@place>]
2405 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2405 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2406 [ui.debug log.files|files+: b]
2406 [ui.debug log.files|files+: b]
2407 [ui.debug log.extra|extra: branch=default]
2407 [ui.debug log.extra|extra: branch=default]
2408 [ui.note log.description|description:]
2408 [ui.note log.description|description:]
2409 [ui.note log.description|other 1
2409 [ui.note log.description|other 1
2410 other 2
2410 other 2
2411
2411
2412 other 3]
2412 other 3]
2413
2413
2414
2414
2415 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2415 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2416 [log.bisect bisect.untested|bisect: untested]
2416 [log.bisect bisect.untested|bisect: untested]
2417 [log.phase|phase: public]
2417 [log.phase|phase: public]
2418 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2418 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2419 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2419 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2420 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2420 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2421 [log.user|user: other@place]
2421 [log.user|user: other@place]
2422 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2422 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2423 [ui.debug log.files|files+: c]
2423 [ui.debug log.files|files+: c]
2424 [ui.debug log.extra|extra: branch=default]
2424 [ui.debug log.extra|extra: branch=default]
2425 [ui.note log.description|description:]
2425 [ui.note log.description|description:]
2426 [ui.note log.description|no person]
2426 [ui.note log.description|no person]
2427
2427
2428
2428
2429 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2429 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2430 [log.bisect bisect.bad|bisect: bad]
2430 [log.bisect bisect.bad|bisect: bad]
2431 [log.phase|phase: public]
2431 [log.phase|phase: public]
2432 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2432 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2433 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2433 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2434 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2434 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2435 [log.user|user: person]
2435 [log.user|user: person]
2436 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2436 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2437 [ui.debug log.files|files: c]
2437 [ui.debug log.files|files: c]
2438 [ui.debug log.extra|extra: branch=default]
2438 [ui.debug log.extra|extra: branch=default]
2439 [ui.note log.description|description:]
2439 [ui.note log.description|description:]
2440 [ui.note log.description|no user, no domain]
2440 [ui.note log.description|no user, no domain]
2441
2441
2442
2442
2443 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2443 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2444 [log.bisect bisect.bad|bisect: bad (implicit)]
2444 [log.bisect bisect.bad|bisect: bad (implicit)]
2445 [log.branch|branch: foo]
2445 [log.branch|branch: foo]
2446 [log.phase|phase: draft]
2446 [log.phase|phase: draft]
2447 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2447 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2448 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2448 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2449 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2449 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2450 [log.user|user: person]
2450 [log.user|user: person]
2451 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2451 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2452 [ui.debug log.extra|extra: branch=foo]
2452 [ui.debug log.extra|extra: branch=foo]
2453 [ui.note log.description|description:]
2453 [ui.note log.description|description:]
2454 [ui.note log.description|new branch]
2454 [ui.note log.description|new branch]
2455
2455
2456
2456
2457 $ hg --color=debug log -v -T bisect -r 0:4
2457 $ hg --color=debug log -v -T bisect -r 0:4
2458 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2458 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2459 [log.bisect bisect.good|bisect: good (implicit)]
2459 [log.bisect bisect.good|bisect: good (implicit)]
2460 [log.user|user: User Name <user@hostname>]
2460 [log.user|user: User Name <user@hostname>]
2461 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2461 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2462 [ui.note log.files|files: a]
2462 [ui.note log.files|files: a]
2463 [ui.note log.description|description:]
2463 [ui.note log.description|description:]
2464 [ui.note log.description|line 1
2464 [ui.note log.description|line 1
2465 line 2]
2465 line 2]
2466
2466
2467
2467
2468 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2468 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2469 [log.bisect bisect.good|bisect: good]
2469 [log.bisect bisect.good|bisect: good]
2470 [log.user|user: A. N. Other <other@place>]
2470 [log.user|user: A. N. Other <other@place>]
2471 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2471 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2472 [ui.note log.files|files: b]
2472 [ui.note log.files|files: b]
2473 [ui.note log.description|description:]
2473 [ui.note log.description|description:]
2474 [ui.note log.description|other 1
2474 [ui.note log.description|other 1
2475 other 2
2475 other 2
2476
2476
2477 other 3]
2477 other 3]
2478
2478
2479
2479
2480 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2480 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2481 [log.bisect bisect.untested|bisect: untested]
2481 [log.bisect bisect.untested|bisect: untested]
2482 [log.user|user: other@place]
2482 [log.user|user: other@place]
2483 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2483 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2484 [ui.note log.files|files: c]
2484 [ui.note log.files|files: c]
2485 [ui.note log.description|description:]
2485 [ui.note log.description|description:]
2486 [ui.note log.description|no person]
2486 [ui.note log.description|no person]
2487
2487
2488
2488
2489 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2489 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2490 [log.bisect bisect.bad|bisect: bad]
2490 [log.bisect bisect.bad|bisect: bad]
2491 [log.user|user: person]
2491 [log.user|user: person]
2492 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2492 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2493 [ui.note log.files|files: c]
2493 [ui.note log.files|files: c]
2494 [ui.note log.description|description:]
2494 [ui.note log.description|description:]
2495 [ui.note log.description|no user, no domain]
2495 [ui.note log.description|no user, no domain]
2496
2496
2497
2497
2498 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2498 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2499 [log.bisect bisect.bad|bisect: bad (implicit)]
2499 [log.bisect bisect.bad|bisect: bad (implicit)]
2500 [log.branch|branch: foo]
2500 [log.branch|branch: foo]
2501 [log.user|user: person]
2501 [log.user|user: person]
2502 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2502 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2503 [ui.note log.description|description:]
2503 [ui.note log.description|description:]
2504 [ui.note log.description|new branch]
2504 [ui.note log.description|new branch]
2505
2505
2506
2506
2507 $ hg bisect --reset
2507 $ hg bisect --reset
2508
2508
2509 Error on syntax:
2509 Error on syntax:
2510
2510
2511 $ echo 'x = "f' >> t
2511 $ echo 'x = "f' >> t
2512 $ hg log
2512 $ hg log
2513 hg: parse error at t:3: unmatched quotes
2513 hg: parse error at t:3: unmatched quotes
2514 [255]
2514 [255]
2515
2515
2516 $ hg log -T '{date'
2516 $ hg log -T '{date'
2517 hg: parse error at 1: unterminated template expansion
2517 hg: parse error at 1: unterminated template expansion
2518 [255]
2518 [255]
2519
2519
2520 Behind the scenes, this will throw TypeError
2520 Behind the scenes, this will throw TypeError
2521
2521
2522 $ hg log -l 3 --template '{date|obfuscate}\n'
2522 $ hg log -l 3 --template '{date|obfuscate}\n'
2523 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2523 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2524 [255]
2524 [255]
2525
2525
2526 Behind the scenes, this will throw a ValueError
2526 Behind the scenes, this will throw a ValueError
2527
2527
2528 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2528 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2529 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2529 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2530 [255]
2530 [255]
2531
2531
2532 Behind the scenes, this will throw AttributeError
2532 Behind the scenes, this will throw AttributeError
2533
2533
2534 $ hg log -l 3 --template 'line: {date|escape}\n'
2534 $ hg log -l 3 --template 'line: {date|escape}\n'
2535 abort: template filter 'escape' is not compatible with keyword 'date'
2535 abort: template filter 'escape' is not compatible with keyword 'date'
2536 [255]
2536 [255]
2537
2537
2538 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2538 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2539 hg: parse error: localdate expects a date information
2539 hg: parse error: localdate expects a date information
2540 [255]
2540 [255]
2541
2541
2542 Behind the scenes, this will throw ValueError
2542 Behind the scenes, this will throw ValueError
2543
2543
2544 $ hg tip --template '{author|email|date}\n'
2544 $ hg tip --template '{author|email|date}\n'
2545 hg: parse error: date expects a date information
2545 hg: parse error: date expects a date information
2546 [255]
2546 [255]
2547
2547
2548 Error in nested template:
2548 Error in nested template:
2549
2549
2550 $ hg log -T '{"date'
2550 $ hg log -T '{"date'
2551 hg: parse error at 2: unterminated string
2551 hg: parse error at 2: unterminated string
2552 [255]
2552 [255]
2553
2553
2554 $ hg log -T '{"foo{date|=}"}'
2554 $ hg log -T '{"foo{date|=}"}'
2555 hg: parse error at 11: syntax error
2555 hg: parse error at 11: syntax error
2556 [255]
2556 [255]
2557
2557
2558 Thrown an error if a template function doesn't exist
2558 Thrown an error if a template function doesn't exist
2559
2559
2560 $ hg tip --template '{foo()}\n'
2560 $ hg tip --template '{foo()}\n'
2561 hg: parse error: unknown function 'foo'
2561 hg: parse error: unknown function 'foo'
2562 [255]
2562 [255]
2563
2563
2564 Pass generator object created by template function to filter
2564 Pass generator object created by template function to filter
2565
2565
2566 $ hg log -l 1 --template '{if(author, author)|user}\n'
2566 $ hg log -l 1 --template '{if(author, author)|user}\n'
2567 test
2567 test
2568
2568
2569 Test diff function:
2569 Test diff function:
2570
2570
2571 $ hg diff -c 8
2571 $ hg diff -c 8
2572 diff -r 29114dbae42b -r 95c24699272e fourth
2572 diff -r 29114dbae42b -r 95c24699272e fourth
2573 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2573 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2574 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2574 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2575 @@ -0,0 +1,1 @@
2575 @@ -0,0 +1,1 @@
2576 +second
2576 +second
2577 diff -r 29114dbae42b -r 95c24699272e second
2577 diff -r 29114dbae42b -r 95c24699272e second
2578 --- a/second Mon Jan 12 13:46:40 1970 +0000
2578 --- a/second Mon Jan 12 13:46:40 1970 +0000
2579 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2579 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2580 @@ -1,1 +0,0 @@
2580 @@ -1,1 +0,0 @@
2581 -second
2581 -second
2582 diff -r 29114dbae42b -r 95c24699272e third
2582 diff -r 29114dbae42b -r 95c24699272e third
2583 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2583 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2584 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2584 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2585 @@ -0,0 +1,1 @@
2585 @@ -0,0 +1,1 @@
2586 +third
2586 +third
2587
2587
2588 $ hg log -r 8 -T "{diff()}"
2588 $ hg log -r 8 -T "{diff()}"
2589 diff -r 29114dbae42b -r 95c24699272e fourth
2589 diff -r 29114dbae42b -r 95c24699272e fourth
2590 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2590 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2591 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2591 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2592 @@ -0,0 +1,1 @@
2592 @@ -0,0 +1,1 @@
2593 +second
2593 +second
2594 diff -r 29114dbae42b -r 95c24699272e second
2594 diff -r 29114dbae42b -r 95c24699272e second
2595 --- a/second Mon Jan 12 13:46:40 1970 +0000
2595 --- a/second Mon Jan 12 13:46:40 1970 +0000
2596 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2596 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2597 @@ -1,1 +0,0 @@
2597 @@ -1,1 +0,0 @@
2598 -second
2598 -second
2599 diff -r 29114dbae42b -r 95c24699272e third
2599 diff -r 29114dbae42b -r 95c24699272e third
2600 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2600 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2601 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2601 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2602 @@ -0,0 +1,1 @@
2602 @@ -0,0 +1,1 @@
2603 +third
2603 +third
2604
2604
2605 $ hg log -r 8 -T "{diff('glob:f*')}"
2605 $ hg log -r 8 -T "{diff('glob:f*')}"
2606 diff -r 29114dbae42b -r 95c24699272e fourth
2606 diff -r 29114dbae42b -r 95c24699272e fourth
2607 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2607 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2608 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2608 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2609 @@ -0,0 +1,1 @@
2609 @@ -0,0 +1,1 @@
2610 +second
2610 +second
2611
2611
2612 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2612 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2613 diff -r 29114dbae42b -r 95c24699272e second
2613 diff -r 29114dbae42b -r 95c24699272e second
2614 --- a/second Mon Jan 12 13:46:40 1970 +0000
2614 --- a/second Mon Jan 12 13:46:40 1970 +0000
2615 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2615 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2616 @@ -1,1 +0,0 @@
2616 @@ -1,1 +0,0 @@
2617 -second
2617 -second
2618 diff -r 29114dbae42b -r 95c24699272e third
2618 diff -r 29114dbae42b -r 95c24699272e third
2619 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2619 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2620 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2620 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2621 @@ -0,0 +1,1 @@
2621 @@ -0,0 +1,1 @@
2622 +third
2622 +third
2623
2623
2624 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2624 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2625 diff -r 29114dbae42b -r 95c24699272e fourth
2625 diff -r 29114dbae42b -r 95c24699272e fourth
2626 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2626 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2627 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2627 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2628 @@ -0,0 +1,1 @@
2628 @@ -0,0 +1,1 @@
2629 +second
2629 +second
2630
2630
2631 $ cd ..
2631 $ cd ..
2632
2632
2633
2633
2634 latesttag:
2634 latesttag:
2635
2635
2636 $ hg init latesttag
2636 $ hg init latesttag
2637 $ cd latesttag
2637 $ cd latesttag
2638
2638
2639 $ echo a > file
2639 $ echo a > file
2640 $ hg ci -Am a -d '0 0'
2640 $ hg ci -Am a -d '0 0'
2641 adding file
2641 adding file
2642
2642
2643 $ echo b >> file
2643 $ echo b >> file
2644 $ hg ci -m b -d '1 0'
2644 $ hg ci -m b -d '1 0'
2645
2645
2646 $ echo c >> head1
2646 $ echo c >> head1
2647 $ hg ci -Am h1c -d '2 0'
2647 $ hg ci -Am h1c -d '2 0'
2648 adding head1
2648 adding head1
2649
2649
2650 $ hg update -q 1
2650 $ hg update -q 1
2651 $ echo d >> head2
2651 $ echo d >> head2
2652 $ hg ci -Am h2d -d '3 0'
2652 $ hg ci -Am h2d -d '3 0'
2653 adding head2
2653 adding head2
2654 created new head
2654 created new head
2655
2655
2656 $ echo e >> head2
2656 $ echo e >> head2
2657 $ hg ci -m h2e -d '4 0'
2657 $ hg ci -m h2e -d '4 0'
2658
2658
2659 $ hg merge -q
2659 $ hg merge -q
2660 $ hg ci -m merge -d '5 -3600'
2660 $ hg ci -m merge -d '5 -3600'
2661
2661
2662 No tag set:
2662 No tag set:
2663
2663
2664 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2664 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2665 5: null+5
2665 5: null+5
2666 4: null+4
2666 4: null+4
2667 3: null+3
2667 3: null+3
2668 2: null+3
2668 2: null+3
2669 1: null+2
2669 1: null+2
2670 0: null+1
2670 0: null+1
2671
2671
2672 One common tag: longest path wins:
2672 One common tag: longest path wins:
2673
2673
2674 $ hg tag -r 1 -m t1 -d '6 0' t1
2674 $ hg tag -r 1 -m t1 -d '6 0' t1
2675 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2675 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2676 6: t1+4
2676 6: t1+4
2677 5: t1+3
2677 5: t1+3
2678 4: t1+2
2678 4: t1+2
2679 3: t1+1
2679 3: t1+1
2680 2: t1+1
2680 2: t1+1
2681 1: t1+0
2681 1: t1+0
2682 0: null+1
2682 0: null+1
2683
2683
2684 One ancestor tag: more recent wins:
2684 One ancestor tag: more recent wins:
2685
2685
2686 $ hg tag -r 2 -m t2 -d '7 0' t2
2686 $ hg tag -r 2 -m t2 -d '7 0' t2
2687 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2687 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2688 7: t2+3
2688 7: t2+3
2689 6: t2+2
2689 6: t2+2
2690 5: t2+1
2690 5: t2+1
2691 4: t1+2
2691 4: t1+2
2692 3: t1+1
2692 3: t1+1
2693 2: t2+0
2693 2: t2+0
2694 1: t1+0
2694 1: t1+0
2695 0: null+1
2695 0: null+1
2696
2696
2697 Two branch tags: more recent wins:
2697 Two branch tags: more recent wins:
2698
2698
2699 $ hg tag -r 3 -m t3 -d '8 0' t3
2699 $ hg tag -r 3 -m t3 -d '8 0' t3
2700 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2700 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2701 8: t3+5
2701 8: t3+5
2702 7: t3+4
2702 7: t3+4
2703 6: t3+3
2703 6: t3+3
2704 5: t3+2
2704 5: t3+2
2705 4: t3+1
2705 4: t3+1
2706 3: t3+0
2706 3: t3+0
2707 2: t2+0
2707 2: t2+0
2708 1: t1+0
2708 1: t1+0
2709 0: null+1
2709 0: null+1
2710
2710
2711 Merged tag overrides:
2711 Merged tag overrides:
2712
2712
2713 $ hg tag -r 5 -m t5 -d '9 0' t5
2713 $ hg tag -r 5 -m t5 -d '9 0' t5
2714 $ hg tag -r 3 -m at3 -d '10 0' at3
2714 $ hg tag -r 3 -m at3 -d '10 0' at3
2715 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2715 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2716 10: t5+5
2716 10: t5+5
2717 9: t5+4
2717 9: t5+4
2718 8: t5+3
2718 8: t5+3
2719 7: t5+2
2719 7: t5+2
2720 6: t5+1
2720 6: t5+1
2721 5: t5+0
2721 5: t5+0
2722 4: at3:t3+1
2722 4: at3:t3+1
2723 3: at3:t3+0
2723 3: at3:t3+0
2724 2: t2+0
2724 2: t2+0
2725 1: t1+0
2725 1: t1+0
2726 0: null+1
2726 0: null+1
2727
2727
2728 $ hg log --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
2728 $ hg log --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
2729 10: t5+5,5
2729 10: t5+5,5
2730 9: t5+4,4
2730 9: t5+4,4
2731 8: t5+3,3
2731 8: t5+3,3
2732 7: t5+2,2
2732 7: t5+2,2
2733 6: t5+1,1
2733 6: t5+1,1
2734 5: t5+0,0
2734 5: t5+0,0
2735 4: at3+1,1 t3+1,1
2735 4: at3+1,1 t3+1,1
2736 3: at3+0,0 t3+0,0
2736 3: at3+0,0 t3+0,0
2737 2: t2+0,0
2737 2: t2+0,0
2738 1: t1+0,0
2738 1: t1+0,0
2739 0: null+1,1
2739 0: null+1,1
2740
2740
2741 $ hg log --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
2741 $ hg log --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
2742 10: t3, C: 8, D: 7
2742 10: t3, C: 8, D: 7
2743 9: t3, C: 7, D: 6
2743 9: t3, C: 7, D: 6
2744 8: t3, C: 6, D: 5
2744 8: t3, C: 6, D: 5
2745 7: t3, C: 5, D: 4
2745 7: t3, C: 5, D: 4
2746 6: t3, C: 4, D: 3
2746 6: t3, C: 4, D: 3
2747 5: t3, C: 3, D: 2
2747 5: t3, C: 3, D: 2
2748 4: t3, C: 1, D: 1
2748 4: t3, C: 1, D: 1
2749 3: t3, C: 0, D: 0
2749 3: t3, C: 0, D: 0
2750 2: t1, C: 1, D: 1
2750 2: t1, C: 1, D: 1
2751 1: t1, C: 0, D: 0
2751 1: t1, C: 0, D: 0
2752 0: null, C: 1, D: 1
2752 0: null, C: 1, D: 1
2753
2753
2754 $ cd ..
2754 $ cd ..
2755
2755
2756
2756
2757 Style path expansion: issue1948 - ui.style option doesn't work on OSX
2757 Style path expansion: issue1948 - ui.style option doesn't work on OSX
2758 if it is a relative path
2758 if it is a relative path
2759
2759
2760 $ mkdir -p home/styles
2760 $ mkdir -p home/styles
2761
2761
2762 $ cat > home/styles/teststyle <<EOF
2762 $ cat > home/styles/teststyle <<EOF
2763 > changeset = 'test {rev}:{node|short}\n'
2763 > changeset = 'test {rev}:{node|short}\n'
2764 > EOF
2764 > EOF
2765
2765
2766 $ HOME=`pwd`/home; export HOME
2766 $ HOME=`pwd`/home; export HOME
2767
2767
2768 $ cat > latesttag/.hg/hgrc <<EOF
2768 $ cat > latesttag/.hg/hgrc <<EOF
2769 > [ui]
2769 > [ui]
2770 > style = ~/styles/teststyle
2770 > style = ~/styles/teststyle
2771 > EOF
2771 > EOF
2772
2772
2773 $ hg -R latesttag tip
2773 $ hg -R latesttag tip
2774 test 10:9b4a630e5f5f
2774 test 10:9b4a630e5f5f
2775
2775
2776 Test recursive showlist template (issue1989):
2776 Test recursive showlist template (issue1989):
2777
2777
2778 $ cat > style1989 <<EOF
2778 $ cat > style1989 <<EOF
2779 > changeset = '{file_mods}{manifest}{extras}'
2779 > changeset = '{file_mods}{manifest}{extras}'
2780 > file_mod = 'M|{author|person}\n'
2780 > file_mod = 'M|{author|person}\n'
2781 > manifest = '{rev},{author}\n'
2781 > manifest = '{rev},{author}\n'
2782 > extra = '{key}: {author}\n'
2782 > extra = '{key}: {author}\n'
2783 > EOF
2783 > EOF
2784
2784
2785 $ hg -R latesttag log -r tip --style=style1989
2785 $ hg -R latesttag log -r tip --style=style1989
2786 M|test
2786 M|test
2787 10,test
2787 10,test
2788 branch: test
2788 branch: test
2789
2789
2790 Test new-style inline templating:
2790 Test new-style inline templating:
2791
2791
2792 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
2792 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
2793 modified files: .hgtags
2793 modified files: .hgtags
2794
2794
2795
2795
2796 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
2796 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
2797 hg: parse error: keyword 'rev' is not iterable
2797 hg: parse error: keyword 'rev' is not iterable
2798 [255]
2798 [255]
2799 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
2799 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
2800 hg: parse error: None is not iterable
2800 hg: parse error: None is not iterable
2801 [255]
2801 [255]
2802
2802
2803 Test the sub function of templating for expansion:
2803 Test the sub function of templating for expansion:
2804
2804
2805 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
2805 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
2806 xx
2806 xx
2807
2807
2808 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
2808 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
2809 hg: parse error: sub got an invalid pattern: [
2809 hg: parse error: sub got an invalid pattern: [
2810 [255]
2810 [255]
2811 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
2811 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
2812 hg: parse error: sub got an invalid replacement: \1
2812 hg: parse error: sub got an invalid replacement: \1
2813 [255]
2813 [255]
2814
2814
2815 Test the strip function with chars specified:
2815 Test the strip function with chars specified:
2816
2816
2817 $ hg log -R latesttag --template '{desc}\n'
2817 $ hg log -R latesttag --template '{desc}\n'
2818 at3
2818 at3
2819 t5
2819 t5
2820 t3
2820 t3
2821 t2
2821 t2
2822 t1
2822 t1
2823 merge
2823 merge
2824 h2e
2824 h2e
2825 h2d
2825 h2d
2826 h1c
2826 h1c
2827 b
2827 b
2828 a
2828 a
2829
2829
2830 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
2830 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
2831 at3
2831 at3
2832 5
2832 5
2833 3
2833 3
2834 2
2834 2
2835 1
2835 1
2836 merg
2836 merg
2837 h2
2837 h2
2838 h2d
2838 h2d
2839 h1c
2839 h1c
2840 b
2840 b
2841 a
2841 a
2842
2842
2843 Test date format:
2843 Test date format:
2844
2844
2845 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
2845 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
2846 date: 70 01 01 10 +0000
2846 date: 70 01 01 10 +0000
2847 date: 70 01 01 09 +0000
2847 date: 70 01 01 09 +0000
2848 date: 70 01 01 08 +0000
2848 date: 70 01 01 08 +0000
2849 date: 70 01 01 07 +0000
2849 date: 70 01 01 07 +0000
2850 date: 70 01 01 06 +0000
2850 date: 70 01 01 06 +0000
2851 date: 70 01 01 05 +0100
2851 date: 70 01 01 05 +0100
2852 date: 70 01 01 04 +0000
2852 date: 70 01 01 04 +0000
2853 date: 70 01 01 03 +0000
2853 date: 70 01 01 03 +0000
2854 date: 70 01 01 02 +0000
2854 date: 70 01 01 02 +0000
2855 date: 70 01 01 01 +0000
2855 date: 70 01 01 01 +0000
2856 date: 70 01 01 00 +0000
2856 date: 70 01 01 00 +0000
2857
2857
2858 Test invalid date:
2858 Test invalid date:
2859
2859
2860 $ hg log -R latesttag -T '{date(rev)}\n'
2860 $ hg log -R latesttag -T '{date(rev)}\n'
2861 hg: parse error: date expects a date information
2861 hg: parse error: date expects a date information
2862 [255]
2862 [255]
2863
2863
2864 Test integer literal:
2864 Test integer literal:
2865
2865
2866 $ hg debugtemplate -v '{(0)}\n'
2866 $ hg debugtemplate -v '{(0)}\n'
2867 (template
2867 (template
2868 (group
2868 (group
2869 ('integer', '0'))
2869 ('integer', '0'))
2870 ('string', '\n'))
2870 ('string', '\n'))
2871 0
2871 0
2872 $ hg debugtemplate -v '{(123)}\n'
2872 $ hg debugtemplate -v '{(123)}\n'
2873 (template
2873 (template
2874 (group
2874 (group
2875 ('integer', '123'))
2875 ('integer', '123'))
2876 ('string', '\n'))
2876 ('string', '\n'))
2877 123
2877 123
2878 $ hg debugtemplate -v '{(-4)}\n'
2878 $ hg debugtemplate -v '{(-4)}\n'
2879 (template
2879 (template
2880 (group
2880 (group
2881 ('integer', '-4'))
2881 ('integer', '-4'))
2882 ('string', '\n'))
2882 ('string', '\n'))
2883 -4
2883 -4
2884 $ hg debugtemplate '{(-)}\n'
2884 $ hg debugtemplate '{(-)}\n'
2885 hg: parse error at 2: integer literal without digits
2885 hg: parse error at 2: integer literal without digits
2886 [255]
2886 [255]
2887 $ hg debugtemplate '{(-a)}\n'
2887 $ hg debugtemplate '{(-a)}\n'
2888 hg: parse error at 2: integer literal without digits
2888 hg: parse error at 2: integer literal without digits
2889 [255]
2889 [255]
2890
2890
2891 top-level integer literal is interpreted as symbol (i.e. variable name):
2891 top-level integer literal is interpreted as symbol (i.e. variable name):
2892
2892
2893 $ hg debugtemplate -D 1=one -v '{1}\n'
2893 $ hg debugtemplate -D 1=one -v '{1}\n'
2894 (template
2894 (template
2895 ('integer', '1')
2895 ('integer', '1')
2896 ('string', '\n'))
2896 ('string', '\n'))
2897 one
2897 one
2898 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
2898 $ hg debugtemplate -D 1=one -v '{if("t", "{1}")}\n'
2899 (template
2899 (template
2900 (func
2900 (func
2901 ('symbol', 'if')
2901 ('symbol', 'if')
2902 (list
2902 (list
2903 ('string', 't')
2903 ('string', 't')
2904 (template
2904 (template
2905 ('integer', '1'))))
2905 ('integer', '1'))))
2906 ('string', '\n'))
2906 ('string', '\n'))
2907 one
2907 one
2908 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
2908 $ hg debugtemplate -D 1=one -v '{1|stringify}\n'
2909 (template
2909 (template
2910 (|
2910 (|
2911 ('integer', '1')
2911 ('integer', '1')
2912 ('symbol', 'stringify'))
2912 ('symbol', 'stringify'))
2913 ('string', '\n'))
2913 ('string', '\n'))
2914 one
2914 one
2915
2915
2916 unless explicit symbol is expected:
2916 unless explicit symbol is expected:
2917
2917
2918 $ hg log -Ra -r0 -T '{desc|1}\n'
2918 $ hg log -Ra -r0 -T '{desc|1}\n'
2919 hg: parse error: expected a symbol, got 'integer'
2919 hg: parse error: expected a symbol, got 'integer'
2920 [255]
2920 [255]
2921 $ hg log -Ra -r0 -T '{1()}\n'
2921 $ hg log -Ra -r0 -T '{1()}\n'
2922 hg: parse error: expected a symbol, got 'integer'
2922 hg: parse error: expected a symbol, got 'integer'
2923 [255]
2923 [255]
2924
2924
2925 Test string literal:
2925 Test string literal:
2926
2926
2927 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
2927 $ hg debugtemplate -Ra -r0 -v '{"string with no template fragment"}\n'
2928 (template
2928 (template
2929 ('string', 'string with no template fragment')
2929 ('string', 'string with no template fragment')
2930 ('string', '\n'))
2930 ('string', '\n'))
2931 string with no template fragment
2931 string with no template fragment
2932 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
2932 $ hg debugtemplate -Ra -r0 -v '{"template: {rev}"}\n'
2933 (template
2933 (template
2934 (template
2934 (template
2935 ('string', 'template: ')
2935 ('string', 'template: ')
2936 ('symbol', 'rev'))
2936 ('symbol', 'rev'))
2937 ('string', '\n'))
2937 ('string', '\n'))
2938 template: 0
2938 template: 0
2939 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
2939 $ hg debugtemplate -Ra -r0 -v '{r"rawstring: {rev}"}\n'
2940 (template
2940 (template
2941 ('string', 'rawstring: {rev}')
2941 ('string', 'rawstring: {rev}')
2942 ('string', '\n'))
2942 ('string', '\n'))
2943 rawstring: {rev}
2943 rawstring: {rev}
2944 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
2944 $ hg debugtemplate -Ra -r0 -v '{files % r"rawstring: {file}"}\n'
2945 (template
2945 (template
2946 (%
2946 (%
2947 ('symbol', 'files')
2947 ('symbol', 'files')
2948 ('string', 'rawstring: {file}'))
2948 ('string', 'rawstring: {file}'))
2949 ('string', '\n'))
2949 ('string', '\n'))
2950 rawstring: {file}
2950 rawstring: {file}
2951
2951
2952 Test string escaping:
2952 Test string escaping:
2953
2953
2954 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2954 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2955 >
2955 >
2956 <>\n<[>
2956 <>\n<[>
2957 <>\n<]>
2957 <>\n<]>
2958 <>\n<
2958 <>\n<
2959
2959
2960 $ hg log -R latesttag -r 0 \
2960 $ hg log -R latesttag -r 0 \
2961 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2961 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2962 >
2962 >
2963 <>\n<[>
2963 <>\n<[>
2964 <>\n<]>
2964 <>\n<]>
2965 <>\n<
2965 <>\n<
2966
2966
2967 $ hg log -R latesttag -r 0 -T esc \
2967 $ hg log -R latesttag -r 0 -T esc \
2968 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2968 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2969 >
2969 >
2970 <>\n<[>
2970 <>\n<[>
2971 <>\n<]>
2971 <>\n<]>
2972 <>\n<
2972 <>\n<
2973
2973
2974 $ cat <<'EOF' > esctmpl
2974 $ cat <<'EOF' > esctmpl
2975 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2975 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2976 > EOF
2976 > EOF
2977 $ hg log -R latesttag -r 0 --style ./esctmpl
2977 $ hg log -R latesttag -r 0 --style ./esctmpl
2978 >
2978 >
2979 <>\n<[>
2979 <>\n<[>
2980 <>\n<]>
2980 <>\n<]>
2981 <>\n<
2981 <>\n<
2982
2982
2983 Test string escaping of quotes:
2983 Test string escaping of quotes:
2984
2984
2985 $ hg log -Ra -r0 -T '{"\""}\n'
2985 $ hg log -Ra -r0 -T '{"\""}\n'
2986 "
2986 "
2987 $ hg log -Ra -r0 -T '{"\\\""}\n'
2987 $ hg log -Ra -r0 -T '{"\\\""}\n'
2988 \"
2988 \"
2989 $ hg log -Ra -r0 -T '{r"\""}\n'
2989 $ hg log -Ra -r0 -T '{r"\""}\n'
2990 \"
2990 \"
2991 $ hg log -Ra -r0 -T '{r"\\\""}\n'
2991 $ hg log -Ra -r0 -T '{r"\\\""}\n'
2992 \\\"
2992 \\\"
2993
2993
2994
2994
2995 $ hg log -Ra -r0 -T '{"\""}\n'
2995 $ hg log -Ra -r0 -T '{"\""}\n'
2996 "
2996 "
2997 $ hg log -Ra -r0 -T '{"\\\""}\n'
2997 $ hg log -Ra -r0 -T '{"\\\""}\n'
2998 \"
2998 \"
2999 $ hg log -Ra -r0 -T '{r"\""}\n'
2999 $ hg log -Ra -r0 -T '{r"\""}\n'
3000 \"
3000 \"
3001 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3001 $ hg log -Ra -r0 -T '{r"\\\""}\n'
3002 \\\"
3002 \\\"
3003
3003
3004 Test exception in quoted template. single backslash before quotation mark is
3004 Test exception in quoted template. single backslash before quotation mark is
3005 stripped before parsing:
3005 stripped before parsing:
3006
3006
3007 $ cat <<'EOF' > escquotetmpl
3007 $ cat <<'EOF' > escquotetmpl
3008 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3008 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
3009 > EOF
3009 > EOF
3010 $ cd latesttag
3010 $ cd latesttag
3011 $ hg log -r 2 --style ../escquotetmpl
3011 $ hg log -r 2 --style ../escquotetmpl
3012 " \" \" \\" head1
3012 " \" \" \\" head1
3013
3013
3014 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3014 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
3015 valid
3015 valid
3016 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3016 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
3017 valid
3017 valid
3018
3018
3019 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3019 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
3020 _evalifliteral() templates (issue4733):
3020 _evalifliteral() templates (issue4733):
3021
3021
3022 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3022 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
3023 "2
3023 "2
3024 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3024 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
3025 "2
3025 "2
3026 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3026 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
3027 "2
3027 "2
3028
3028
3029 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3029 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
3030 \"
3030 \"
3031 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3031 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
3032 \"
3032 \"
3033 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3033 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3034 \"
3034 \"
3035
3035
3036 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3036 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
3037 \\\"
3037 \\\"
3038 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3038 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
3039 \\\"
3039 \\\"
3040 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3040 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
3041 \\\"
3041 \\\"
3042
3042
3043 escaped single quotes and errors:
3043 escaped single quotes and errors:
3044
3044
3045 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3045 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3046 foo
3046 foo
3047 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3047 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3048 foo
3048 foo
3049 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3049 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3050 hg: parse error at 21: unterminated string
3050 hg: parse error at 21: unterminated string
3051 [255]
3051 [255]
3052 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3052 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3053 hg: parse error: trailing \ in string
3053 hg: parse error: trailing \ in string
3054 [255]
3054 [255]
3055 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3055 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3056 hg: parse error: trailing \ in string
3056 hg: parse error: trailing \ in string
3057 [255]
3057 [255]
3058
3058
3059 $ cd ..
3059 $ cd ..
3060
3060
3061 Test leading backslashes:
3061 Test leading backslashes:
3062
3062
3063 $ cd latesttag
3063 $ cd latesttag
3064 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3064 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3065 {rev} {file}
3065 {rev} {file}
3066 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3066 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3067 \2 \head1
3067 \2 \head1
3068 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3068 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3069 \{rev} \{file}
3069 \{rev} \{file}
3070 $ cd ..
3070 $ cd ..
3071
3071
3072 Test leading backslashes in "if" expression (issue4714):
3072 Test leading backslashes in "if" expression (issue4714):
3073
3073
3074 $ cd latesttag
3074 $ cd latesttag
3075 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3075 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3076 {rev} \{rev}
3076 {rev} \{rev}
3077 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3077 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3078 \2 \\{rev}
3078 \2 \\{rev}
3079 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3079 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3080 \{rev} \\\{rev}
3080 \{rev} \\\{rev}
3081 $ cd ..
3081 $ cd ..
3082
3082
3083 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3083 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3084
3084
3085 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3085 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3086 \x6e
3086 \x6e
3087 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3087 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3088 \x5c\x786e
3088 \x5c\x786e
3089 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3089 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3090 \x6e
3090 \x6e
3091 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3091 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3092 \x5c\x786e
3092 \x5c\x786e
3093
3093
3094 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3094 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3095 \x6e
3095 \x6e
3096 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3096 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3097 \x5c\x786e
3097 \x5c\x786e
3098 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3098 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3099 \x6e
3099 \x6e
3100 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3100 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3101 \x5c\x786e
3101 \x5c\x786e
3102
3102
3103 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3103 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3104 fourth
3104 fourth
3105 second
3105 second
3106 third
3106 third
3107 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3107 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3108 fourth\nsecond\nthird
3108 fourth\nsecond\nthird
3109
3109
3110 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3110 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3111 <p>
3111 <p>
3112 1st
3112 1st
3113 </p>
3113 </p>
3114 <p>
3114 <p>
3115 2nd
3115 2nd
3116 </p>
3116 </p>
3117 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3117 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3118 <p>
3118 <p>
3119 1st\n\n2nd
3119 1st\n\n2nd
3120 </p>
3120 </p>
3121 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3121 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3122 1st
3122 1st
3123
3123
3124 2nd
3124 2nd
3125
3125
3126 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3126 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3127 o perso
3127 o perso
3128 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3128 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3129 no person
3129 no person
3130 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3130 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3131 o perso
3131 o perso
3132 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3132 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3133 no perso
3133 no perso
3134
3134
3135 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3135 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3136 -o perso-
3136 -o perso-
3137 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3137 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3138 no person
3138 no person
3139 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3139 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3140 \x2do perso\x2d
3140 \x2do perso\x2d
3141 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3141 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3142 -o perso-
3142 -o perso-
3143 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3143 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3144 \x2do perso\x6e
3144 \x2do perso\x6e
3145
3145
3146 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3146 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3147 fourth
3147 fourth
3148 second
3148 second
3149 third
3149 third
3150
3150
3151 Test string escaping in nested expression:
3151 Test string escaping in nested expression:
3152
3152
3153 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3153 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3154 fourth\x6esecond\x6ethird
3154 fourth\x6esecond\x6ethird
3155 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3155 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3156 fourth\x6esecond\x6ethird
3156 fourth\x6esecond\x6ethird
3157
3157
3158 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3158 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3159 fourth\x6esecond\x6ethird
3159 fourth\x6esecond\x6ethird
3160 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3160 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3161 fourth\x5c\x786esecond\x5c\x786ethird
3161 fourth\x5c\x786esecond\x5c\x786ethird
3162
3162
3163 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3163 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3164 3:\x6eo user, \x6eo domai\x6e
3164 3:\x6eo user, \x6eo domai\x6e
3165 4:\x5c\x786eew bra\x5c\x786ech
3165 4:\x5c\x786eew bra\x5c\x786ech
3166
3166
3167 Test quotes in nested expression are evaluated just like a $(command)
3167 Test quotes in nested expression are evaluated just like a $(command)
3168 substitution in POSIX shells:
3168 substitution in POSIX shells:
3169
3169
3170 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3170 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3171 8:95c24699272e
3171 8:95c24699272e
3172 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3172 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3173 {8} "95c24699272e"
3173 {8} "95c24699272e"
3174
3174
3175 Test recursive evaluation:
3175 Test recursive evaluation:
3176
3176
3177 $ hg init r
3177 $ hg init r
3178 $ cd r
3178 $ cd r
3179 $ echo a > a
3179 $ echo a > a
3180 $ hg ci -Am '{rev}'
3180 $ hg ci -Am '{rev}'
3181 adding a
3181 adding a
3182 $ hg log -r 0 --template '{if(rev, desc)}\n'
3182 $ hg log -r 0 --template '{if(rev, desc)}\n'
3183 {rev}
3183 {rev}
3184 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3184 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3185 test 0
3185 test 0
3186
3186
3187 $ hg branch -q 'text.{rev}'
3187 $ hg branch -q 'text.{rev}'
3188 $ echo aa >> aa
3188 $ echo aa >> aa
3189 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3189 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3190
3190
3191 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3191 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3192 {node|short}desc to
3192 {node|short}desc to
3193 text.{rev}be wrapped
3193 text.{rev}be wrapped
3194 text.{rev}desc to be
3194 text.{rev}desc to be
3195 text.{rev}wrapped (no-eol)
3195 text.{rev}wrapped (no-eol)
3196 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3196 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3197 bcc7ff960b8e:desc to
3197 bcc7ff960b8e:desc to
3198 text.1:be wrapped
3198 text.1:be wrapped
3199 text.1:desc to be
3199 text.1:desc to be
3200 text.1:wrapped (no-eol)
3200 text.1:wrapped (no-eol)
3201 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3201 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3202 hg: parse error: fill expects an integer width
3202 hg: parse error: fill expects an integer width
3203 [255]
3203 [255]
3204
3204
3205 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3205 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3206 {node|short} (no-eol)
3206 {node|short} (no-eol)
3207 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3207 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3208 bcc-ff---b-e (no-eol)
3208 bcc-ff---b-e (no-eol)
3209
3209
3210 $ cat >> .hg/hgrc <<EOF
3210 $ cat >> .hg/hgrc <<EOF
3211 > [extensions]
3211 > [extensions]
3212 > color=
3212 > color=
3213 > [color]
3213 > [color]
3214 > mode=ansi
3214 > mode=ansi
3215 > text.{rev} = red
3215 > text.{rev} = red
3216 > text.1 = green
3216 > text.1 = green
3217 > EOF
3217 > EOF
3218 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3218 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3219 \x1b[0;31mtext\x1b[0m (esc)
3219 \x1b[0;31mtext\x1b[0m (esc)
3220 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3220 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3221 \x1b[0;32mtext\x1b[0m (esc)
3221 \x1b[0;32mtext\x1b[0m (esc)
3222
3222
3223 color effect can be specified without quoting:
3223 color effect can be specified without quoting:
3224
3224
3225 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3225 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3226 \x1b[0;31mtext\x1b[0m (esc)
3226 \x1b[0;31mtext\x1b[0m (esc)
3227
3227
3228 label should be no-op if color is disabled:
3228 label should be no-op if color is disabled:
3229
3229
3230 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3230 $ hg log --color=never -l 1 --template '{label(red, "text\n")}'
3231 text
3231 text
3232 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3232 $ hg log --config extensions.color=! -l 1 --template '{label(red, "text\n")}'
3233 text
3233 text
3234
3234
3235 Test branches inside if statement:
3235 Test branches inside if statement:
3236
3236
3237 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3237 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3238 no
3238 no
3239
3239
3240 Test get function:
3240 Test get function:
3241
3241
3242 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3242 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3243 default
3243 default
3244 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3244 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3245 default
3245 default
3246 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3246 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3247 hg: parse error: get() expects a dict as first argument
3247 hg: parse error: get() expects a dict as first argument
3248 [255]
3248 [255]
3249
3249
3250 Test localdate(date, tz) function:
3250 Test localdate(date, tz) function:
3251
3251
3252 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3252 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3253 1970-01-01 09:00 +0900
3253 1970-01-01 09:00 +0900
3254 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3254 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3255 1970-01-01 00:00 +0000
3255 1970-01-01 00:00 +0000
3256 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3256 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3257 1970-01-01 02:00 +0200
3257 1970-01-01 02:00 +0200
3258 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3258 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3259 1970-01-01 00:00 +0000
3259 1970-01-01 00:00 +0000
3260 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3260 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3261 1970-01-01 00:00 +0000
3261 1970-01-01 00:00 +0000
3262 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3262 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3263 hg: parse error: localdate expects a timezone
3263 hg: parse error: localdate expects a timezone
3264 [255]
3264 [255]
3265 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3265 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3266 hg: parse error: localdate expects a timezone
3266 hg: parse error: localdate expects a timezone
3267 [255]
3267 [255]
3268
3268
3269 Test shortest(node) function:
3269 Test shortest(node) function:
3270
3270
3271 $ echo b > b
3271 $ echo b > b
3272 $ hg ci -qAm b
3272 $ hg ci -qAm b
3273 $ hg log --template '{shortest(node)}\n'
3273 $ hg log --template '{shortest(node)}\n'
3274 e777
3274 e777
3275 bcc7
3275 bcc7
3276 f776
3276 f776
3277 $ hg log --template '{shortest(node, 10)}\n'
3277 $ hg log --template '{shortest(node, 10)}\n'
3278 e777603221
3278 e777603221
3279 bcc7ff960b
3279 bcc7ff960b
3280 f7769ec2ab
3280 f7769ec2ab
3281 $ hg log --template '{node|shortest}\n' -l1
3281 $ hg log --template '{node|shortest}\n' -l1
3282 e777
3282 e777
3283
3283
3284 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3284 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3285 f7769ec2ab
3285 f7769ec2ab
3286 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3286 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3287 hg: parse error: shortest() expects an integer minlength
3287 hg: parse error: shortest() expects an integer minlength
3288 [255]
3288 [255]
3289
3289
3290 Test pad function
3290 Test pad function
3291
3291
3292 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3292 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3293 2 test
3293 2 test
3294 1 {node|short}
3294 1 {node|short}
3295 0 test
3295 0 test
3296
3296
3297 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3297 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3298 2 test
3298 2 test
3299 1 {node|short}
3299 1 {node|short}
3300 0 test
3300 0 test
3301
3301
3302 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3302 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3303 2------------------- test
3303 2------------------- test
3304 1------------------- {node|short}
3304 1------------------- {node|short}
3305 0------------------- test
3305 0------------------- test
3306
3306
3307 Test template string in pad function
3307 Test template string in pad function
3308
3308
3309 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3309 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3310 {0} test
3310 {0} test
3311
3311
3312 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3312 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3313 \{rev} test
3313 \{rev} test
3314
3314
3315 Test width argument passed to pad function
3315 Test width argument passed to pad function
3316
3316
3317 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
3317 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
3318 0 test
3318 0 test
3319 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
3319 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
3320 hg: parse error: pad() expects an integer width
3320 hg: parse error: pad() expects an integer width
3321 [255]
3321 [255]
3322
3322
3323 Test ifcontains function
3323 Test ifcontains function
3324
3324
3325 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3325 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3326 2 is in the string
3326 2 is in the string
3327 1 is not
3327 1 is not
3328 0 is in the string
3328 0 is in the string
3329
3329
3330 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
3330 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
3331 2 is in the string
3331 2 is in the string
3332 1 is not
3332 1 is not
3333 0 is in the string
3333 0 is in the string
3334
3334
3335 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3335 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3336 2 did not add a
3336 2 did not add a
3337 1 did not add a
3337 1 did not add a
3338 0 added a
3338 0 added a
3339
3339
3340 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
3340 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
3341 2 is parent of 1
3341 2 is parent of 1
3342 1
3342 1
3343 0
3343 0
3344
3344
3345 Test revset function
3345 Test revset function
3346
3346
3347 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3347 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3348 2 current rev
3348 2 current rev
3349 1 not current rev
3349 1 not current rev
3350 0 not current rev
3350 0 not current rev
3351
3351
3352 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
3352 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
3353 2 match rev
3353 2 match rev
3354 1 match rev
3354 1 match rev
3355 0 not match rev
3355 0 not match rev
3356
3356
3357 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
3357 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
3358 2 Parents: 1
3358 2 Parents: 1
3359 1 Parents: 0
3359 1 Parents: 0
3360 0 Parents:
3360 0 Parents:
3361
3361
3362 $ cat >> .hg/hgrc <<EOF
3362 $ cat >> .hg/hgrc <<EOF
3363 > [revsetalias]
3363 > [revsetalias]
3364 > myparents(\$1) = parents(\$1)
3364 > myparents(\$1) = parents(\$1)
3365 > EOF
3365 > EOF
3366 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
3366 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
3367 2 Parents: 1
3367 2 Parents: 1
3368 1 Parents: 0
3368 1 Parents: 0
3369 0 Parents:
3369 0 Parents:
3370
3370
3371 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
3371 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
3372 Rev: 2
3372 Rev: 2
3373 Ancestor: 0
3373 Ancestor: 0
3374 Ancestor: 1
3374 Ancestor: 1
3375 Ancestor: 2
3375 Ancestor: 2
3376
3376
3377 Rev: 1
3377 Rev: 1
3378 Ancestor: 0
3378 Ancestor: 0
3379 Ancestor: 1
3379 Ancestor: 1
3380
3380
3381 Rev: 0
3381 Rev: 0
3382 Ancestor: 0
3382 Ancestor: 0
3383
3383
3384 $ hg log --template '{revset("TIP"|lower)}\n' -l1
3384 $ hg log --template '{revset("TIP"|lower)}\n' -l1
3385 2
3385 2
3386
3386
3387 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
3387 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
3388 2
3388 2
3389
3389
3390 a list template is evaluated for each item of revset/parents
3390 a list template is evaluated for each item of revset/parents
3391
3391
3392 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
3392 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
3393 2 p: 1:bcc7ff960b8e
3393 2 p: 1:bcc7ff960b8e
3394 1 p: 0:f7769ec2ab97
3394 1 p: 0:f7769ec2ab97
3395 0 p:
3395 0 p:
3396
3396
3397 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
3397 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
3398 2 p: 1:bcc7ff960b8e -1:000000000000
3398 2 p: 1:bcc7ff960b8e -1:000000000000
3399 1 p: 0:f7769ec2ab97 -1:000000000000
3399 1 p: 0:f7769ec2ab97 -1:000000000000
3400 0 p: -1:000000000000 -1:000000000000
3400 0 p: -1:000000000000 -1:000000000000
3401
3401
3402 therefore, 'revcache' should be recreated for each rev
3402 therefore, 'revcache' should be recreated for each rev
3403
3403
3404 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
3404 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
3405 2 aa b
3405 2 aa b
3406 p
3406 p
3407 1
3407 1
3408 p a
3408 p a
3409 0 a
3409 0 a
3410 p
3410 p
3411
3411
3412 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
3412 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
3413 2 aa b
3413 2 aa b
3414 p
3414 p
3415 1
3415 1
3416 p a
3416 p a
3417 0 a
3417 0 a
3418 p
3418 p
3419
3419
3420 a revset item must be evaluated as an integer revision, not an offset from tip
3420 a revset item must be evaluated as an integer revision, not an offset from tip
3421
3421
3422 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
3422 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
3423 -1:000000000000
3423 -1:000000000000
3424 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
3424 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
3425 -1:000000000000
3425 -1:000000000000
3426
3426
3427 Test active bookmark templating
3427 Test active bookmark templating
3428
3428
3429 $ hg book foo
3429 $ hg book foo
3430 $ hg book bar
3430 $ hg book bar
3431 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
3431 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
3432 2 bar* foo
3432 2 bar* foo
3433 1
3433 1
3434 0
3434 0
3435 $ hg log --template "{rev} {activebookmark}\n"
3435 $ hg log --template "{rev} {activebookmark}\n"
3436 2 bar
3436 2 bar
3437 1
3437 1
3438 0
3438 0
3439 $ hg bookmarks --inactive bar
3439 $ hg bookmarks --inactive bar
3440 $ hg log --template "{rev} {activebookmark}\n"
3440 $ hg log --template "{rev} {activebookmark}\n"
3441 2
3441 2
3442 1
3442 1
3443 0
3443 0
3444 $ hg book -r1 baz
3444 $ hg book -r1 baz
3445 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
3445 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
3446 2 bar foo
3446 2 bar foo
3447 1 baz
3447 1 baz
3448 0
3448 0
3449 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
3449 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
3450 2 t
3450 2 t
3451 1 f
3451 1 f
3452 0 f
3452 0 f
3453
3453
3454 Test namespaces dict
3454 Test namespaces dict
3455
3455
3456 $ hg log -T '{rev}{namespaces % " {namespace}={join(names, ",")}"}\n'
3456 $ hg log -T '{rev}{namespaces % " {namespace}={join(names, ",")}"}\n'
3457 2 bookmarks=bar,foo tags=tip branches=text.{rev}
3457 2 bookmarks=bar,foo tags=tip branches=text.{rev}
3458 1 bookmarks=baz tags= branches=text.{rev}
3458 1 bookmarks=baz tags= branches=text.{rev}
3459 0 bookmarks= tags= branches=default
3459 0 bookmarks= tags= branches=default
3460 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
3460 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
3461 bookmarks: bar foo
3461 bookmarks: bar foo
3462 tags: tip
3462 tags: tip
3463 branches: text.{rev}
3463 branches: text.{rev}
3464 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
3464 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
3465 bookmarks:
3465 bookmarks:
3466 bar
3466 bar
3467 foo
3467 foo
3468 tags:
3468 tags:
3469 tip
3469 tip
3470 branches:
3470 branches:
3471 text.{rev}
3471 text.{rev}
3472 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
3472 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
3473 bar
3473 bar
3474 foo
3474 foo
3475
3475
3476 Test stringify on sub expressions
3476 Test stringify on sub expressions
3477
3477
3478 $ cd ..
3478 $ cd ..
3479 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
3479 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
3480 fourth, second, third
3480 fourth, second, third
3481 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
3481 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
3482 abc
3482 abc
3483
3483
3484 Test splitlines
3484 Test splitlines
3485
3485
3486 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
3486 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
3487 @ foo Modify, add, remove, rename
3487 @ foo Modify, add, remove, rename
3488 |
3488 |
3489 o foo future
3489 o foo future
3490 |
3490 |
3491 o foo third
3491 o foo third
3492 |
3492 |
3493 o foo second
3493 o foo second
3494
3494
3495 o foo merge
3495 o foo merge
3496 |\
3496 |\
3497 | o foo new head
3497 | o foo new head
3498 | |
3498 | |
3499 o | foo new branch
3499 o | foo new branch
3500 |/
3500 |/
3501 o foo no user, no domain
3501 o foo no user, no domain
3502 |
3502 |
3503 o foo no person
3503 o foo no person
3504 |
3504 |
3505 o foo other 1
3505 o foo other 1
3506 | foo other 2
3506 | foo other 2
3507 | foo
3507 | foo
3508 | foo other 3
3508 | foo other 3
3509 o foo line 1
3509 o foo line 1
3510 foo line 2
3510 foo line 2
3511
3511
3512 Test startswith
3512 Test startswith
3513 $ hg log -Gv -R a --template "{startswith(desc)}"
3513 $ hg log -Gv -R a --template "{startswith(desc)}"
3514 hg: parse error: startswith expects two arguments
3514 hg: parse error: startswith expects two arguments
3515 [255]
3515 [255]
3516
3516
3517 $ hg log -Gv -R a --template "{startswith('line', desc)}"
3517 $ hg log -Gv -R a --template "{startswith('line', desc)}"
3518 @
3518 @
3519 |
3519 |
3520 o
3520 o
3521 |
3521 |
3522 o
3522 o
3523 |
3523 |
3524 o
3524 o
3525
3525
3526 o
3526 o
3527 |\
3527 |\
3528 | o
3528 | o
3529 | |
3529 | |
3530 o |
3530 o |
3531 |/
3531 |/
3532 o
3532 o
3533 |
3533 |
3534 o
3534 o
3535 |
3535 |
3536 o
3536 o
3537 |
3537 |
3538 o line 1
3538 o line 1
3539 line 2
3539 line 2
3540
3540
3541 Test bad template with better error message
3541 Test bad template with better error message
3542
3542
3543 $ hg log -Gv -R a --template '{desc|user()}'
3543 $ hg log -Gv -R a --template '{desc|user()}'
3544 hg: parse error: expected a symbol, got 'func'
3544 hg: parse error: expected a symbol, got 'func'
3545 [255]
3545 [255]
3546
3546
3547 Test word function (including index out of bounds graceful failure)
3547 Test word function (including index out of bounds graceful failure)
3548
3548
3549 $ hg log -Gv -R a --template "{word('1', desc)}"
3549 $ hg log -Gv -R a --template "{word('1', desc)}"
3550 @ add,
3550 @ add,
3551 |
3551 |
3552 o
3552 o
3553 |
3553 |
3554 o
3554 o
3555 |
3555 |
3556 o
3556 o
3557
3557
3558 o
3558 o
3559 |\
3559 |\
3560 | o head
3560 | o head
3561 | |
3561 | |
3562 o | branch
3562 o | branch
3563 |/
3563 |/
3564 o user,
3564 o user,
3565 |
3565 |
3566 o person
3566 o person
3567 |
3567 |
3568 o 1
3568 o 1
3569 |
3569 |
3570 o 1
3570 o 1
3571
3571
3572
3572
3573 Test word third parameter used as splitter
3573 Test word third parameter used as splitter
3574
3574
3575 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
3575 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
3576 @ M
3576 @ M
3577 |
3577 |
3578 o future
3578 o future
3579 |
3579 |
3580 o third
3580 o third
3581 |
3581 |
3582 o sec
3582 o sec
3583
3583
3584 o merge
3584 o merge
3585 |\
3585 |\
3586 | o new head
3586 | o new head
3587 | |
3587 | |
3588 o | new branch
3588 o | new branch
3589 |/
3589 |/
3590 o n
3590 o n
3591 |
3591 |
3592 o n
3592 o n
3593 |
3593 |
3594 o
3594 o
3595 |
3595 |
3596 o line 1
3596 o line 1
3597 line 2
3597 line 2
3598
3598
3599 Test word error messages for not enough and too many arguments
3599 Test word error messages for not enough and too many arguments
3600
3600
3601 $ hg log -Gv -R a --template "{word('0')}"
3601 $ hg log -Gv -R a --template "{word('0')}"
3602 hg: parse error: word expects two or three arguments, got 1
3602 hg: parse error: word expects two or three arguments, got 1
3603 [255]
3603 [255]
3604
3604
3605 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
3605 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
3606 hg: parse error: word expects two or three arguments, got 7
3606 hg: parse error: word expects two or three arguments, got 7
3607 [255]
3607 [255]
3608
3608
3609 Test word for integer literal
3609 Test word for integer literal
3610
3610
3611 $ hg log -R a --template "{word(2, desc)}\n" -r0
3611 $ hg log -R a --template "{word(2, desc)}\n" -r0
3612 line
3612 line
3613
3613
3614 Test word for invalid numbers
3614 Test word for invalid numbers
3615
3615
3616 $ hg log -Gv -R a --template "{word('a', desc)}"
3616 $ hg log -Gv -R a --template "{word('a', desc)}"
3617 hg: parse error: word expects an integer index
3617 hg: parse error: word expects an integer index
3618 [255]
3618 [255]
3619
3619
3620 Test word for out of range
3620 Test word for out of range
3621
3621
3622 $ hg log -R a --template "{word(10000, desc)}"
3622 $ hg log -R a --template "{word(10000, desc)}"
3623 $ hg log -R a --template "{word(-10000, desc)}"
3623 $ hg log -R a --template "{word(-10000, desc)}"
3624
3624
3625 Test indent and not adding to empty lines
3625 Test indent and not adding to empty lines
3626
3626
3627 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
3627 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
3628 -----
3628 -----
3629 > line 1
3629 > line 1
3630 >> line 2
3630 >> line 2
3631 -----
3631 -----
3632 > other 1
3632 > other 1
3633 >> other 2
3633 >> other 2
3634
3634
3635 >> other 3
3635 >> other 3
3636
3636
3637 Test with non-strings like dates
3637 Test with non-strings like dates
3638
3638
3639 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
3639 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
3640 1200000.00
3640 1200000.00
3641 1300000.00
3641 1300000.00
3642
3642
3643 Test broken string escapes:
3643 Test broken string escapes:
3644
3644
3645 $ hg log -T "bogus\\" -R a
3645 $ hg log -T "bogus\\" -R a
3646 hg: parse error: trailing \ in string
3646 hg: parse error: trailing \ in string
3647 [255]
3647 [255]
3648 $ hg log -T "\\xy" -R a
3648 $ hg log -T "\\xy" -R a
3649 hg: parse error: invalid \x escape
3649 hg: parse error: invalid \x escape
3650 [255]
3650 [255]
3651
3651
3652 json filter should escape HTML tags so that the output can be embedded in hgweb:
3652 json filter should escape HTML tags so that the output can be embedded in hgweb:
3653
3653
3654 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
3654 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
3655 "\u003cfoo@example.org\u003e"
3655 "\u003cfoo@example.org\u003e"
3656
3656
3657 Templater supports aliases of symbol and func() styles:
3658
3659 $ hg clone -q a aliases
3660 $ cd aliases
3661 $ cat <<EOF >> .hg/hgrc
3662 > [templatealias]
3663 > r = rev
3664 > rn = "{r}:{node|short}"
3665 > status(c, files) = files % "{c} {file}\n"
3666 > utcdate(d) = localdate(d, "UTC")
3667 > EOF
3668
3669 $ hg debugtemplate -vr0 '{rn} {utcdate(date)|isodate}\n'
3670 (template
3671 ('symbol', 'rn')
3672 ('string', ' ')
3673 (|
3674 (func
3675 ('symbol', 'utcdate')
3676 ('symbol', 'date'))
3677 ('symbol', 'isodate'))
3678 ('string', '\n'))
3679 * expanded:
3680 (template
3681 (template
3682 ('symbol', 'rev')
3683 ('string', ':')
3684 (|
3685 ('symbol', 'node')
3686 ('symbol', 'short')))
3687 ('string', ' ')
3688 (|
3689 (func
3690 ('symbol', 'localdate')
3691 (list
3692 ('symbol', 'date')
3693 ('string', 'UTC')))
3694 ('symbol', 'isodate'))
3695 ('string', '\n'))
3696 hg: parse error: unknown function 'utcdate'
3697 [255]
3698
3699 $ hg debugtemplate -vr0 '{status("A", file_adds)}'
3700 (template
3701 (func
3702 ('symbol', 'status')
3703 (list
3704 ('string', 'A')
3705 ('symbol', 'file_adds'))))
3706 * expanded:
3707 (template
3708 (%
3709 ('symbol', 'file_adds')
3710 (template
3711 ('string', 'A')
3712 ('string', ' ')
3713 ('symbol', 'file')
3714 ('string', '\n'))))
3715 hg: parse error: unknown function 'status'
3716 [255]
3717
3718 A unary function alias can be called as a filter:
3719
3720 $ hg debugtemplate -vr0 '{date|utcdate|isodate}\n'
3721 (template
3722 (|
3723 (|
3724 ('symbol', 'date')
3725 ('symbol', 'utcdate'))
3726 ('symbol', 'isodate'))
3727 ('string', '\n'))
3728 * expanded:
3729 (template
3730 (|
3731 (func
3732 ('symbol', 'localdate')
3733 (list
3734 ('symbol', 'date')
3735 ('string', 'UTC')))
3736 ('symbol', 'isodate'))
3737 ('string', '\n'))
3738 hg: parse error: unknown function 'utcdate'
3739 [255]
3740
3741 Unparsable alias:
3742
3743 $ hg debugtemplate --config templatealias.bad='x(' -v '{bad}'
3744 (template
3745 ('symbol', 'bad'))
3746 abort: failed to parse the definition of template alias "bad": at 2: not a prefix: end
3747 [255]
3748
3749 $ cd ..
3750
3657 Set up repository for non-ascii encoding tests:
3751 Set up repository for non-ascii encoding tests:
3658
3752
3659 $ hg init nonascii
3753 $ hg init nonascii
3660 $ cd nonascii
3754 $ cd nonascii
3661 $ python <<EOF
3755 $ python <<EOF
3662 > open('latin1', 'w').write('\xe9')
3756 > open('latin1', 'w').write('\xe9')
3663 > open('utf-8', 'w').write('\xc3\xa9')
3757 > open('utf-8', 'w').write('\xc3\xa9')
3664 > EOF
3758 > EOF
3665 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
3759 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
3666 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
3760 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
3667
3761
3668 json filter should try round-trip conversion to utf-8:
3762 json filter should try round-trip conversion to utf-8:
3669
3763
3670 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
3764 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
3671 "\u00e9"
3765 "\u00e9"
3672 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
3766 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
3673 "non-ascii branch: \u00e9"
3767 "non-ascii branch: \u00e9"
3674
3768
3675 json filter takes input as utf-8b:
3769 json filter takes input as utf-8b:
3676
3770
3677 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
3771 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
3678 "\u00e9"
3772 "\u00e9"
3679 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
3773 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
3680 "\udce9"
3774 "\udce9"
3681
3775
3682 utf8 filter:
3776 utf8 filter:
3683
3777
3684 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
3778 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
3685 round-trip: c3a9
3779 round-trip: c3a9
3686 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
3780 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
3687 decoded: c3a9
3781 decoded: c3a9
3688 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
3782 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
3689 abort: decoding near * (glob)
3783 abort: decoding near * (glob)
3690 [255]
3784 [255]
3691 $ hg log -T "invalid type: {rev|utf8}\n" -r0
3785 $ hg log -T "invalid type: {rev|utf8}\n" -r0
3692 abort: template filter 'utf8' is not compatible with keyword 'rev'
3786 abort: template filter 'utf8' is not compatible with keyword 'rev'
3693 [255]
3787 [255]
3694
3788
3695 $ cd ..
3789 $ cd ..
3696
3790
3697 Test that template function in extension is registered as expected
3791 Test that template function in extension is registered as expected
3698
3792
3699 $ cd a
3793 $ cd a
3700
3794
3701 $ cat <<EOF > $TESTTMP/customfunc.py
3795 $ cat <<EOF > $TESTTMP/customfunc.py
3702 > from mercurial import registrar
3796 > from mercurial import registrar
3703 >
3797 >
3704 > templatefunc = registrar.templatefunc()
3798 > templatefunc = registrar.templatefunc()
3705 >
3799 >
3706 > @templatefunc('custom()')
3800 > @templatefunc('custom()')
3707 > def custom(context, mapping, args):
3801 > def custom(context, mapping, args):
3708 > return 'custom'
3802 > return 'custom'
3709 > EOF
3803 > EOF
3710 $ cat <<EOF > .hg/hgrc
3804 $ cat <<EOF > .hg/hgrc
3711 > [extensions]
3805 > [extensions]
3712 > customfunc = $TESTTMP/customfunc.py
3806 > customfunc = $TESTTMP/customfunc.py
3713 > EOF
3807 > EOF
3714
3808
3715 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
3809 $ hg log -r . -T "{custom()}\n" --config customfunc.enabled=true
3716 custom
3810 custom
3717
3811
3718 $ cd ..
3812 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now