##// END OF EJS Templates
debugrevspec: show expanded/concatenated states before printing trees...
Yuya Nishihara -
r28629:d6f8a153 default
parent child Browse files
Show More
@@ -1,7197 +1,7197 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import 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 base:
1402 if base:
1403 if dest:
1403 if dest:
1404 raise error.Abort(_("--base is incompatible with specifying "
1404 raise error.Abort(_("--base is incompatible with specifying "
1405 "a destination"))
1405 "a destination"))
1406 common = [repo.lookup(rev) for rev in base]
1406 common = [repo.lookup(rev) for rev in base]
1407 heads = revs and map(repo.lookup, revs) or revs
1407 heads = revs and map(repo.lookup, revs) or revs
1408 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1408 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1409 common=common, bundlecaps=bundlecaps,
1409 common=common, bundlecaps=bundlecaps,
1410 version=cgversion)
1410 version=cgversion)
1411 outgoing = None
1411 outgoing = None
1412 else:
1412 else:
1413 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1413 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1414 dest, branches = hg.parseurl(dest, opts.get('branch'))
1414 dest, branches = hg.parseurl(dest, opts.get('branch'))
1415 other = hg.peer(repo, opts, dest)
1415 other = hg.peer(repo, opts, dest)
1416 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1416 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1417 heads = revs and map(repo.lookup, revs) or revs
1417 heads = revs and map(repo.lookup, revs) or revs
1418 outgoing = discovery.findcommonoutgoing(repo, other,
1418 outgoing = discovery.findcommonoutgoing(repo, other,
1419 onlyheads=heads,
1419 onlyheads=heads,
1420 force=opts.get('force'),
1420 force=opts.get('force'),
1421 portable=True)
1421 portable=True)
1422 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1422 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1423 bundlecaps, version=cgversion)
1423 bundlecaps, version=cgversion)
1424 if not cg:
1424 if not cg:
1425 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1425 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1426 return 1
1426 return 1
1427
1427
1428 if cgversion == '01': #bundle1
1428 if cgversion == '01': #bundle1
1429 if bcompression is None:
1429 if bcompression is None:
1430 bcompression = 'UN'
1430 bcompression = 'UN'
1431 bversion = 'HG10' + bcompression
1431 bversion = 'HG10' + bcompression
1432 bcompression = None
1432 bcompression = None
1433 else:
1433 else:
1434 assert cgversion == '02'
1434 assert cgversion == '02'
1435 bversion = 'HG20'
1435 bversion = 'HG20'
1436
1436
1437
1437
1438 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1438 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1439
1439
1440 @command('cat',
1440 @command('cat',
1441 [('o', 'output', '',
1441 [('o', 'output', '',
1442 _('print output to file with formatted name'), _('FORMAT')),
1442 _('print output to file with formatted name'), _('FORMAT')),
1443 ('r', 'rev', '', _('print the given revision'), _('REV')),
1443 ('r', 'rev', '', _('print the given revision'), _('REV')),
1444 ('', 'decode', None, _('apply any matching decode filter')),
1444 ('', 'decode', None, _('apply any matching decode filter')),
1445 ] + walkopts,
1445 ] + walkopts,
1446 _('[OPTION]... FILE...'),
1446 _('[OPTION]... FILE...'),
1447 inferrepo=True)
1447 inferrepo=True)
1448 def cat(ui, repo, file1, *pats, **opts):
1448 def cat(ui, repo, file1, *pats, **opts):
1449 """output the current or given revision of files
1449 """output the current or given revision of files
1450
1450
1451 Print the specified files as they were at the given revision. If
1451 Print the specified files as they were at the given revision. If
1452 no revision is given, the parent of the working directory is used.
1452 no revision is given, the parent of the working directory is used.
1453
1453
1454 Output may be to a file, in which case the name of the file is
1454 Output may be to a file, in which case the name of the file is
1455 given using a format string. The formatting rules as follows:
1455 given using a format string. The formatting rules as follows:
1456
1456
1457 :``%%``: literal "%" character
1457 :``%%``: literal "%" character
1458 :``%s``: basename of file being printed
1458 :``%s``: basename of file being printed
1459 :``%d``: dirname of file being printed, or '.' if in repository root
1459 :``%d``: dirname of file being printed, or '.' if in repository root
1460 :``%p``: root-relative path name of file being printed
1460 :``%p``: root-relative path name of file being printed
1461 :``%H``: changeset hash (40 hexadecimal digits)
1461 :``%H``: changeset hash (40 hexadecimal digits)
1462 :``%R``: changeset revision number
1462 :``%R``: changeset revision number
1463 :``%h``: short-form changeset hash (12 hexadecimal digits)
1463 :``%h``: short-form changeset hash (12 hexadecimal digits)
1464 :``%r``: zero-padded changeset revision number
1464 :``%r``: zero-padded changeset revision number
1465 :``%b``: basename of the exporting repository
1465 :``%b``: basename of the exporting repository
1466
1466
1467 Returns 0 on success.
1467 Returns 0 on success.
1468 """
1468 """
1469 ctx = scmutil.revsingle(repo, opts.get('rev'))
1469 ctx = scmutil.revsingle(repo, opts.get('rev'))
1470 m = scmutil.match(ctx, (file1,) + pats, opts)
1470 m = scmutil.match(ctx, (file1,) + pats, opts)
1471
1471
1472 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1472 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1473
1473
1474 @command('^clone',
1474 @command('^clone',
1475 [('U', 'noupdate', None, _('the clone will include an empty working '
1475 [('U', 'noupdate', None, _('the clone will include an empty working '
1476 'directory (only a repository)')),
1476 'directory (only a repository)')),
1477 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1477 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1478 _('REV')),
1478 _('REV')),
1479 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1479 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1480 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1480 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1481 ('', 'pull', None, _('use pull protocol to copy metadata')),
1481 ('', 'pull', None, _('use pull protocol to copy metadata')),
1482 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1482 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1483 ] + remoteopts,
1483 ] + remoteopts,
1484 _('[OPTION]... SOURCE [DEST]'),
1484 _('[OPTION]... SOURCE [DEST]'),
1485 norepo=True)
1485 norepo=True)
1486 def clone(ui, source, dest=None, **opts):
1486 def clone(ui, source, dest=None, **opts):
1487 """make a copy of an existing repository
1487 """make a copy of an existing repository
1488
1488
1489 Create a copy of an existing repository in a new directory.
1489 Create a copy of an existing repository in a new directory.
1490
1490
1491 If no destination directory name is specified, it defaults to the
1491 If no destination directory name is specified, it defaults to the
1492 basename of the source.
1492 basename of the source.
1493
1493
1494 The location of the source is added to the new repository's
1494 The location of the source is added to the new repository's
1495 ``.hg/hgrc`` file, as the default to be used for future pulls.
1495 ``.hg/hgrc`` file, as the default to be used for future pulls.
1496
1496
1497 Only local paths and ``ssh://`` URLs are supported as
1497 Only local paths and ``ssh://`` URLs are supported as
1498 destinations. For ``ssh://`` destinations, no working directory or
1498 destinations. For ``ssh://`` destinations, no working directory or
1499 ``.hg/hgrc`` will be created on the remote side.
1499 ``.hg/hgrc`` will be created on the remote side.
1500
1500
1501 If the source repository has a bookmark called '@' set, that
1501 If the source repository has a bookmark called '@' set, that
1502 revision will be checked out in the new repository by default.
1502 revision will be checked out in the new repository by default.
1503
1503
1504 To check out a particular version, use -u/--update, or
1504 To check out a particular version, use -u/--update, or
1505 -U/--noupdate to create a clone with no working directory.
1505 -U/--noupdate to create a clone with no working directory.
1506
1506
1507 To pull only a subset of changesets, specify one or more revisions
1507 To pull only a subset of changesets, specify one or more revisions
1508 identifiers with -r/--rev or branches with -b/--branch. The
1508 identifiers with -r/--rev or branches with -b/--branch. The
1509 resulting clone will contain only the specified changesets and
1509 resulting clone will contain only the specified changesets and
1510 their ancestors. These options (or 'clone src#rev dest') imply
1510 their ancestors. These options (or 'clone src#rev dest') imply
1511 --pull, even for local source repositories.
1511 --pull, even for local source repositories.
1512
1512
1513 .. note::
1513 .. note::
1514
1514
1515 Specifying a tag will include the tagged changeset but not the
1515 Specifying a tag will include the tagged changeset but not the
1516 changeset containing the tag.
1516 changeset containing the tag.
1517
1517
1518 .. container:: verbose
1518 .. container:: verbose
1519
1519
1520 For efficiency, hardlinks are used for cloning whenever the
1520 For efficiency, hardlinks are used for cloning whenever the
1521 source and destination are on the same filesystem (note this
1521 source and destination are on the same filesystem (note this
1522 applies only to the repository data, not to the working
1522 applies only to the repository data, not to the working
1523 directory). Some filesystems, such as AFS, implement hardlinking
1523 directory). Some filesystems, such as AFS, implement hardlinking
1524 incorrectly, but do not report errors. In these cases, use the
1524 incorrectly, but do not report errors. In these cases, use the
1525 --pull option to avoid hardlinking.
1525 --pull option to avoid hardlinking.
1526
1526
1527 In some cases, you can clone repositories and the working
1527 In some cases, you can clone repositories and the working
1528 directory using full hardlinks with ::
1528 directory using full hardlinks with ::
1529
1529
1530 $ cp -al REPO REPOCLONE
1530 $ cp -al REPO REPOCLONE
1531
1531
1532 This is the fastest way to clone, but it is not always safe. The
1532 This is the fastest way to clone, but it is not always safe. The
1533 operation is not atomic (making sure REPO is not modified during
1533 operation is not atomic (making sure REPO is not modified during
1534 the operation is up to you) and you have to make sure your
1534 the operation is up to you) and you have to make sure your
1535 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1535 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1536 so). Also, this is not compatible with certain extensions that
1536 so). Also, this is not compatible with certain extensions that
1537 place their metadata under the .hg directory, such as mq.
1537 place their metadata under the .hg directory, such as mq.
1538
1538
1539 Mercurial will update the working directory to the first applicable
1539 Mercurial will update the working directory to the first applicable
1540 revision from this list:
1540 revision from this list:
1541
1541
1542 a) null if -U or the source repository has no changesets
1542 a) null if -U or the source repository has no changesets
1543 b) if -u . and the source repository is local, the first parent of
1543 b) if -u . and the source repository is local, the first parent of
1544 the source repository's working directory
1544 the source repository's working directory
1545 c) the changeset specified with -u (if a branch name, this means the
1545 c) the changeset specified with -u (if a branch name, this means the
1546 latest head of that branch)
1546 latest head of that branch)
1547 d) the changeset specified with -r
1547 d) the changeset specified with -r
1548 e) the tipmost head specified with -b
1548 e) the tipmost head specified with -b
1549 f) the tipmost head specified with the url#branch source syntax
1549 f) the tipmost head specified with the url#branch source syntax
1550 g) the revision marked with the '@' bookmark, if present
1550 g) the revision marked with the '@' bookmark, if present
1551 h) the tipmost head of the default branch
1551 h) the tipmost head of the default branch
1552 i) tip
1552 i) tip
1553
1553
1554 When cloning from servers that support it, Mercurial may fetch
1554 When cloning from servers that support it, Mercurial may fetch
1555 pre-generated data from a server-advertised URL. When this is done,
1555 pre-generated data from a server-advertised URL. When this is done,
1556 hooks operating on incoming changesets and changegroups may fire twice,
1556 hooks operating on incoming changesets and changegroups may fire twice,
1557 once for the bundle fetched from the URL and another for any additional
1557 once for the bundle fetched from the URL and another for any additional
1558 data not fetched from this URL. In addition, if an error occurs, the
1558 data not fetched from this URL. In addition, if an error occurs, the
1559 repository may be rolled back to a partial clone. This behavior may
1559 repository may be rolled back to a partial clone. This behavior may
1560 change in future releases. See :hg:`help -e clonebundles` for more.
1560 change in future releases. See :hg:`help -e clonebundles` for more.
1561
1561
1562 Examples:
1562 Examples:
1563
1563
1564 - clone a remote repository to a new directory named hg/::
1564 - clone a remote repository to a new directory named hg/::
1565
1565
1566 hg clone http://selenic.com/hg
1566 hg clone http://selenic.com/hg
1567
1567
1568 - create a lightweight local clone::
1568 - create a lightweight local clone::
1569
1569
1570 hg clone project/ project-feature/
1570 hg clone project/ project-feature/
1571
1571
1572 - clone from an absolute path on an ssh server (note double-slash)::
1572 - clone from an absolute path on an ssh server (note double-slash)::
1573
1573
1574 hg clone ssh://user@server//home/projects/alpha/
1574 hg clone ssh://user@server//home/projects/alpha/
1575
1575
1576 - do a high-speed clone over a LAN while checking out a
1576 - do a high-speed clone over a LAN while checking out a
1577 specified version::
1577 specified version::
1578
1578
1579 hg clone --uncompressed http://server/repo -u 1.5
1579 hg clone --uncompressed http://server/repo -u 1.5
1580
1580
1581 - create a repository without changesets after a particular revision::
1581 - create a repository without changesets after a particular revision::
1582
1582
1583 hg clone -r 04e544 experimental/ good/
1583 hg clone -r 04e544 experimental/ good/
1584
1584
1585 - clone (and track) a particular named branch::
1585 - clone (and track) a particular named branch::
1586
1586
1587 hg clone http://selenic.com/hg#stable
1587 hg clone http://selenic.com/hg#stable
1588
1588
1589 See :hg:`help urls` for details on specifying URLs.
1589 See :hg:`help urls` for details on specifying URLs.
1590
1590
1591 Returns 0 on success.
1591 Returns 0 on success.
1592 """
1592 """
1593 if opts.get('noupdate') and opts.get('updaterev'):
1593 if opts.get('noupdate') and opts.get('updaterev'):
1594 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1594 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1595
1595
1596 r = hg.clone(ui, opts, source, dest,
1596 r = hg.clone(ui, opts, source, dest,
1597 pull=opts.get('pull'),
1597 pull=opts.get('pull'),
1598 stream=opts.get('uncompressed'),
1598 stream=opts.get('uncompressed'),
1599 rev=opts.get('rev'),
1599 rev=opts.get('rev'),
1600 update=opts.get('updaterev') or not opts.get('noupdate'),
1600 update=opts.get('updaterev') or not opts.get('noupdate'),
1601 branch=opts.get('branch'),
1601 branch=opts.get('branch'),
1602 shareopts=opts.get('shareopts'))
1602 shareopts=opts.get('shareopts'))
1603
1603
1604 return r is None
1604 return r is None
1605
1605
1606 @command('^commit|ci',
1606 @command('^commit|ci',
1607 [('A', 'addremove', None,
1607 [('A', 'addremove', None,
1608 _('mark new/missing files as added/removed before committing')),
1608 _('mark new/missing files as added/removed before committing')),
1609 ('', 'close-branch', None,
1609 ('', 'close-branch', None,
1610 _('mark a branch head as closed')),
1610 _('mark a branch head as closed')),
1611 ('', 'amend', None, _('amend the parent of the working directory')),
1611 ('', 'amend', None, _('amend the parent of the working directory')),
1612 ('s', 'secret', None, _('use the secret phase for committing')),
1612 ('s', 'secret', None, _('use the secret phase for committing')),
1613 ('e', 'edit', None, _('invoke editor on commit messages')),
1613 ('e', 'edit', None, _('invoke editor on commit messages')),
1614 ('i', 'interactive', None, _('use interactive mode')),
1614 ('i', 'interactive', None, _('use interactive mode')),
1615 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1615 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1616 _('[OPTION]... [FILE]...'),
1616 _('[OPTION]... [FILE]...'),
1617 inferrepo=True)
1617 inferrepo=True)
1618 def commit(ui, repo, *pats, **opts):
1618 def commit(ui, repo, *pats, **opts):
1619 """commit the specified files or all outstanding changes
1619 """commit the specified files or all outstanding changes
1620
1620
1621 Commit changes to the given files into the repository. Unlike a
1621 Commit changes to the given files into the repository. Unlike a
1622 centralized SCM, this operation is a local operation. See
1622 centralized SCM, this operation is a local operation. See
1623 :hg:`push` for a way to actively distribute your changes.
1623 :hg:`push` for a way to actively distribute your changes.
1624
1624
1625 If a list of files is omitted, all changes reported by :hg:`status`
1625 If a list of files is omitted, all changes reported by :hg:`status`
1626 will be committed.
1626 will be committed.
1627
1627
1628 If you are committing the result of a merge, do not provide any
1628 If you are committing the result of a merge, do not provide any
1629 filenames or -I/-X filters.
1629 filenames or -I/-X filters.
1630
1630
1631 If no commit message is specified, Mercurial starts your
1631 If no commit message is specified, Mercurial starts your
1632 configured editor where you can enter a message. In case your
1632 configured editor where you can enter a message. In case your
1633 commit fails, you will find a backup of your message in
1633 commit fails, you will find a backup of your message in
1634 ``.hg/last-message.txt``.
1634 ``.hg/last-message.txt``.
1635
1635
1636 The --close-branch flag can be used to mark the current branch
1636 The --close-branch flag can be used to mark the current branch
1637 head closed. When all heads of a branch are closed, the branch
1637 head closed. When all heads of a branch are closed, the branch
1638 will be considered closed and no longer listed.
1638 will be considered closed and no longer listed.
1639
1639
1640 The --amend flag can be used to amend the parent of the
1640 The --amend flag can be used to amend the parent of the
1641 working directory with a new commit that contains the changes
1641 working directory with a new commit that contains the changes
1642 in the parent in addition to those currently reported by :hg:`status`,
1642 in the parent in addition to those currently reported by :hg:`status`,
1643 if there are any. The old commit is stored in a backup bundle in
1643 if there are any. The old commit is stored in a backup bundle in
1644 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1644 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1645 on how to restore it).
1645 on how to restore it).
1646
1646
1647 Message, user and date are taken from the amended commit unless
1647 Message, user and date are taken from the amended commit unless
1648 specified. When a message isn't specified on the command line,
1648 specified. When a message isn't specified on the command line,
1649 the editor will open with the message of the amended commit.
1649 the editor will open with the message of the amended commit.
1650
1650
1651 It is not possible to amend public changesets (see :hg:`help phases`)
1651 It is not possible to amend public changesets (see :hg:`help phases`)
1652 or changesets that have children.
1652 or changesets that have children.
1653
1653
1654 See :hg:`help dates` for a list of formats valid for -d/--date.
1654 See :hg:`help dates` for a list of formats valid for -d/--date.
1655
1655
1656 Returns 0 on success, 1 if nothing changed.
1656 Returns 0 on success, 1 if nothing changed.
1657
1657
1658 .. container:: verbose
1658 .. container:: verbose
1659
1659
1660 Examples:
1660 Examples:
1661
1661
1662 - commit all files ending in .py::
1662 - commit all files ending in .py::
1663
1663
1664 hg commit --include "set:**.py"
1664 hg commit --include "set:**.py"
1665
1665
1666 - commit all non-binary files::
1666 - commit all non-binary files::
1667
1667
1668 hg commit --exclude "set:binary()"
1668 hg commit --exclude "set:binary()"
1669
1669
1670 - amend the current commit and set the date to now::
1670 - amend the current commit and set the date to now::
1671
1671
1672 hg commit --amend --date now
1672 hg commit --amend --date now
1673 """
1673 """
1674 wlock = lock = None
1674 wlock = lock = None
1675 try:
1675 try:
1676 wlock = repo.wlock()
1676 wlock = repo.wlock()
1677 lock = repo.lock()
1677 lock = repo.lock()
1678 return _docommit(ui, repo, *pats, **opts)
1678 return _docommit(ui, repo, *pats, **opts)
1679 finally:
1679 finally:
1680 release(lock, wlock)
1680 release(lock, wlock)
1681
1681
1682 def _docommit(ui, repo, *pats, **opts):
1682 def _docommit(ui, repo, *pats, **opts):
1683 if opts.get('interactive'):
1683 if opts.get('interactive'):
1684 opts.pop('interactive')
1684 opts.pop('interactive')
1685 cmdutil.dorecord(ui, repo, commit, None, False,
1685 cmdutil.dorecord(ui, repo, commit, None, False,
1686 cmdutil.recordfilter, *pats, **opts)
1686 cmdutil.recordfilter, *pats, **opts)
1687 return
1687 return
1688
1688
1689 if opts.get('subrepos'):
1689 if opts.get('subrepos'):
1690 if opts.get('amend'):
1690 if opts.get('amend'):
1691 raise error.Abort(_('cannot amend with --subrepos'))
1691 raise error.Abort(_('cannot amend with --subrepos'))
1692 # Let --subrepos on the command line override config setting.
1692 # Let --subrepos on the command line override config setting.
1693 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1693 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1694
1694
1695 cmdutil.checkunfinished(repo, commit=True)
1695 cmdutil.checkunfinished(repo, commit=True)
1696
1696
1697 branch = repo[None].branch()
1697 branch = repo[None].branch()
1698 bheads = repo.branchheads(branch)
1698 bheads = repo.branchheads(branch)
1699
1699
1700 extra = {}
1700 extra = {}
1701 if opts.get('close_branch'):
1701 if opts.get('close_branch'):
1702 extra['close'] = 1
1702 extra['close'] = 1
1703
1703
1704 if not bheads:
1704 if not bheads:
1705 raise error.Abort(_('can only close branch heads'))
1705 raise error.Abort(_('can only close branch heads'))
1706 elif opts.get('amend'):
1706 elif opts.get('amend'):
1707 if repo[None].parents()[0].p1().branch() != branch and \
1707 if repo[None].parents()[0].p1().branch() != branch and \
1708 repo[None].parents()[0].p2().branch() != branch:
1708 repo[None].parents()[0].p2().branch() != branch:
1709 raise error.Abort(_('can only close branch heads'))
1709 raise error.Abort(_('can only close branch heads'))
1710
1710
1711 if opts.get('amend'):
1711 if opts.get('amend'):
1712 if ui.configbool('ui', 'commitsubrepos'):
1712 if ui.configbool('ui', 'commitsubrepos'):
1713 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1713 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1714
1714
1715 old = repo['.']
1715 old = repo['.']
1716 if not old.mutable():
1716 if not old.mutable():
1717 raise error.Abort(_('cannot amend public changesets'))
1717 raise error.Abort(_('cannot amend public changesets'))
1718 if len(repo[None].parents()) > 1:
1718 if len(repo[None].parents()) > 1:
1719 raise error.Abort(_('cannot amend while merging'))
1719 raise error.Abort(_('cannot amend while merging'))
1720 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1720 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1721 if not allowunstable and old.children():
1721 if not allowunstable and old.children():
1722 raise error.Abort(_('cannot amend changeset with children'))
1722 raise error.Abort(_('cannot amend changeset with children'))
1723
1723
1724 # Currently histedit gets confused if an amend happens while histedit
1724 # Currently histedit gets confused if an amend happens while histedit
1725 # is in progress. Since we have a checkunfinished command, we are
1725 # is in progress. Since we have a checkunfinished command, we are
1726 # temporarily honoring it.
1726 # temporarily honoring it.
1727 #
1727 #
1728 # Note: eventually this guard will be removed. Please do not expect
1728 # Note: eventually this guard will be removed. Please do not expect
1729 # this behavior to remain.
1729 # this behavior to remain.
1730 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1730 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1731 cmdutil.checkunfinished(repo)
1731 cmdutil.checkunfinished(repo)
1732
1732
1733 # commitfunc is used only for temporary amend commit by cmdutil.amend
1733 # commitfunc is used only for temporary amend commit by cmdutil.amend
1734 def commitfunc(ui, repo, message, match, opts):
1734 def commitfunc(ui, repo, message, match, opts):
1735 return repo.commit(message,
1735 return repo.commit(message,
1736 opts.get('user') or old.user(),
1736 opts.get('user') or old.user(),
1737 opts.get('date') or old.date(),
1737 opts.get('date') or old.date(),
1738 match,
1738 match,
1739 extra=extra)
1739 extra=extra)
1740
1740
1741 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1741 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1742 if node == old.node():
1742 if node == old.node():
1743 ui.status(_("nothing changed\n"))
1743 ui.status(_("nothing changed\n"))
1744 return 1
1744 return 1
1745 else:
1745 else:
1746 def commitfunc(ui, repo, message, match, opts):
1746 def commitfunc(ui, repo, message, match, opts):
1747 backup = ui.backupconfig('phases', 'new-commit')
1747 backup = ui.backupconfig('phases', 'new-commit')
1748 baseui = repo.baseui
1748 baseui = repo.baseui
1749 basebackup = baseui.backupconfig('phases', 'new-commit')
1749 basebackup = baseui.backupconfig('phases', 'new-commit')
1750 try:
1750 try:
1751 if opts.get('secret'):
1751 if opts.get('secret'):
1752 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1752 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1753 # Propagate to subrepos
1753 # Propagate to subrepos
1754 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1754 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1755
1755
1756 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1756 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1757 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1757 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1758 return repo.commit(message, opts.get('user'), opts.get('date'),
1758 return repo.commit(message, opts.get('user'), opts.get('date'),
1759 match,
1759 match,
1760 editor=editor,
1760 editor=editor,
1761 extra=extra)
1761 extra=extra)
1762 finally:
1762 finally:
1763 ui.restoreconfig(backup)
1763 ui.restoreconfig(backup)
1764 repo.baseui.restoreconfig(basebackup)
1764 repo.baseui.restoreconfig(basebackup)
1765
1765
1766
1766
1767 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1767 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1768
1768
1769 if not node:
1769 if not node:
1770 stat = cmdutil.postcommitstatus(repo, pats, opts)
1770 stat = cmdutil.postcommitstatus(repo, pats, opts)
1771 if stat[3]:
1771 if stat[3]:
1772 ui.status(_("nothing changed (%d missing files, see "
1772 ui.status(_("nothing changed (%d missing files, see "
1773 "'hg status')\n") % len(stat[3]))
1773 "'hg status')\n") % len(stat[3]))
1774 else:
1774 else:
1775 ui.status(_("nothing changed\n"))
1775 ui.status(_("nothing changed\n"))
1776 return 1
1776 return 1
1777
1777
1778 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1778 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1779
1779
1780 @command('config|showconfig|debugconfig',
1780 @command('config|showconfig|debugconfig',
1781 [('u', 'untrusted', None, _('show untrusted configuration options')),
1781 [('u', 'untrusted', None, _('show untrusted configuration options')),
1782 ('e', 'edit', None, _('edit user config')),
1782 ('e', 'edit', None, _('edit user config')),
1783 ('l', 'local', None, _('edit repository config')),
1783 ('l', 'local', None, _('edit repository config')),
1784 ('g', 'global', None, _('edit global config'))],
1784 ('g', 'global', None, _('edit global config'))],
1785 _('[-u] [NAME]...'),
1785 _('[-u] [NAME]...'),
1786 optionalrepo=True)
1786 optionalrepo=True)
1787 def config(ui, repo, *values, **opts):
1787 def config(ui, repo, *values, **opts):
1788 """show combined config settings from all hgrc files
1788 """show combined config settings from all hgrc files
1789
1789
1790 With no arguments, print names and values of all config items.
1790 With no arguments, print names and values of all config items.
1791
1791
1792 With one argument of the form section.name, print just the value
1792 With one argument of the form section.name, print just the value
1793 of that config item.
1793 of that config item.
1794
1794
1795 With multiple arguments, print names and values of all config
1795 With multiple arguments, print names and values of all config
1796 items with matching section names.
1796 items with matching section names.
1797
1797
1798 With --edit, start an editor on the user-level config file. With
1798 With --edit, start an editor on the user-level config file. With
1799 --global, edit the system-wide config file. With --local, edit the
1799 --global, edit the system-wide config file. With --local, edit the
1800 repository-level config file.
1800 repository-level config file.
1801
1801
1802 With --debug, the source (filename and line number) is printed
1802 With --debug, the source (filename and line number) is printed
1803 for each config item.
1803 for each config item.
1804
1804
1805 See :hg:`help config` for more information about config files.
1805 See :hg:`help config` for more information about config files.
1806
1806
1807 Returns 0 on success, 1 if NAME does not exist.
1807 Returns 0 on success, 1 if NAME does not exist.
1808
1808
1809 """
1809 """
1810
1810
1811 if opts.get('edit') or opts.get('local') or opts.get('global'):
1811 if opts.get('edit') or opts.get('local') or opts.get('global'):
1812 if opts.get('local') and opts.get('global'):
1812 if opts.get('local') and opts.get('global'):
1813 raise error.Abort(_("can't use --local and --global together"))
1813 raise error.Abort(_("can't use --local and --global together"))
1814
1814
1815 if opts.get('local'):
1815 if opts.get('local'):
1816 if not repo:
1816 if not repo:
1817 raise error.Abort(_("can't use --local outside a repository"))
1817 raise error.Abort(_("can't use --local outside a repository"))
1818 paths = [repo.join('hgrc')]
1818 paths = [repo.join('hgrc')]
1819 elif opts.get('global'):
1819 elif opts.get('global'):
1820 paths = scmutil.systemrcpath()
1820 paths = scmutil.systemrcpath()
1821 else:
1821 else:
1822 paths = scmutil.userrcpath()
1822 paths = scmutil.userrcpath()
1823
1823
1824 for f in paths:
1824 for f in paths:
1825 if os.path.exists(f):
1825 if os.path.exists(f):
1826 break
1826 break
1827 else:
1827 else:
1828 if opts.get('global'):
1828 if opts.get('global'):
1829 samplehgrc = uimod.samplehgrcs['global']
1829 samplehgrc = uimod.samplehgrcs['global']
1830 elif opts.get('local'):
1830 elif opts.get('local'):
1831 samplehgrc = uimod.samplehgrcs['local']
1831 samplehgrc = uimod.samplehgrcs['local']
1832 else:
1832 else:
1833 samplehgrc = uimod.samplehgrcs['user']
1833 samplehgrc = uimod.samplehgrcs['user']
1834
1834
1835 f = paths[0]
1835 f = paths[0]
1836 fp = open(f, "w")
1836 fp = open(f, "w")
1837 fp.write(samplehgrc)
1837 fp.write(samplehgrc)
1838 fp.close()
1838 fp.close()
1839
1839
1840 editor = ui.geteditor()
1840 editor = ui.geteditor()
1841 ui.system("%s \"%s\"" % (editor, f),
1841 ui.system("%s \"%s\"" % (editor, f),
1842 onerr=error.Abort, errprefix=_("edit failed"))
1842 onerr=error.Abort, errprefix=_("edit failed"))
1843 return
1843 return
1844
1844
1845 for f in scmutil.rcpath():
1845 for f in scmutil.rcpath():
1846 ui.debug('read config from: %s\n' % f)
1846 ui.debug('read config from: %s\n' % f)
1847 untrusted = bool(opts.get('untrusted'))
1847 untrusted = bool(opts.get('untrusted'))
1848 if values:
1848 if values:
1849 sections = [v for v in values if '.' not in v]
1849 sections = [v for v in values if '.' not in v]
1850 items = [v for v in values if '.' in v]
1850 items = [v for v in values if '.' in v]
1851 if len(items) > 1 or items and sections:
1851 if len(items) > 1 or items and sections:
1852 raise error.Abort(_('only one config item permitted'))
1852 raise error.Abort(_('only one config item permitted'))
1853 matched = False
1853 matched = False
1854 for section, name, value in ui.walkconfig(untrusted=untrusted):
1854 for section, name, value in ui.walkconfig(untrusted=untrusted):
1855 value = str(value).replace('\n', '\\n')
1855 value = str(value).replace('\n', '\\n')
1856 sectname = section + '.' + name
1856 sectname = section + '.' + name
1857 if values:
1857 if values:
1858 for v in values:
1858 for v in values:
1859 if v == section:
1859 if v == section:
1860 ui.debug('%s: ' %
1860 ui.debug('%s: ' %
1861 ui.configsource(section, name, untrusted))
1861 ui.configsource(section, name, untrusted))
1862 ui.write('%s=%s\n' % (sectname, value))
1862 ui.write('%s=%s\n' % (sectname, value))
1863 matched = True
1863 matched = True
1864 elif v == sectname:
1864 elif v == sectname:
1865 ui.debug('%s: ' %
1865 ui.debug('%s: ' %
1866 ui.configsource(section, name, untrusted))
1866 ui.configsource(section, name, untrusted))
1867 ui.write(value, '\n')
1867 ui.write(value, '\n')
1868 matched = True
1868 matched = True
1869 else:
1869 else:
1870 ui.debug('%s: ' %
1870 ui.debug('%s: ' %
1871 ui.configsource(section, name, untrusted))
1871 ui.configsource(section, name, untrusted))
1872 ui.write('%s=%s\n' % (sectname, value))
1872 ui.write('%s=%s\n' % (sectname, value))
1873 matched = True
1873 matched = True
1874 if matched:
1874 if matched:
1875 return 0
1875 return 0
1876 return 1
1876 return 1
1877
1877
1878 @command('copy|cp',
1878 @command('copy|cp',
1879 [('A', 'after', None, _('record a copy that has already occurred')),
1879 [('A', 'after', None, _('record a copy that has already occurred')),
1880 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1880 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1881 ] + walkopts + dryrunopts,
1881 ] + walkopts + dryrunopts,
1882 _('[OPTION]... [SOURCE]... DEST'))
1882 _('[OPTION]... [SOURCE]... DEST'))
1883 def copy(ui, repo, *pats, **opts):
1883 def copy(ui, repo, *pats, **opts):
1884 """mark files as copied for the next commit
1884 """mark files as copied for the next commit
1885
1885
1886 Mark dest as having copies of source files. If dest is a
1886 Mark dest as having copies of source files. If dest is a
1887 directory, copies are put in that directory. If dest is a file,
1887 directory, copies are put in that directory. If dest is a file,
1888 the source must be a single file.
1888 the source must be a single file.
1889
1889
1890 By default, this command copies the contents of files as they
1890 By default, this command copies the contents of files as they
1891 exist in the working directory. If invoked with -A/--after, the
1891 exist in the working directory. If invoked with -A/--after, the
1892 operation is recorded, but no copying is performed.
1892 operation is recorded, but no copying is performed.
1893
1893
1894 This command takes effect with the next commit. To undo a copy
1894 This command takes effect with the next commit. To undo a copy
1895 before that, see :hg:`revert`.
1895 before that, see :hg:`revert`.
1896
1896
1897 Returns 0 on success, 1 if errors are encountered.
1897 Returns 0 on success, 1 if errors are encountered.
1898 """
1898 """
1899 with repo.wlock(False):
1899 with repo.wlock(False):
1900 return cmdutil.copy(ui, repo, pats, opts)
1900 return cmdutil.copy(ui, repo, pats, opts)
1901
1901
1902 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1902 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1903 def debugancestor(ui, repo, *args):
1903 def debugancestor(ui, repo, *args):
1904 """find the ancestor revision of two revisions in a given index"""
1904 """find the ancestor revision of two revisions in a given index"""
1905 if len(args) == 3:
1905 if len(args) == 3:
1906 index, rev1, rev2 = args
1906 index, rev1, rev2 = args
1907 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1907 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1908 lookup = r.lookup
1908 lookup = r.lookup
1909 elif len(args) == 2:
1909 elif len(args) == 2:
1910 if not repo:
1910 if not repo:
1911 raise error.Abort(_("there is no Mercurial repository here "
1911 raise error.Abort(_("there is no Mercurial repository here "
1912 "(.hg not found)"))
1912 "(.hg not found)"))
1913 rev1, rev2 = args
1913 rev1, rev2 = args
1914 r = repo.changelog
1914 r = repo.changelog
1915 lookup = repo.lookup
1915 lookup = repo.lookup
1916 else:
1916 else:
1917 raise error.Abort(_('either two or three arguments required'))
1917 raise error.Abort(_('either two or three arguments required'))
1918 a = r.ancestor(lookup(rev1), lookup(rev2))
1918 a = r.ancestor(lookup(rev1), lookup(rev2))
1919 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1919 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1920
1920
1921 @command('debugbuilddag',
1921 @command('debugbuilddag',
1922 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1922 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1923 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1923 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1924 ('n', 'new-file', None, _('add new file at each rev'))],
1924 ('n', 'new-file', None, _('add new file at each rev'))],
1925 _('[OPTION]... [TEXT]'))
1925 _('[OPTION]... [TEXT]'))
1926 def debugbuilddag(ui, repo, text=None,
1926 def debugbuilddag(ui, repo, text=None,
1927 mergeable_file=False,
1927 mergeable_file=False,
1928 overwritten_file=False,
1928 overwritten_file=False,
1929 new_file=False):
1929 new_file=False):
1930 """builds a repo with a given DAG from scratch in the current empty repo
1930 """builds a repo with a given DAG from scratch in the current empty repo
1931
1931
1932 The description of the DAG is read from stdin if not given on the
1932 The description of the DAG is read from stdin if not given on the
1933 command line.
1933 command line.
1934
1934
1935 Elements:
1935 Elements:
1936
1936
1937 - "+n" is a linear run of n nodes based on the current default parent
1937 - "+n" is a linear run of n nodes based on the current default parent
1938 - "." is a single node based on the current default parent
1938 - "." is a single node based on the current default parent
1939 - "$" resets the default parent to null (implied at the start);
1939 - "$" resets the default parent to null (implied at the start);
1940 otherwise the default parent is always the last node created
1940 otherwise the default parent is always the last node created
1941 - "<p" sets the default parent to the backref p
1941 - "<p" sets the default parent to the backref p
1942 - "*p" is a fork at parent p, which is a backref
1942 - "*p" is a fork at parent p, which is a backref
1943 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1943 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1944 - "/p2" is a merge of the preceding node and p2
1944 - "/p2" is a merge of the preceding node and p2
1945 - ":tag" defines a local tag for the preceding node
1945 - ":tag" defines a local tag for the preceding node
1946 - "@branch" sets the named branch for subsequent nodes
1946 - "@branch" sets the named branch for subsequent nodes
1947 - "#...\\n" is a comment up to the end of the line
1947 - "#...\\n" is a comment up to the end of the line
1948
1948
1949 Whitespace between the above elements is ignored.
1949 Whitespace between the above elements is ignored.
1950
1950
1951 A backref is either
1951 A backref is either
1952
1952
1953 - a number n, which references the node curr-n, where curr is the current
1953 - a number n, which references the node curr-n, where curr is the current
1954 node, or
1954 node, or
1955 - the name of a local tag you placed earlier using ":tag", or
1955 - the name of a local tag you placed earlier using ":tag", or
1956 - empty to denote the default parent.
1956 - empty to denote the default parent.
1957
1957
1958 All string valued-elements are either strictly alphanumeric, or must
1958 All string valued-elements are either strictly alphanumeric, or must
1959 be enclosed in double quotes ("..."), with "\\" as escape character.
1959 be enclosed in double quotes ("..."), with "\\" as escape character.
1960 """
1960 """
1961
1961
1962 if text is None:
1962 if text is None:
1963 ui.status(_("reading DAG from stdin\n"))
1963 ui.status(_("reading DAG from stdin\n"))
1964 text = ui.fin.read()
1964 text = ui.fin.read()
1965
1965
1966 cl = repo.changelog
1966 cl = repo.changelog
1967 if len(cl) > 0:
1967 if len(cl) > 0:
1968 raise error.Abort(_('repository is not empty'))
1968 raise error.Abort(_('repository is not empty'))
1969
1969
1970 # determine number of revs in DAG
1970 # determine number of revs in DAG
1971 total = 0
1971 total = 0
1972 for type, data in dagparser.parsedag(text):
1972 for type, data in dagparser.parsedag(text):
1973 if type == 'n':
1973 if type == 'n':
1974 total += 1
1974 total += 1
1975
1975
1976 if mergeable_file:
1976 if mergeable_file:
1977 linesperrev = 2
1977 linesperrev = 2
1978 # make a file with k lines per rev
1978 # make a file with k lines per rev
1979 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1979 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1980 initialmergedlines.append("")
1980 initialmergedlines.append("")
1981
1981
1982 tags = []
1982 tags = []
1983
1983
1984 lock = tr = None
1984 lock = tr = None
1985 try:
1985 try:
1986 lock = repo.lock()
1986 lock = repo.lock()
1987 tr = repo.transaction("builddag")
1987 tr = repo.transaction("builddag")
1988
1988
1989 at = -1
1989 at = -1
1990 atbranch = 'default'
1990 atbranch = 'default'
1991 nodeids = []
1991 nodeids = []
1992 id = 0
1992 id = 0
1993 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1993 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1994 for type, data in dagparser.parsedag(text):
1994 for type, data in dagparser.parsedag(text):
1995 if type == 'n':
1995 if type == 'n':
1996 ui.note(('node %s\n' % str(data)))
1996 ui.note(('node %s\n' % str(data)))
1997 id, ps = data
1997 id, ps = data
1998
1998
1999 files = []
1999 files = []
2000 fctxs = {}
2000 fctxs = {}
2001
2001
2002 p2 = None
2002 p2 = None
2003 if mergeable_file:
2003 if mergeable_file:
2004 fn = "mf"
2004 fn = "mf"
2005 p1 = repo[ps[0]]
2005 p1 = repo[ps[0]]
2006 if len(ps) > 1:
2006 if len(ps) > 1:
2007 p2 = repo[ps[1]]
2007 p2 = repo[ps[1]]
2008 pa = p1.ancestor(p2)
2008 pa = p1.ancestor(p2)
2009 base, local, other = [x[fn].data() for x in (pa, p1,
2009 base, local, other = [x[fn].data() for x in (pa, p1,
2010 p2)]
2010 p2)]
2011 m3 = simplemerge.Merge3Text(base, local, other)
2011 m3 = simplemerge.Merge3Text(base, local, other)
2012 ml = [l.strip() for l in m3.merge_lines()]
2012 ml = [l.strip() for l in m3.merge_lines()]
2013 ml.append("")
2013 ml.append("")
2014 elif at > 0:
2014 elif at > 0:
2015 ml = p1[fn].data().split("\n")
2015 ml = p1[fn].data().split("\n")
2016 else:
2016 else:
2017 ml = initialmergedlines
2017 ml = initialmergedlines
2018 ml[id * linesperrev] += " r%i" % id
2018 ml[id * linesperrev] += " r%i" % id
2019 mergedtext = "\n".join(ml)
2019 mergedtext = "\n".join(ml)
2020 files.append(fn)
2020 files.append(fn)
2021 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2021 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2022
2022
2023 if overwritten_file:
2023 if overwritten_file:
2024 fn = "of"
2024 fn = "of"
2025 files.append(fn)
2025 files.append(fn)
2026 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2026 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2027
2027
2028 if new_file:
2028 if new_file:
2029 fn = "nf%i" % id
2029 fn = "nf%i" % id
2030 files.append(fn)
2030 files.append(fn)
2031 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2031 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2032 if len(ps) > 1:
2032 if len(ps) > 1:
2033 if not p2:
2033 if not p2:
2034 p2 = repo[ps[1]]
2034 p2 = repo[ps[1]]
2035 for fn in p2:
2035 for fn in p2:
2036 if fn.startswith("nf"):
2036 if fn.startswith("nf"):
2037 files.append(fn)
2037 files.append(fn)
2038 fctxs[fn] = p2[fn]
2038 fctxs[fn] = p2[fn]
2039
2039
2040 def fctxfn(repo, cx, path):
2040 def fctxfn(repo, cx, path):
2041 return fctxs.get(path)
2041 return fctxs.get(path)
2042
2042
2043 if len(ps) == 0 or ps[0] < 0:
2043 if len(ps) == 0 or ps[0] < 0:
2044 pars = [None, None]
2044 pars = [None, None]
2045 elif len(ps) == 1:
2045 elif len(ps) == 1:
2046 pars = [nodeids[ps[0]], None]
2046 pars = [nodeids[ps[0]], None]
2047 else:
2047 else:
2048 pars = [nodeids[p] for p in ps]
2048 pars = [nodeids[p] for p in ps]
2049 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2049 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2050 date=(id, 0),
2050 date=(id, 0),
2051 user="debugbuilddag",
2051 user="debugbuilddag",
2052 extra={'branch': atbranch})
2052 extra={'branch': atbranch})
2053 nodeid = repo.commitctx(cx)
2053 nodeid = repo.commitctx(cx)
2054 nodeids.append(nodeid)
2054 nodeids.append(nodeid)
2055 at = id
2055 at = id
2056 elif type == 'l':
2056 elif type == 'l':
2057 id, name = data
2057 id, name = data
2058 ui.note(('tag %s\n' % name))
2058 ui.note(('tag %s\n' % name))
2059 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2059 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2060 elif type == 'a':
2060 elif type == 'a':
2061 ui.note(('branch %s\n' % data))
2061 ui.note(('branch %s\n' % data))
2062 atbranch = data
2062 atbranch = data
2063 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2063 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2064 tr.close()
2064 tr.close()
2065
2065
2066 if tags:
2066 if tags:
2067 repo.vfs.write("localtags", "".join(tags))
2067 repo.vfs.write("localtags", "".join(tags))
2068 finally:
2068 finally:
2069 ui.progress(_('building'), None)
2069 ui.progress(_('building'), None)
2070 release(tr, lock)
2070 release(tr, lock)
2071
2071
2072 @command('debugbundle',
2072 @command('debugbundle',
2073 [('a', 'all', None, _('show all details')),
2073 [('a', 'all', None, _('show all details')),
2074 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2074 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2075 _('FILE'),
2075 _('FILE'),
2076 norepo=True)
2076 norepo=True)
2077 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2077 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2078 """lists the contents of a bundle"""
2078 """lists the contents of a bundle"""
2079 with hg.openpath(ui, bundlepath) as f:
2079 with hg.openpath(ui, bundlepath) as f:
2080 if spec:
2080 if spec:
2081 spec = exchange.getbundlespec(ui, f)
2081 spec = exchange.getbundlespec(ui, f)
2082 ui.write('%s\n' % spec)
2082 ui.write('%s\n' % spec)
2083 return
2083 return
2084
2084
2085 gen = exchange.readbundle(ui, f, bundlepath)
2085 gen = exchange.readbundle(ui, f, bundlepath)
2086 if isinstance(gen, bundle2.unbundle20):
2086 if isinstance(gen, bundle2.unbundle20):
2087 return _debugbundle2(ui, gen, all=all, **opts)
2087 return _debugbundle2(ui, gen, all=all, **opts)
2088 if all:
2088 if all:
2089 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2089 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2090
2090
2091 def showchunks(named):
2091 def showchunks(named):
2092 ui.write("\n%s\n" % named)
2092 ui.write("\n%s\n" % named)
2093 chain = None
2093 chain = None
2094 while True:
2094 while True:
2095 chunkdata = gen.deltachunk(chain)
2095 chunkdata = gen.deltachunk(chain)
2096 if not chunkdata:
2096 if not chunkdata:
2097 break
2097 break
2098 node = chunkdata['node']
2098 node = chunkdata['node']
2099 p1 = chunkdata['p1']
2099 p1 = chunkdata['p1']
2100 p2 = chunkdata['p2']
2100 p2 = chunkdata['p2']
2101 cs = chunkdata['cs']
2101 cs = chunkdata['cs']
2102 deltabase = chunkdata['deltabase']
2102 deltabase = chunkdata['deltabase']
2103 delta = chunkdata['delta']
2103 delta = chunkdata['delta']
2104 ui.write("%s %s %s %s %s %s\n" %
2104 ui.write("%s %s %s %s %s %s\n" %
2105 (hex(node), hex(p1), hex(p2),
2105 (hex(node), hex(p1), hex(p2),
2106 hex(cs), hex(deltabase), len(delta)))
2106 hex(cs), hex(deltabase), len(delta)))
2107 chain = node
2107 chain = node
2108
2108
2109 chunkdata = gen.changelogheader()
2109 chunkdata = gen.changelogheader()
2110 showchunks("changelog")
2110 showchunks("changelog")
2111 chunkdata = gen.manifestheader()
2111 chunkdata = gen.manifestheader()
2112 showchunks("manifest")
2112 showchunks("manifest")
2113 while True:
2113 while True:
2114 chunkdata = gen.filelogheader()
2114 chunkdata = gen.filelogheader()
2115 if not chunkdata:
2115 if not chunkdata:
2116 break
2116 break
2117 fname = chunkdata['filename']
2117 fname = chunkdata['filename']
2118 showchunks(fname)
2118 showchunks(fname)
2119 else:
2119 else:
2120 if isinstance(gen, bundle2.unbundle20):
2120 if isinstance(gen, bundle2.unbundle20):
2121 raise error.Abort(_('use debugbundle2 for this file'))
2121 raise error.Abort(_('use debugbundle2 for this file'))
2122 chunkdata = gen.changelogheader()
2122 chunkdata = gen.changelogheader()
2123 chain = None
2123 chain = None
2124 while True:
2124 while True:
2125 chunkdata = gen.deltachunk(chain)
2125 chunkdata = gen.deltachunk(chain)
2126 if not chunkdata:
2126 if not chunkdata:
2127 break
2127 break
2128 node = chunkdata['node']
2128 node = chunkdata['node']
2129 ui.write("%s\n" % hex(node))
2129 ui.write("%s\n" % hex(node))
2130 chain = node
2130 chain = node
2131
2131
2132 def _debugbundle2(ui, gen, **opts):
2132 def _debugbundle2(ui, gen, **opts):
2133 """lists the contents of a bundle2"""
2133 """lists the contents of a bundle2"""
2134 if not isinstance(gen, bundle2.unbundle20):
2134 if not isinstance(gen, bundle2.unbundle20):
2135 raise error.Abort(_('not a bundle2 file'))
2135 raise error.Abort(_('not a bundle2 file'))
2136 ui.write(('Stream params: %s\n' % repr(gen.params)))
2136 ui.write(('Stream params: %s\n' % repr(gen.params)))
2137 for part in gen.iterparts():
2137 for part in gen.iterparts():
2138 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2138 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2139 if part.type == 'changegroup':
2139 if part.type == 'changegroup':
2140 version = part.params.get('version', '01')
2140 version = part.params.get('version', '01')
2141 cg = changegroup.getunbundler(version, part, 'UN')
2141 cg = changegroup.getunbundler(version, part, 'UN')
2142 chunkdata = cg.changelogheader()
2142 chunkdata = cg.changelogheader()
2143 chain = None
2143 chain = None
2144 while True:
2144 while True:
2145 chunkdata = cg.deltachunk(chain)
2145 chunkdata = cg.deltachunk(chain)
2146 if not chunkdata:
2146 if not chunkdata:
2147 break
2147 break
2148 node = chunkdata['node']
2148 node = chunkdata['node']
2149 ui.write(" %s\n" % hex(node))
2149 ui.write(" %s\n" % hex(node))
2150 chain = node
2150 chain = node
2151
2151
2152 @command('debugcreatestreamclonebundle', [], 'FILE')
2152 @command('debugcreatestreamclonebundle', [], 'FILE')
2153 def debugcreatestreamclonebundle(ui, repo, fname):
2153 def debugcreatestreamclonebundle(ui, repo, fname):
2154 """create a stream clone bundle file
2154 """create a stream clone bundle file
2155
2155
2156 Stream bundles are special bundles that are essentially archives of
2156 Stream bundles are special bundles that are essentially archives of
2157 revlog files. They are commonly used for cloning very quickly.
2157 revlog files. They are commonly used for cloning very quickly.
2158 """
2158 """
2159 requirements, gen = streamclone.generatebundlev1(repo)
2159 requirements, gen = streamclone.generatebundlev1(repo)
2160 changegroup.writechunks(ui, gen, fname)
2160 changegroup.writechunks(ui, gen, fname)
2161
2161
2162 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2162 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2163
2163
2164 @command('debugapplystreamclonebundle', [], 'FILE')
2164 @command('debugapplystreamclonebundle', [], 'FILE')
2165 def debugapplystreamclonebundle(ui, repo, fname):
2165 def debugapplystreamclonebundle(ui, repo, fname):
2166 """apply a stream clone bundle file"""
2166 """apply a stream clone bundle file"""
2167 f = hg.openpath(ui, fname)
2167 f = hg.openpath(ui, fname)
2168 gen = exchange.readbundle(ui, f, fname)
2168 gen = exchange.readbundle(ui, f, fname)
2169 gen.apply(repo)
2169 gen.apply(repo)
2170
2170
2171 @command('debugcheckstate', [], '')
2171 @command('debugcheckstate', [], '')
2172 def debugcheckstate(ui, repo):
2172 def debugcheckstate(ui, repo):
2173 """validate the correctness of the current dirstate"""
2173 """validate the correctness of the current dirstate"""
2174 parent1, parent2 = repo.dirstate.parents()
2174 parent1, parent2 = repo.dirstate.parents()
2175 m1 = repo[parent1].manifest()
2175 m1 = repo[parent1].manifest()
2176 m2 = repo[parent2].manifest()
2176 m2 = repo[parent2].manifest()
2177 errors = 0
2177 errors = 0
2178 for f in repo.dirstate:
2178 for f in repo.dirstate:
2179 state = repo.dirstate[f]
2179 state = repo.dirstate[f]
2180 if state in "nr" and f not in m1:
2180 if state in "nr" and f not in m1:
2181 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2181 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2182 errors += 1
2182 errors += 1
2183 if state in "a" and f in m1:
2183 if state in "a" and f in m1:
2184 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2184 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2185 errors += 1
2185 errors += 1
2186 if state in "m" and f not in m1 and f not in m2:
2186 if state in "m" and f not in m1 and f not in m2:
2187 ui.warn(_("%s in state %s, but not in either manifest\n") %
2187 ui.warn(_("%s in state %s, but not in either manifest\n") %
2188 (f, state))
2188 (f, state))
2189 errors += 1
2189 errors += 1
2190 for f in m1:
2190 for f in m1:
2191 state = repo.dirstate[f]
2191 state = repo.dirstate[f]
2192 if state not in "nrm":
2192 if state not in "nrm":
2193 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2193 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2194 errors += 1
2194 errors += 1
2195 if errors:
2195 if errors:
2196 error = _(".hg/dirstate inconsistent with current parent's manifest")
2196 error = _(".hg/dirstate inconsistent with current parent's manifest")
2197 raise error.Abort(error)
2197 raise error.Abort(error)
2198
2198
2199 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2199 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2200 def debugcommands(ui, cmd='', *args):
2200 def debugcommands(ui, cmd='', *args):
2201 """list all available commands and options"""
2201 """list all available commands and options"""
2202 for cmd, vals in sorted(table.iteritems()):
2202 for cmd, vals in sorted(table.iteritems()):
2203 cmd = cmd.split('|')[0].strip('^')
2203 cmd = cmd.split('|')[0].strip('^')
2204 opts = ', '.join([i[1] for i in vals[1]])
2204 opts = ', '.join([i[1] for i in vals[1]])
2205 ui.write('%s: %s\n' % (cmd, opts))
2205 ui.write('%s: %s\n' % (cmd, opts))
2206
2206
2207 @command('debugcomplete',
2207 @command('debugcomplete',
2208 [('o', 'options', None, _('show the command options'))],
2208 [('o', 'options', None, _('show the command options'))],
2209 _('[-o] CMD'),
2209 _('[-o] CMD'),
2210 norepo=True)
2210 norepo=True)
2211 def debugcomplete(ui, cmd='', **opts):
2211 def debugcomplete(ui, cmd='', **opts):
2212 """returns the completion list associated with the given command"""
2212 """returns the completion list associated with the given command"""
2213
2213
2214 if opts.get('options'):
2214 if opts.get('options'):
2215 options = []
2215 options = []
2216 otables = [globalopts]
2216 otables = [globalopts]
2217 if cmd:
2217 if cmd:
2218 aliases, entry = cmdutil.findcmd(cmd, table, False)
2218 aliases, entry = cmdutil.findcmd(cmd, table, False)
2219 otables.append(entry[1])
2219 otables.append(entry[1])
2220 for t in otables:
2220 for t in otables:
2221 for o in t:
2221 for o in t:
2222 if "(DEPRECATED)" in o[3]:
2222 if "(DEPRECATED)" in o[3]:
2223 continue
2223 continue
2224 if o[0]:
2224 if o[0]:
2225 options.append('-%s' % o[0])
2225 options.append('-%s' % o[0])
2226 options.append('--%s' % o[1])
2226 options.append('--%s' % o[1])
2227 ui.write("%s\n" % "\n".join(options))
2227 ui.write("%s\n" % "\n".join(options))
2228 return
2228 return
2229
2229
2230 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2230 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2231 if ui.verbose:
2231 if ui.verbose:
2232 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2232 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2233 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2233 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2234
2234
2235 @command('debugdag',
2235 @command('debugdag',
2236 [('t', 'tags', None, _('use tags as labels')),
2236 [('t', 'tags', None, _('use tags as labels')),
2237 ('b', 'branches', None, _('annotate with branch names')),
2237 ('b', 'branches', None, _('annotate with branch names')),
2238 ('', 'dots', None, _('use dots for runs')),
2238 ('', 'dots', None, _('use dots for runs')),
2239 ('s', 'spaces', None, _('separate elements by spaces'))],
2239 ('s', 'spaces', None, _('separate elements by spaces'))],
2240 _('[OPTION]... [FILE [REV]...]'),
2240 _('[OPTION]... [FILE [REV]...]'),
2241 optionalrepo=True)
2241 optionalrepo=True)
2242 def debugdag(ui, repo, file_=None, *revs, **opts):
2242 def debugdag(ui, repo, file_=None, *revs, **opts):
2243 """format the changelog or an index DAG as a concise textual description
2243 """format the changelog or an index DAG as a concise textual description
2244
2244
2245 If you pass a revlog index, the revlog's DAG is emitted. If you list
2245 If you pass a revlog index, the revlog's DAG is emitted. If you list
2246 revision numbers, they get labeled in the output as rN.
2246 revision numbers, they get labeled in the output as rN.
2247
2247
2248 Otherwise, the changelog DAG of the current repo is emitted.
2248 Otherwise, the changelog DAG of the current repo is emitted.
2249 """
2249 """
2250 spaces = opts.get('spaces')
2250 spaces = opts.get('spaces')
2251 dots = opts.get('dots')
2251 dots = opts.get('dots')
2252 if file_:
2252 if file_:
2253 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2253 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2254 revs = set((int(r) for r in revs))
2254 revs = set((int(r) for r in revs))
2255 def events():
2255 def events():
2256 for r in rlog:
2256 for r in rlog:
2257 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2257 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2258 if p != -1))
2258 if p != -1))
2259 if r in revs:
2259 if r in revs:
2260 yield 'l', (r, "r%i" % r)
2260 yield 'l', (r, "r%i" % r)
2261 elif repo:
2261 elif repo:
2262 cl = repo.changelog
2262 cl = repo.changelog
2263 tags = opts.get('tags')
2263 tags = opts.get('tags')
2264 branches = opts.get('branches')
2264 branches = opts.get('branches')
2265 if tags:
2265 if tags:
2266 labels = {}
2266 labels = {}
2267 for l, n in repo.tags().items():
2267 for l, n in repo.tags().items():
2268 labels.setdefault(cl.rev(n), []).append(l)
2268 labels.setdefault(cl.rev(n), []).append(l)
2269 def events():
2269 def events():
2270 b = "default"
2270 b = "default"
2271 for r in cl:
2271 for r in cl:
2272 if branches:
2272 if branches:
2273 newb = cl.read(cl.node(r))[5]['branch']
2273 newb = cl.read(cl.node(r))[5]['branch']
2274 if newb != b:
2274 if newb != b:
2275 yield 'a', newb
2275 yield 'a', newb
2276 b = newb
2276 b = newb
2277 yield 'n', (r, list(p for p in cl.parentrevs(r)
2277 yield 'n', (r, list(p for p in cl.parentrevs(r)
2278 if p != -1))
2278 if p != -1))
2279 if tags:
2279 if tags:
2280 ls = labels.get(r)
2280 ls = labels.get(r)
2281 if ls:
2281 if ls:
2282 for l in ls:
2282 for l in ls:
2283 yield 'l', (r, l)
2283 yield 'l', (r, l)
2284 else:
2284 else:
2285 raise error.Abort(_('need repo for changelog dag'))
2285 raise error.Abort(_('need repo for changelog dag'))
2286
2286
2287 for line in dagparser.dagtextlines(events(),
2287 for line in dagparser.dagtextlines(events(),
2288 addspaces=spaces,
2288 addspaces=spaces,
2289 wraplabels=True,
2289 wraplabels=True,
2290 wrapannotations=True,
2290 wrapannotations=True,
2291 wrapnonlinear=dots,
2291 wrapnonlinear=dots,
2292 usedots=dots,
2292 usedots=dots,
2293 maxlinewidth=70):
2293 maxlinewidth=70):
2294 ui.write(line)
2294 ui.write(line)
2295 ui.write("\n")
2295 ui.write("\n")
2296
2296
2297 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2297 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2298 def debugdata(ui, repo, file_, rev=None, **opts):
2298 def debugdata(ui, repo, file_, rev=None, **opts):
2299 """dump the contents of a data file revision"""
2299 """dump the contents of a data file revision"""
2300 if opts.get('changelog') or opts.get('manifest'):
2300 if opts.get('changelog') or opts.get('manifest'):
2301 file_, rev = None, file_
2301 file_, rev = None, file_
2302 elif rev is None:
2302 elif rev is None:
2303 raise error.CommandError('debugdata', _('invalid arguments'))
2303 raise error.CommandError('debugdata', _('invalid arguments'))
2304 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2304 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2305 try:
2305 try:
2306 ui.write(r.revision(r.lookup(rev)))
2306 ui.write(r.revision(r.lookup(rev)))
2307 except KeyError:
2307 except KeyError:
2308 raise error.Abort(_('invalid revision identifier %s') % rev)
2308 raise error.Abort(_('invalid revision identifier %s') % rev)
2309
2309
2310 @command('debugdate',
2310 @command('debugdate',
2311 [('e', 'extended', None, _('try extended date formats'))],
2311 [('e', 'extended', None, _('try extended date formats'))],
2312 _('[-e] DATE [RANGE]'),
2312 _('[-e] DATE [RANGE]'),
2313 norepo=True, optionalrepo=True)
2313 norepo=True, optionalrepo=True)
2314 def debugdate(ui, date, range=None, **opts):
2314 def debugdate(ui, date, range=None, **opts):
2315 """parse and display a date"""
2315 """parse and display a date"""
2316 if opts["extended"]:
2316 if opts["extended"]:
2317 d = util.parsedate(date, util.extendeddateformats)
2317 d = util.parsedate(date, util.extendeddateformats)
2318 else:
2318 else:
2319 d = util.parsedate(date)
2319 d = util.parsedate(date)
2320 ui.write(("internal: %s %s\n") % d)
2320 ui.write(("internal: %s %s\n") % d)
2321 ui.write(("standard: %s\n") % util.datestr(d))
2321 ui.write(("standard: %s\n") % util.datestr(d))
2322 if range:
2322 if range:
2323 m = util.matchdate(range)
2323 m = util.matchdate(range)
2324 ui.write(("match: %s\n") % m(d[0]))
2324 ui.write(("match: %s\n") % m(d[0]))
2325
2325
2326 @command('debugdiscovery',
2326 @command('debugdiscovery',
2327 [('', 'old', None, _('use old-style discovery')),
2327 [('', 'old', None, _('use old-style discovery')),
2328 ('', 'nonheads', None,
2328 ('', 'nonheads', None,
2329 _('use old-style discovery with non-heads included')),
2329 _('use old-style discovery with non-heads included')),
2330 ] + remoteopts,
2330 ] + remoteopts,
2331 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2331 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2332 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2332 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2333 """runs the changeset discovery protocol in isolation"""
2333 """runs the changeset discovery protocol in isolation"""
2334 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2334 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2335 opts.get('branch'))
2335 opts.get('branch'))
2336 remote = hg.peer(repo, opts, remoteurl)
2336 remote = hg.peer(repo, opts, remoteurl)
2337 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2337 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2338
2338
2339 # make sure tests are repeatable
2339 # make sure tests are repeatable
2340 random.seed(12323)
2340 random.seed(12323)
2341
2341
2342 def doit(localheads, remoteheads, remote=remote):
2342 def doit(localheads, remoteheads, remote=remote):
2343 if opts.get('old'):
2343 if opts.get('old'):
2344 if localheads:
2344 if localheads:
2345 raise error.Abort('cannot use localheads with old style '
2345 raise error.Abort('cannot use localheads with old style '
2346 'discovery')
2346 'discovery')
2347 if not util.safehasattr(remote, 'branches'):
2347 if not util.safehasattr(remote, 'branches'):
2348 # enable in-client legacy support
2348 # enable in-client legacy support
2349 remote = localrepo.locallegacypeer(remote.local())
2349 remote = localrepo.locallegacypeer(remote.local())
2350 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2350 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2351 force=True)
2351 force=True)
2352 common = set(common)
2352 common = set(common)
2353 if not opts.get('nonheads'):
2353 if not opts.get('nonheads'):
2354 ui.write(("unpruned common: %s\n") %
2354 ui.write(("unpruned common: %s\n") %
2355 " ".join(sorted(short(n) for n in common)))
2355 " ".join(sorted(short(n) for n in common)))
2356 dag = dagutil.revlogdag(repo.changelog)
2356 dag = dagutil.revlogdag(repo.changelog)
2357 all = dag.ancestorset(dag.internalizeall(common))
2357 all = dag.ancestorset(dag.internalizeall(common))
2358 common = dag.externalizeall(dag.headsetofconnecteds(all))
2358 common = dag.externalizeall(dag.headsetofconnecteds(all))
2359 else:
2359 else:
2360 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2360 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2361 common = set(common)
2361 common = set(common)
2362 rheads = set(hds)
2362 rheads = set(hds)
2363 lheads = set(repo.heads())
2363 lheads = set(repo.heads())
2364 ui.write(("common heads: %s\n") %
2364 ui.write(("common heads: %s\n") %
2365 " ".join(sorted(short(n) for n in common)))
2365 " ".join(sorted(short(n) for n in common)))
2366 if lheads <= common:
2366 if lheads <= common:
2367 ui.write(("local is subset\n"))
2367 ui.write(("local is subset\n"))
2368 elif rheads <= common:
2368 elif rheads <= common:
2369 ui.write(("remote is subset\n"))
2369 ui.write(("remote is subset\n"))
2370
2370
2371 serverlogs = opts.get('serverlog')
2371 serverlogs = opts.get('serverlog')
2372 if serverlogs:
2372 if serverlogs:
2373 for filename in serverlogs:
2373 for filename in serverlogs:
2374 with open(filename, 'r') as logfile:
2374 with open(filename, 'r') as logfile:
2375 line = logfile.readline()
2375 line = logfile.readline()
2376 while line:
2376 while line:
2377 parts = line.strip().split(';')
2377 parts = line.strip().split(';')
2378 op = parts[1]
2378 op = parts[1]
2379 if op == 'cg':
2379 if op == 'cg':
2380 pass
2380 pass
2381 elif op == 'cgss':
2381 elif op == 'cgss':
2382 doit(parts[2].split(' '), parts[3].split(' '))
2382 doit(parts[2].split(' '), parts[3].split(' '))
2383 elif op == 'unb':
2383 elif op == 'unb':
2384 doit(parts[3].split(' '), parts[2].split(' '))
2384 doit(parts[3].split(' '), parts[2].split(' '))
2385 line = logfile.readline()
2385 line = logfile.readline()
2386 else:
2386 else:
2387 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2387 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2388 opts.get('remote_head'))
2388 opts.get('remote_head'))
2389 localrevs = opts.get('local_head')
2389 localrevs = opts.get('local_head')
2390 doit(localrevs, remoterevs)
2390 doit(localrevs, remoterevs)
2391
2391
2392 @command('debugextensions', formatteropts, [], norepo=True)
2392 @command('debugextensions', formatteropts, [], norepo=True)
2393 def debugextensions(ui, **opts):
2393 def debugextensions(ui, **opts):
2394 '''show information about active extensions'''
2394 '''show information about active extensions'''
2395 exts = extensions.extensions(ui)
2395 exts = extensions.extensions(ui)
2396 fm = ui.formatter('debugextensions', opts)
2396 fm = ui.formatter('debugextensions', opts)
2397 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2397 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2398 extsource = extmod.__file__
2398 extsource = extmod.__file__
2399 exttestedwith = getattr(extmod, 'testedwith', None)
2399 exttestedwith = getattr(extmod, 'testedwith', None)
2400 if exttestedwith is not None:
2400 if exttestedwith is not None:
2401 exttestedwith = exttestedwith.split()
2401 exttestedwith = exttestedwith.split()
2402 extbuglink = getattr(extmod, 'buglink', None)
2402 extbuglink = getattr(extmod, 'buglink', None)
2403
2403
2404 fm.startitem()
2404 fm.startitem()
2405
2405
2406 if ui.quiet or ui.verbose:
2406 if ui.quiet or ui.verbose:
2407 fm.write('name', '%s\n', extname)
2407 fm.write('name', '%s\n', extname)
2408 else:
2408 else:
2409 fm.write('name', '%s', extname)
2409 fm.write('name', '%s', extname)
2410 if not exttestedwith:
2410 if not exttestedwith:
2411 fm.plain(_(' (untested!)\n'))
2411 fm.plain(_(' (untested!)\n'))
2412 else:
2412 else:
2413 if exttestedwith == ['internal'] or \
2413 if exttestedwith == ['internal'] or \
2414 util.version() in exttestedwith:
2414 util.version() in exttestedwith:
2415 fm.plain('\n')
2415 fm.plain('\n')
2416 else:
2416 else:
2417 lasttestedversion = exttestedwith[-1]
2417 lasttestedversion = exttestedwith[-1]
2418 fm.plain(' (%s!)\n' % lasttestedversion)
2418 fm.plain(' (%s!)\n' % lasttestedversion)
2419
2419
2420 fm.condwrite(ui.verbose and extsource, 'source',
2420 fm.condwrite(ui.verbose and extsource, 'source',
2421 _(' location: %s\n'), extsource or "")
2421 _(' location: %s\n'), extsource or "")
2422
2422
2423 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2423 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2424 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2424 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2425
2425
2426 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2426 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2427 _(' bug reporting: %s\n'), extbuglink or "")
2427 _(' bug reporting: %s\n'), extbuglink or "")
2428
2428
2429 fm.end()
2429 fm.end()
2430
2430
2431 @command('debugfileset',
2431 @command('debugfileset',
2432 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2432 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2433 _('[-r REV] FILESPEC'))
2433 _('[-r REV] FILESPEC'))
2434 def debugfileset(ui, repo, expr, **opts):
2434 def debugfileset(ui, repo, expr, **opts):
2435 '''parse and apply a fileset specification'''
2435 '''parse and apply a fileset specification'''
2436 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2436 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2437 if ui.verbose:
2437 if ui.verbose:
2438 tree = fileset.parse(expr)
2438 tree = fileset.parse(expr)
2439 ui.note(fileset.prettyformat(tree), "\n")
2439 ui.note(fileset.prettyformat(tree), "\n")
2440
2440
2441 for f in ctx.getfileset(expr):
2441 for f in ctx.getfileset(expr):
2442 ui.write("%s\n" % f)
2442 ui.write("%s\n" % f)
2443
2443
2444 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2444 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2445 def debugfsinfo(ui, path="."):
2445 def debugfsinfo(ui, path="."):
2446 """show information detected about current filesystem"""
2446 """show information detected about current filesystem"""
2447 util.writefile('.debugfsinfo', '')
2447 util.writefile('.debugfsinfo', '')
2448 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2448 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2449 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2449 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2450 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2450 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2451 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2451 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2452 and 'yes' or 'no'))
2452 and 'yes' or 'no'))
2453 os.unlink('.debugfsinfo')
2453 os.unlink('.debugfsinfo')
2454
2454
2455 @command('debuggetbundle',
2455 @command('debuggetbundle',
2456 [('H', 'head', [], _('id of head node'), _('ID')),
2456 [('H', 'head', [], _('id of head node'), _('ID')),
2457 ('C', 'common', [], _('id of common node'), _('ID')),
2457 ('C', 'common', [], _('id of common node'), _('ID')),
2458 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2458 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2459 _('REPO FILE [-H|-C ID]...'),
2459 _('REPO FILE [-H|-C ID]...'),
2460 norepo=True)
2460 norepo=True)
2461 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2461 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2462 """retrieves a bundle from a repo
2462 """retrieves a bundle from a repo
2463
2463
2464 Every ID must be a full-length hex node id string. Saves the bundle to the
2464 Every ID must be a full-length hex node id string. Saves the bundle to the
2465 given file.
2465 given file.
2466 """
2466 """
2467 repo = hg.peer(ui, opts, repopath)
2467 repo = hg.peer(ui, opts, repopath)
2468 if not repo.capable('getbundle'):
2468 if not repo.capable('getbundle'):
2469 raise error.Abort("getbundle() not supported by target repository")
2469 raise error.Abort("getbundle() not supported by target repository")
2470 args = {}
2470 args = {}
2471 if common:
2471 if common:
2472 args['common'] = [bin(s) for s in common]
2472 args['common'] = [bin(s) for s in common]
2473 if head:
2473 if head:
2474 args['heads'] = [bin(s) for s in head]
2474 args['heads'] = [bin(s) for s in head]
2475 # TODO: get desired bundlecaps from command line.
2475 # TODO: get desired bundlecaps from command line.
2476 args['bundlecaps'] = None
2476 args['bundlecaps'] = None
2477 bundle = repo.getbundle('debug', **args)
2477 bundle = repo.getbundle('debug', **args)
2478
2478
2479 bundletype = opts.get('type', 'bzip2').lower()
2479 bundletype = opts.get('type', 'bzip2').lower()
2480 btypes = {'none': 'HG10UN',
2480 btypes = {'none': 'HG10UN',
2481 'bzip2': 'HG10BZ',
2481 'bzip2': 'HG10BZ',
2482 'gzip': 'HG10GZ',
2482 'gzip': 'HG10GZ',
2483 'bundle2': 'HG20'}
2483 'bundle2': 'HG20'}
2484 bundletype = btypes.get(bundletype)
2484 bundletype = btypes.get(bundletype)
2485 if bundletype not in changegroup.bundletypes:
2485 if bundletype not in changegroup.bundletypes:
2486 raise error.Abort(_('unknown bundle type specified with --type'))
2486 raise error.Abort(_('unknown bundle type specified with --type'))
2487 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2487 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2488
2488
2489 @command('debugignore', [], '[FILE]')
2489 @command('debugignore', [], '[FILE]')
2490 def debugignore(ui, repo, *files, **opts):
2490 def debugignore(ui, repo, *files, **opts):
2491 """display the combined ignore pattern and information about ignored files
2491 """display the combined ignore pattern and information about ignored files
2492
2492
2493 With no argument display the combined ignore pattern.
2493 With no argument display the combined ignore pattern.
2494
2494
2495 Given space separated file names, shows if the given file is ignored and
2495 Given space separated file names, shows if the given file is ignored and
2496 if so, show the ignore rule (file and line number) that matched it.
2496 if so, show the ignore rule (file and line number) that matched it.
2497 """
2497 """
2498 ignore = repo.dirstate._ignore
2498 ignore = repo.dirstate._ignore
2499 if not files:
2499 if not files:
2500 # Show all the patterns
2500 # Show all the patterns
2501 includepat = getattr(ignore, 'includepat', None)
2501 includepat = getattr(ignore, 'includepat', None)
2502 if includepat is not None:
2502 if includepat is not None:
2503 ui.write("%s\n" % includepat)
2503 ui.write("%s\n" % includepat)
2504 else:
2504 else:
2505 raise error.Abort(_("no ignore patterns found"))
2505 raise error.Abort(_("no ignore patterns found"))
2506 else:
2506 else:
2507 for f in files:
2507 for f in files:
2508 nf = util.normpath(f)
2508 nf = util.normpath(f)
2509 ignored = None
2509 ignored = None
2510 ignoredata = None
2510 ignoredata = None
2511 if nf != '.':
2511 if nf != '.':
2512 if ignore(nf):
2512 if ignore(nf):
2513 ignored = nf
2513 ignored = nf
2514 ignoredata = repo.dirstate._ignorefileandline(nf)
2514 ignoredata = repo.dirstate._ignorefileandline(nf)
2515 else:
2515 else:
2516 for p in util.finddirs(nf):
2516 for p in util.finddirs(nf):
2517 if ignore(p):
2517 if ignore(p):
2518 ignored = p
2518 ignored = p
2519 ignoredata = repo.dirstate._ignorefileandline(p)
2519 ignoredata = repo.dirstate._ignorefileandline(p)
2520 break
2520 break
2521 if ignored:
2521 if ignored:
2522 if ignored == nf:
2522 if ignored == nf:
2523 ui.write("%s is ignored\n" % f)
2523 ui.write("%s is ignored\n" % f)
2524 else:
2524 else:
2525 ui.write("%s is ignored because of containing folder %s\n"
2525 ui.write("%s is ignored because of containing folder %s\n"
2526 % (f, ignored))
2526 % (f, ignored))
2527 ignorefile, lineno, line = ignoredata
2527 ignorefile, lineno, line = ignoredata
2528 ui.write("(ignore rule in %s, line %d: '%s')\n"
2528 ui.write("(ignore rule in %s, line %d: '%s')\n"
2529 % (ignorefile, lineno, line))
2529 % (ignorefile, lineno, line))
2530 else:
2530 else:
2531 ui.write("%s is not ignored\n" % f)
2531 ui.write("%s is not ignored\n" % f)
2532
2532
2533 @command('debugindex', debugrevlogopts +
2533 @command('debugindex', debugrevlogopts +
2534 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2534 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2535 _('[-f FORMAT] -c|-m|FILE'),
2535 _('[-f FORMAT] -c|-m|FILE'),
2536 optionalrepo=True)
2536 optionalrepo=True)
2537 def debugindex(ui, repo, file_=None, **opts):
2537 def debugindex(ui, repo, file_=None, **opts):
2538 """dump the contents of an index file"""
2538 """dump the contents of an index file"""
2539 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2539 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2540 format = opts.get('format', 0)
2540 format = opts.get('format', 0)
2541 if format not in (0, 1):
2541 if format not in (0, 1):
2542 raise error.Abort(_("unknown format %d") % format)
2542 raise error.Abort(_("unknown format %d") % format)
2543
2543
2544 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2544 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2545 if generaldelta:
2545 if generaldelta:
2546 basehdr = ' delta'
2546 basehdr = ' delta'
2547 else:
2547 else:
2548 basehdr = ' base'
2548 basehdr = ' base'
2549
2549
2550 if ui.debugflag:
2550 if ui.debugflag:
2551 shortfn = hex
2551 shortfn = hex
2552 else:
2552 else:
2553 shortfn = short
2553 shortfn = short
2554
2554
2555 # There might not be anything in r, so have a sane default
2555 # There might not be anything in r, so have a sane default
2556 idlen = 12
2556 idlen = 12
2557 for i in r:
2557 for i in r:
2558 idlen = len(shortfn(r.node(i)))
2558 idlen = len(shortfn(r.node(i)))
2559 break
2559 break
2560
2560
2561 if format == 0:
2561 if format == 0:
2562 ui.write(" rev offset length " + basehdr + " linkrev"
2562 ui.write(" rev offset length " + basehdr + " linkrev"
2563 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2563 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2564 elif format == 1:
2564 elif format == 1:
2565 ui.write(" rev flag offset length"
2565 ui.write(" rev flag offset length"
2566 " size " + basehdr + " link p1 p2"
2566 " size " + basehdr + " link p1 p2"
2567 " %s\n" % "nodeid".rjust(idlen))
2567 " %s\n" % "nodeid".rjust(idlen))
2568
2568
2569 for i in r:
2569 for i in r:
2570 node = r.node(i)
2570 node = r.node(i)
2571 if generaldelta:
2571 if generaldelta:
2572 base = r.deltaparent(i)
2572 base = r.deltaparent(i)
2573 else:
2573 else:
2574 base = r.chainbase(i)
2574 base = r.chainbase(i)
2575 if format == 0:
2575 if format == 0:
2576 try:
2576 try:
2577 pp = r.parents(node)
2577 pp = r.parents(node)
2578 except Exception:
2578 except Exception:
2579 pp = [nullid, nullid]
2579 pp = [nullid, nullid]
2580 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2580 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2581 i, r.start(i), r.length(i), base, r.linkrev(i),
2581 i, r.start(i), r.length(i), base, r.linkrev(i),
2582 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2582 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2583 elif format == 1:
2583 elif format == 1:
2584 pr = r.parentrevs(i)
2584 pr = r.parentrevs(i)
2585 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2585 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2586 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2586 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2587 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2587 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2588
2588
2589 @command('debugindexdot', debugrevlogopts,
2589 @command('debugindexdot', debugrevlogopts,
2590 _('-c|-m|FILE'), optionalrepo=True)
2590 _('-c|-m|FILE'), optionalrepo=True)
2591 def debugindexdot(ui, repo, file_=None, **opts):
2591 def debugindexdot(ui, repo, file_=None, **opts):
2592 """dump an index DAG as a graphviz dot file"""
2592 """dump an index DAG as a graphviz dot file"""
2593 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2593 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2594 ui.write(("digraph G {\n"))
2594 ui.write(("digraph G {\n"))
2595 for i in r:
2595 for i in r:
2596 node = r.node(i)
2596 node = r.node(i)
2597 pp = r.parents(node)
2597 pp = r.parents(node)
2598 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2598 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2599 if pp[1] != nullid:
2599 if pp[1] != nullid:
2600 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2600 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2601 ui.write("}\n")
2601 ui.write("}\n")
2602
2602
2603 @command('debugdeltachain',
2603 @command('debugdeltachain',
2604 debugrevlogopts + formatteropts,
2604 debugrevlogopts + formatteropts,
2605 _('-c|-m|FILE'),
2605 _('-c|-m|FILE'),
2606 optionalrepo=True)
2606 optionalrepo=True)
2607 def debugdeltachain(ui, repo, file_=None, **opts):
2607 def debugdeltachain(ui, repo, file_=None, **opts):
2608 """dump information about delta chains in a revlog
2608 """dump information about delta chains in a revlog
2609
2609
2610 Output can be templatized. Available template keywords are:
2610 Output can be templatized. Available template keywords are:
2611
2611
2612 rev revision number
2612 rev revision number
2613 chainid delta chain identifier (numbered by unique base)
2613 chainid delta chain identifier (numbered by unique base)
2614 chainlen delta chain length to this revision
2614 chainlen delta chain length to this revision
2615 prevrev previous revision in delta chain
2615 prevrev previous revision in delta chain
2616 deltatype role of delta / how it was computed
2616 deltatype role of delta / how it was computed
2617 compsize compressed size of revision
2617 compsize compressed size of revision
2618 uncompsize uncompressed size of revision
2618 uncompsize uncompressed size of revision
2619 chainsize total size of compressed revisions in chain
2619 chainsize total size of compressed revisions in chain
2620 chainratio total chain size divided by uncompressed revision size
2620 chainratio total chain size divided by uncompressed revision size
2621 (new delta chains typically start at ratio 2.00)
2621 (new delta chains typically start at ratio 2.00)
2622 lindist linear distance from base revision in delta chain to end
2622 lindist linear distance from base revision in delta chain to end
2623 of this revision
2623 of this revision
2624 extradist total size of revisions not part of this delta chain from
2624 extradist total size of revisions not part of this delta chain from
2625 base of delta chain to end of this revision; a measurement
2625 base of delta chain to end of this revision; a measurement
2626 of how much extra data we need to read/seek across to read
2626 of how much extra data we need to read/seek across to read
2627 the delta chain for this revision
2627 the delta chain for this revision
2628 extraratio extradist divided by chainsize; another representation of
2628 extraratio extradist divided by chainsize; another representation of
2629 how much unrelated data is needed to load this delta chain
2629 how much unrelated data is needed to load this delta chain
2630 """
2630 """
2631 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2631 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2632 index = r.index
2632 index = r.index
2633 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2633 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2634
2634
2635 def revinfo(rev):
2635 def revinfo(rev):
2636 e = index[rev]
2636 e = index[rev]
2637 compsize = e[1]
2637 compsize = e[1]
2638 uncompsize = e[2]
2638 uncompsize = e[2]
2639 chainsize = 0
2639 chainsize = 0
2640
2640
2641 if generaldelta:
2641 if generaldelta:
2642 if e[3] == e[5]:
2642 if e[3] == e[5]:
2643 deltatype = 'p1'
2643 deltatype = 'p1'
2644 elif e[3] == e[6]:
2644 elif e[3] == e[6]:
2645 deltatype = 'p2'
2645 deltatype = 'p2'
2646 elif e[3] == rev - 1:
2646 elif e[3] == rev - 1:
2647 deltatype = 'prev'
2647 deltatype = 'prev'
2648 elif e[3] == rev:
2648 elif e[3] == rev:
2649 deltatype = 'base'
2649 deltatype = 'base'
2650 else:
2650 else:
2651 deltatype = 'other'
2651 deltatype = 'other'
2652 else:
2652 else:
2653 if e[3] == rev:
2653 if e[3] == rev:
2654 deltatype = 'base'
2654 deltatype = 'base'
2655 else:
2655 else:
2656 deltatype = 'prev'
2656 deltatype = 'prev'
2657
2657
2658 chain = r._deltachain(rev)[0]
2658 chain = r._deltachain(rev)[0]
2659 for iterrev in chain:
2659 for iterrev in chain:
2660 e = index[iterrev]
2660 e = index[iterrev]
2661 chainsize += e[1]
2661 chainsize += e[1]
2662
2662
2663 return compsize, uncompsize, deltatype, chain, chainsize
2663 return compsize, uncompsize, deltatype, chain, chainsize
2664
2664
2665 fm = ui.formatter('debugdeltachain', opts)
2665 fm = ui.formatter('debugdeltachain', opts)
2666
2666
2667 fm.plain(' rev chain# chainlen prev delta '
2667 fm.plain(' rev chain# chainlen prev delta '
2668 'size rawsize chainsize ratio lindist extradist '
2668 'size rawsize chainsize ratio lindist extradist '
2669 'extraratio\n')
2669 'extraratio\n')
2670
2670
2671 chainbases = {}
2671 chainbases = {}
2672 for rev in r:
2672 for rev in r:
2673 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2673 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2674 chainbase = chain[0]
2674 chainbase = chain[0]
2675 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2675 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2676 basestart = r.start(chainbase)
2676 basestart = r.start(chainbase)
2677 revstart = r.start(rev)
2677 revstart = r.start(rev)
2678 lineardist = revstart + comp - basestart
2678 lineardist = revstart + comp - basestart
2679 extradist = lineardist - chainsize
2679 extradist = lineardist - chainsize
2680 try:
2680 try:
2681 prevrev = chain[-2]
2681 prevrev = chain[-2]
2682 except IndexError:
2682 except IndexError:
2683 prevrev = -1
2683 prevrev = -1
2684
2684
2685 chainratio = float(chainsize) / float(uncomp)
2685 chainratio = float(chainsize) / float(uncomp)
2686 extraratio = float(extradist) / float(chainsize)
2686 extraratio = float(extradist) / float(chainsize)
2687
2687
2688 fm.startitem()
2688 fm.startitem()
2689 fm.write('rev chainid chainlen prevrev deltatype compsize '
2689 fm.write('rev chainid chainlen prevrev deltatype compsize '
2690 'uncompsize chainsize chainratio lindist extradist '
2690 'uncompsize chainsize chainratio lindist extradist '
2691 'extraratio',
2691 'extraratio',
2692 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2692 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2693 rev, chainid, len(chain), prevrev, deltatype, comp,
2693 rev, chainid, len(chain), prevrev, deltatype, comp,
2694 uncomp, chainsize, chainratio, lineardist, extradist,
2694 uncomp, chainsize, chainratio, lineardist, extradist,
2695 extraratio,
2695 extraratio,
2696 rev=rev, chainid=chainid, chainlen=len(chain),
2696 rev=rev, chainid=chainid, chainlen=len(chain),
2697 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2697 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2698 uncompsize=uncomp, chainsize=chainsize,
2698 uncompsize=uncomp, chainsize=chainsize,
2699 chainratio=chainratio, lindist=lineardist,
2699 chainratio=chainratio, lindist=lineardist,
2700 extradist=extradist, extraratio=extraratio)
2700 extradist=extradist, extraratio=extraratio)
2701
2701
2702 fm.end()
2702 fm.end()
2703
2703
2704 @command('debuginstall', [] + formatteropts, '', norepo=True)
2704 @command('debuginstall', [] + formatteropts, '', norepo=True)
2705 def debuginstall(ui, **opts):
2705 def debuginstall(ui, **opts):
2706 '''test Mercurial installation
2706 '''test Mercurial installation
2707
2707
2708 Returns 0 on success.
2708 Returns 0 on success.
2709 '''
2709 '''
2710
2710
2711 def writetemp(contents):
2711 def writetemp(contents):
2712 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2712 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2713 f = os.fdopen(fd, "wb")
2713 f = os.fdopen(fd, "wb")
2714 f.write(contents)
2714 f.write(contents)
2715 f.close()
2715 f.close()
2716 return name
2716 return name
2717
2717
2718 problems = 0
2718 problems = 0
2719
2719
2720 fm = ui.formatter('debuginstall', opts)
2720 fm = ui.formatter('debuginstall', opts)
2721 fm.startitem()
2721 fm.startitem()
2722
2722
2723 # encoding
2723 # encoding
2724 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2724 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2725 err = None
2725 err = None
2726 try:
2726 try:
2727 encoding.fromlocal("test")
2727 encoding.fromlocal("test")
2728 except error.Abort as inst:
2728 except error.Abort as inst:
2729 err = inst
2729 err = inst
2730 problems += 1
2730 problems += 1
2731 fm.condwrite(err, 'encodingerror', _(" %s\n"
2731 fm.condwrite(err, 'encodingerror', _(" %s\n"
2732 " (check that your locale is properly set)\n"), err)
2732 " (check that your locale is properly set)\n"), err)
2733
2733
2734 # Python
2734 # Python
2735 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2735 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2736 sys.executable)
2736 sys.executable)
2737 fm.write('pythonver', _("checking Python version (%s)\n"),
2737 fm.write('pythonver', _("checking Python version (%s)\n"),
2738 ("%s.%s.%s" % sys.version_info[:3]))
2738 ("%s.%s.%s" % sys.version_info[:3]))
2739 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2739 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2740 os.path.dirname(os.__file__))
2740 os.path.dirname(os.__file__))
2741
2741
2742 # compiled modules
2742 # compiled modules
2743 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2743 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2744 os.path.dirname(__file__))
2744 os.path.dirname(__file__))
2745
2745
2746 err = None
2746 err = None
2747 try:
2747 try:
2748 from . import (
2748 from . import (
2749 base85,
2749 base85,
2750 bdiff,
2750 bdiff,
2751 mpatch,
2751 mpatch,
2752 osutil,
2752 osutil,
2753 )
2753 )
2754 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2754 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2755 except Exception as inst:
2755 except Exception as inst:
2756 err = inst
2756 err = inst
2757 problems += 1
2757 problems += 1
2758 fm.condwrite(err, 'extensionserror', " %s\n", err)
2758 fm.condwrite(err, 'extensionserror', " %s\n", err)
2759
2759
2760 # templates
2760 # templates
2761 p = templater.templatepaths()
2761 p = templater.templatepaths()
2762 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2762 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2763 fm.condwrite(not p, '', _(" no template directories found\n"))
2763 fm.condwrite(not p, '', _(" no template directories found\n"))
2764 if p:
2764 if p:
2765 m = templater.templatepath("map-cmdline.default")
2765 m = templater.templatepath("map-cmdline.default")
2766 if m:
2766 if m:
2767 # template found, check if it is working
2767 # template found, check if it is working
2768 err = None
2768 err = None
2769 try:
2769 try:
2770 templater.templater(m)
2770 templater.templater(m)
2771 except Exception as inst:
2771 except Exception as inst:
2772 err = inst
2772 err = inst
2773 p = None
2773 p = None
2774 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2774 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2775 else:
2775 else:
2776 p = None
2776 p = None
2777 fm.condwrite(p, 'defaulttemplate',
2777 fm.condwrite(p, 'defaulttemplate',
2778 _("checking default template (%s)\n"), m)
2778 _("checking default template (%s)\n"), m)
2779 fm.condwrite(not m, 'defaulttemplatenotfound',
2779 fm.condwrite(not m, 'defaulttemplatenotfound',
2780 _(" template '%s' not found\n"), "default")
2780 _(" template '%s' not found\n"), "default")
2781 if not p:
2781 if not p:
2782 problems += 1
2782 problems += 1
2783 fm.condwrite(not p, '',
2783 fm.condwrite(not p, '',
2784 _(" (templates seem to have been installed incorrectly)\n"))
2784 _(" (templates seem to have been installed incorrectly)\n"))
2785
2785
2786 # editor
2786 # editor
2787 editor = ui.geteditor()
2787 editor = ui.geteditor()
2788 editor = util.expandpath(editor)
2788 editor = util.expandpath(editor)
2789 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2789 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2790 cmdpath = util.findexe(shlex.split(editor)[0])
2790 cmdpath = util.findexe(shlex.split(editor)[0])
2791 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2791 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2792 _(" No commit editor set and can't find %s in PATH\n"
2792 _(" No commit editor set and can't find %s in PATH\n"
2793 " (specify a commit editor in your configuration"
2793 " (specify a commit editor in your configuration"
2794 " file)\n"), not cmdpath and editor == 'vi' and editor)
2794 " file)\n"), not cmdpath and editor == 'vi' and editor)
2795 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2795 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2796 _(" Can't find editor '%s' in PATH\n"
2796 _(" Can't find editor '%s' in PATH\n"
2797 " (specify a commit editor in your configuration"
2797 " (specify a commit editor in your configuration"
2798 " file)\n"), not cmdpath and editor)
2798 " file)\n"), not cmdpath and editor)
2799 if not cmdpath and editor != 'vi':
2799 if not cmdpath and editor != 'vi':
2800 problems += 1
2800 problems += 1
2801
2801
2802 # check username
2802 # check username
2803 username = None
2803 username = None
2804 err = None
2804 err = None
2805 try:
2805 try:
2806 username = ui.username()
2806 username = ui.username()
2807 except error.Abort as e:
2807 except error.Abort as e:
2808 err = e
2808 err = e
2809 problems += 1
2809 problems += 1
2810
2810
2811 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2811 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2812 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2812 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2813 " (specify a username in your configuration file)\n"), err)
2813 " (specify a username in your configuration file)\n"), err)
2814
2814
2815 fm.condwrite(not problems, '',
2815 fm.condwrite(not problems, '',
2816 _("no problems detected\n"))
2816 _("no problems detected\n"))
2817 if not problems:
2817 if not problems:
2818 fm.data(problems=problems)
2818 fm.data(problems=problems)
2819 fm.condwrite(problems, 'problems',
2819 fm.condwrite(problems, 'problems',
2820 _("%s problems detected,"
2820 _("%s problems detected,"
2821 " please check your install!\n"), problems)
2821 " please check your install!\n"), problems)
2822 fm.end()
2822 fm.end()
2823
2823
2824 return problems
2824 return problems
2825
2825
2826 @command('debugknown', [], _('REPO ID...'), norepo=True)
2826 @command('debugknown', [], _('REPO ID...'), norepo=True)
2827 def debugknown(ui, repopath, *ids, **opts):
2827 def debugknown(ui, repopath, *ids, **opts):
2828 """test whether node ids are known to a repo
2828 """test whether node ids are known to a repo
2829
2829
2830 Every ID must be a full-length hex node id string. Returns a list of 0s
2830 Every ID must be a full-length hex node id string. Returns a list of 0s
2831 and 1s indicating unknown/known.
2831 and 1s indicating unknown/known.
2832 """
2832 """
2833 repo = hg.peer(ui, opts, repopath)
2833 repo = hg.peer(ui, opts, repopath)
2834 if not repo.capable('known'):
2834 if not repo.capable('known'):
2835 raise error.Abort("known() not supported by target repository")
2835 raise error.Abort("known() not supported by target repository")
2836 flags = repo.known([bin(s) for s in ids])
2836 flags = repo.known([bin(s) for s in ids])
2837 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2837 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2838
2838
2839 @command('debuglabelcomplete', [], _('LABEL...'))
2839 @command('debuglabelcomplete', [], _('LABEL...'))
2840 def debuglabelcomplete(ui, repo, *args):
2840 def debuglabelcomplete(ui, repo, *args):
2841 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2841 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2842 debugnamecomplete(ui, repo, *args)
2842 debugnamecomplete(ui, repo, *args)
2843
2843
2844 @command('debugmergestate', [], '')
2844 @command('debugmergestate', [], '')
2845 def debugmergestate(ui, repo, *args):
2845 def debugmergestate(ui, repo, *args):
2846 """print merge state
2846 """print merge state
2847
2847
2848 Use --verbose to print out information about whether v1 or v2 merge state
2848 Use --verbose to print out information about whether v1 or v2 merge state
2849 was chosen."""
2849 was chosen."""
2850 def _hashornull(h):
2850 def _hashornull(h):
2851 if h == nullhex:
2851 if h == nullhex:
2852 return 'null'
2852 return 'null'
2853 else:
2853 else:
2854 return h
2854 return h
2855
2855
2856 def printrecords(version):
2856 def printrecords(version):
2857 ui.write(('* version %s records\n') % version)
2857 ui.write(('* version %s records\n') % version)
2858 if version == 1:
2858 if version == 1:
2859 records = v1records
2859 records = v1records
2860 else:
2860 else:
2861 records = v2records
2861 records = v2records
2862
2862
2863 for rtype, record in records:
2863 for rtype, record in records:
2864 # pretty print some record types
2864 # pretty print some record types
2865 if rtype == 'L':
2865 if rtype == 'L':
2866 ui.write(('local: %s\n') % record)
2866 ui.write(('local: %s\n') % record)
2867 elif rtype == 'O':
2867 elif rtype == 'O':
2868 ui.write(('other: %s\n') % record)
2868 ui.write(('other: %s\n') % record)
2869 elif rtype == 'm':
2869 elif rtype == 'm':
2870 driver, mdstate = record.split('\0', 1)
2870 driver, mdstate = record.split('\0', 1)
2871 ui.write(('merge driver: %s (state "%s")\n')
2871 ui.write(('merge driver: %s (state "%s")\n')
2872 % (driver, mdstate))
2872 % (driver, mdstate))
2873 elif rtype in 'FDC':
2873 elif rtype in 'FDC':
2874 r = record.split('\0')
2874 r = record.split('\0')
2875 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2875 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2876 if version == 1:
2876 if version == 1:
2877 onode = 'not stored in v1 format'
2877 onode = 'not stored in v1 format'
2878 flags = r[7]
2878 flags = r[7]
2879 else:
2879 else:
2880 onode, flags = r[7:9]
2880 onode, flags = r[7:9]
2881 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2881 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2882 % (f, rtype, state, _hashornull(hash)))
2882 % (f, rtype, state, _hashornull(hash)))
2883 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2883 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2884 ui.write((' ancestor path: %s (node %s)\n')
2884 ui.write((' ancestor path: %s (node %s)\n')
2885 % (afile, _hashornull(anode)))
2885 % (afile, _hashornull(anode)))
2886 ui.write((' other path: %s (node %s)\n')
2886 ui.write((' other path: %s (node %s)\n')
2887 % (ofile, _hashornull(onode)))
2887 % (ofile, _hashornull(onode)))
2888 elif rtype == 'f':
2888 elif rtype == 'f':
2889 filename, rawextras = record.split('\0', 1)
2889 filename, rawextras = record.split('\0', 1)
2890 extras = rawextras.split('\0')
2890 extras = rawextras.split('\0')
2891 i = 0
2891 i = 0
2892 extrastrings = []
2892 extrastrings = []
2893 while i < len(extras):
2893 while i < len(extras):
2894 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2894 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2895 i += 2
2895 i += 2
2896
2896
2897 ui.write(('file extras: %s (%s)\n')
2897 ui.write(('file extras: %s (%s)\n')
2898 % (filename, ', '.join(extrastrings)))
2898 % (filename, ', '.join(extrastrings)))
2899 else:
2899 else:
2900 ui.write(('unrecognized entry: %s\t%s\n')
2900 ui.write(('unrecognized entry: %s\t%s\n')
2901 % (rtype, record.replace('\0', '\t')))
2901 % (rtype, record.replace('\0', '\t')))
2902
2902
2903 # Avoid mergestate.read() since it may raise an exception for unsupported
2903 # Avoid mergestate.read() since it may raise an exception for unsupported
2904 # merge state records. We shouldn't be doing this, but this is OK since this
2904 # merge state records. We shouldn't be doing this, but this is OK since this
2905 # command is pretty low-level.
2905 # command is pretty low-level.
2906 ms = mergemod.mergestate(repo)
2906 ms = mergemod.mergestate(repo)
2907
2907
2908 # sort so that reasonable information is on top
2908 # sort so that reasonable information is on top
2909 v1records = ms._readrecordsv1()
2909 v1records = ms._readrecordsv1()
2910 v2records = ms._readrecordsv2()
2910 v2records = ms._readrecordsv2()
2911 order = 'LOm'
2911 order = 'LOm'
2912 def key(r):
2912 def key(r):
2913 idx = order.find(r[0])
2913 idx = order.find(r[0])
2914 if idx == -1:
2914 if idx == -1:
2915 return (1, r[1])
2915 return (1, r[1])
2916 else:
2916 else:
2917 return (0, idx)
2917 return (0, idx)
2918 v1records.sort(key=key)
2918 v1records.sort(key=key)
2919 v2records.sort(key=key)
2919 v2records.sort(key=key)
2920
2920
2921 if not v1records and not v2records:
2921 if not v1records and not v2records:
2922 ui.write(('no merge state found\n'))
2922 ui.write(('no merge state found\n'))
2923 elif not v2records:
2923 elif not v2records:
2924 ui.note(('no version 2 merge state\n'))
2924 ui.note(('no version 2 merge state\n'))
2925 printrecords(1)
2925 printrecords(1)
2926 elif ms._v1v2match(v1records, v2records):
2926 elif ms._v1v2match(v1records, v2records):
2927 ui.note(('v1 and v2 states match: using v2\n'))
2927 ui.note(('v1 and v2 states match: using v2\n'))
2928 printrecords(2)
2928 printrecords(2)
2929 else:
2929 else:
2930 ui.note(('v1 and v2 states mismatch: using v1\n'))
2930 ui.note(('v1 and v2 states mismatch: using v1\n'))
2931 printrecords(1)
2931 printrecords(1)
2932 if ui.verbose:
2932 if ui.verbose:
2933 printrecords(2)
2933 printrecords(2)
2934
2934
2935 @command('debugnamecomplete', [], _('NAME...'))
2935 @command('debugnamecomplete', [], _('NAME...'))
2936 def debugnamecomplete(ui, repo, *args):
2936 def debugnamecomplete(ui, repo, *args):
2937 '''complete "names" - tags, open branch names, bookmark names'''
2937 '''complete "names" - tags, open branch names, bookmark names'''
2938
2938
2939 names = set()
2939 names = set()
2940 # since we previously only listed open branches, we will handle that
2940 # since we previously only listed open branches, we will handle that
2941 # specially (after this for loop)
2941 # specially (after this for loop)
2942 for name, ns in repo.names.iteritems():
2942 for name, ns in repo.names.iteritems():
2943 if name != 'branches':
2943 if name != 'branches':
2944 names.update(ns.listnames(repo))
2944 names.update(ns.listnames(repo))
2945 names.update(tag for (tag, heads, tip, closed)
2945 names.update(tag for (tag, heads, tip, closed)
2946 in repo.branchmap().iterbranches() if not closed)
2946 in repo.branchmap().iterbranches() if not closed)
2947 completions = set()
2947 completions = set()
2948 if not args:
2948 if not args:
2949 args = ['']
2949 args = ['']
2950 for a in args:
2950 for a in args:
2951 completions.update(n for n in names if n.startswith(a))
2951 completions.update(n for n in names if n.startswith(a))
2952 ui.write('\n'.join(sorted(completions)))
2952 ui.write('\n'.join(sorted(completions)))
2953 ui.write('\n')
2953 ui.write('\n')
2954
2954
2955 @command('debuglocks',
2955 @command('debuglocks',
2956 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2956 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2957 ('W', 'force-wlock', None,
2957 ('W', 'force-wlock', None,
2958 _('free the working state lock (DANGEROUS)'))],
2958 _('free the working state lock (DANGEROUS)'))],
2959 _('[OPTION]...'))
2959 _('[OPTION]...'))
2960 def debuglocks(ui, repo, **opts):
2960 def debuglocks(ui, repo, **opts):
2961 """show or modify state of locks
2961 """show or modify state of locks
2962
2962
2963 By default, this command will show which locks are held. This
2963 By default, this command will show which locks are held. This
2964 includes the user and process holding the lock, the amount of time
2964 includes the user and process holding the lock, the amount of time
2965 the lock has been held, and the machine name where the process is
2965 the lock has been held, and the machine name where the process is
2966 running if it's not local.
2966 running if it's not local.
2967
2967
2968 Locks protect the integrity of Mercurial's data, so should be
2968 Locks protect the integrity of Mercurial's data, so should be
2969 treated with care. System crashes or other interruptions may cause
2969 treated with care. System crashes or other interruptions may cause
2970 locks to not be properly released, though Mercurial will usually
2970 locks to not be properly released, though Mercurial will usually
2971 detect and remove such stale locks automatically.
2971 detect and remove such stale locks automatically.
2972
2972
2973 However, detecting stale locks may not always be possible (for
2973 However, detecting stale locks may not always be possible (for
2974 instance, on a shared filesystem). Removing locks may also be
2974 instance, on a shared filesystem). Removing locks may also be
2975 blocked by filesystem permissions.
2975 blocked by filesystem permissions.
2976
2976
2977 Returns 0 if no locks are held.
2977 Returns 0 if no locks are held.
2978
2978
2979 """
2979 """
2980
2980
2981 if opts.get('force_lock'):
2981 if opts.get('force_lock'):
2982 repo.svfs.unlink('lock')
2982 repo.svfs.unlink('lock')
2983 if opts.get('force_wlock'):
2983 if opts.get('force_wlock'):
2984 repo.vfs.unlink('wlock')
2984 repo.vfs.unlink('wlock')
2985 if opts.get('force_lock') or opts.get('force_lock'):
2985 if opts.get('force_lock') or opts.get('force_lock'):
2986 return 0
2986 return 0
2987
2987
2988 now = time.time()
2988 now = time.time()
2989 held = 0
2989 held = 0
2990
2990
2991 def report(vfs, name, method):
2991 def report(vfs, name, method):
2992 # this causes stale locks to get reaped for more accurate reporting
2992 # this causes stale locks to get reaped for more accurate reporting
2993 try:
2993 try:
2994 l = method(False)
2994 l = method(False)
2995 except error.LockHeld:
2995 except error.LockHeld:
2996 l = None
2996 l = None
2997
2997
2998 if l:
2998 if l:
2999 l.release()
2999 l.release()
3000 else:
3000 else:
3001 try:
3001 try:
3002 stat = vfs.lstat(name)
3002 stat = vfs.lstat(name)
3003 age = now - stat.st_mtime
3003 age = now - stat.st_mtime
3004 user = util.username(stat.st_uid)
3004 user = util.username(stat.st_uid)
3005 locker = vfs.readlock(name)
3005 locker = vfs.readlock(name)
3006 if ":" in locker:
3006 if ":" in locker:
3007 host, pid = locker.split(':')
3007 host, pid = locker.split(':')
3008 if host == socket.gethostname():
3008 if host == socket.gethostname():
3009 locker = 'user %s, process %s' % (user, pid)
3009 locker = 'user %s, process %s' % (user, pid)
3010 else:
3010 else:
3011 locker = 'user %s, process %s, host %s' \
3011 locker = 'user %s, process %s, host %s' \
3012 % (user, pid, host)
3012 % (user, pid, host)
3013 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3013 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3014 return 1
3014 return 1
3015 except OSError as e:
3015 except OSError as e:
3016 if e.errno != errno.ENOENT:
3016 if e.errno != errno.ENOENT:
3017 raise
3017 raise
3018
3018
3019 ui.write("%-6s free\n" % (name + ":"))
3019 ui.write("%-6s free\n" % (name + ":"))
3020 return 0
3020 return 0
3021
3021
3022 held += report(repo.svfs, "lock", repo.lock)
3022 held += report(repo.svfs, "lock", repo.lock)
3023 held += report(repo.vfs, "wlock", repo.wlock)
3023 held += report(repo.vfs, "wlock", repo.wlock)
3024
3024
3025 return held
3025 return held
3026
3026
3027 @command('debugobsolete',
3027 @command('debugobsolete',
3028 [('', 'flags', 0, _('markers flag')),
3028 [('', 'flags', 0, _('markers flag')),
3029 ('', 'record-parents', False,
3029 ('', 'record-parents', False,
3030 _('record parent information for the precursor')),
3030 _('record parent information for the precursor')),
3031 ('r', 'rev', [], _('display markers relevant to REV')),
3031 ('r', 'rev', [], _('display markers relevant to REV')),
3032 ('', 'index', False, _('display index of the marker')),
3032 ('', 'index', False, _('display index of the marker')),
3033 ] + commitopts2,
3033 ] + commitopts2,
3034 _('[OBSOLETED [REPLACEMENT ...]]'))
3034 _('[OBSOLETED [REPLACEMENT ...]]'))
3035 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3035 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3036 """create arbitrary obsolete marker
3036 """create arbitrary obsolete marker
3037
3037
3038 With no arguments, displays the list of obsolescence markers."""
3038 With no arguments, displays the list of obsolescence markers."""
3039
3039
3040 def parsenodeid(s):
3040 def parsenodeid(s):
3041 try:
3041 try:
3042 # We do not use revsingle/revrange functions here to accept
3042 # We do not use revsingle/revrange functions here to accept
3043 # arbitrary node identifiers, possibly not present in the
3043 # arbitrary node identifiers, possibly not present in the
3044 # local repository.
3044 # local repository.
3045 n = bin(s)
3045 n = bin(s)
3046 if len(n) != len(nullid):
3046 if len(n) != len(nullid):
3047 raise TypeError()
3047 raise TypeError()
3048 return n
3048 return n
3049 except TypeError:
3049 except TypeError:
3050 raise error.Abort('changeset references must be full hexadecimal '
3050 raise error.Abort('changeset references must be full hexadecimal '
3051 'node identifiers')
3051 'node identifiers')
3052
3052
3053 if precursor is not None:
3053 if precursor is not None:
3054 if opts['rev']:
3054 if opts['rev']:
3055 raise error.Abort('cannot select revision when creating marker')
3055 raise error.Abort('cannot select revision when creating marker')
3056 metadata = {}
3056 metadata = {}
3057 metadata['user'] = opts['user'] or ui.username()
3057 metadata['user'] = opts['user'] or ui.username()
3058 succs = tuple(parsenodeid(succ) for succ in successors)
3058 succs = tuple(parsenodeid(succ) for succ in successors)
3059 l = repo.lock()
3059 l = repo.lock()
3060 try:
3060 try:
3061 tr = repo.transaction('debugobsolete')
3061 tr = repo.transaction('debugobsolete')
3062 try:
3062 try:
3063 date = opts.get('date')
3063 date = opts.get('date')
3064 if date:
3064 if date:
3065 date = util.parsedate(date)
3065 date = util.parsedate(date)
3066 else:
3066 else:
3067 date = None
3067 date = None
3068 prec = parsenodeid(precursor)
3068 prec = parsenodeid(precursor)
3069 parents = None
3069 parents = None
3070 if opts['record_parents']:
3070 if opts['record_parents']:
3071 if prec not in repo.unfiltered():
3071 if prec not in repo.unfiltered():
3072 raise error.Abort('cannot used --record-parents on '
3072 raise error.Abort('cannot used --record-parents on '
3073 'unknown changesets')
3073 'unknown changesets')
3074 parents = repo.unfiltered()[prec].parents()
3074 parents = repo.unfiltered()[prec].parents()
3075 parents = tuple(p.node() for p in parents)
3075 parents = tuple(p.node() for p in parents)
3076 repo.obsstore.create(tr, prec, succs, opts['flags'],
3076 repo.obsstore.create(tr, prec, succs, opts['flags'],
3077 parents=parents, date=date,
3077 parents=parents, date=date,
3078 metadata=metadata)
3078 metadata=metadata)
3079 tr.close()
3079 tr.close()
3080 except ValueError as exc:
3080 except ValueError as exc:
3081 raise error.Abort(_('bad obsmarker input: %s') % exc)
3081 raise error.Abort(_('bad obsmarker input: %s') % exc)
3082 finally:
3082 finally:
3083 tr.release()
3083 tr.release()
3084 finally:
3084 finally:
3085 l.release()
3085 l.release()
3086 else:
3086 else:
3087 if opts['rev']:
3087 if opts['rev']:
3088 revs = scmutil.revrange(repo, opts['rev'])
3088 revs = scmutil.revrange(repo, opts['rev'])
3089 nodes = [repo[r].node() for r in revs]
3089 nodes = [repo[r].node() for r in revs]
3090 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3090 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3091 markers.sort(key=lambda x: x._data)
3091 markers.sort(key=lambda x: x._data)
3092 else:
3092 else:
3093 markers = obsolete.getmarkers(repo)
3093 markers = obsolete.getmarkers(repo)
3094
3094
3095 for i, m in enumerate(markers):
3095 for i, m in enumerate(markers):
3096 ind = i if opts.get('index') else None
3096 ind = i if opts.get('index') else None
3097 cmdutil.showmarker(ui, m, index=ind)
3097 cmdutil.showmarker(ui, m, index=ind)
3098
3098
3099 @command('debugpathcomplete',
3099 @command('debugpathcomplete',
3100 [('f', 'full', None, _('complete an entire path')),
3100 [('f', 'full', None, _('complete an entire path')),
3101 ('n', 'normal', None, _('show only normal files')),
3101 ('n', 'normal', None, _('show only normal files')),
3102 ('a', 'added', None, _('show only added files')),
3102 ('a', 'added', None, _('show only added files')),
3103 ('r', 'removed', None, _('show only removed files'))],
3103 ('r', 'removed', None, _('show only removed files'))],
3104 _('FILESPEC...'))
3104 _('FILESPEC...'))
3105 def debugpathcomplete(ui, repo, *specs, **opts):
3105 def debugpathcomplete(ui, repo, *specs, **opts):
3106 '''complete part or all of a tracked path
3106 '''complete part or all of a tracked path
3107
3107
3108 This command supports shells that offer path name completion. It
3108 This command supports shells that offer path name completion. It
3109 currently completes only files already known to the dirstate.
3109 currently completes only files already known to the dirstate.
3110
3110
3111 Completion extends only to the next path segment unless
3111 Completion extends only to the next path segment unless
3112 --full is specified, in which case entire paths are used.'''
3112 --full is specified, in which case entire paths are used.'''
3113
3113
3114 def complete(path, acceptable):
3114 def complete(path, acceptable):
3115 dirstate = repo.dirstate
3115 dirstate = repo.dirstate
3116 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3116 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3117 rootdir = repo.root + os.sep
3117 rootdir = repo.root + os.sep
3118 if spec != repo.root and not spec.startswith(rootdir):
3118 if spec != repo.root and not spec.startswith(rootdir):
3119 return [], []
3119 return [], []
3120 if os.path.isdir(spec):
3120 if os.path.isdir(spec):
3121 spec += '/'
3121 spec += '/'
3122 spec = spec[len(rootdir):]
3122 spec = spec[len(rootdir):]
3123 fixpaths = os.sep != '/'
3123 fixpaths = os.sep != '/'
3124 if fixpaths:
3124 if fixpaths:
3125 spec = spec.replace(os.sep, '/')
3125 spec = spec.replace(os.sep, '/')
3126 speclen = len(spec)
3126 speclen = len(spec)
3127 fullpaths = opts['full']
3127 fullpaths = opts['full']
3128 files, dirs = set(), set()
3128 files, dirs = set(), set()
3129 adddir, addfile = dirs.add, files.add
3129 adddir, addfile = dirs.add, files.add
3130 for f, st in dirstate.iteritems():
3130 for f, st in dirstate.iteritems():
3131 if f.startswith(spec) and st[0] in acceptable:
3131 if f.startswith(spec) and st[0] in acceptable:
3132 if fixpaths:
3132 if fixpaths:
3133 f = f.replace('/', os.sep)
3133 f = f.replace('/', os.sep)
3134 if fullpaths:
3134 if fullpaths:
3135 addfile(f)
3135 addfile(f)
3136 continue
3136 continue
3137 s = f.find(os.sep, speclen)
3137 s = f.find(os.sep, speclen)
3138 if s >= 0:
3138 if s >= 0:
3139 adddir(f[:s])
3139 adddir(f[:s])
3140 else:
3140 else:
3141 addfile(f)
3141 addfile(f)
3142 return files, dirs
3142 return files, dirs
3143
3143
3144 acceptable = ''
3144 acceptable = ''
3145 if opts['normal']:
3145 if opts['normal']:
3146 acceptable += 'nm'
3146 acceptable += 'nm'
3147 if opts['added']:
3147 if opts['added']:
3148 acceptable += 'a'
3148 acceptable += 'a'
3149 if opts['removed']:
3149 if opts['removed']:
3150 acceptable += 'r'
3150 acceptable += 'r'
3151 cwd = repo.getcwd()
3151 cwd = repo.getcwd()
3152 if not specs:
3152 if not specs:
3153 specs = ['.']
3153 specs = ['.']
3154
3154
3155 files, dirs = set(), set()
3155 files, dirs = set(), set()
3156 for spec in specs:
3156 for spec in specs:
3157 f, d = complete(spec, acceptable or 'nmar')
3157 f, d = complete(spec, acceptable or 'nmar')
3158 files.update(f)
3158 files.update(f)
3159 dirs.update(d)
3159 dirs.update(d)
3160 files.update(dirs)
3160 files.update(dirs)
3161 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3161 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3162 ui.write('\n')
3162 ui.write('\n')
3163
3163
3164 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3164 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3165 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3165 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3166 '''access the pushkey key/value protocol
3166 '''access the pushkey key/value protocol
3167
3167
3168 With two args, list the keys in the given namespace.
3168 With two args, list the keys in the given namespace.
3169
3169
3170 With five args, set a key to new if it currently is set to old.
3170 With five args, set a key to new if it currently is set to old.
3171 Reports success or failure.
3171 Reports success or failure.
3172 '''
3172 '''
3173
3173
3174 target = hg.peer(ui, {}, repopath)
3174 target = hg.peer(ui, {}, repopath)
3175 if keyinfo:
3175 if keyinfo:
3176 key, old, new = keyinfo
3176 key, old, new = keyinfo
3177 r = target.pushkey(namespace, key, old, new)
3177 r = target.pushkey(namespace, key, old, new)
3178 ui.status(str(r) + '\n')
3178 ui.status(str(r) + '\n')
3179 return not r
3179 return not r
3180 else:
3180 else:
3181 for k, v in sorted(target.listkeys(namespace).iteritems()):
3181 for k, v in sorted(target.listkeys(namespace).iteritems()):
3182 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3182 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3183 v.encode('string-escape')))
3183 v.encode('string-escape')))
3184
3184
3185 @command('debugpvec', [], _('A B'))
3185 @command('debugpvec', [], _('A B'))
3186 def debugpvec(ui, repo, a, b=None):
3186 def debugpvec(ui, repo, a, b=None):
3187 ca = scmutil.revsingle(repo, a)
3187 ca = scmutil.revsingle(repo, a)
3188 cb = scmutil.revsingle(repo, b)
3188 cb = scmutil.revsingle(repo, b)
3189 pa = pvec.ctxpvec(ca)
3189 pa = pvec.ctxpvec(ca)
3190 pb = pvec.ctxpvec(cb)
3190 pb = pvec.ctxpvec(cb)
3191 if pa == pb:
3191 if pa == pb:
3192 rel = "="
3192 rel = "="
3193 elif pa > pb:
3193 elif pa > pb:
3194 rel = ">"
3194 rel = ">"
3195 elif pa < pb:
3195 elif pa < pb:
3196 rel = "<"
3196 rel = "<"
3197 elif pa | pb:
3197 elif pa | pb:
3198 rel = "|"
3198 rel = "|"
3199 ui.write(_("a: %s\n") % pa)
3199 ui.write(_("a: %s\n") % pa)
3200 ui.write(_("b: %s\n") % pb)
3200 ui.write(_("b: %s\n") % pb)
3201 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3201 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3202 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3202 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3203 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3203 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3204 pa.distance(pb), rel))
3204 pa.distance(pb), rel))
3205
3205
3206 @command('debugrebuilddirstate|debugrebuildstate',
3206 @command('debugrebuilddirstate|debugrebuildstate',
3207 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3207 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3208 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3208 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3209 'the working copy parent')),
3209 'the working copy parent')),
3210 ],
3210 ],
3211 _('[-r REV]'))
3211 _('[-r REV]'))
3212 def debugrebuilddirstate(ui, repo, rev, **opts):
3212 def debugrebuilddirstate(ui, repo, rev, **opts):
3213 """rebuild the dirstate as it would look like for the given revision
3213 """rebuild the dirstate as it would look like for the given revision
3214
3214
3215 If no revision is specified the first current parent will be used.
3215 If no revision is specified the first current parent will be used.
3216
3216
3217 The dirstate will be set to the files of the given revision.
3217 The dirstate will be set to the files of the given revision.
3218 The actual working directory content or existing dirstate
3218 The actual working directory content or existing dirstate
3219 information such as adds or removes is not considered.
3219 information such as adds or removes is not considered.
3220
3220
3221 ``minimal`` will only rebuild the dirstate status for files that claim to be
3221 ``minimal`` will only rebuild the dirstate status for files that claim to be
3222 tracked but are not in the parent manifest, or that exist in the parent
3222 tracked but are not in the parent manifest, or that exist in the parent
3223 manifest but are not in the dirstate. It will not change adds, removes, or
3223 manifest but are not in the dirstate. It will not change adds, removes, or
3224 modified files that are in the working copy parent.
3224 modified files that are in the working copy parent.
3225
3225
3226 One use of this command is to make the next :hg:`status` invocation
3226 One use of this command is to make the next :hg:`status` invocation
3227 check the actual file content.
3227 check the actual file content.
3228 """
3228 """
3229 ctx = scmutil.revsingle(repo, rev)
3229 ctx = scmutil.revsingle(repo, rev)
3230 with repo.wlock():
3230 with repo.wlock():
3231 dirstate = repo.dirstate
3231 dirstate = repo.dirstate
3232 changedfiles = None
3232 changedfiles = None
3233 # See command doc for what minimal does.
3233 # See command doc for what minimal does.
3234 if opts.get('minimal'):
3234 if opts.get('minimal'):
3235 manifestfiles = set(ctx.manifest().keys())
3235 manifestfiles = set(ctx.manifest().keys())
3236 dirstatefiles = set(dirstate)
3236 dirstatefiles = set(dirstate)
3237 manifestonly = manifestfiles - dirstatefiles
3237 manifestonly = manifestfiles - dirstatefiles
3238 dsonly = dirstatefiles - manifestfiles
3238 dsonly = dirstatefiles - manifestfiles
3239 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3239 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3240 changedfiles = manifestonly | dsnotadded
3240 changedfiles = manifestonly | dsnotadded
3241
3241
3242 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3242 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3243
3243
3244 @command('debugrebuildfncache', [], '')
3244 @command('debugrebuildfncache', [], '')
3245 def debugrebuildfncache(ui, repo):
3245 def debugrebuildfncache(ui, repo):
3246 """rebuild the fncache file"""
3246 """rebuild the fncache file"""
3247 repair.rebuildfncache(ui, repo)
3247 repair.rebuildfncache(ui, repo)
3248
3248
3249 @command('debugrename',
3249 @command('debugrename',
3250 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3250 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3251 _('[-r REV] FILE'))
3251 _('[-r REV] FILE'))
3252 def debugrename(ui, repo, file1, *pats, **opts):
3252 def debugrename(ui, repo, file1, *pats, **opts):
3253 """dump rename information"""
3253 """dump rename information"""
3254
3254
3255 ctx = scmutil.revsingle(repo, opts.get('rev'))
3255 ctx = scmutil.revsingle(repo, opts.get('rev'))
3256 m = scmutil.match(ctx, (file1,) + pats, opts)
3256 m = scmutil.match(ctx, (file1,) + pats, opts)
3257 for abs in ctx.walk(m):
3257 for abs in ctx.walk(m):
3258 fctx = ctx[abs]
3258 fctx = ctx[abs]
3259 o = fctx.filelog().renamed(fctx.filenode())
3259 o = fctx.filelog().renamed(fctx.filenode())
3260 rel = m.rel(abs)
3260 rel = m.rel(abs)
3261 if o:
3261 if o:
3262 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3262 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3263 else:
3263 else:
3264 ui.write(_("%s not renamed\n") % rel)
3264 ui.write(_("%s not renamed\n") % rel)
3265
3265
3266 @command('debugrevlog', debugrevlogopts +
3266 @command('debugrevlog', debugrevlogopts +
3267 [('d', 'dump', False, _('dump index data'))],
3267 [('d', 'dump', False, _('dump index data'))],
3268 _('-c|-m|FILE'),
3268 _('-c|-m|FILE'),
3269 optionalrepo=True)
3269 optionalrepo=True)
3270 def debugrevlog(ui, repo, file_=None, **opts):
3270 def debugrevlog(ui, repo, file_=None, **opts):
3271 """show data and statistics about a revlog"""
3271 """show data and statistics about a revlog"""
3272 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3272 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3273
3273
3274 if opts.get("dump"):
3274 if opts.get("dump"):
3275 numrevs = len(r)
3275 numrevs = len(r)
3276 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3276 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3277 " rawsize totalsize compression heads chainlen\n")
3277 " rawsize totalsize compression heads chainlen\n")
3278 ts = 0
3278 ts = 0
3279 heads = set()
3279 heads = set()
3280
3280
3281 for rev in xrange(numrevs):
3281 for rev in xrange(numrevs):
3282 dbase = r.deltaparent(rev)
3282 dbase = r.deltaparent(rev)
3283 if dbase == -1:
3283 if dbase == -1:
3284 dbase = rev
3284 dbase = rev
3285 cbase = r.chainbase(rev)
3285 cbase = r.chainbase(rev)
3286 clen = r.chainlen(rev)
3286 clen = r.chainlen(rev)
3287 p1, p2 = r.parentrevs(rev)
3287 p1, p2 = r.parentrevs(rev)
3288 rs = r.rawsize(rev)
3288 rs = r.rawsize(rev)
3289 ts = ts + rs
3289 ts = ts + rs
3290 heads -= set(r.parentrevs(rev))
3290 heads -= set(r.parentrevs(rev))
3291 heads.add(rev)
3291 heads.add(rev)
3292 try:
3292 try:
3293 compression = ts / r.end(rev)
3293 compression = ts / r.end(rev)
3294 except ZeroDivisionError:
3294 except ZeroDivisionError:
3295 compression = 0
3295 compression = 0
3296 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3296 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3297 "%11d %5d %8d\n" %
3297 "%11d %5d %8d\n" %
3298 (rev, p1, p2, r.start(rev), r.end(rev),
3298 (rev, p1, p2, r.start(rev), r.end(rev),
3299 r.start(dbase), r.start(cbase),
3299 r.start(dbase), r.start(cbase),
3300 r.start(p1), r.start(p2),
3300 r.start(p1), r.start(p2),
3301 rs, ts, compression, len(heads), clen))
3301 rs, ts, compression, len(heads), clen))
3302 return 0
3302 return 0
3303
3303
3304 v = r.version
3304 v = r.version
3305 format = v & 0xFFFF
3305 format = v & 0xFFFF
3306 flags = []
3306 flags = []
3307 gdelta = False
3307 gdelta = False
3308 if v & revlog.REVLOGNGINLINEDATA:
3308 if v & revlog.REVLOGNGINLINEDATA:
3309 flags.append('inline')
3309 flags.append('inline')
3310 if v & revlog.REVLOGGENERALDELTA:
3310 if v & revlog.REVLOGGENERALDELTA:
3311 gdelta = True
3311 gdelta = True
3312 flags.append('generaldelta')
3312 flags.append('generaldelta')
3313 if not flags:
3313 if not flags:
3314 flags = ['(none)']
3314 flags = ['(none)']
3315
3315
3316 nummerges = 0
3316 nummerges = 0
3317 numfull = 0
3317 numfull = 0
3318 numprev = 0
3318 numprev = 0
3319 nump1 = 0
3319 nump1 = 0
3320 nump2 = 0
3320 nump2 = 0
3321 numother = 0
3321 numother = 0
3322 nump1prev = 0
3322 nump1prev = 0
3323 nump2prev = 0
3323 nump2prev = 0
3324 chainlengths = []
3324 chainlengths = []
3325
3325
3326 datasize = [None, 0, 0L]
3326 datasize = [None, 0, 0L]
3327 fullsize = [None, 0, 0L]
3327 fullsize = [None, 0, 0L]
3328 deltasize = [None, 0, 0L]
3328 deltasize = [None, 0, 0L]
3329
3329
3330 def addsize(size, l):
3330 def addsize(size, l):
3331 if l[0] is None or size < l[0]:
3331 if l[0] is None or size < l[0]:
3332 l[0] = size
3332 l[0] = size
3333 if size > l[1]:
3333 if size > l[1]:
3334 l[1] = size
3334 l[1] = size
3335 l[2] += size
3335 l[2] += size
3336
3336
3337 numrevs = len(r)
3337 numrevs = len(r)
3338 for rev in xrange(numrevs):
3338 for rev in xrange(numrevs):
3339 p1, p2 = r.parentrevs(rev)
3339 p1, p2 = r.parentrevs(rev)
3340 delta = r.deltaparent(rev)
3340 delta = r.deltaparent(rev)
3341 if format > 0:
3341 if format > 0:
3342 addsize(r.rawsize(rev), datasize)
3342 addsize(r.rawsize(rev), datasize)
3343 if p2 != nullrev:
3343 if p2 != nullrev:
3344 nummerges += 1
3344 nummerges += 1
3345 size = r.length(rev)
3345 size = r.length(rev)
3346 if delta == nullrev:
3346 if delta == nullrev:
3347 chainlengths.append(0)
3347 chainlengths.append(0)
3348 numfull += 1
3348 numfull += 1
3349 addsize(size, fullsize)
3349 addsize(size, fullsize)
3350 else:
3350 else:
3351 chainlengths.append(chainlengths[delta] + 1)
3351 chainlengths.append(chainlengths[delta] + 1)
3352 addsize(size, deltasize)
3352 addsize(size, deltasize)
3353 if delta == rev - 1:
3353 if delta == rev - 1:
3354 numprev += 1
3354 numprev += 1
3355 if delta == p1:
3355 if delta == p1:
3356 nump1prev += 1
3356 nump1prev += 1
3357 elif delta == p2:
3357 elif delta == p2:
3358 nump2prev += 1
3358 nump2prev += 1
3359 elif delta == p1:
3359 elif delta == p1:
3360 nump1 += 1
3360 nump1 += 1
3361 elif delta == p2:
3361 elif delta == p2:
3362 nump2 += 1
3362 nump2 += 1
3363 elif delta != nullrev:
3363 elif delta != nullrev:
3364 numother += 1
3364 numother += 1
3365
3365
3366 # Adjust size min value for empty cases
3366 # Adjust size min value for empty cases
3367 for size in (datasize, fullsize, deltasize):
3367 for size in (datasize, fullsize, deltasize):
3368 if size[0] is None:
3368 if size[0] is None:
3369 size[0] = 0
3369 size[0] = 0
3370
3370
3371 numdeltas = numrevs - numfull
3371 numdeltas = numrevs - numfull
3372 numoprev = numprev - nump1prev - nump2prev
3372 numoprev = numprev - nump1prev - nump2prev
3373 totalrawsize = datasize[2]
3373 totalrawsize = datasize[2]
3374 datasize[2] /= numrevs
3374 datasize[2] /= numrevs
3375 fulltotal = fullsize[2]
3375 fulltotal = fullsize[2]
3376 fullsize[2] /= numfull
3376 fullsize[2] /= numfull
3377 deltatotal = deltasize[2]
3377 deltatotal = deltasize[2]
3378 if numrevs - numfull > 0:
3378 if numrevs - numfull > 0:
3379 deltasize[2] /= numrevs - numfull
3379 deltasize[2] /= numrevs - numfull
3380 totalsize = fulltotal + deltatotal
3380 totalsize = fulltotal + deltatotal
3381 avgchainlen = sum(chainlengths) / numrevs
3381 avgchainlen = sum(chainlengths) / numrevs
3382 maxchainlen = max(chainlengths)
3382 maxchainlen = max(chainlengths)
3383 compratio = 1
3383 compratio = 1
3384 if totalsize:
3384 if totalsize:
3385 compratio = totalrawsize / totalsize
3385 compratio = totalrawsize / totalsize
3386
3386
3387 basedfmtstr = '%%%dd\n'
3387 basedfmtstr = '%%%dd\n'
3388 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3388 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3389
3389
3390 def dfmtstr(max):
3390 def dfmtstr(max):
3391 return basedfmtstr % len(str(max))
3391 return basedfmtstr % len(str(max))
3392 def pcfmtstr(max, padding=0):
3392 def pcfmtstr(max, padding=0):
3393 return basepcfmtstr % (len(str(max)), ' ' * padding)
3393 return basepcfmtstr % (len(str(max)), ' ' * padding)
3394
3394
3395 def pcfmt(value, total):
3395 def pcfmt(value, total):
3396 if total:
3396 if total:
3397 return (value, 100 * float(value) / total)
3397 return (value, 100 * float(value) / total)
3398 else:
3398 else:
3399 return value, 100.0
3399 return value, 100.0
3400
3400
3401 ui.write(('format : %d\n') % format)
3401 ui.write(('format : %d\n') % format)
3402 ui.write(('flags : %s\n') % ', '.join(flags))
3402 ui.write(('flags : %s\n') % ', '.join(flags))
3403
3403
3404 ui.write('\n')
3404 ui.write('\n')
3405 fmt = pcfmtstr(totalsize)
3405 fmt = pcfmtstr(totalsize)
3406 fmt2 = dfmtstr(totalsize)
3406 fmt2 = dfmtstr(totalsize)
3407 ui.write(('revisions : ') + fmt2 % numrevs)
3407 ui.write(('revisions : ') + fmt2 % numrevs)
3408 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3408 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3409 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3409 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3410 ui.write(('revisions : ') + fmt2 % numrevs)
3410 ui.write(('revisions : ') + fmt2 % numrevs)
3411 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3411 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3412 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3412 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3413 ui.write(('revision size : ') + fmt2 % totalsize)
3413 ui.write(('revision size : ') + fmt2 % totalsize)
3414 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3414 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3415 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3415 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3416
3416
3417 ui.write('\n')
3417 ui.write('\n')
3418 fmt = dfmtstr(max(avgchainlen, compratio))
3418 fmt = dfmtstr(max(avgchainlen, compratio))
3419 ui.write(('avg chain length : ') + fmt % avgchainlen)
3419 ui.write(('avg chain length : ') + fmt % avgchainlen)
3420 ui.write(('max chain length : ') + fmt % maxchainlen)
3420 ui.write(('max chain length : ') + fmt % maxchainlen)
3421 ui.write(('compression ratio : ') + fmt % compratio)
3421 ui.write(('compression ratio : ') + fmt % compratio)
3422
3422
3423 if format > 0:
3423 if format > 0:
3424 ui.write('\n')
3424 ui.write('\n')
3425 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3425 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3426 % tuple(datasize))
3426 % tuple(datasize))
3427 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3427 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3428 % tuple(fullsize))
3428 % tuple(fullsize))
3429 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3429 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3430 % tuple(deltasize))
3430 % tuple(deltasize))
3431
3431
3432 if numdeltas > 0:
3432 if numdeltas > 0:
3433 ui.write('\n')
3433 ui.write('\n')
3434 fmt = pcfmtstr(numdeltas)
3434 fmt = pcfmtstr(numdeltas)
3435 fmt2 = pcfmtstr(numdeltas, 4)
3435 fmt2 = pcfmtstr(numdeltas, 4)
3436 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3436 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3437 if numprev > 0:
3437 if numprev > 0:
3438 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3438 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3439 numprev))
3439 numprev))
3440 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3440 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3441 numprev))
3441 numprev))
3442 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3442 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3443 numprev))
3443 numprev))
3444 if gdelta:
3444 if gdelta:
3445 ui.write(('deltas against p1 : ')
3445 ui.write(('deltas against p1 : ')
3446 + fmt % pcfmt(nump1, numdeltas))
3446 + fmt % pcfmt(nump1, numdeltas))
3447 ui.write(('deltas against p2 : ')
3447 ui.write(('deltas against p2 : ')
3448 + fmt % pcfmt(nump2, numdeltas))
3448 + fmt % pcfmt(nump2, numdeltas))
3449 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3449 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3450 numdeltas))
3450 numdeltas))
3451
3451
3452 @command('debugrevspec',
3452 @command('debugrevspec',
3453 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3453 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3454 ('REVSPEC'))
3454 ('REVSPEC'))
3455 def debugrevspec(ui, repo, expr, **opts):
3455 def debugrevspec(ui, repo, expr, **opts):
3456 """parse and apply a revision specification
3456 """parse and apply a revision specification
3457
3457
3458 Use --verbose to print the parsed tree before and after aliases
3458 Use --verbose to print the parsed tree before and after aliases
3459 expansion.
3459 expansion.
3460 """
3460 """
3461 if ui.verbose:
3461 if ui.verbose:
3462 tree = revset.parse(expr, lookup=repo.__contains__)
3462 tree = revset.parse(expr, lookup=repo.__contains__)
3463 ui.note(revset.prettyformat(tree), "\n")
3463 ui.note(revset.prettyformat(tree), "\n")
3464 newtree = revset.findaliases(ui, tree)
3464 newtree = revset.findaliases(ui, tree)
3465 if newtree != tree:
3465 if newtree != tree:
3466 ui.note(revset.prettyformat(newtree), "\n")
3466 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3467 tree = newtree
3467 tree = newtree
3468 newtree = revset.foldconcat(tree)
3468 newtree = revset.foldconcat(tree)
3469 if newtree != tree:
3469 if newtree != tree:
3470 ui.note(revset.prettyformat(newtree), "\n")
3470 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3471 if opts["optimize"]:
3471 if opts["optimize"]:
3472 weight, optimizedtree = revset.optimize(newtree, True)
3472 weight, optimizedtree = revset.optimize(newtree, True)
3473 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3473 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3474 func = revset.match(ui, expr, repo)
3474 func = revset.match(ui, expr, repo)
3475 revs = func(repo)
3475 revs = func(repo)
3476 if ui.verbose:
3476 if ui.verbose:
3477 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3477 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3478 for c in revs:
3478 for c in revs:
3479 ui.write("%s\n" % c)
3479 ui.write("%s\n" % c)
3480
3480
3481 @command('debugsetparents', [], _('REV1 [REV2]'))
3481 @command('debugsetparents', [], _('REV1 [REV2]'))
3482 def debugsetparents(ui, repo, rev1, rev2=None):
3482 def debugsetparents(ui, repo, rev1, rev2=None):
3483 """manually set the parents of the current working directory
3483 """manually set the parents of the current working directory
3484
3484
3485 This is useful for writing repository conversion tools, but should
3485 This is useful for writing repository conversion tools, but should
3486 be used with care. For example, neither the working directory nor the
3486 be used with care. For example, neither the working directory nor the
3487 dirstate is updated, so file status may be incorrect after running this
3487 dirstate is updated, so file status may be incorrect after running this
3488 command.
3488 command.
3489
3489
3490 Returns 0 on success.
3490 Returns 0 on success.
3491 """
3491 """
3492
3492
3493 r1 = scmutil.revsingle(repo, rev1).node()
3493 r1 = scmutil.revsingle(repo, rev1).node()
3494 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3494 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3495
3495
3496 with repo.wlock():
3496 with repo.wlock():
3497 repo.dirstate.beginparentchange()
3497 repo.dirstate.beginparentchange()
3498 repo.setparents(r1, r2)
3498 repo.setparents(r1, r2)
3499 repo.dirstate.endparentchange()
3499 repo.dirstate.endparentchange()
3500
3500
3501 @command('debugdirstate|debugstate',
3501 @command('debugdirstate|debugstate',
3502 [('', 'nodates', None, _('do not display the saved mtime')),
3502 [('', 'nodates', None, _('do not display the saved mtime')),
3503 ('', 'datesort', None, _('sort by saved mtime'))],
3503 ('', 'datesort', None, _('sort by saved mtime'))],
3504 _('[OPTION]...'))
3504 _('[OPTION]...'))
3505 def debugstate(ui, repo, **opts):
3505 def debugstate(ui, repo, **opts):
3506 """show the contents of the current dirstate"""
3506 """show the contents of the current dirstate"""
3507
3507
3508 nodates = opts.get('nodates')
3508 nodates = opts.get('nodates')
3509 datesort = opts.get('datesort')
3509 datesort = opts.get('datesort')
3510
3510
3511 timestr = ""
3511 timestr = ""
3512 if datesort:
3512 if datesort:
3513 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3513 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3514 else:
3514 else:
3515 keyfunc = None # sort by filename
3515 keyfunc = None # sort by filename
3516 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3516 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3517 if ent[3] == -1:
3517 if ent[3] == -1:
3518 timestr = 'unset '
3518 timestr = 'unset '
3519 elif nodates:
3519 elif nodates:
3520 timestr = 'set '
3520 timestr = 'set '
3521 else:
3521 else:
3522 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3522 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3523 time.localtime(ent[3]))
3523 time.localtime(ent[3]))
3524 if ent[1] & 0o20000:
3524 if ent[1] & 0o20000:
3525 mode = 'lnk'
3525 mode = 'lnk'
3526 else:
3526 else:
3527 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3527 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3528 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3528 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3529 for f in repo.dirstate.copies():
3529 for f in repo.dirstate.copies():
3530 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3530 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3531
3531
3532 @command('debugsub',
3532 @command('debugsub',
3533 [('r', 'rev', '',
3533 [('r', 'rev', '',
3534 _('revision to check'), _('REV'))],
3534 _('revision to check'), _('REV'))],
3535 _('[-r REV] [REV]'))
3535 _('[-r REV] [REV]'))
3536 def debugsub(ui, repo, rev=None):
3536 def debugsub(ui, repo, rev=None):
3537 ctx = scmutil.revsingle(repo, rev, None)
3537 ctx = scmutil.revsingle(repo, rev, None)
3538 for k, v in sorted(ctx.substate.items()):
3538 for k, v in sorted(ctx.substate.items()):
3539 ui.write(('path %s\n') % k)
3539 ui.write(('path %s\n') % k)
3540 ui.write((' source %s\n') % v[0])
3540 ui.write((' source %s\n') % v[0])
3541 ui.write((' revision %s\n') % v[1])
3541 ui.write((' revision %s\n') % v[1])
3542
3542
3543 @command('debugsuccessorssets',
3543 @command('debugsuccessorssets',
3544 [],
3544 [],
3545 _('[REV]'))
3545 _('[REV]'))
3546 def debugsuccessorssets(ui, repo, *revs):
3546 def debugsuccessorssets(ui, repo, *revs):
3547 """show set of successors for revision
3547 """show set of successors for revision
3548
3548
3549 A successors set of changeset A is a consistent group of revisions that
3549 A successors set of changeset A is a consistent group of revisions that
3550 succeed A. It contains non-obsolete changesets only.
3550 succeed A. It contains non-obsolete changesets only.
3551
3551
3552 In most cases a changeset A has a single successors set containing a single
3552 In most cases a changeset A has a single successors set containing a single
3553 successor (changeset A replaced by A').
3553 successor (changeset A replaced by A').
3554
3554
3555 A changeset that is made obsolete with no successors are called "pruned".
3555 A changeset that is made obsolete with no successors are called "pruned".
3556 Such changesets have no successors sets at all.
3556 Such changesets have no successors sets at all.
3557
3557
3558 A changeset that has been "split" will have a successors set containing
3558 A changeset that has been "split" will have a successors set containing
3559 more than one successor.
3559 more than one successor.
3560
3560
3561 A changeset that has been rewritten in multiple different ways is called
3561 A changeset that has been rewritten in multiple different ways is called
3562 "divergent". Such changesets have multiple successor sets (each of which
3562 "divergent". Such changesets have multiple successor sets (each of which
3563 may also be split, i.e. have multiple successors).
3563 may also be split, i.e. have multiple successors).
3564
3564
3565 Results are displayed as follows::
3565 Results are displayed as follows::
3566
3566
3567 <rev1>
3567 <rev1>
3568 <successors-1A>
3568 <successors-1A>
3569 <rev2>
3569 <rev2>
3570 <successors-2A>
3570 <successors-2A>
3571 <successors-2B1> <successors-2B2> <successors-2B3>
3571 <successors-2B1> <successors-2B2> <successors-2B3>
3572
3572
3573 Here rev2 has two possible (i.e. divergent) successors sets. The first
3573 Here rev2 has two possible (i.e. divergent) successors sets. The first
3574 holds one element, whereas the second holds three (i.e. the changeset has
3574 holds one element, whereas the second holds three (i.e. the changeset has
3575 been split).
3575 been split).
3576 """
3576 """
3577 # passed to successorssets caching computation from one call to another
3577 # passed to successorssets caching computation from one call to another
3578 cache = {}
3578 cache = {}
3579 ctx2str = str
3579 ctx2str = str
3580 node2str = short
3580 node2str = short
3581 if ui.debug():
3581 if ui.debug():
3582 def ctx2str(ctx):
3582 def ctx2str(ctx):
3583 return ctx.hex()
3583 return ctx.hex()
3584 node2str = hex
3584 node2str = hex
3585 for rev in scmutil.revrange(repo, revs):
3585 for rev in scmutil.revrange(repo, revs):
3586 ctx = repo[rev]
3586 ctx = repo[rev]
3587 ui.write('%s\n'% ctx2str(ctx))
3587 ui.write('%s\n'% ctx2str(ctx))
3588 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3588 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3589 if succsset:
3589 if succsset:
3590 ui.write(' ')
3590 ui.write(' ')
3591 ui.write(node2str(succsset[0]))
3591 ui.write(node2str(succsset[0]))
3592 for node in succsset[1:]:
3592 for node in succsset[1:]:
3593 ui.write(' ')
3593 ui.write(' ')
3594 ui.write(node2str(node))
3594 ui.write(node2str(node))
3595 ui.write('\n')
3595 ui.write('\n')
3596
3596
3597 @command('debugtemplate',
3597 @command('debugtemplate',
3598 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3598 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3599 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3599 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3600 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3600 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3601 optionalrepo=True)
3601 optionalrepo=True)
3602 def debugtemplate(ui, repo, tmpl, **opts):
3602 def debugtemplate(ui, repo, tmpl, **opts):
3603 """parse and apply a template
3603 """parse and apply a template
3604
3604
3605 If -r/--rev is given, the template is processed as a log template and
3605 If -r/--rev is given, the template is processed as a log template and
3606 applied to the given changesets. Otherwise, it is processed as a generic
3606 applied to the given changesets. Otherwise, it is processed as a generic
3607 template.
3607 template.
3608
3608
3609 Use --verbose to print the parsed tree.
3609 Use --verbose to print the parsed tree.
3610 """
3610 """
3611 revs = None
3611 revs = None
3612 if opts['rev']:
3612 if opts['rev']:
3613 if repo is None:
3613 if repo is None:
3614 raise error.RepoError(_('there is no Mercurial repository here '
3614 raise error.RepoError(_('there is no Mercurial repository here '
3615 '(.hg not found)'))
3615 '(.hg not found)'))
3616 revs = scmutil.revrange(repo, opts['rev'])
3616 revs = scmutil.revrange(repo, opts['rev'])
3617
3617
3618 props = {}
3618 props = {}
3619 for d in opts['define']:
3619 for d in opts['define']:
3620 try:
3620 try:
3621 k, v = (e.strip() for e in d.split('=', 1))
3621 k, v = (e.strip() for e in d.split('=', 1))
3622 if not k:
3622 if not k:
3623 raise ValueError
3623 raise ValueError
3624 props[k] = v
3624 props[k] = v
3625 except ValueError:
3625 except ValueError:
3626 raise error.Abort(_('malformed keyword definition: %s') % d)
3626 raise error.Abort(_('malformed keyword definition: %s') % d)
3627
3627
3628 if ui.verbose:
3628 if ui.verbose:
3629 tree = templater.parse(tmpl)
3629 tree = templater.parse(tmpl)
3630 ui.note(templater.prettyformat(tree), '\n')
3630 ui.note(templater.prettyformat(tree), '\n')
3631
3631
3632 mapfile = None
3632 mapfile = None
3633 if revs is None:
3633 if revs is None:
3634 k = 'debugtemplate'
3634 k = 'debugtemplate'
3635 t = templater.templater(mapfile)
3635 t = templater.templater(mapfile)
3636 t.cache[k] = tmpl
3636 t.cache[k] = tmpl
3637 ui.write(templater.stringify(t(k, **props)))
3637 ui.write(templater.stringify(t(k, **props)))
3638 else:
3638 else:
3639 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3639 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3640 mapfile, buffered=False)
3640 mapfile, buffered=False)
3641 for r in revs:
3641 for r in revs:
3642 displayer.show(repo[r], **props)
3642 displayer.show(repo[r], **props)
3643 displayer.close()
3643 displayer.close()
3644
3644
3645 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3645 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3646 def debugwalk(ui, repo, *pats, **opts):
3646 def debugwalk(ui, repo, *pats, **opts):
3647 """show how files match on given patterns"""
3647 """show how files match on given patterns"""
3648 m = scmutil.match(repo[None], pats, opts)
3648 m = scmutil.match(repo[None], pats, opts)
3649 items = list(repo.walk(m))
3649 items = list(repo.walk(m))
3650 if not items:
3650 if not items:
3651 return
3651 return
3652 f = lambda fn: fn
3652 f = lambda fn: fn
3653 if ui.configbool('ui', 'slash') and os.sep != '/':
3653 if ui.configbool('ui', 'slash') and os.sep != '/':
3654 f = lambda fn: util.normpath(fn)
3654 f = lambda fn: util.normpath(fn)
3655 fmt = 'f %%-%ds %%-%ds %%s' % (
3655 fmt = 'f %%-%ds %%-%ds %%s' % (
3656 max([len(abs) for abs in items]),
3656 max([len(abs) for abs in items]),
3657 max([len(m.rel(abs)) for abs in items]))
3657 max([len(m.rel(abs)) for abs in items]))
3658 for abs in items:
3658 for abs in items:
3659 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3659 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3660 ui.write("%s\n" % line.rstrip())
3660 ui.write("%s\n" % line.rstrip())
3661
3661
3662 @command('debugwireargs',
3662 @command('debugwireargs',
3663 [('', 'three', '', 'three'),
3663 [('', 'three', '', 'three'),
3664 ('', 'four', '', 'four'),
3664 ('', 'four', '', 'four'),
3665 ('', 'five', '', 'five'),
3665 ('', 'five', '', 'five'),
3666 ] + remoteopts,
3666 ] + remoteopts,
3667 _('REPO [OPTIONS]... [ONE [TWO]]'),
3667 _('REPO [OPTIONS]... [ONE [TWO]]'),
3668 norepo=True)
3668 norepo=True)
3669 def debugwireargs(ui, repopath, *vals, **opts):
3669 def debugwireargs(ui, repopath, *vals, **opts):
3670 repo = hg.peer(ui, opts, repopath)
3670 repo = hg.peer(ui, opts, repopath)
3671 for opt in remoteopts:
3671 for opt in remoteopts:
3672 del opts[opt[1]]
3672 del opts[opt[1]]
3673 args = {}
3673 args = {}
3674 for k, v in opts.iteritems():
3674 for k, v in opts.iteritems():
3675 if v:
3675 if v:
3676 args[k] = v
3676 args[k] = v
3677 # run twice to check that we don't mess up the stream for the next command
3677 # run twice to check that we don't mess up the stream for the next command
3678 res1 = repo.debugwireargs(*vals, **args)
3678 res1 = repo.debugwireargs(*vals, **args)
3679 res2 = repo.debugwireargs(*vals, **args)
3679 res2 = repo.debugwireargs(*vals, **args)
3680 ui.write("%s\n" % res1)
3680 ui.write("%s\n" % res1)
3681 if res1 != res2:
3681 if res1 != res2:
3682 ui.warn("%s\n" % res2)
3682 ui.warn("%s\n" % res2)
3683
3683
3684 @command('^diff',
3684 @command('^diff',
3685 [('r', 'rev', [], _('revision'), _('REV')),
3685 [('r', 'rev', [], _('revision'), _('REV')),
3686 ('c', 'change', '', _('change made by revision'), _('REV'))
3686 ('c', 'change', '', _('change made by revision'), _('REV'))
3687 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3687 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3688 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3688 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3689 inferrepo=True)
3689 inferrepo=True)
3690 def diff(ui, repo, *pats, **opts):
3690 def diff(ui, repo, *pats, **opts):
3691 """diff repository (or selected files)
3691 """diff repository (or selected files)
3692
3692
3693 Show differences between revisions for the specified files.
3693 Show differences between revisions for the specified files.
3694
3694
3695 Differences between files are shown using the unified diff format.
3695 Differences between files are shown using the unified diff format.
3696
3696
3697 .. note::
3697 .. note::
3698
3698
3699 :hg:`diff` may generate unexpected results for merges, as it will
3699 :hg:`diff` may generate unexpected results for merges, as it will
3700 default to comparing against the working directory's first
3700 default to comparing against the working directory's first
3701 parent changeset if no revisions are specified.
3701 parent changeset if no revisions are specified.
3702
3702
3703 When two revision arguments are given, then changes are shown
3703 When two revision arguments are given, then changes are shown
3704 between those revisions. If only one revision is specified then
3704 between those revisions. If only one revision is specified then
3705 that revision is compared to the working directory, and, when no
3705 that revision is compared to the working directory, and, when no
3706 revisions are specified, the working directory files are compared
3706 revisions are specified, the working directory files are compared
3707 to its first parent.
3707 to its first parent.
3708
3708
3709 Alternatively you can specify -c/--change with a revision to see
3709 Alternatively you can specify -c/--change with a revision to see
3710 the changes in that changeset relative to its first parent.
3710 the changes in that changeset relative to its first parent.
3711
3711
3712 Without the -a/--text option, diff will avoid generating diffs of
3712 Without the -a/--text option, diff will avoid generating diffs of
3713 files it detects as binary. With -a, diff will generate a diff
3713 files it detects as binary. With -a, diff will generate a diff
3714 anyway, probably with undesirable results.
3714 anyway, probably with undesirable results.
3715
3715
3716 Use the -g/--git option to generate diffs in the git extended diff
3716 Use the -g/--git option to generate diffs in the git extended diff
3717 format. For more information, read :hg:`help diffs`.
3717 format. For more information, read :hg:`help diffs`.
3718
3718
3719 .. container:: verbose
3719 .. container:: verbose
3720
3720
3721 Examples:
3721 Examples:
3722
3722
3723 - compare a file in the current working directory to its parent::
3723 - compare a file in the current working directory to its parent::
3724
3724
3725 hg diff foo.c
3725 hg diff foo.c
3726
3726
3727 - compare two historical versions of a directory, with rename info::
3727 - compare two historical versions of a directory, with rename info::
3728
3728
3729 hg diff --git -r 1.0:1.2 lib/
3729 hg diff --git -r 1.0:1.2 lib/
3730
3730
3731 - get change stats relative to the last change on some date::
3731 - get change stats relative to the last change on some date::
3732
3732
3733 hg diff --stat -r "date('may 2')"
3733 hg diff --stat -r "date('may 2')"
3734
3734
3735 - diff all newly-added files that contain a keyword::
3735 - diff all newly-added files that contain a keyword::
3736
3736
3737 hg diff "set:added() and grep(GNU)"
3737 hg diff "set:added() and grep(GNU)"
3738
3738
3739 - compare a revision and its parents::
3739 - compare a revision and its parents::
3740
3740
3741 hg diff -c 9353 # compare against first parent
3741 hg diff -c 9353 # compare against first parent
3742 hg diff -r 9353^:9353 # same using revset syntax
3742 hg diff -r 9353^:9353 # same using revset syntax
3743 hg diff -r 9353^2:9353 # compare against the second parent
3743 hg diff -r 9353^2:9353 # compare against the second parent
3744
3744
3745 Returns 0 on success.
3745 Returns 0 on success.
3746 """
3746 """
3747
3747
3748 revs = opts.get('rev')
3748 revs = opts.get('rev')
3749 change = opts.get('change')
3749 change = opts.get('change')
3750 stat = opts.get('stat')
3750 stat = opts.get('stat')
3751 reverse = opts.get('reverse')
3751 reverse = opts.get('reverse')
3752
3752
3753 if revs and change:
3753 if revs and change:
3754 msg = _('cannot specify --rev and --change at the same time')
3754 msg = _('cannot specify --rev and --change at the same time')
3755 raise error.Abort(msg)
3755 raise error.Abort(msg)
3756 elif change:
3756 elif change:
3757 node2 = scmutil.revsingle(repo, change, None).node()
3757 node2 = scmutil.revsingle(repo, change, None).node()
3758 node1 = repo[node2].p1().node()
3758 node1 = repo[node2].p1().node()
3759 else:
3759 else:
3760 node1, node2 = scmutil.revpair(repo, revs)
3760 node1, node2 = scmutil.revpair(repo, revs)
3761
3761
3762 if reverse:
3762 if reverse:
3763 node1, node2 = node2, node1
3763 node1, node2 = node2, node1
3764
3764
3765 diffopts = patch.diffallopts(ui, opts)
3765 diffopts = patch.diffallopts(ui, opts)
3766 m = scmutil.match(repo[node2], pats, opts)
3766 m = scmutil.match(repo[node2], pats, opts)
3767 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3767 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3768 listsubrepos=opts.get('subrepos'),
3768 listsubrepos=opts.get('subrepos'),
3769 root=opts.get('root'))
3769 root=opts.get('root'))
3770
3770
3771 @command('^export',
3771 @command('^export',
3772 [('o', 'output', '',
3772 [('o', 'output', '',
3773 _('print output to file with formatted name'), _('FORMAT')),
3773 _('print output to file with formatted name'), _('FORMAT')),
3774 ('', 'switch-parent', None, _('diff against the second parent')),
3774 ('', 'switch-parent', None, _('diff against the second parent')),
3775 ('r', 'rev', [], _('revisions to export'), _('REV')),
3775 ('r', 'rev', [], _('revisions to export'), _('REV')),
3776 ] + diffopts,
3776 ] + diffopts,
3777 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3777 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3778 def export(ui, repo, *changesets, **opts):
3778 def export(ui, repo, *changesets, **opts):
3779 """dump the header and diffs for one or more changesets
3779 """dump the header and diffs for one or more changesets
3780
3780
3781 Print the changeset header and diffs for one or more revisions.
3781 Print the changeset header and diffs for one or more revisions.
3782 If no revision is given, the parent of the working directory is used.
3782 If no revision is given, the parent of the working directory is used.
3783
3783
3784 The information shown in the changeset header is: author, date,
3784 The information shown in the changeset header is: author, date,
3785 branch name (if non-default), changeset hash, parent(s) and commit
3785 branch name (if non-default), changeset hash, parent(s) and commit
3786 comment.
3786 comment.
3787
3787
3788 .. note::
3788 .. note::
3789
3789
3790 :hg:`export` may generate unexpected diff output for merge
3790 :hg:`export` may generate unexpected diff output for merge
3791 changesets, as it will compare the merge changeset against its
3791 changesets, as it will compare the merge changeset against its
3792 first parent only.
3792 first parent only.
3793
3793
3794 Output may be to a file, in which case the name of the file is
3794 Output may be to a file, in which case the name of the file is
3795 given using a format string. The formatting rules are as follows:
3795 given using a format string. The formatting rules are as follows:
3796
3796
3797 :``%%``: literal "%" character
3797 :``%%``: literal "%" character
3798 :``%H``: changeset hash (40 hexadecimal digits)
3798 :``%H``: changeset hash (40 hexadecimal digits)
3799 :``%N``: number of patches being generated
3799 :``%N``: number of patches being generated
3800 :``%R``: changeset revision number
3800 :``%R``: changeset revision number
3801 :``%b``: basename of the exporting repository
3801 :``%b``: basename of the exporting repository
3802 :``%h``: short-form changeset hash (12 hexadecimal digits)
3802 :``%h``: short-form changeset hash (12 hexadecimal digits)
3803 :``%m``: first line of the commit message (only alphanumeric characters)
3803 :``%m``: first line of the commit message (only alphanumeric characters)
3804 :``%n``: zero-padded sequence number, starting at 1
3804 :``%n``: zero-padded sequence number, starting at 1
3805 :``%r``: zero-padded changeset revision number
3805 :``%r``: zero-padded changeset revision number
3806
3806
3807 Without the -a/--text option, export will avoid generating diffs
3807 Without the -a/--text option, export will avoid generating diffs
3808 of files it detects as binary. With -a, export will generate a
3808 of files it detects as binary. With -a, export will generate a
3809 diff anyway, probably with undesirable results.
3809 diff anyway, probably with undesirable results.
3810
3810
3811 Use the -g/--git option to generate diffs in the git extended diff
3811 Use the -g/--git option to generate diffs in the git extended diff
3812 format. See :hg:`help diffs` for more information.
3812 format. See :hg:`help diffs` for more information.
3813
3813
3814 With the --switch-parent option, the diff will be against the
3814 With the --switch-parent option, the diff will be against the
3815 second parent. It can be useful to review a merge.
3815 second parent. It can be useful to review a merge.
3816
3816
3817 .. container:: verbose
3817 .. container:: verbose
3818
3818
3819 Examples:
3819 Examples:
3820
3820
3821 - use export and import to transplant a bugfix to the current
3821 - use export and import to transplant a bugfix to the current
3822 branch::
3822 branch::
3823
3823
3824 hg export -r 9353 | hg import -
3824 hg export -r 9353 | hg import -
3825
3825
3826 - export all the changesets between two revisions to a file with
3826 - export all the changesets between two revisions to a file with
3827 rename information::
3827 rename information::
3828
3828
3829 hg export --git -r 123:150 > changes.txt
3829 hg export --git -r 123:150 > changes.txt
3830
3830
3831 - split outgoing changes into a series of patches with
3831 - split outgoing changes into a series of patches with
3832 descriptive names::
3832 descriptive names::
3833
3833
3834 hg export -r "outgoing()" -o "%n-%m.patch"
3834 hg export -r "outgoing()" -o "%n-%m.patch"
3835
3835
3836 Returns 0 on success.
3836 Returns 0 on success.
3837 """
3837 """
3838 changesets += tuple(opts.get('rev', []))
3838 changesets += tuple(opts.get('rev', []))
3839 if not changesets:
3839 if not changesets:
3840 changesets = ['.']
3840 changesets = ['.']
3841 revs = scmutil.revrange(repo, changesets)
3841 revs = scmutil.revrange(repo, changesets)
3842 if not revs:
3842 if not revs:
3843 raise error.Abort(_("export requires at least one changeset"))
3843 raise error.Abort(_("export requires at least one changeset"))
3844 if len(revs) > 1:
3844 if len(revs) > 1:
3845 ui.note(_('exporting patches:\n'))
3845 ui.note(_('exporting patches:\n'))
3846 else:
3846 else:
3847 ui.note(_('exporting patch:\n'))
3847 ui.note(_('exporting patch:\n'))
3848 cmdutil.export(repo, revs, template=opts.get('output'),
3848 cmdutil.export(repo, revs, template=opts.get('output'),
3849 switch_parent=opts.get('switch_parent'),
3849 switch_parent=opts.get('switch_parent'),
3850 opts=patch.diffallopts(ui, opts))
3850 opts=patch.diffallopts(ui, opts))
3851
3851
3852 @command('files',
3852 @command('files',
3853 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3853 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3854 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3854 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3855 ] + walkopts + formatteropts + subrepoopts,
3855 ] + walkopts + formatteropts + subrepoopts,
3856 _('[OPTION]... [PATTERN]...'))
3856 _('[OPTION]... [PATTERN]...'))
3857 def files(ui, repo, *pats, **opts):
3857 def files(ui, repo, *pats, **opts):
3858 """list tracked files
3858 """list tracked files
3859
3859
3860 Print files under Mercurial control in the working directory or
3860 Print files under Mercurial control in the working directory or
3861 specified revision whose names match the given patterns (excluding
3861 specified revision whose names match the given patterns (excluding
3862 removed files).
3862 removed files).
3863
3863
3864 If no patterns are given to match, this command prints the names
3864 If no patterns are given to match, this command prints the names
3865 of all files under Mercurial control in the working directory.
3865 of all files under Mercurial control in the working directory.
3866
3866
3867 .. container:: verbose
3867 .. container:: verbose
3868
3868
3869 Examples:
3869 Examples:
3870
3870
3871 - list all files under the current directory::
3871 - list all files under the current directory::
3872
3872
3873 hg files .
3873 hg files .
3874
3874
3875 - shows sizes and flags for current revision::
3875 - shows sizes and flags for current revision::
3876
3876
3877 hg files -vr .
3877 hg files -vr .
3878
3878
3879 - list all files named README::
3879 - list all files named README::
3880
3880
3881 hg files -I "**/README"
3881 hg files -I "**/README"
3882
3882
3883 - list all binary files::
3883 - list all binary files::
3884
3884
3885 hg files "set:binary()"
3885 hg files "set:binary()"
3886
3886
3887 - find files containing a regular expression::
3887 - find files containing a regular expression::
3888
3888
3889 hg files "set:grep('bob')"
3889 hg files "set:grep('bob')"
3890
3890
3891 - search tracked file contents with xargs and grep::
3891 - search tracked file contents with xargs and grep::
3892
3892
3893 hg files -0 | xargs -0 grep foo
3893 hg files -0 | xargs -0 grep foo
3894
3894
3895 See :hg:`help patterns` and :hg:`help filesets` for more information
3895 See :hg:`help patterns` and :hg:`help filesets` for more information
3896 on specifying file patterns.
3896 on specifying file patterns.
3897
3897
3898 Returns 0 if a match is found, 1 otherwise.
3898 Returns 0 if a match is found, 1 otherwise.
3899
3899
3900 """
3900 """
3901 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3901 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3902
3902
3903 end = '\n'
3903 end = '\n'
3904 if opts.get('print0'):
3904 if opts.get('print0'):
3905 end = '\0'
3905 end = '\0'
3906 fm = ui.formatter('files', opts)
3906 fm = ui.formatter('files', opts)
3907 fmt = '%s' + end
3907 fmt = '%s' + end
3908
3908
3909 m = scmutil.match(ctx, pats, opts)
3909 m = scmutil.match(ctx, pats, opts)
3910 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3910 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3911
3911
3912 fm.end()
3912 fm.end()
3913
3913
3914 return ret
3914 return ret
3915
3915
3916 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3916 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3917 def forget(ui, repo, *pats, **opts):
3917 def forget(ui, repo, *pats, **opts):
3918 """forget the specified files on the next commit
3918 """forget the specified files on the next commit
3919
3919
3920 Mark the specified files so they will no longer be tracked
3920 Mark the specified files so they will no longer be tracked
3921 after the next commit.
3921 after the next commit.
3922
3922
3923 This only removes files from the current branch, not from the
3923 This only removes files from the current branch, not from the
3924 entire project history, and it does not delete them from the
3924 entire project history, and it does not delete them from the
3925 working directory.
3925 working directory.
3926
3926
3927 To delete the file from the working directory, see :hg:`remove`.
3927 To delete the file from the working directory, see :hg:`remove`.
3928
3928
3929 To undo a forget before the next commit, see :hg:`add`.
3929 To undo a forget before the next commit, see :hg:`add`.
3930
3930
3931 .. container:: verbose
3931 .. container:: verbose
3932
3932
3933 Examples:
3933 Examples:
3934
3934
3935 - forget newly-added binary files::
3935 - forget newly-added binary files::
3936
3936
3937 hg forget "set:added() and binary()"
3937 hg forget "set:added() and binary()"
3938
3938
3939 - forget files that would be excluded by .hgignore::
3939 - forget files that would be excluded by .hgignore::
3940
3940
3941 hg forget "set:hgignore()"
3941 hg forget "set:hgignore()"
3942
3942
3943 Returns 0 on success.
3943 Returns 0 on success.
3944 """
3944 """
3945
3945
3946 if not pats:
3946 if not pats:
3947 raise error.Abort(_('no files specified'))
3947 raise error.Abort(_('no files specified'))
3948
3948
3949 m = scmutil.match(repo[None], pats, opts)
3949 m = scmutil.match(repo[None], pats, opts)
3950 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3950 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3951 return rejected and 1 or 0
3951 return rejected and 1 or 0
3952
3952
3953 @command(
3953 @command(
3954 'graft',
3954 'graft',
3955 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3955 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3956 ('c', 'continue', False, _('resume interrupted graft')),
3956 ('c', 'continue', False, _('resume interrupted graft')),
3957 ('e', 'edit', False, _('invoke editor on commit messages')),
3957 ('e', 'edit', False, _('invoke editor on commit messages')),
3958 ('', 'log', None, _('append graft info to log message')),
3958 ('', 'log', None, _('append graft info to log message')),
3959 ('f', 'force', False, _('force graft')),
3959 ('f', 'force', False, _('force graft')),
3960 ('D', 'currentdate', False,
3960 ('D', 'currentdate', False,
3961 _('record the current date as commit date')),
3961 _('record the current date as commit date')),
3962 ('U', 'currentuser', False,
3962 ('U', 'currentuser', False,
3963 _('record the current user as committer'), _('DATE'))]
3963 _('record the current user as committer'), _('DATE'))]
3964 + commitopts2 + mergetoolopts + dryrunopts,
3964 + commitopts2 + mergetoolopts + dryrunopts,
3965 _('[OPTION]... [-r REV]... REV...'))
3965 _('[OPTION]... [-r REV]... REV...'))
3966 def graft(ui, repo, *revs, **opts):
3966 def graft(ui, repo, *revs, **opts):
3967 '''copy changes from other branches onto the current branch
3967 '''copy changes from other branches onto the current branch
3968
3968
3969 This command uses Mercurial's merge logic to copy individual
3969 This command uses Mercurial's merge logic to copy individual
3970 changes from other branches without merging branches in the
3970 changes from other branches without merging branches in the
3971 history graph. This is sometimes known as 'backporting' or
3971 history graph. This is sometimes known as 'backporting' or
3972 'cherry-picking'. By default, graft will copy user, date, and
3972 'cherry-picking'. By default, graft will copy user, date, and
3973 description from the source changesets.
3973 description from the source changesets.
3974
3974
3975 Changesets that are ancestors of the current revision, that have
3975 Changesets that are ancestors of the current revision, that have
3976 already been grafted, or that are merges will be skipped.
3976 already been grafted, or that are merges will be skipped.
3977
3977
3978 If --log is specified, log messages will have a comment appended
3978 If --log is specified, log messages will have a comment appended
3979 of the form::
3979 of the form::
3980
3980
3981 (grafted from CHANGESETHASH)
3981 (grafted from CHANGESETHASH)
3982
3982
3983 If --force is specified, revisions will be grafted even if they
3983 If --force is specified, revisions will be grafted even if they
3984 are already ancestors of or have been grafted to the destination.
3984 are already ancestors of or have been grafted to the destination.
3985 This is useful when the revisions have since been backed out.
3985 This is useful when the revisions have since been backed out.
3986
3986
3987 If a graft merge results in conflicts, the graft process is
3987 If a graft merge results in conflicts, the graft process is
3988 interrupted so that the current merge can be manually resolved.
3988 interrupted so that the current merge can be manually resolved.
3989 Once all conflicts are addressed, the graft process can be
3989 Once all conflicts are addressed, the graft process can be
3990 continued with the -c/--continue option.
3990 continued with the -c/--continue option.
3991
3991
3992 .. note::
3992 .. note::
3993
3993
3994 The -c/--continue option does not reapply earlier options, except
3994 The -c/--continue option does not reapply earlier options, except
3995 for --force.
3995 for --force.
3996
3996
3997 .. container:: verbose
3997 .. container:: verbose
3998
3998
3999 Examples:
3999 Examples:
4000
4000
4001 - copy a single change to the stable branch and edit its description::
4001 - copy a single change to the stable branch and edit its description::
4002
4002
4003 hg update stable
4003 hg update stable
4004 hg graft --edit 9393
4004 hg graft --edit 9393
4005
4005
4006 - graft a range of changesets with one exception, updating dates::
4006 - graft a range of changesets with one exception, updating dates::
4007
4007
4008 hg graft -D "2085::2093 and not 2091"
4008 hg graft -D "2085::2093 and not 2091"
4009
4009
4010 - continue a graft after resolving conflicts::
4010 - continue a graft after resolving conflicts::
4011
4011
4012 hg graft -c
4012 hg graft -c
4013
4013
4014 - show the source of a grafted changeset::
4014 - show the source of a grafted changeset::
4015
4015
4016 hg log --debug -r .
4016 hg log --debug -r .
4017
4017
4018 - show revisions sorted by date::
4018 - show revisions sorted by date::
4019
4019
4020 hg log -r 'sort(all(), date)'
4020 hg log -r 'sort(all(), date)'
4021
4021
4022 See :hg:`help revisions` and :hg:`help revsets` for more about
4022 See :hg:`help revisions` and :hg:`help revsets` for more about
4023 specifying revisions.
4023 specifying revisions.
4024
4024
4025 Returns 0 on successful completion.
4025 Returns 0 on successful completion.
4026 '''
4026 '''
4027 with repo.wlock():
4027 with repo.wlock():
4028 return _dograft(ui, repo, *revs, **opts)
4028 return _dograft(ui, repo, *revs, **opts)
4029
4029
4030 def _dograft(ui, repo, *revs, **opts):
4030 def _dograft(ui, repo, *revs, **opts):
4031 if revs and opts['rev']:
4031 if revs and opts['rev']:
4032 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4032 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4033 'revision ordering!\n'))
4033 'revision ordering!\n'))
4034
4034
4035 revs = list(revs)
4035 revs = list(revs)
4036 revs.extend(opts['rev'])
4036 revs.extend(opts['rev'])
4037
4037
4038 if not opts.get('user') and opts.get('currentuser'):
4038 if not opts.get('user') and opts.get('currentuser'):
4039 opts['user'] = ui.username()
4039 opts['user'] = ui.username()
4040 if not opts.get('date') and opts.get('currentdate'):
4040 if not opts.get('date') and opts.get('currentdate'):
4041 opts['date'] = "%d %d" % util.makedate()
4041 opts['date'] = "%d %d" % util.makedate()
4042
4042
4043 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4043 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4044
4044
4045 cont = False
4045 cont = False
4046 if opts['continue']:
4046 if opts['continue']:
4047 cont = True
4047 cont = True
4048 if revs:
4048 if revs:
4049 raise error.Abort(_("can't specify --continue and revisions"))
4049 raise error.Abort(_("can't specify --continue and revisions"))
4050 # read in unfinished revisions
4050 # read in unfinished revisions
4051 try:
4051 try:
4052 nodes = repo.vfs.read('graftstate').splitlines()
4052 nodes = repo.vfs.read('graftstate').splitlines()
4053 revs = [repo[node].rev() for node in nodes]
4053 revs = [repo[node].rev() for node in nodes]
4054 except IOError as inst:
4054 except IOError as inst:
4055 if inst.errno != errno.ENOENT:
4055 if inst.errno != errno.ENOENT:
4056 raise
4056 raise
4057 cmdutil.wrongtooltocontinue(repo, _('graft'))
4057 cmdutil.wrongtooltocontinue(repo, _('graft'))
4058 else:
4058 else:
4059 cmdutil.checkunfinished(repo)
4059 cmdutil.checkunfinished(repo)
4060 cmdutil.bailifchanged(repo)
4060 cmdutil.bailifchanged(repo)
4061 if not revs:
4061 if not revs:
4062 raise error.Abort(_('no revisions specified'))
4062 raise error.Abort(_('no revisions specified'))
4063 revs = scmutil.revrange(repo, revs)
4063 revs = scmutil.revrange(repo, revs)
4064
4064
4065 skipped = set()
4065 skipped = set()
4066 # check for merges
4066 # check for merges
4067 for rev in repo.revs('%ld and merge()', revs):
4067 for rev in repo.revs('%ld and merge()', revs):
4068 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4068 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4069 skipped.add(rev)
4069 skipped.add(rev)
4070 revs = [r for r in revs if r not in skipped]
4070 revs = [r for r in revs if r not in skipped]
4071 if not revs:
4071 if not revs:
4072 return -1
4072 return -1
4073
4073
4074 # Don't check in the --continue case, in effect retaining --force across
4074 # Don't check in the --continue case, in effect retaining --force across
4075 # --continues. That's because without --force, any revisions we decided to
4075 # --continues. That's because without --force, any revisions we decided to
4076 # skip would have been filtered out here, so they wouldn't have made their
4076 # skip would have been filtered out here, so they wouldn't have made their
4077 # way to the graftstate. With --force, any revisions we would have otherwise
4077 # way to the graftstate. With --force, any revisions we would have otherwise
4078 # skipped would not have been filtered out, and if they hadn't been applied
4078 # skipped would not have been filtered out, and if they hadn't been applied
4079 # already, they'd have been in the graftstate.
4079 # already, they'd have been in the graftstate.
4080 if not (cont or opts.get('force')):
4080 if not (cont or opts.get('force')):
4081 # check for ancestors of dest branch
4081 # check for ancestors of dest branch
4082 crev = repo['.'].rev()
4082 crev = repo['.'].rev()
4083 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4083 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4084 # Cannot use x.remove(y) on smart set, this has to be a list.
4084 # Cannot use x.remove(y) on smart set, this has to be a list.
4085 # XXX make this lazy in the future
4085 # XXX make this lazy in the future
4086 revs = list(revs)
4086 revs = list(revs)
4087 # don't mutate while iterating, create a copy
4087 # don't mutate while iterating, create a copy
4088 for rev in list(revs):
4088 for rev in list(revs):
4089 if rev in ancestors:
4089 if rev in ancestors:
4090 ui.warn(_('skipping ancestor revision %d:%s\n') %
4090 ui.warn(_('skipping ancestor revision %d:%s\n') %
4091 (rev, repo[rev]))
4091 (rev, repo[rev]))
4092 # XXX remove on list is slow
4092 # XXX remove on list is slow
4093 revs.remove(rev)
4093 revs.remove(rev)
4094 if not revs:
4094 if not revs:
4095 return -1
4095 return -1
4096
4096
4097 # analyze revs for earlier grafts
4097 # analyze revs for earlier grafts
4098 ids = {}
4098 ids = {}
4099 for ctx in repo.set("%ld", revs):
4099 for ctx in repo.set("%ld", revs):
4100 ids[ctx.hex()] = ctx.rev()
4100 ids[ctx.hex()] = ctx.rev()
4101 n = ctx.extra().get('source')
4101 n = ctx.extra().get('source')
4102 if n:
4102 if n:
4103 ids[n] = ctx.rev()
4103 ids[n] = ctx.rev()
4104
4104
4105 # check ancestors for earlier grafts
4105 # check ancestors for earlier grafts
4106 ui.debug('scanning for duplicate grafts\n')
4106 ui.debug('scanning for duplicate grafts\n')
4107
4107
4108 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4108 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4109 ctx = repo[rev]
4109 ctx = repo[rev]
4110 n = ctx.extra().get('source')
4110 n = ctx.extra().get('source')
4111 if n in ids:
4111 if n in ids:
4112 try:
4112 try:
4113 r = repo[n].rev()
4113 r = repo[n].rev()
4114 except error.RepoLookupError:
4114 except error.RepoLookupError:
4115 r = None
4115 r = None
4116 if r in revs:
4116 if r in revs:
4117 ui.warn(_('skipping revision %d:%s '
4117 ui.warn(_('skipping revision %d:%s '
4118 '(already grafted to %d:%s)\n')
4118 '(already grafted to %d:%s)\n')
4119 % (r, repo[r], rev, ctx))
4119 % (r, repo[r], rev, ctx))
4120 revs.remove(r)
4120 revs.remove(r)
4121 elif ids[n] in revs:
4121 elif ids[n] in revs:
4122 if r is None:
4122 if r is None:
4123 ui.warn(_('skipping already grafted revision %d:%s '
4123 ui.warn(_('skipping already grafted revision %d:%s '
4124 '(%d:%s also has unknown origin %s)\n')
4124 '(%d:%s also has unknown origin %s)\n')
4125 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4125 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4126 else:
4126 else:
4127 ui.warn(_('skipping already grafted revision %d:%s '
4127 ui.warn(_('skipping already grafted revision %d:%s '
4128 '(%d:%s also has origin %d:%s)\n')
4128 '(%d:%s also has origin %d:%s)\n')
4129 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4129 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4130 revs.remove(ids[n])
4130 revs.remove(ids[n])
4131 elif ctx.hex() in ids:
4131 elif ctx.hex() in ids:
4132 r = ids[ctx.hex()]
4132 r = ids[ctx.hex()]
4133 ui.warn(_('skipping already grafted revision %d:%s '
4133 ui.warn(_('skipping already grafted revision %d:%s '
4134 '(was grafted from %d:%s)\n') %
4134 '(was grafted from %d:%s)\n') %
4135 (r, repo[r], rev, ctx))
4135 (r, repo[r], rev, ctx))
4136 revs.remove(r)
4136 revs.remove(r)
4137 if not revs:
4137 if not revs:
4138 return -1
4138 return -1
4139
4139
4140 for pos, ctx in enumerate(repo.set("%ld", revs)):
4140 for pos, ctx in enumerate(repo.set("%ld", revs)):
4141 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4141 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4142 ctx.description().split('\n', 1)[0])
4142 ctx.description().split('\n', 1)[0])
4143 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4143 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4144 if names:
4144 if names:
4145 desc += ' (%s)' % ' '.join(names)
4145 desc += ' (%s)' % ' '.join(names)
4146 ui.status(_('grafting %s\n') % desc)
4146 ui.status(_('grafting %s\n') % desc)
4147 if opts.get('dry_run'):
4147 if opts.get('dry_run'):
4148 continue
4148 continue
4149
4149
4150 source = ctx.extra().get('source')
4150 source = ctx.extra().get('source')
4151 extra = {}
4151 extra = {}
4152 if source:
4152 if source:
4153 extra['source'] = source
4153 extra['source'] = source
4154 extra['intermediate-source'] = ctx.hex()
4154 extra['intermediate-source'] = ctx.hex()
4155 else:
4155 else:
4156 extra['source'] = ctx.hex()
4156 extra['source'] = ctx.hex()
4157 user = ctx.user()
4157 user = ctx.user()
4158 if opts.get('user'):
4158 if opts.get('user'):
4159 user = opts['user']
4159 user = opts['user']
4160 date = ctx.date()
4160 date = ctx.date()
4161 if opts.get('date'):
4161 if opts.get('date'):
4162 date = opts['date']
4162 date = opts['date']
4163 message = ctx.description()
4163 message = ctx.description()
4164 if opts.get('log'):
4164 if opts.get('log'):
4165 message += '\n(grafted from %s)' % ctx.hex()
4165 message += '\n(grafted from %s)' % ctx.hex()
4166
4166
4167 # we don't merge the first commit when continuing
4167 # we don't merge the first commit when continuing
4168 if not cont:
4168 if not cont:
4169 # perform the graft merge with p1(rev) as 'ancestor'
4169 # perform the graft merge with p1(rev) as 'ancestor'
4170 try:
4170 try:
4171 # ui.forcemerge is an internal variable, do not document
4171 # ui.forcemerge is an internal variable, do not document
4172 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4172 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4173 'graft')
4173 'graft')
4174 stats = mergemod.graft(repo, ctx, ctx.p1(),
4174 stats = mergemod.graft(repo, ctx, ctx.p1(),
4175 ['local', 'graft'])
4175 ['local', 'graft'])
4176 finally:
4176 finally:
4177 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4177 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4178 # report any conflicts
4178 # report any conflicts
4179 if stats and stats[3] > 0:
4179 if stats and stats[3] > 0:
4180 # write out state for --continue
4180 # write out state for --continue
4181 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4181 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4182 repo.vfs.write('graftstate', ''.join(nodelines))
4182 repo.vfs.write('graftstate', ''.join(nodelines))
4183 extra = ''
4183 extra = ''
4184 if opts.get('user'):
4184 if opts.get('user'):
4185 extra += ' --user %s' % opts['user']
4185 extra += ' --user %s' % opts['user']
4186 if opts.get('date'):
4186 if opts.get('date'):
4187 extra += ' --date %s' % opts['date']
4187 extra += ' --date %s' % opts['date']
4188 if opts.get('log'):
4188 if opts.get('log'):
4189 extra += ' --log'
4189 extra += ' --log'
4190 hint=_('use hg resolve and hg graft --continue%s') % extra
4190 hint=_('use hg resolve and hg graft --continue%s') % extra
4191 raise error.Abort(
4191 raise error.Abort(
4192 _("unresolved conflicts, can't continue"),
4192 _("unresolved conflicts, can't continue"),
4193 hint=hint)
4193 hint=hint)
4194 else:
4194 else:
4195 cont = False
4195 cont = False
4196
4196
4197 # commit
4197 # commit
4198 node = repo.commit(text=message, user=user,
4198 node = repo.commit(text=message, user=user,
4199 date=date, extra=extra, editor=editor)
4199 date=date, extra=extra, editor=editor)
4200 if node is None:
4200 if node is None:
4201 ui.warn(
4201 ui.warn(
4202 _('note: graft of %d:%s created no changes to commit\n') %
4202 _('note: graft of %d:%s created no changes to commit\n') %
4203 (ctx.rev(), ctx))
4203 (ctx.rev(), ctx))
4204
4204
4205 # remove state when we complete successfully
4205 # remove state when we complete successfully
4206 if not opts.get('dry_run'):
4206 if not opts.get('dry_run'):
4207 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4207 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4208
4208
4209 return 0
4209 return 0
4210
4210
4211 @command('grep',
4211 @command('grep',
4212 [('0', 'print0', None, _('end fields with NUL')),
4212 [('0', 'print0', None, _('end fields with NUL')),
4213 ('', 'all', None, _('print all revisions that match')),
4213 ('', 'all', None, _('print all revisions that match')),
4214 ('a', 'text', None, _('treat all files as text')),
4214 ('a', 'text', None, _('treat all files as text')),
4215 ('f', 'follow', None,
4215 ('f', 'follow', None,
4216 _('follow changeset history,'
4216 _('follow changeset history,'
4217 ' or file history across copies and renames')),
4217 ' or file history across copies and renames')),
4218 ('i', 'ignore-case', None, _('ignore case when matching')),
4218 ('i', 'ignore-case', None, _('ignore case when matching')),
4219 ('l', 'files-with-matches', None,
4219 ('l', 'files-with-matches', None,
4220 _('print only filenames and revisions that match')),
4220 _('print only filenames and revisions that match')),
4221 ('n', 'line-number', None, _('print matching line numbers')),
4221 ('n', 'line-number', None, _('print matching line numbers')),
4222 ('r', 'rev', [],
4222 ('r', 'rev', [],
4223 _('only search files changed within revision range'), _('REV')),
4223 _('only search files changed within revision range'), _('REV')),
4224 ('u', 'user', None, _('list the author (long with -v)')),
4224 ('u', 'user', None, _('list the author (long with -v)')),
4225 ('d', 'date', None, _('list the date (short with -q)')),
4225 ('d', 'date', None, _('list the date (short with -q)')),
4226 ] + walkopts,
4226 ] + walkopts,
4227 _('[OPTION]... PATTERN [FILE]...'),
4227 _('[OPTION]... PATTERN [FILE]...'),
4228 inferrepo=True)
4228 inferrepo=True)
4229 def grep(ui, repo, pattern, *pats, **opts):
4229 def grep(ui, repo, pattern, *pats, **opts):
4230 """search for a pattern in specified files and revisions
4230 """search for a pattern in specified files and revisions
4231
4231
4232 Search revisions of files for a regular expression.
4232 Search revisions of files for a regular expression.
4233
4233
4234 This command behaves differently than Unix grep. It only accepts
4234 This command behaves differently than Unix grep. It only accepts
4235 Python/Perl regexps. It searches repository history, not the
4235 Python/Perl regexps. It searches repository history, not the
4236 working directory. It always prints the revision number in which a
4236 working directory. It always prints the revision number in which a
4237 match appears.
4237 match appears.
4238
4238
4239 By default, grep only prints output for the first revision of a
4239 By default, grep only prints output for the first revision of a
4240 file in which it finds a match. To get it to print every revision
4240 file in which it finds a match. To get it to print every revision
4241 that contains a change in match status ("-" for a match that
4241 that contains a change in match status ("-" for a match that
4242 becomes a non-match, or "+" for a non-match that becomes a match),
4242 becomes a non-match, or "+" for a non-match that becomes a match),
4243 use the --all flag.
4243 use the --all flag.
4244
4244
4245 Returns 0 if a match is found, 1 otherwise.
4245 Returns 0 if a match is found, 1 otherwise.
4246 """
4246 """
4247 reflags = re.M
4247 reflags = re.M
4248 if opts.get('ignore_case'):
4248 if opts.get('ignore_case'):
4249 reflags |= re.I
4249 reflags |= re.I
4250 try:
4250 try:
4251 regexp = util.re.compile(pattern, reflags)
4251 regexp = util.re.compile(pattern, reflags)
4252 except re.error as inst:
4252 except re.error as inst:
4253 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4253 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4254 return 1
4254 return 1
4255 sep, eol = ':', '\n'
4255 sep, eol = ':', '\n'
4256 if opts.get('print0'):
4256 if opts.get('print0'):
4257 sep = eol = '\0'
4257 sep = eol = '\0'
4258
4258
4259 getfile = util.lrucachefunc(repo.file)
4259 getfile = util.lrucachefunc(repo.file)
4260
4260
4261 def matchlines(body):
4261 def matchlines(body):
4262 begin = 0
4262 begin = 0
4263 linenum = 0
4263 linenum = 0
4264 while begin < len(body):
4264 while begin < len(body):
4265 match = regexp.search(body, begin)
4265 match = regexp.search(body, begin)
4266 if not match:
4266 if not match:
4267 break
4267 break
4268 mstart, mend = match.span()
4268 mstart, mend = match.span()
4269 linenum += body.count('\n', begin, mstart) + 1
4269 linenum += body.count('\n', begin, mstart) + 1
4270 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4270 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4271 begin = body.find('\n', mend) + 1 or len(body) + 1
4271 begin = body.find('\n', mend) + 1 or len(body) + 1
4272 lend = begin - 1
4272 lend = begin - 1
4273 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4273 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4274
4274
4275 class linestate(object):
4275 class linestate(object):
4276 def __init__(self, line, linenum, colstart, colend):
4276 def __init__(self, line, linenum, colstart, colend):
4277 self.line = line
4277 self.line = line
4278 self.linenum = linenum
4278 self.linenum = linenum
4279 self.colstart = colstart
4279 self.colstart = colstart
4280 self.colend = colend
4280 self.colend = colend
4281
4281
4282 def __hash__(self):
4282 def __hash__(self):
4283 return hash((self.linenum, self.line))
4283 return hash((self.linenum, self.line))
4284
4284
4285 def __eq__(self, other):
4285 def __eq__(self, other):
4286 return self.line == other.line
4286 return self.line == other.line
4287
4287
4288 def __iter__(self):
4288 def __iter__(self):
4289 yield (self.line[:self.colstart], '')
4289 yield (self.line[:self.colstart], '')
4290 yield (self.line[self.colstart:self.colend], 'grep.match')
4290 yield (self.line[self.colstart:self.colend], 'grep.match')
4291 rest = self.line[self.colend:]
4291 rest = self.line[self.colend:]
4292 while rest != '':
4292 while rest != '':
4293 match = regexp.search(rest)
4293 match = regexp.search(rest)
4294 if not match:
4294 if not match:
4295 yield (rest, '')
4295 yield (rest, '')
4296 break
4296 break
4297 mstart, mend = match.span()
4297 mstart, mend = match.span()
4298 yield (rest[:mstart], '')
4298 yield (rest[:mstart], '')
4299 yield (rest[mstart:mend], 'grep.match')
4299 yield (rest[mstart:mend], 'grep.match')
4300 rest = rest[mend:]
4300 rest = rest[mend:]
4301
4301
4302 matches = {}
4302 matches = {}
4303 copies = {}
4303 copies = {}
4304 def grepbody(fn, rev, body):
4304 def grepbody(fn, rev, body):
4305 matches[rev].setdefault(fn, [])
4305 matches[rev].setdefault(fn, [])
4306 m = matches[rev][fn]
4306 m = matches[rev][fn]
4307 for lnum, cstart, cend, line in matchlines(body):
4307 for lnum, cstart, cend, line in matchlines(body):
4308 s = linestate(line, lnum, cstart, cend)
4308 s = linestate(line, lnum, cstart, cend)
4309 m.append(s)
4309 m.append(s)
4310
4310
4311 def difflinestates(a, b):
4311 def difflinestates(a, b):
4312 sm = difflib.SequenceMatcher(None, a, b)
4312 sm = difflib.SequenceMatcher(None, a, b)
4313 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4313 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4314 if tag == 'insert':
4314 if tag == 'insert':
4315 for i in xrange(blo, bhi):
4315 for i in xrange(blo, bhi):
4316 yield ('+', b[i])
4316 yield ('+', b[i])
4317 elif tag == 'delete':
4317 elif tag == 'delete':
4318 for i in xrange(alo, ahi):
4318 for i in xrange(alo, ahi):
4319 yield ('-', a[i])
4319 yield ('-', a[i])
4320 elif tag == 'replace':
4320 elif tag == 'replace':
4321 for i in xrange(alo, ahi):
4321 for i in xrange(alo, ahi):
4322 yield ('-', a[i])
4322 yield ('-', a[i])
4323 for i in xrange(blo, bhi):
4323 for i in xrange(blo, bhi):
4324 yield ('+', b[i])
4324 yield ('+', b[i])
4325
4325
4326 def display(fn, ctx, pstates, states):
4326 def display(fn, ctx, pstates, states):
4327 rev = ctx.rev()
4327 rev = ctx.rev()
4328 if ui.quiet:
4328 if ui.quiet:
4329 datefunc = util.shortdate
4329 datefunc = util.shortdate
4330 else:
4330 else:
4331 datefunc = util.datestr
4331 datefunc = util.datestr
4332 found = False
4332 found = False
4333 @util.cachefunc
4333 @util.cachefunc
4334 def binary():
4334 def binary():
4335 flog = getfile(fn)
4335 flog = getfile(fn)
4336 return util.binary(flog.read(ctx.filenode(fn)))
4336 return util.binary(flog.read(ctx.filenode(fn)))
4337
4337
4338 if opts.get('all'):
4338 if opts.get('all'):
4339 iter = difflinestates(pstates, states)
4339 iter = difflinestates(pstates, states)
4340 else:
4340 else:
4341 iter = [('', l) for l in states]
4341 iter = [('', l) for l in states]
4342 for change, l in iter:
4342 for change, l in iter:
4343 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4343 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4344
4344
4345 if opts.get('line_number'):
4345 if opts.get('line_number'):
4346 cols.append((str(l.linenum), 'grep.linenumber'))
4346 cols.append((str(l.linenum), 'grep.linenumber'))
4347 if opts.get('all'):
4347 if opts.get('all'):
4348 cols.append((change, 'grep.change'))
4348 cols.append((change, 'grep.change'))
4349 if opts.get('user'):
4349 if opts.get('user'):
4350 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4350 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4351 if opts.get('date'):
4351 if opts.get('date'):
4352 cols.append((datefunc(ctx.date()), 'grep.date'))
4352 cols.append((datefunc(ctx.date()), 'grep.date'))
4353 for col, label in cols[:-1]:
4353 for col, label in cols[:-1]:
4354 ui.write(col, label=label)
4354 ui.write(col, label=label)
4355 ui.write(sep, label='grep.sep')
4355 ui.write(sep, label='grep.sep')
4356 ui.write(cols[-1][0], label=cols[-1][1])
4356 ui.write(cols[-1][0], label=cols[-1][1])
4357 if not opts.get('files_with_matches'):
4357 if not opts.get('files_with_matches'):
4358 ui.write(sep, label='grep.sep')
4358 ui.write(sep, label='grep.sep')
4359 if not opts.get('text') and binary():
4359 if not opts.get('text') and binary():
4360 ui.write(" Binary file matches")
4360 ui.write(" Binary file matches")
4361 else:
4361 else:
4362 for s, label in l:
4362 for s, label in l:
4363 ui.write(s, label=label)
4363 ui.write(s, label=label)
4364 ui.write(eol)
4364 ui.write(eol)
4365 found = True
4365 found = True
4366 if opts.get('files_with_matches'):
4366 if opts.get('files_with_matches'):
4367 break
4367 break
4368 return found
4368 return found
4369
4369
4370 skip = {}
4370 skip = {}
4371 revfiles = {}
4371 revfiles = {}
4372 matchfn = scmutil.match(repo[None], pats, opts)
4372 matchfn = scmutil.match(repo[None], pats, opts)
4373 found = False
4373 found = False
4374 follow = opts.get('follow')
4374 follow = opts.get('follow')
4375
4375
4376 def prep(ctx, fns):
4376 def prep(ctx, fns):
4377 rev = ctx.rev()
4377 rev = ctx.rev()
4378 pctx = ctx.p1()
4378 pctx = ctx.p1()
4379 parent = pctx.rev()
4379 parent = pctx.rev()
4380 matches.setdefault(rev, {})
4380 matches.setdefault(rev, {})
4381 matches.setdefault(parent, {})
4381 matches.setdefault(parent, {})
4382 files = revfiles.setdefault(rev, [])
4382 files = revfiles.setdefault(rev, [])
4383 for fn in fns:
4383 for fn in fns:
4384 flog = getfile(fn)
4384 flog = getfile(fn)
4385 try:
4385 try:
4386 fnode = ctx.filenode(fn)
4386 fnode = ctx.filenode(fn)
4387 except error.LookupError:
4387 except error.LookupError:
4388 continue
4388 continue
4389
4389
4390 copied = flog.renamed(fnode)
4390 copied = flog.renamed(fnode)
4391 copy = follow and copied and copied[0]
4391 copy = follow and copied and copied[0]
4392 if copy:
4392 if copy:
4393 copies.setdefault(rev, {})[fn] = copy
4393 copies.setdefault(rev, {})[fn] = copy
4394 if fn in skip:
4394 if fn in skip:
4395 if copy:
4395 if copy:
4396 skip[copy] = True
4396 skip[copy] = True
4397 continue
4397 continue
4398 files.append(fn)
4398 files.append(fn)
4399
4399
4400 if fn not in matches[rev]:
4400 if fn not in matches[rev]:
4401 grepbody(fn, rev, flog.read(fnode))
4401 grepbody(fn, rev, flog.read(fnode))
4402
4402
4403 pfn = copy or fn
4403 pfn = copy or fn
4404 if pfn not in matches[parent]:
4404 if pfn not in matches[parent]:
4405 try:
4405 try:
4406 fnode = pctx.filenode(pfn)
4406 fnode = pctx.filenode(pfn)
4407 grepbody(pfn, parent, flog.read(fnode))
4407 grepbody(pfn, parent, flog.read(fnode))
4408 except error.LookupError:
4408 except error.LookupError:
4409 pass
4409 pass
4410
4410
4411 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4411 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4412 rev = ctx.rev()
4412 rev = ctx.rev()
4413 parent = ctx.p1().rev()
4413 parent = ctx.p1().rev()
4414 for fn in sorted(revfiles.get(rev, [])):
4414 for fn in sorted(revfiles.get(rev, [])):
4415 states = matches[rev][fn]
4415 states = matches[rev][fn]
4416 copy = copies.get(rev, {}).get(fn)
4416 copy = copies.get(rev, {}).get(fn)
4417 if fn in skip:
4417 if fn in skip:
4418 if copy:
4418 if copy:
4419 skip[copy] = True
4419 skip[copy] = True
4420 continue
4420 continue
4421 pstates = matches.get(parent, {}).get(copy or fn, [])
4421 pstates = matches.get(parent, {}).get(copy or fn, [])
4422 if pstates or states:
4422 if pstates or states:
4423 r = display(fn, ctx, pstates, states)
4423 r = display(fn, ctx, pstates, states)
4424 found = found or r
4424 found = found or r
4425 if r and not opts.get('all'):
4425 if r and not opts.get('all'):
4426 skip[fn] = True
4426 skip[fn] = True
4427 if copy:
4427 if copy:
4428 skip[copy] = True
4428 skip[copy] = True
4429 del matches[rev]
4429 del matches[rev]
4430 del revfiles[rev]
4430 del revfiles[rev]
4431
4431
4432 return not found
4432 return not found
4433
4433
4434 @command('heads',
4434 @command('heads',
4435 [('r', 'rev', '',
4435 [('r', 'rev', '',
4436 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4436 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4437 ('t', 'topo', False, _('show topological heads only')),
4437 ('t', 'topo', False, _('show topological heads only')),
4438 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4438 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4439 ('c', 'closed', False, _('show normal and closed branch heads')),
4439 ('c', 'closed', False, _('show normal and closed branch heads')),
4440 ] + templateopts,
4440 ] + templateopts,
4441 _('[-ct] [-r STARTREV] [REV]...'))
4441 _('[-ct] [-r STARTREV] [REV]...'))
4442 def heads(ui, repo, *branchrevs, **opts):
4442 def heads(ui, repo, *branchrevs, **opts):
4443 """show branch heads
4443 """show branch heads
4444
4444
4445 With no arguments, show all open branch heads in the repository.
4445 With no arguments, show all open branch heads in the repository.
4446 Branch heads are changesets that have no descendants on the
4446 Branch heads are changesets that have no descendants on the
4447 same branch. They are where development generally takes place and
4447 same branch. They are where development generally takes place and
4448 are the usual targets for update and merge operations.
4448 are the usual targets for update and merge operations.
4449
4449
4450 If one or more REVs are given, only open branch heads on the
4450 If one or more REVs are given, only open branch heads on the
4451 branches associated with the specified changesets are shown. This
4451 branches associated with the specified changesets are shown. This
4452 means that you can use :hg:`heads .` to see the heads on the
4452 means that you can use :hg:`heads .` to see the heads on the
4453 currently checked-out branch.
4453 currently checked-out branch.
4454
4454
4455 If -c/--closed is specified, also show branch heads marked closed
4455 If -c/--closed is specified, also show branch heads marked closed
4456 (see :hg:`commit --close-branch`).
4456 (see :hg:`commit --close-branch`).
4457
4457
4458 If STARTREV is specified, only those heads that are descendants of
4458 If STARTREV is specified, only those heads that are descendants of
4459 STARTREV will be displayed.
4459 STARTREV will be displayed.
4460
4460
4461 If -t/--topo is specified, named branch mechanics will be ignored and only
4461 If -t/--topo is specified, named branch mechanics will be ignored and only
4462 topological heads (changesets with no children) will be shown.
4462 topological heads (changesets with no children) will be shown.
4463
4463
4464 Returns 0 if matching heads are found, 1 if not.
4464 Returns 0 if matching heads are found, 1 if not.
4465 """
4465 """
4466
4466
4467 start = None
4467 start = None
4468 if 'rev' in opts:
4468 if 'rev' in opts:
4469 start = scmutil.revsingle(repo, opts['rev'], None).node()
4469 start = scmutil.revsingle(repo, opts['rev'], None).node()
4470
4470
4471 if opts.get('topo'):
4471 if opts.get('topo'):
4472 heads = [repo[h] for h in repo.heads(start)]
4472 heads = [repo[h] for h in repo.heads(start)]
4473 else:
4473 else:
4474 heads = []
4474 heads = []
4475 for branch in repo.branchmap():
4475 for branch in repo.branchmap():
4476 heads += repo.branchheads(branch, start, opts.get('closed'))
4476 heads += repo.branchheads(branch, start, opts.get('closed'))
4477 heads = [repo[h] for h in heads]
4477 heads = [repo[h] for h in heads]
4478
4478
4479 if branchrevs:
4479 if branchrevs:
4480 branches = set(repo[br].branch() for br in branchrevs)
4480 branches = set(repo[br].branch() for br in branchrevs)
4481 heads = [h for h in heads if h.branch() in branches]
4481 heads = [h for h in heads if h.branch() in branches]
4482
4482
4483 if opts.get('active') and branchrevs:
4483 if opts.get('active') and branchrevs:
4484 dagheads = repo.heads(start)
4484 dagheads = repo.heads(start)
4485 heads = [h for h in heads if h.node() in dagheads]
4485 heads = [h for h in heads if h.node() in dagheads]
4486
4486
4487 if branchrevs:
4487 if branchrevs:
4488 haveheads = set(h.branch() for h in heads)
4488 haveheads = set(h.branch() for h in heads)
4489 if branches - haveheads:
4489 if branches - haveheads:
4490 headless = ', '.join(b for b in branches - haveheads)
4490 headless = ', '.join(b for b in branches - haveheads)
4491 msg = _('no open branch heads found on branches %s')
4491 msg = _('no open branch heads found on branches %s')
4492 if opts.get('rev'):
4492 if opts.get('rev'):
4493 msg += _(' (started at %s)') % opts['rev']
4493 msg += _(' (started at %s)') % opts['rev']
4494 ui.warn((msg + '\n') % headless)
4494 ui.warn((msg + '\n') % headless)
4495
4495
4496 if not heads:
4496 if not heads:
4497 return 1
4497 return 1
4498
4498
4499 heads = sorted(heads, key=lambda x: -x.rev())
4499 heads = sorted(heads, key=lambda x: -x.rev())
4500 displayer = cmdutil.show_changeset(ui, repo, opts)
4500 displayer = cmdutil.show_changeset(ui, repo, opts)
4501 for ctx in heads:
4501 for ctx in heads:
4502 displayer.show(ctx)
4502 displayer.show(ctx)
4503 displayer.close()
4503 displayer.close()
4504
4504
4505 @command('help',
4505 @command('help',
4506 [('e', 'extension', None, _('show only help for extensions')),
4506 [('e', 'extension', None, _('show only help for extensions')),
4507 ('c', 'command', None, _('show only help for commands')),
4507 ('c', 'command', None, _('show only help for commands')),
4508 ('k', 'keyword', None, _('show topics matching keyword')),
4508 ('k', 'keyword', None, _('show topics matching keyword')),
4509 ('s', 'system', [], _('show help for specific platform(s)')),
4509 ('s', 'system', [], _('show help for specific platform(s)')),
4510 ],
4510 ],
4511 _('[-ecks] [TOPIC]'),
4511 _('[-ecks] [TOPIC]'),
4512 norepo=True)
4512 norepo=True)
4513 def help_(ui, name=None, **opts):
4513 def help_(ui, name=None, **opts):
4514 """show help for a given topic or a help overview
4514 """show help for a given topic or a help overview
4515
4515
4516 With no arguments, print a list of commands with short help messages.
4516 With no arguments, print a list of commands with short help messages.
4517
4517
4518 Given a topic, extension, or command name, print help for that
4518 Given a topic, extension, or command name, print help for that
4519 topic.
4519 topic.
4520
4520
4521 Returns 0 if successful.
4521 Returns 0 if successful.
4522 """
4522 """
4523
4523
4524 textwidth = min(ui.termwidth(), 80) - 2
4524 textwidth = min(ui.termwidth(), 80) - 2
4525
4525
4526 keep = opts.get('system') or []
4526 keep = opts.get('system') or []
4527 if len(keep) == 0:
4527 if len(keep) == 0:
4528 if sys.platform.startswith('win'):
4528 if sys.platform.startswith('win'):
4529 keep.append('windows')
4529 keep.append('windows')
4530 elif sys.platform == 'OpenVMS':
4530 elif sys.platform == 'OpenVMS':
4531 keep.append('vms')
4531 keep.append('vms')
4532 elif sys.platform == 'plan9':
4532 elif sys.platform == 'plan9':
4533 keep.append('plan9')
4533 keep.append('plan9')
4534 else:
4534 else:
4535 keep.append('unix')
4535 keep.append('unix')
4536 keep.append(sys.platform.lower())
4536 keep.append(sys.platform.lower())
4537 if ui.verbose:
4537 if ui.verbose:
4538 keep.append('verbose')
4538 keep.append('verbose')
4539
4539
4540 section = None
4540 section = None
4541 subtopic = None
4541 subtopic = None
4542 if name and '.' in name:
4542 if name and '.' in name:
4543 name, section = name.split('.', 1)
4543 name, section = name.split('.', 1)
4544 section = section.lower()
4544 section = section.lower()
4545 if '.' in section:
4545 if '.' in section:
4546 subtopic, section = section.split('.', 1)
4546 subtopic, section = section.split('.', 1)
4547 else:
4547 else:
4548 subtopic = section
4548 subtopic = section
4549
4549
4550 text = help.help_(ui, name, subtopic=subtopic, **opts)
4550 text = help.help_(ui, name, subtopic=subtopic, **opts)
4551
4551
4552 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4552 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4553 section=section)
4553 section=section)
4554
4554
4555 # We could have been given a weird ".foo" section without a name
4555 # We could have been given a weird ".foo" section without a name
4556 # to look for, or we could have simply failed to found "foo.bar"
4556 # to look for, or we could have simply failed to found "foo.bar"
4557 # because bar isn't a section of foo
4557 # because bar isn't a section of foo
4558 if section and not (formatted and name):
4558 if section and not (formatted and name):
4559 raise error.Abort(_("help section not found"))
4559 raise error.Abort(_("help section not found"))
4560
4560
4561 if 'verbose' in pruned:
4561 if 'verbose' in pruned:
4562 keep.append('omitted')
4562 keep.append('omitted')
4563 else:
4563 else:
4564 keep.append('notomitted')
4564 keep.append('notomitted')
4565 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4565 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4566 section=section)
4566 section=section)
4567 ui.write(formatted)
4567 ui.write(formatted)
4568
4568
4569
4569
4570 @command('identify|id',
4570 @command('identify|id',
4571 [('r', 'rev', '',
4571 [('r', 'rev', '',
4572 _('identify the specified revision'), _('REV')),
4572 _('identify the specified revision'), _('REV')),
4573 ('n', 'num', None, _('show local revision number')),
4573 ('n', 'num', None, _('show local revision number')),
4574 ('i', 'id', None, _('show global revision id')),
4574 ('i', 'id', None, _('show global revision id')),
4575 ('b', 'branch', None, _('show branch')),
4575 ('b', 'branch', None, _('show branch')),
4576 ('t', 'tags', None, _('show tags')),
4576 ('t', 'tags', None, _('show tags')),
4577 ('B', 'bookmarks', None, _('show bookmarks')),
4577 ('B', 'bookmarks', None, _('show bookmarks')),
4578 ] + remoteopts,
4578 ] + remoteopts,
4579 _('[-nibtB] [-r REV] [SOURCE]'),
4579 _('[-nibtB] [-r REV] [SOURCE]'),
4580 optionalrepo=True)
4580 optionalrepo=True)
4581 def identify(ui, repo, source=None, rev=None,
4581 def identify(ui, repo, source=None, rev=None,
4582 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4582 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4583 """identify the working directory or specified revision
4583 """identify the working directory or specified revision
4584
4584
4585 Print a summary identifying the repository state at REV using one or
4585 Print a summary identifying the repository state at REV using one or
4586 two parent hash identifiers, followed by a "+" if the working
4586 two parent hash identifiers, followed by a "+" if the working
4587 directory has uncommitted changes, the branch name (if not default),
4587 directory has uncommitted changes, the branch name (if not default),
4588 a list of tags, and a list of bookmarks.
4588 a list of tags, and a list of bookmarks.
4589
4589
4590 When REV is not given, print a summary of the current state of the
4590 When REV is not given, print a summary of the current state of the
4591 repository.
4591 repository.
4592
4592
4593 Specifying a path to a repository root or Mercurial bundle will
4593 Specifying a path to a repository root or Mercurial bundle will
4594 cause lookup to operate on that repository/bundle.
4594 cause lookup to operate on that repository/bundle.
4595
4595
4596 .. container:: verbose
4596 .. container:: verbose
4597
4597
4598 Examples:
4598 Examples:
4599
4599
4600 - generate a build identifier for the working directory::
4600 - generate a build identifier for the working directory::
4601
4601
4602 hg id --id > build-id.dat
4602 hg id --id > build-id.dat
4603
4603
4604 - find the revision corresponding to a tag::
4604 - find the revision corresponding to a tag::
4605
4605
4606 hg id -n -r 1.3
4606 hg id -n -r 1.3
4607
4607
4608 - check the most recent revision of a remote repository::
4608 - check the most recent revision of a remote repository::
4609
4609
4610 hg id -r tip http://selenic.com/hg/
4610 hg id -r tip http://selenic.com/hg/
4611
4611
4612 See :hg:`log` for generating more information about specific revisions,
4612 See :hg:`log` for generating more information about specific revisions,
4613 including full hash identifiers.
4613 including full hash identifiers.
4614
4614
4615 Returns 0 if successful.
4615 Returns 0 if successful.
4616 """
4616 """
4617
4617
4618 if not repo and not source:
4618 if not repo and not source:
4619 raise error.Abort(_("there is no Mercurial repository here "
4619 raise error.Abort(_("there is no Mercurial repository here "
4620 "(.hg not found)"))
4620 "(.hg not found)"))
4621
4621
4622 if ui.debugflag:
4622 if ui.debugflag:
4623 hexfunc = hex
4623 hexfunc = hex
4624 else:
4624 else:
4625 hexfunc = short
4625 hexfunc = short
4626 default = not (num or id or branch or tags or bookmarks)
4626 default = not (num or id or branch or tags or bookmarks)
4627 output = []
4627 output = []
4628 revs = []
4628 revs = []
4629
4629
4630 if source:
4630 if source:
4631 source, branches = hg.parseurl(ui.expandpath(source))
4631 source, branches = hg.parseurl(ui.expandpath(source))
4632 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4632 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4633 repo = peer.local()
4633 repo = peer.local()
4634 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4634 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4635
4635
4636 if not repo:
4636 if not repo:
4637 if num or branch or tags:
4637 if num or branch or tags:
4638 raise error.Abort(
4638 raise error.Abort(
4639 _("can't query remote revision number, branch, or tags"))
4639 _("can't query remote revision number, branch, or tags"))
4640 if not rev and revs:
4640 if not rev and revs:
4641 rev = revs[0]
4641 rev = revs[0]
4642 if not rev:
4642 if not rev:
4643 rev = "tip"
4643 rev = "tip"
4644
4644
4645 remoterev = peer.lookup(rev)
4645 remoterev = peer.lookup(rev)
4646 if default or id:
4646 if default or id:
4647 output = [hexfunc(remoterev)]
4647 output = [hexfunc(remoterev)]
4648
4648
4649 def getbms():
4649 def getbms():
4650 bms = []
4650 bms = []
4651
4651
4652 if 'bookmarks' in peer.listkeys('namespaces'):
4652 if 'bookmarks' in peer.listkeys('namespaces'):
4653 hexremoterev = hex(remoterev)
4653 hexremoterev = hex(remoterev)
4654 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4654 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4655 if bmr == hexremoterev]
4655 if bmr == hexremoterev]
4656
4656
4657 return sorted(bms)
4657 return sorted(bms)
4658
4658
4659 if bookmarks:
4659 if bookmarks:
4660 output.extend(getbms())
4660 output.extend(getbms())
4661 elif default and not ui.quiet:
4661 elif default and not ui.quiet:
4662 # multiple bookmarks for a single parent separated by '/'
4662 # multiple bookmarks for a single parent separated by '/'
4663 bm = '/'.join(getbms())
4663 bm = '/'.join(getbms())
4664 if bm:
4664 if bm:
4665 output.append(bm)
4665 output.append(bm)
4666 else:
4666 else:
4667 ctx = scmutil.revsingle(repo, rev, None)
4667 ctx = scmutil.revsingle(repo, rev, None)
4668
4668
4669 if ctx.rev() is None:
4669 if ctx.rev() is None:
4670 ctx = repo[None]
4670 ctx = repo[None]
4671 parents = ctx.parents()
4671 parents = ctx.parents()
4672 taglist = []
4672 taglist = []
4673 for p in parents:
4673 for p in parents:
4674 taglist.extend(p.tags())
4674 taglist.extend(p.tags())
4675
4675
4676 changed = ""
4676 changed = ""
4677 if default or id or num:
4677 if default or id or num:
4678 if (any(repo.status())
4678 if (any(repo.status())
4679 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4679 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4680 changed = '+'
4680 changed = '+'
4681 if default or id:
4681 if default or id:
4682 output = ["%s%s" %
4682 output = ["%s%s" %
4683 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4683 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4684 if num:
4684 if num:
4685 output.append("%s%s" %
4685 output.append("%s%s" %
4686 ('+'.join([str(p.rev()) for p in parents]), changed))
4686 ('+'.join([str(p.rev()) for p in parents]), changed))
4687 else:
4687 else:
4688 if default or id:
4688 if default or id:
4689 output = [hexfunc(ctx.node())]
4689 output = [hexfunc(ctx.node())]
4690 if num:
4690 if num:
4691 output.append(str(ctx.rev()))
4691 output.append(str(ctx.rev()))
4692 taglist = ctx.tags()
4692 taglist = ctx.tags()
4693
4693
4694 if default and not ui.quiet:
4694 if default and not ui.quiet:
4695 b = ctx.branch()
4695 b = ctx.branch()
4696 if b != 'default':
4696 if b != 'default':
4697 output.append("(%s)" % b)
4697 output.append("(%s)" % b)
4698
4698
4699 # multiple tags for a single parent separated by '/'
4699 # multiple tags for a single parent separated by '/'
4700 t = '/'.join(taglist)
4700 t = '/'.join(taglist)
4701 if t:
4701 if t:
4702 output.append(t)
4702 output.append(t)
4703
4703
4704 # multiple bookmarks for a single parent separated by '/'
4704 # multiple bookmarks for a single parent separated by '/'
4705 bm = '/'.join(ctx.bookmarks())
4705 bm = '/'.join(ctx.bookmarks())
4706 if bm:
4706 if bm:
4707 output.append(bm)
4707 output.append(bm)
4708 else:
4708 else:
4709 if branch:
4709 if branch:
4710 output.append(ctx.branch())
4710 output.append(ctx.branch())
4711
4711
4712 if tags:
4712 if tags:
4713 output.extend(taglist)
4713 output.extend(taglist)
4714
4714
4715 if bookmarks:
4715 if bookmarks:
4716 output.extend(ctx.bookmarks())
4716 output.extend(ctx.bookmarks())
4717
4717
4718 ui.write("%s\n" % ' '.join(output))
4718 ui.write("%s\n" % ' '.join(output))
4719
4719
4720 @command('import|patch',
4720 @command('import|patch',
4721 [('p', 'strip', 1,
4721 [('p', 'strip', 1,
4722 _('directory strip option for patch. This has the same '
4722 _('directory strip option for patch. This has the same '
4723 'meaning as the corresponding patch option'), _('NUM')),
4723 'meaning as the corresponding patch option'), _('NUM')),
4724 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4724 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4725 ('e', 'edit', False, _('invoke editor on commit messages')),
4725 ('e', 'edit', False, _('invoke editor on commit messages')),
4726 ('f', 'force', None,
4726 ('f', 'force', None,
4727 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4727 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4728 ('', 'no-commit', None,
4728 ('', 'no-commit', None,
4729 _("don't commit, just update the working directory")),
4729 _("don't commit, just update the working directory")),
4730 ('', 'bypass', None,
4730 ('', 'bypass', None,
4731 _("apply patch without touching the working directory")),
4731 _("apply patch without touching the working directory")),
4732 ('', 'partial', None,
4732 ('', 'partial', None,
4733 _('commit even if some hunks fail')),
4733 _('commit even if some hunks fail')),
4734 ('', 'exact', None,
4734 ('', 'exact', None,
4735 _('apply patch to the nodes from which it was generated')),
4735 _('apply patch to the nodes from which it was generated')),
4736 ('', 'prefix', '',
4736 ('', 'prefix', '',
4737 _('apply patch to subdirectory'), _('DIR')),
4737 _('apply patch to subdirectory'), _('DIR')),
4738 ('', 'import-branch', None,
4738 ('', 'import-branch', None,
4739 _('use any branch information in patch (implied by --exact)'))] +
4739 _('use any branch information in patch (implied by --exact)'))] +
4740 commitopts + commitopts2 + similarityopts,
4740 commitopts + commitopts2 + similarityopts,
4741 _('[OPTION]... PATCH...'))
4741 _('[OPTION]... PATCH...'))
4742 def import_(ui, repo, patch1=None, *patches, **opts):
4742 def import_(ui, repo, patch1=None, *patches, **opts):
4743 """import an ordered set of patches
4743 """import an ordered set of patches
4744
4744
4745 Import a list of patches and commit them individually (unless
4745 Import a list of patches and commit them individually (unless
4746 --no-commit is specified).
4746 --no-commit is specified).
4747
4747
4748 To read a patch from standard input, use "-" as the patch name. If
4748 To read a patch from standard input, use "-" as the patch name. If
4749 a URL is specified, the patch will be downloaded from there.
4749 a URL is specified, the patch will be downloaded from there.
4750
4750
4751 Import first applies changes to the working directory (unless
4751 Import first applies changes to the working directory (unless
4752 --bypass is specified), import will abort if there are outstanding
4752 --bypass is specified), import will abort if there are outstanding
4753 changes.
4753 changes.
4754
4754
4755 Use --bypass to apply and commit patches directly to the
4755 Use --bypass to apply and commit patches directly to the
4756 repository, without affecting the working directory. Without
4756 repository, without affecting the working directory. Without
4757 --exact, patches will be applied on top of the working directory
4757 --exact, patches will be applied on top of the working directory
4758 parent revision.
4758 parent revision.
4759
4759
4760 You can import a patch straight from a mail message. Even patches
4760 You can import a patch straight from a mail message. Even patches
4761 as attachments work (to use the body part, it must have type
4761 as attachments work (to use the body part, it must have type
4762 text/plain or text/x-patch). From and Subject headers of email
4762 text/plain or text/x-patch). From and Subject headers of email
4763 message are used as default committer and commit message. All
4763 message are used as default committer and commit message. All
4764 text/plain body parts before first diff are added to the commit
4764 text/plain body parts before first diff are added to the commit
4765 message.
4765 message.
4766
4766
4767 If the imported patch was generated by :hg:`export`, user and
4767 If the imported patch was generated by :hg:`export`, user and
4768 description from patch override values from message headers and
4768 description from patch override values from message headers and
4769 body. Values given on command line with -m/--message and -u/--user
4769 body. Values given on command line with -m/--message and -u/--user
4770 override these.
4770 override these.
4771
4771
4772 If --exact is specified, import will set the working directory to
4772 If --exact is specified, import will set the working directory to
4773 the parent of each patch before applying it, and will abort if the
4773 the parent of each patch before applying it, and will abort if the
4774 resulting changeset has a different ID than the one recorded in
4774 resulting changeset has a different ID than the one recorded in
4775 the patch. This may happen due to character set problems or other
4775 the patch. This may happen due to character set problems or other
4776 deficiencies in the text patch format.
4776 deficiencies in the text patch format.
4777
4777
4778 Use --partial to ensure a changeset will be created from the patch
4778 Use --partial to ensure a changeset will be created from the patch
4779 even if some hunks fail to apply. Hunks that fail to apply will be
4779 even if some hunks fail to apply. Hunks that fail to apply will be
4780 written to a <target-file>.rej file. Conflicts can then be resolved
4780 written to a <target-file>.rej file. Conflicts can then be resolved
4781 by hand before :hg:`commit --amend` is run to update the created
4781 by hand before :hg:`commit --amend` is run to update the created
4782 changeset. This flag exists to let people import patches that
4782 changeset. This flag exists to let people import patches that
4783 partially apply without losing the associated metadata (author,
4783 partially apply without losing the associated metadata (author,
4784 date, description, ...).
4784 date, description, ...).
4785
4785
4786 .. note::
4786 .. note::
4787
4787
4788 When no hunks apply cleanly, :hg:`import --partial` will create
4788 When no hunks apply cleanly, :hg:`import --partial` will create
4789 an empty changeset, importing only the patch metadata.
4789 an empty changeset, importing only the patch metadata.
4790
4790
4791 With -s/--similarity, hg will attempt to discover renames and
4791 With -s/--similarity, hg will attempt to discover renames and
4792 copies in the patch in the same way as :hg:`addremove`.
4792 copies in the patch in the same way as :hg:`addremove`.
4793
4793
4794 It is possible to use external patch programs to perform the patch
4794 It is possible to use external patch programs to perform the patch
4795 by setting the ``ui.patch`` configuration option. For the default
4795 by setting the ``ui.patch`` configuration option. For the default
4796 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4796 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4797 See :hg:`help config` for more information about configuration
4797 See :hg:`help config` for more information about configuration
4798 files and how to use these options.
4798 files and how to use these options.
4799
4799
4800 See :hg:`help dates` for a list of formats valid for -d/--date.
4800 See :hg:`help dates` for a list of formats valid for -d/--date.
4801
4801
4802 .. container:: verbose
4802 .. container:: verbose
4803
4803
4804 Examples:
4804 Examples:
4805
4805
4806 - import a traditional patch from a website and detect renames::
4806 - import a traditional patch from a website and detect renames::
4807
4807
4808 hg import -s 80 http://example.com/bugfix.patch
4808 hg import -s 80 http://example.com/bugfix.patch
4809
4809
4810 - import a changeset from an hgweb server::
4810 - import a changeset from an hgweb server::
4811
4811
4812 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4812 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4813
4813
4814 - import all the patches in an Unix-style mbox::
4814 - import all the patches in an Unix-style mbox::
4815
4815
4816 hg import incoming-patches.mbox
4816 hg import incoming-patches.mbox
4817
4817
4818 - attempt to exactly restore an exported changeset (not always
4818 - attempt to exactly restore an exported changeset (not always
4819 possible)::
4819 possible)::
4820
4820
4821 hg import --exact proposed-fix.patch
4821 hg import --exact proposed-fix.patch
4822
4822
4823 - use an external tool to apply a patch which is too fuzzy for
4823 - use an external tool to apply a patch which is too fuzzy for
4824 the default internal tool.
4824 the default internal tool.
4825
4825
4826 hg import --config ui.patch="patch --merge" fuzzy.patch
4826 hg import --config ui.patch="patch --merge" fuzzy.patch
4827
4827
4828 - change the default fuzzing from 2 to a less strict 7
4828 - change the default fuzzing from 2 to a less strict 7
4829
4829
4830 hg import --config ui.fuzz=7 fuzz.patch
4830 hg import --config ui.fuzz=7 fuzz.patch
4831
4831
4832 Returns 0 on success, 1 on partial success (see --partial).
4832 Returns 0 on success, 1 on partial success (see --partial).
4833 """
4833 """
4834
4834
4835 if not patch1:
4835 if not patch1:
4836 raise error.Abort(_('need at least one patch to import'))
4836 raise error.Abort(_('need at least one patch to import'))
4837
4837
4838 patches = (patch1,) + patches
4838 patches = (patch1,) + patches
4839
4839
4840 date = opts.get('date')
4840 date = opts.get('date')
4841 if date:
4841 if date:
4842 opts['date'] = util.parsedate(date)
4842 opts['date'] = util.parsedate(date)
4843
4843
4844 exact = opts.get('exact')
4844 exact = opts.get('exact')
4845 update = not opts.get('bypass')
4845 update = not opts.get('bypass')
4846 if not update and opts.get('no_commit'):
4846 if not update and opts.get('no_commit'):
4847 raise error.Abort(_('cannot use --no-commit with --bypass'))
4847 raise error.Abort(_('cannot use --no-commit with --bypass'))
4848 try:
4848 try:
4849 sim = float(opts.get('similarity') or 0)
4849 sim = float(opts.get('similarity') or 0)
4850 except ValueError:
4850 except ValueError:
4851 raise error.Abort(_('similarity must be a number'))
4851 raise error.Abort(_('similarity must be a number'))
4852 if sim < 0 or sim > 100:
4852 if sim < 0 or sim > 100:
4853 raise error.Abort(_('similarity must be between 0 and 100'))
4853 raise error.Abort(_('similarity must be between 0 and 100'))
4854 if sim and not update:
4854 if sim and not update:
4855 raise error.Abort(_('cannot use --similarity with --bypass'))
4855 raise error.Abort(_('cannot use --similarity with --bypass'))
4856 if exact:
4856 if exact:
4857 if opts.get('edit'):
4857 if opts.get('edit'):
4858 raise error.Abort(_('cannot use --exact with --edit'))
4858 raise error.Abort(_('cannot use --exact with --edit'))
4859 if opts.get('prefix'):
4859 if opts.get('prefix'):
4860 raise error.Abort(_('cannot use --exact with --prefix'))
4860 raise error.Abort(_('cannot use --exact with --prefix'))
4861
4861
4862 base = opts["base"]
4862 base = opts["base"]
4863 wlock = dsguard = lock = tr = None
4863 wlock = dsguard = lock = tr = None
4864 msgs = []
4864 msgs = []
4865 ret = 0
4865 ret = 0
4866
4866
4867
4867
4868 try:
4868 try:
4869 wlock = repo.wlock()
4869 wlock = repo.wlock()
4870
4870
4871 if update:
4871 if update:
4872 cmdutil.checkunfinished(repo)
4872 cmdutil.checkunfinished(repo)
4873 if (exact or not opts.get('force')):
4873 if (exact or not opts.get('force')):
4874 cmdutil.bailifchanged(repo)
4874 cmdutil.bailifchanged(repo)
4875
4875
4876 if not opts.get('no_commit'):
4876 if not opts.get('no_commit'):
4877 lock = repo.lock()
4877 lock = repo.lock()
4878 tr = repo.transaction('import')
4878 tr = repo.transaction('import')
4879 else:
4879 else:
4880 dsguard = cmdutil.dirstateguard(repo, 'import')
4880 dsguard = cmdutil.dirstateguard(repo, 'import')
4881 parents = repo[None].parents()
4881 parents = repo[None].parents()
4882 for patchurl in patches:
4882 for patchurl in patches:
4883 if patchurl == '-':
4883 if patchurl == '-':
4884 ui.status(_('applying patch from stdin\n'))
4884 ui.status(_('applying patch from stdin\n'))
4885 patchfile = ui.fin
4885 patchfile = ui.fin
4886 patchurl = 'stdin' # for error message
4886 patchurl = 'stdin' # for error message
4887 else:
4887 else:
4888 patchurl = os.path.join(base, patchurl)
4888 patchurl = os.path.join(base, patchurl)
4889 ui.status(_('applying %s\n') % patchurl)
4889 ui.status(_('applying %s\n') % patchurl)
4890 patchfile = hg.openpath(ui, patchurl)
4890 patchfile = hg.openpath(ui, patchurl)
4891
4891
4892 haspatch = False
4892 haspatch = False
4893 for hunk in patch.split(patchfile):
4893 for hunk in patch.split(patchfile):
4894 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4894 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4895 parents, opts,
4895 parents, opts,
4896 msgs, hg.clean)
4896 msgs, hg.clean)
4897 if msg:
4897 if msg:
4898 haspatch = True
4898 haspatch = True
4899 ui.note(msg + '\n')
4899 ui.note(msg + '\n')
4900 if update or exact:
4900 if update or exact:
4901 parents = repo[None].parents()
4901 parents = repo[None].parents()
4902 else:
4902 else:
4903 parents = [repo[node]]
4903 parents = [repo[node]]
4904 if rej:
4904 if rej:
4905 ui.write_err(_("patch applied partially\n"))
4905 ui.write_err(_("patch applied partially\n"))
4906 ui.write_err(_("(fix the .rej files and run "
4906 ui.write_err(_("(fix the .rej files and run "
4907 "`hg commit --amend`)\n"))
4907 "`hg commit --amend`)\n"))
4908 ret = 1
4908 ret = 1
4909 break
4909 break
4910
4910
4911 if not haspatch:
4911 if not haspatch:
4912 raise error.Abort(_('%s: no diffs found') % patchurl)
4912 raise error.Abort(_('%s: no diffs found') % patchurl)
4913
4913
4914 if tr:
4914 if tr:
4915 tr.close()
4915 tr.close()
4916 if msgs:
4916 if msgs:
4917 repo.savecommitmessage('\n* * *\n'.join(msgs))
4917 repo.savecommitmessage('\n* * *\n'.join(msgs))
4918 if dsguard:
4918 if dsguard:
4919 dsguard.close()
4919 dsguard.close()
4920 return ret
4920 return ret
4921 finally:
4921 finally:
4922 if tr:
4922 if tr:
4923 tr.release()
4923 tr.release()
4924 release(lock, dsguard, wlock)
4924 release(lock, dsguard, wlock)
4925
4925
4926 @command('incoming|in',
4926 @command('incoming|in',
4927 [('f', 'force', None,
4927 [('f', 'force', None,
4928 _('run even if remote repository is unrelated')),
4928 _('run even if remote repository is unrelated')),
4929 ('n', 'newest-first', None, _('show newest record first')),
4929 ('n', 'newest-first', None, _('show newest record first')),
4930 ('', 'bundle', '',
4930 ('', 'bundle', '',
4931 _('file to store the bundles into'), _('FILE')),
4931 _('file to store the bundles into'), _('FILE')),
4932 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4932 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4933 ('B', 'bookmarks', False, _("compare bookmarks")),
4933 ('B', 'bookmarks', False, _("compare bookmarks")),
4934 ('b', 'branch', [],
4934 ('b', 'branch', [],
4935 _('a specific branch you would like to pull'), _('BRANCH')),
4935 _('a specific branch you would like to pull'), _('BRANCH')),
4936 ] + logopts + remoteopts + subrepoopts,
4936 ] + logopts + remoteopts + subrepoopts,
4937 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4937 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4938 def incoming(ui, repo, source="default", **opts):
4938 def incoming(ui, repo, source="default", **opts):
4939 """show new changesets found in source
4939 """show new changesets found in source
4940
4940
4941 Show new changesets found in the specified path/URL or the default
4941 Show new changesets found in the specified path/URL or the default
4942 pull location. These are the changesets that would have been pulled
4942 pull location. These are the changesets that would have been pulled
4943 if a pull at the time you issued this command.
4943 if a pull at the time you issued this command.
4944
4944
4945 See pull for valid source format details.
4945 See pull for valid source format details.
4946
4946
4947 .. container:: verbose
4947 .. container:: verbose
4948
4948
4949 With -B/--bookmarks, the result of bookmark comparison between
4949 With -B/--bookmarks, the result of bookmark comparison between
4950 local and remote repositories is displayed. With -v/--verbose,
4950 local and remote repositories is displayed. With -v/--verbose,
4951 status is also displayed for each bookmark like below::
4951 status is also displayed for each bookmark like below::
4952
4952
4953 BM1 01234567890a added
4953 BM1 01234567890a added
4954 BM2 1234567890ab advanced
4954 BM2 1234567890ab advanced
4955 BM3 234567890abc diverged
4955 BM3 234567890abc diverged
4956 BM4 34567890abcd changed
4956 BM4 34567890abcd changed
4957
4957
4958 The action taken locally when pulling depends on the
4958 The action taken locally when pulling depends on the
4959 status of each bookmark:
4959 status of each bookmark:
4960
4960
4961 :``added``: pull will create it
4961 :``added``: pull will create it
4962 :``advanced``: pull will update it
4962 :``advanced``: pull will update it
4963 :``diverged``: pull will create a divergent bookmark
4963 :``diverged``: pull will create a divergent bookmark
4964 :``changed``: result depends on remote changesets
4964 :``changed``: result depends on remote changesets
4965
4965
4966 From the point of view of pulling behavior, bookmark
4966 From the point of view of pulling behavior, bookmark
4967 existing only in the remote repository are treated as ``added``,
4967 existing only in the remote repository are treated as ``added``,
4968 even if it is in fact locally deleted.
4968 even if it is in fact locally deleted.
4969
4969
4970 .. container:: verbose
4970 .. container:: verbose
4971
4971
4972 For remote repository, using --bundle avoids downloading the
4972 For remote repository, using --bundle avoids downloading the
4973 changesets twice if the incoming is followed by a pull.
4973 changesets twice if the incoming is followed by a pull.
4974
4974
4975 Examples:
4975 Examples:
4976
4976
4977 - show incoming changes with patches and full description::
4977 - show incoming changes with patches and full description::
4978
4978
4979 hg incoming -vp
4979 hg incoming -vp
4980
4980
4981 - show incoming changes excluding merges, store a bundle::
4981 - show incoming changes excluding merges, store a bundle::
4982
4982
4983 hg in -vpM --bundle incoming.hg
4983 hg in -vpM --bundle incoming.hg
4984 hg pull incoming.hg
4984 hg pull incoming.hg
4985
4985
4986 - briefly list changes inside a bundle::
4986 - briefly list changes inside a bundle::
4987
4987
4988 hg in changes.hg -T "{desc|firstline}\\n"
4988 hg in changes.hg -T "{desc|firstline}\\n"
4989
4989
4990 Returns 0 if there are incoming changes, 1 otherwise.
4990 Returns 0 if there are incoming changes, 1 otherwise.
4991 """
4991 """
4992 if opts.get('graph'):
4992 if opts.get('graph'):
4993 cmdutil.checkunsupportedgraphflags([], opts)
4993 cmdutil.checkunsupportedgraphflags([], opts)
4994 def display(other, chlist, displayer):
4994 def display(other, chlist, displayer):
4995 revdag = cmdutil.graphrevs(other, chlist, opts)
4995 revdag = cmdutil.graphrevs(other, chlist, opts)
4996 cmdutil.displaygraph(ui, repo, revdag, displayer,
4996 cmdutil.displaygraph(ui, repo, revdag, displayer,
4997 graphmod.asciiedges)
4997 graphmod.asciiedges)
4998
4998
4999 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4999 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5000 return 0
5000 return 0
5001
5001
5002 if opts.get('bundle') and opts.get('subrepos'):
5002 if opts.get('bundle') and opts.get('subrepos'):
5003 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5003 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5004
5004
5005 if opts.get('bookmarks'):
5005 if opts.get('bookmarks'):
5006 source, branches = hg.parseurl(ui.expandpath(source),
5006 source, branches = hg.parseurl(ui.expandpath(source),
5007 opts.get('branch'))
5007 opts.get('branch'))
5008 other = hg.peer(repo, opts, source)
5008 other = hg.peer(repo, opts, source)
5009 if 'bookmarks' not in other.listkeys('namespaces'):
5009 if 'bookmarks' not in other.listkeys('namespaces'):
5010 ui.warn(_("remote doesn't support bookmarks\n"))
5010 ui.warn(_("remote doesn't support bookmarks\n"))
5011 return 0
5011 return 0
5012 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5012 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5013 return bookmarks.incoming(ui, repo, other)
5013 return bookmarks.incoming(ui, repo, other)
5014
5014
5015 repo._subtoppath = ui.expandpath(source)
5015 repo._subtoppath = ui.expandpath(source)
5016 try:
5016 try:
5017 return hg.incoming(ui, repo, source, opts)
5017 return hg.incoming(ui, repo, source, opts)
5018 finally:
5018 finally:
5019 del repo._subtoppath
5019 del repo._subtoppath
5020
5020
5021
5021
5022 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5022 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5023 norepo=True)
5023 norepo=True)
5024 def init(ui, dest=".", **opts):
5024 def init(ui, dest=".", **opts):
5025 """create a new repository in the given directory
5025 """create a new repository in the given directory
5026
5026
5027 Initialize a new repository in the given directory. If the given
5027 Initialize a new repository in the given directory. If the given
5028 directory does not exist, it will be created.
5028 directory does not exist, it will be created.
5029
5029
5030 If no directory is given, the current directory is used.
5030 If no directory is given, the current directory is used.
5031
5031
5032 It is possible to specify an ``ssh://`` URL as the destination.
5032 It is possible to specify an ``ssh://`` URL as the destination.
5033 See :hg:`help urls` for more information.
5033 See :hg:`help urls` for more information.
5034
5034
5035 Returns 0 on success.
5035 Returns 0 on success.
5036 """
5036 """
5037 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5037 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5038
5038
5039 @command('locate',
5039 @command('locate',
5040 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5040 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5041 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5041 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5042 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5042 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5043 ] + walkopts,
5043 ] + walkopts,
5044 _('[OPTION]... [PATTERN]...'))
5044 _('[OPTION]... [PATTERN]...'))
5045 def locate(ui, repo, *pats, **opts):
5045 def locate(ui, repo, *pats, **opts):
5046 """locate files matching specific patterns (DEPRECATED)
5046 """locate files matching specific patterns (DEPRECATED)
5047
5047
5048 Print files under Mercurial control in the working directory whose
5048 Print files under Mercurial control in the working directory whose
5049 names match the given patterns.
5049 names match the given patterns.
5050
5050
5051 By default, this command searches all directories in the working
5051 By default, this command searches all directories in the working
5052 directory. To search just the current directory and its
5052 directory. To search just the current directory and its
5053 subdirectories, use "--include .".
5053 subdirectories, use "--include .".
5054
5054
5055 If no patterns are given to match, this command prints the names
5055 If no patterns are given to match, this command prints the names
5056 of all files under Mercurial control in the working directory.
5056 of all files under Mercurial control in the working directory.
5057
5057
5058 If you want to feed the output of this command into the "xargs"
5058 If you want to feed the output of this command into the "xargs"
5059 command, use the -0 option to both this command and "xargs". This
5059 command, use the -0 option to both this command and "xargs". This
5060 will avoid the problem of "xargs" treating single filenames that
5060 will avoid the problem of "xargs" treating single filenames that
5061 contain whitespace as multiple filenames.
5061 contain whitespace as multiple filenames.
5062
5062
5063 See :hg:`help files` for a more versatile command.
5063 See :hg:`help files` for a more versatile command.
5064
5064
5065 Returns 0 if a match is found, 1 otherwise.
5065 Returns 0 if a match is found, 1 otherwise.
5066 """
5066 """
5067 if opts.get('print0'):
5067 if opts.get('print0'):
5068 end = '\0'
5068 end = '\0'
5069 else:
5069 else:
5070 end = '\n'
5070 end = '\n'
5071 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5071 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5072
5072
5073 ret = 1
5073 ret = 1
5074 ctx = repo[rev]
5074 ctx = repo[rev]
5075 m = scmutil.match(ctx, pats, opts, default='relglob',
5075 m = scmutil.match(ctx, pats, opts, default='relglob',
5076 badfn=lambda x, y: False)
5076 badfn=lambda x, y: False)
5077
5077
5078 for abs in ctx.matches(m):
5078 for abs in ctx.matches(m):
5079 if opts.get('fullpath'):
5079 if opts.get('fullpath'):
5080 ui.write(repo.wjoin(abs), end)
5080 ui.write(repo.wjoin(abs), end)
5081 else:
5081 else:
5082 ui.write(((pats and m.rel(abs)) or abs), end)
5082 ui.write(((pats and m.rel(abs)) or abs), end)
5083 ret = 0
5083 ret = 0
5084
5084
5085 return ret
5085 return ret
5086
5086
5087 @command('^log|history',
5087 @command('^log|history',
5088 [('f', 'follow', None,
5088 [('f', 'follow', None,
5089 _('follow changeset history, or file history across copies and renames')),
5089 _('follow changeset history, or file history across copies and renames')),
5090 ('', 'follow-first', None,
5090 ('', 'follow-first', None,
5091 _('only follow the first parent of merge changesets (DEPRECATED)')),
5091 _('only follow the first parent of merge changesets (DEPRECATED)')),
5092 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5092 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5093 ('C', 'copies', None, _('show copied files')),
5093 ('C', 'copies', None, _('show copied files')),
5094 ('k', 'keyword', [],
5094 ('k', 'keyword', [],
5095 _('do case-insensitive search for a given text'), _('TEXT')),
5095 _('do case-insensitive search for a given text'), _('TEXT')),
5096 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5096 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5097 ('', 'removed', None, _('include revisions where files were removed')),
5097 ('', 'removed', None, _('include revisions where files were removed')),
5098 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5098 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5099 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5099 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5100 ('', 'only-branch', [],
5100 ('', 'only-branch', [],
5101 _('show only changesets within the given named branch (DEPRECATED)'),
5101 _('show only changesets within the given named branch (DEPRECATED)'),
5102 _('BRANCH')),
5102 _('BRANCH')),
5103 ('b', 'branch', [],
5103 ('b', 'branch', [],
5104 _('show changesets within the given named branch'), _('BRANCH')),
5104 _('show changesets within the given named branch'), _('BRANCH')),
5105 ('P', 'prune', [],
5105 ('P', 'prune', [],
5106 _('do not display revision or any of its ancestors'), _('REV')),
5106 _('do not display revision or any of its ancestors'), _('REV')),
5107 ] + logopts + walkopts,
5107 ] + logopts + walkopts,
5108 _('[OPTION]... [FILE]'),
5108 _('[OPTION]... [FILE]'),
5109 inferrepo=True)
5109 inferrepo=True)
5110 def log(ui, repo, *pats, **opts):
5110 def log(ui, repo, *pats, **opts):
5111 """show revision history of entire repository or files
5111 """show revision history of entire repository or files
5112
5112
5113 Print the revision history of the specified files or the entire
5113 Print the revision history of the specified files or the entire
5114 project.
5114 project.
5115
5115
5116 If no revision range is specified, the default is ``tip:0`` unless
5116 If no revision range is specified, the default is ``tip:0`` unless
5117 --follow is set, in which case the working directory parent is
5117 --follow is set, in which case the working directory parent is
5118 used as the starting revision.
5118 used as the starting revision.
5119
5119
5120 File history is shown without following rename or copy history of
5120 File history is shown without following rename or copy history of
5121 files. Use -f/--follow with a filename to follow history across
5121 files. Use -f/--follow with a filename to follow history across
5122 renames and copies. --follow without a filename will only show
5122 renames and copies. --follow without a filename will only show
5123 ancestors or descendants of the starting revision.
5123 ancestors or descendants of the starting revision.
5124
5124
5125 By default this command prints revision number and changeset id,
5125 By default this command prints revision number and changeset id,
5126 tags, non-trivial parents, user, date and time, and a summary for
5126 tags, non-trivial parents, user, date and time, and a summary for
5127 each commit. When the -v/--verbose switch is used, the list of
5127 each commit. When the -v/--verbose switch is used, the list of
5128 changed files and full commit message are shown.
5128 changed files and full commit message are shown.
5129
5129
5130 With --graph the revisions are shown as an ASCII art DAG with the most
5130 With --graph the revisions are shown as an ASCII art DAG with the most
5131 recent changeset at the top.
5131 recent changeset at the top.
5132 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5132 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5133 and '+' represents a fork where the changeset from the lines below is a
5133 and '+' represents a fork where the changeset from the lines below is a
5134 parent of the 'o' merge on the same line.
5134 parent of the 'o' merge on the same line.
5135
5135
5136 .. note::
5136 .. note::
5137
5137
5138 :hg:`log --patch` may generate unexpected diff output for merge
5138 :hg:`log --patch` may generate unexpected diff output for merge
5139 changesets, as it will only compare the merge changeset against
5139 changesets, as it will only compare the merge changeset against
5140 its first parent. Also, only files different from BOTH parents
5140 its first parent. Also, only files different from BOTH parents
5141 will appear in files:.
5141 will appear in files:.
5142
5142
5143 .. note::
5143 .. note::
5144
5144
5145 For performance reasons, :hg:`log FILE` may omit duplicate changes
5145 For performance reasons, :hg:`log FILE` may omit duplicate changes
5146 made on branches and will not show removals or mode changes. To
5146 made on branches and will not show removals or mode changes. To
5147 see all such changes, use the --removed switch.
5147 see all such changes, use the --removed switch.
5148
5148
5149 .. container:: verbose
5149 .. container:: verbose
5150
5150
5151 Some examples:
5151 Some examples:
5152
5152
5153 - changesets with full descriptions and file lists::
5153 - changesets with full descriptions and file lists::
5154
5154
5155 hg log -v
5155 hg log -v
5156
5156
5157 - changesets ancestral to the working directory::
5157 - changesets ancestral to the working directory::
5158
5158
5159 hg log -f
5159 hg log -f
5160
5160
5161 - last 10 commits on the current branch::
5161 - last 10 commits on the current branch::
5162
5162
5163 hg log -l 10 -b .
5163 hg log -l 10 -b .
5164
5164
5165 - changesets showing all modifications of a file, including removals::
5165 - changesets showing all modifications of a file, including removals::
5166
5166
5167 hg log --removed file.c
5167 hg log --removed file.c
5168
5168
5169 - all changesets that touch a directory, with diffs, excluding merges::
5169 - all changesets that touch a directory, with diffs, excluding merges::
5170
5170
5171 hg log -Mp lib/
5171 hg log -Mp lib/
5172
5172
5173 - all revision numbers that match a keyword::
5173 - all revision numbers that match a keyword::
5174
5174
5175 hg log -k bug --template "{rev}\\n"
5175 hg log -k bug --template "{rev}\\n"
5176
5176
5177 - the full hash identifier of the working directory parent::
5177 - the full hash identifier of the working directory parent::
5178
5178
5179 hg log -r . --template "{node}\\n"
5179 hg log -r . --template "{node}\\n"
5180
5180
5181 - list available log templates::
5181 - list available log templates::
5182
5182
5183 hg log -T list
5183 hg log -T list
5184
5184
5185 - check if a given changeset is included in a tagged release::
5185 - check if a given changeset is included in a tagged release::
5186
5186
5187 hg log -r "a21ccf and ancestor(1.9)"
5187 hg log -r "a21ccf and ancestor(1.9)"
5188
5188
5189 - find all changesets by some user in a date range::
5189 - find all changesets by some user in a date range::
5190
5190
5191 hg log -k alice -d "may 2008 to jul 2008"
5191 hg log -k alice -d "may 2008 to jul 2008"
5192
5192
5193 - summary of all changesets after the last tag::
5193 - summary of all changesets after the last tag::
5194
5194
5195 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5195 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5196
5196
5197 See :hg:`help dates` for a list of formats valid for -d/--date.
5197 See :hg:`help dates` for a list of formats valid for -d/--date.
5198
5198
5199 See :hg:`help revisions` and :hg:`help revsets` for more about
5199 See :hg:`help revisions` and :hg:`help revsets` for more about
5200 specifying and ordering revisions.
5200 specifying and ordering revisions.
5201
5201
5202 See :hg:`help templates` for more about pre-packaged styles and
5202 See :hg:`help templates` for more about pre-packaged styles and
5203 specifying custom templates.
5203 specifying custom templates.
5204
5204
5205 Returns 0 on success.
5205 Returns 0 on success.
5206
5206
5207 """
5207 """
5208 if opts.get('follow') and opts.get('rev'):
5208 if opts.get('follow') and opts.get('rev'):
5209 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5209 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5210 del opts['follow']
5210 del opts['follow']
5211
5211
5212 if opts.get('graph'):
5212 if opts.get('graph'):
5213 return cmdutil.graphlog(ui, repo, *pats, **opts)
5213 return cmdutil.graphlog(ui, repo, *pats, **opts)
5214
5214
5215 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5215 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5216 limit = cmdutil.loglimit(opts)
5216 limit = cmdutil.loglimit(opts)
5217 count = 0
5217 count = 0
5218
5218
5219 getrenamed = None
5219 getrenamed = None
5220 if opts.get('copies'):
5220 if opts.get('copies'):
5221 endrev = None
5221 endrev = None
5222 if opts.get('rev'):
5222 if opts.get('rev'):
5223 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5223 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5224 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5224 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5225
5225
5226 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5226 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5227 for rev in revs:
5227 for rev in revs:
5228 if count == limit:
5228 if count == limit:
5229 break
5229 break
5230 ctx = repo[rev]
5230 ctx = repo[rev]
5231 copies = None
5231 copies = None
5232 if getrenamed is not None and rev:
5232 if getrenamed is not None and rev:
5233 copies = []
5233 copies = []
5234 for fn in ctx.files():
5234 for fn in ctx.files():
5235 rename = getrenamed(fn, rev)
5235 rename = getrenamed(fn, rev)
5236 if rename:
5236 if rename:
5237 copies.append((fn, rename[0]))
5237 copies.append((fn, rename[0]))
5238 if filematcher:
5238 if filematcher:
5239 revmatchfn = filematcher(ctx.rev())
5239 revmatchfn = filematcher(ctx.rev())
5240 else:
5240 else:
5241 revmatchfn = None
5241 revmatchfn = None
5242 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5242 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5243 if displayer.flush(ctx):
5243 if displayer.flush(ctx):
5244 count += 1
5244 count += 1
5245
5245
5246 displayer.close()
5246 displayer.close()
5247
5247
5248 @command('manifest',
5248 @command('manifest',
5249 [('r', 'rev', '', _('revision to display'), _('REV')),
5249 [('r', 'rev', '', _('revision to display'), _('REV')),
5250 ('', 'all', False, _("list files from all revisions"))]
5250 ('', 'all', False, _("list files from all revisions"))]
5251 + formatteropts,
5251 + formatteropts,
5252 _('[-r REV]'))
5252 _('[-r REV]'))
5253 def manifest(ui, repo, node=None, rev=None, **opts):
5253 def manifest(ui, repo, node=None, rev=None, **opts):
5254 """output the current or given revision of the project manifest
5254 """output the current or given revision of the project manifest
5255
5255
5256 Print a list of version controlled files for the given revision.
5256 Print a list of version controlled files for the given revision.
5257 If no revision is given, the first parent of the working directory
5257 If no revision is given, the first parent of the working directory
5258 is used, or the null revision if no revision is checked out.
5258 is used, or the null revision if no revision is checked out.
5259
5259
5260 With -v, print file permissions, symlink and executable bits.
5260 With -v, print file permissions, symlink and executable bits.
5261 With --debug, print file revision hashes.
5261 With --debug, print file revision hashes.
5262
5262
5263 If option --all is specified, the list of all files from all revisions
5263 If option --all is specified, the list of all files from all revisions
5264 is printed. This includes deleted and renamed files.
5264 is printed. This includes deleted and renamed files.
5265
5265
5266 Returns 0 on success.
5266 Returns 0 on success.
5267 """
5267 """
5268
5268
5269 fm = ui.formatter('manifest', opts)
5269 fm = ui.formatter('manifest', opts)
5270
5270
5271 if opts.get('all'):
5271 if opts.get('all'):
5272 if rev or node:
5272 if rev or node:
5273 raise error.Abort(_("can't specify a revision with --all"))
5273 raise error.Abort(_("can't specify a revision with --all"))
5274
5274
5275 res = []
5275 res = []
5276 prefix = "data/"
5276 prefix = "data/"
5277 suffix = ".i"
5277 suffix = ".i"
5278 plen = len(prefix)
5278 plen = len(prefix)
5279 slen = len(suffix)
5279 slen = len(suffix)
5280 with repo.lock():
5280 with repo.lock():
5281 for fn, b, size in repo.store.datafiles():
5281 for fn, b, size in repo.store.datafiles():
5282 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5282 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5283 res.append(fn[plen:-slen])
5283 res.append(fn[plen:-slen])
5284 for f in res:
5284 for f in res:
5285 fm.startitem()
5285 fm.startitem()
5286 fm.write("path", '%s\n', f)
5286 fm.write("path", '%s\n', f)
5287 fm.end()
5287 fm.end()
5288 return
5288 return
5289
5289
5290 if rev and node:
5290 if rev and node:
5291 raise error.Abort(_("please specify just one revision"))
5291 raise error.Abort(_("please specify just one revision"))
5292
5292
5293 if not node:
5293 if not node:
5294 node = rev
5294 node = rev
5295
5295
5296 char = {'l': '@', 'x': '*', '': ''}
5296 char = {'l': '@', 'x': '*', '': ''}
5297 mode = {'l': '644', 'x': '755', '': '644'}
5297 mode = {'l': '644', 'x': '755', '': '644'}
5298 ctx = scmutil.revsingle(repo, node)
5298 ctx = scmutil.revsingle(repo, node)
5299 mf = ctx.manifest()
5299 mf = ctx.manifest()
5300 for f in ctx:
5300 for f in ctx:
5301 fm.startitem()
5301 fm.startitem()
5302 fl = ctx[f].flags()
5302 fl = ctx[f].flags()
5303 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5303 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5304 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5304 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5305 fm.write('path', '%s\n', f)
5305 fm.write('path', '%s\n', f)
5306 fm.end()
5306 fm.end()
5307
5307
5308 @command('^merge',
5308 @command('^merge',
5309 [('f', 'force', None,
5309 [('f', 'force', None,
5310 _('force a merge including outstanding changes (DEPRECATED)')),
5310 _('force a merge including outstanding changes (DEPRECATED)')),
5311 ('r', 'rev', '', _('revision to merge'), _('REV')),
5311 ('r', 'rev', '', _('revision to merge'), _('REV')),
5312 ('P', 'preview', None,
5312 ('P', 'preview', None,
5313 _('review revisions to merge (no merge is performed)'))
5313 _('review revisions to merge (no merge is performed)'))
5314 ] + mergetoolopts,
5314 ] + mergetoolopts,
5315 _('[-P] [[-r] REV]'))
5315 _('[-P] [[-r] REV]'))
5316 def merge(ui, repo, node=None, **opts):
5316 def merge(ui, repo, node=None, **opts):
5317 """merge another revision into working directory
5317 """merge another revision into working directory
5318
5318
5319 The current working directory is updated with all changes made in
5319 The current working directory is updated with all changes made in
5320 the requested revision since the last common predecessor revision.
5320 the requested revision since the last common predecessor revision.
5321
5321
5322 Files that changed between either parent are marked as changed for
5322 Files that changed between either parent are marked as changed for
5323 the next commit and a commit must be performed before any further
5323 the next commit and a commit must be performed before any further
5324 updates to the repository are allowed. The next commit will have
5324 updates to the repository are allowed. The next commit will have
5325 two parents.
5325 two parents.
5326
5326
5327 ``--tool`` can be used to specify the merge tool used for file
5327 ``--tool`` can be used to specify the merge tool used for file
5328 merges. It overrides the HGMERGE environment variable and your
5328 merges. It overrides the HGMERGE environment variable and your
5329 configuration files. See :hg:`help merge-tools` for options.
5329 configuration files. See :hg:`help merge-tools` for options.
5330
5330
5331 If no revision is specified, the working directory's parent is a
5331 If no revision is specified, the working directory's parent is a
5332 head revision, and the current branch contains exactly one other
5332 head revision, and the current branch contains exactly one other
5333 head, the other head is merged with by default. Otherwise, an
5333 head, the other head is merged with by default. Otherwise, an
5334 explicit revision with which to merge with must be provided.
5334 explicit revision with which to merge with must be provided.
5335
5335
5336 See :hg:`help resolve` for information on handling file conflicts.
5336 See :hg:`help resolve` for information on handling file conflicts.
5337
5337
5338 To undo an uncommitted merge, use :hg:`update --clean .` which
5338 To undo an uncommitted merge, use :hg:`update --clean .` which
5339 will check out a clean copy of the original merge parent, losing
5339 will check out a clean copy of the original merge parent, losing
5340 all changes.
5340 all changes.
5341
5341
5342 Returns 0 on success, 1 if there are unresolved files.
5342 Returns 0 on success, 1 if there are unresolved files.
5343 """
5343 """
5344
5344
5345 if opts.get('rev') and node:
5345 if opts.get('rev') and node:
5346 raise error.Abort(_("please specify just one revision"))
5346 raise error.Abort(_("please specify just one revision"))
5347 if not node:
5347 if not node:
5348 node = opts.get('rev')
5348 node = opts.get('rev')
5349
5349
5350 if node:
5350 if node:
5351 node = scmutil.revsingle(repo, node).node()
5351 node = scmutil.revsingle(repo, node).node()
5352
5352
5353 if not node:
5353 if not node:
5354 node = repo[destutil.destmerge(repo)].node()
5354 node = repo[destutil.destmerge(repo)].node()
5355
5355
5356 if opts.get('preview'):
5356 if opts.get('preview'):
5357 # find nodes that are ancestors of p2 but not of p1
5357 # find nodes that are ancestors of p2 but not of p1
5358 p1 = repo.lookup('.')
5358 p1 = repo.lookup('.')
5359 p2 = repo.lookup(node)
5359 p2 = repo.lookup(node)
5360 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5360 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5361
5361
5362 displayer = cmdutil.show_changeset(ui, repo, opts)
5362 displayer = cmdutil.show_changeset(ui, repo, opts)
5363 for node in nodes:
5363 for node in nodes:
5364 displayer.show(repo[node])
5364 displayer.show(repo[node])
5365 displayer.close()
5365 displayer.close()
5366 return 0
5366 return 0
5367
5367
5368 try:
5368 try:
5369 # ui.forcemerge is an internal variable, do not document
5369 # ui.forcemerge is an internal variable, do not document
5370 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5370 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5371 force = opts.get('force')
5371 force = opts.get('force')
5372 return hg.merge(repo, node, force=force, mergeforce=force)
5372 return hg.merge(repo, node, force=force, mergeforce=force)
5373 finally:
5373 finally:
5374 ui.setconfig('ui', 'forcemerge', '', 'merge')
5374 ui.setconfig('ui', 'forcemerge', '', 'merge')
5375
5375
5376 @command('outgoing|out',
5376 @command('outgoing|out',
5377 [('f', 'force', None, _('run even when the destination is unrelated')),
5377 [('f', 'force', None, _('run even when the destination is unrelated')),
5378 ('r', 'rev', [],
5378 ('r', 'rev', [],
5379 _('a changeset intended to be included in the destination'), _('REV')),
5379 _('a changeset intended to be included in the destination'), _('REV')),
5380 ('n', 'newest-first', None, _('show newest record first')),
5380 ('n', 'newest-first', None, _('show newest record first')),
5381 ('B', 'bookmarks', False, _('compare bookmarks')),
5381 ('B', 'bookmarks', False, _('compare bookmarks')),
5382 ('b', 'branch', [], _('a specific branch you would like to push'),
5382 ('b', 'branch', [], _('a specific branch you would like to push'),
5383 _('BRANCH')),
5383 _('BRANCH')),
5384 ] + logopts + remoteopts + subrepoopts,
5384 ] + logopts + remoteopts + subrepoopts,
5385 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5385 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5386 def outgoing(ui, repo, dest=None, **opts):
5386 def outgoing(ui, repo, dest=None, **opts):
5387 """show changesets not found in the destination
5387 """show changesets not found in the destination
5388
5388
5389 Show changesets not found in the specified destination repository
5389 Show changesets not found in the specified destination repository
5390 or the default push location. These are the changesets that would
5390 or the default push location. These are the changesets that would
5391 be pushed if a push was requested.
5391 be pushed if a push was requested.
5392
5392
5393 See pull for details of valid destination formats.
5393 See pull for details of valid destination formats.
5394
5394
5395 .. container:: verbose
5395 .. container:: verbose
5396
5396
5397 With -B/--bookmarks, the result of bookmark comparison between
5397 With -B/--bookmarks, the result of bookmark comparison between
5398 local and remote repositories is displayed. With -v/--verbose,
5398 local and remote repositories is displayed. With -v/--verbose,
5399 status is also displayed for each bookmark like below::
5399 status is also displayed for each bookmark like below::
5400
5400
5401 BM1 01234567890a added
5401 BM1 01234567890a added
5402 BM2 deleted
5402 BM2 deleted
5403 BM3 234567890abc advanced
5403 BM3 234567890abc advanced
5404 BM4 34567890abcd diverged
5404 BM4 34567890abcd diverged
5405 BM5 4567890abcde changed
5405 BM5 4567890abcde changed
5406
5406
5407 The action taken when pushing depends on the
5407 The action taken when pushing depends on the
5408 status of each bookmark:
5408 status of each bookmark:
5409
5409
5410 :``added``: push with ``-B`` will create it
5410 :``added``: push with ``-B`` will create it
5411 :``deleted``: push with ``-B`` will delete it
5411 :``deleted``: push with ``-B`` will delete it
5412 :``advanced``: push will update it
5412 :``advanced``: push will update it
5413 :``diverged``: push with ``-B`` will update it
5413 :``diverged``: push with ``-B`` will update it
5414 :``changed``: push with ``-B`` will update it
5414 :``changed``: push with ``-B`` will update it
5415
5415
5416 From the point of view of pushing behavior, bookmarks
5416 From the point of view of pushing behavior, bookmarks
5417 existing only in the remote repository are treated as
5417 existing only in the remote repository are treated as
5418 ``deleted``, even if it is in fact added remotely.
5418 ``deleted``, even if it is in fact added remotely.
5419
5419
5420 Returns 0 if there are outgoing changes, 1 otherwise.
5420 Returns 0 if there are outgoing changes, 1 otherwise.
5421 """
5421 """
5422 if opts.get('graph'):
5422 if opts.get('graph'):
5423 cmdutil.checkunsupportedgraphflags([], opts)
5423 cmdutil.checkunsupportedgraphflags([], opts)
5424 o, other = hg._outgoing(ui, repo, dest, opts)
5424 o, other = hg._outgoing(ui, repo, dest, opts)
5425 if not o:
5425 if not o:
5426 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5426 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5427 return
5427 return
5428
5428
5429 revdag = cmdutil.graphrevs(repo, o, opts)
5429 revdag = cmdutil.graphrevs(repo, o, opts)
5430 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5430 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5431 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5431 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5432 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5432 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5433 return 0
5433 return 0
5434
5434
5435 if opts.get('bookmarks'):
5435 if opts.get('bookmarks'):
5436 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5436 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5437 dest, branches = hg.parseurl(dest, opts.get('branch'))
5437 dest, branches = hg.parseurl(dest, opts.get('branch'))
5438 other = hg.peer(repo, opts, dest)
5438 other = hg.peer(repo, opts, dest)
5439 if 'bookmarks' not in other.listkeys('namespaces'):
5439 if 'bookmarks' not in other.listkeys('namespaces'):
5440 ui.warn(_("remote doesn't support bookmarks\n"))
5440 ui.warn(_("remote doesn't support bookmarks\n"))
5441 return 0
5441 return 0
5442 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5442 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5443 return bookmarks.outgoing(ui, repo, other)
5443 return bookmarks.outgoing(ui, repo, other)
5444
5444
5445 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5445 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5446 try:
5446 try:
5447 return hg.outgoing(ui, repo, dest, opts)
5447 return hg.outgoing(ui, repo, dest, opts)
5448 finally:
5448 finally:
5449 del repo._subtoppath
5449 del repo._subtoppath
5450
5450
5451 @command('parents',
5451 @command('parents',
5452 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5452 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5453 ] + templateopts,
5453 ] + templateopts,
5454 _('[-r REV] [FILE]'),
5454 _('[-r REV] [FILE]'),
5455 inferrepo=True)
5455 inferrepo=True)
5456 def parents(ui, repo, file_=None, **opts):
5456 def parents(ui, repo, file_=None, **opts):
5457 """show the parents of the working directory or revision (DEPRECATED)
5457 """show the parents of the working directory or revision (DEPRECATED)
5458
5458
5459 Print the working directory's parent revisions. If a revision is
5459 Print the working directory's parent revisions. If a revision is
5460 given via -r/--rev, the parent of that revision will be printed.
5460 given via -r/--rev, the parent of that revision will be printed.
5461 If a file argument is given, the revision in which the file was
5461 If a file argument is given, the revision in which the file was
5462 last changed (before the working directory revision or the
5462 last changed (before the working directory revision or the
5463 argument to --rev if given) is printed.
5463 argument to --rev if given) is printed.
5464
5464
5465 This command is equivalent to::
5465 This command is equivalent to::
5466
5466
5467 hg log -r "p1()+p2()" or
5467 hg log -r "p1()+p2()" or
5468 hg log -r "p1(REV)+p2(REV)" or
5468 hg log -r "p1(REV)+p2(REV)" or
5469 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5469 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5470 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5470 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5471
5471
5472 See :hg:`summary` and :hg:`help revsets` for related information.
5472 See :hg:`summary` and :hg:`help revsets` for related information.
5473
5473
5474 Returns 0 on success.
5474 Returns 0 on success.
5475 """
5475 """
5476
5476
5477 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5477 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5478
5478
5479 if file_:
5479 if file_:
5480 m = scmutil.match(ctx, (file_,), opts)
5480 m = scmutil.match(ctx, (file_,), opts)
5481 if m.anypats() or len(m.files()) != 1:
5481 if m.anypats() or len(m.files()) != 1:
5482 raise error.Abort(_('can only specify an explicit filename'))
5482 raise error.Abort(_('can only specify an explicit filename'))
5483 file_ = m.files()[0]
5483 file_ = m.files()[0]
5484 filenodes = []
5484 filenodes = []
5485 for cp in ctx.parents():
5485 for cp in ctx.parents():
5486 if not cp:
5486 if not cp:
5487 continue
5487 continue
5488 try:
5488 try:
5489 filenodes.append(cp.filenode(file_))
5489 filenodes.append(cp.filenode(file_))
5490 except error.LookupError:
5490 except error.LookupError:
5491 pass
5491 pass
5492 if not filenodes:
5492 if not filenodes:
5493 raise error.Abort(_("'%s' not found in manifest!") % file_)
5493 raise error.Abort(_("'%s' not found in manifest!") % file_)
5494 p = []
5494 p = []
5495 for fn in filenodes:
5495 for fn in filenodes:
5496 fctx = repo.filectx(file_, fileid=fn)
5496 fctx = repo.filectx(file_, fileid=fn)
5497 p.append(fctx.node())
5497 p.append(fctx.node())
5498 else:
5498 else:
5499 p = [cp.node() for cp in ctx.parents()]
5499 p = [cp.node() for cp in ctx.parents()]
5500
5500
5501 displayer = cmdutil.show_changeset(ui, repo, opts)
5501 displayer = cmdutil.show_changeset(ui, repo, opts)
5502 for n in p:
5502 for n in p:
5503 if n != nullid:
5503 if n != nullid:
5504 displayer.show(repo[n])
5504 displayer.show(repo[n])
5505 displayer.close()
5505 displayer.close()
5506
5506
5507 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5507 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5508 def paths(ui, repo, search=None, **opts):
5508 def paths(ui, repo, search=None, **opts):
5509 """show aliases for remote repositories
5509 """show aliases for remote repositories
5510
5510
5511 Show definition of symbolic path name NAME. If no name is given,
5511 Show definition of symbolic path name NAME. If no name is given,
5512 show definition of all available names.
5512 show definition of all available names.
5513
5513
5514 Option -q/--quiet suppresses all output when searching for NAME
5514 Option -q/--quiet suppresses all output when searching for NAME
5515 and shows only the path names when listing all definitions.
5515 and shows only the path names when listing all definitions.
5516
5516
5517 Path names are defined in the [paths] section of your
5517 Path names are defined in the [paths] section of your
5518 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5518 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5519 repository, ``.hg/hgrc`` is used, too.
5519 repository, ``.hg/hgrc`` is used, too.
5520
5520
5521 The path names ``default`` and ``default-push`` have a special
5521 The path names ``default`` and ``default-push`` have a special
5522 meaning. When performing a push or pull operation, they are used
5522 meaning. When performing a push or pull operation, they are used
5523 as fallbacks if no location is specified on the command-line.
5523 as fallbacks if no location is specified on the command-line.
5524 When ``default-push`` is set, it will be used for push and
5524 When ``default-push`` is set, it will be used for push and
5525 ``default`` will be used for pull; otherwise ``default`` is used
5525 ``default`` will be used for pull; otherwise ``default`` is used
5526 as the fallback for both. When cloning a repository, the clone
5526 as the fallback for both. When cloning a repository, the clone
5527 source is written as ``default`` in ``.hg/hgrc``.
5527 source is written as ``default`` in ``.hg/hgrc``.
5528
5528
5529 .. note::
5529 .. note::
5530
5530
5531 ``default`` and ``default-push`` apply to all inbound (e.g.
5531 ``default`` and ``default-push`` apply to all inbound (e.g.
5532 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5532 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5533 and :hg:`bundle`) operations.
5533 and :hg:`bundle`) operations.
5534
5534
5535 See :hg:`help urls` for more information.
5535 See :hg:`help urls` for more information.
5536
5536
5537 Returns 0 on success.
5537 Returns 0 on success.
5538 """
5538 """
5539 if search:
5539 if search:
5540 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5540 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5541 if name == search]
5541 if name == search]
5542 else:
5542 else:
5543 pathitems = sorted(ui.paths.iteritems())
5543 pathitems = sorted(ui.paths.iteritems())
5544
5544
5545 fm = ui.formatter('paths', opts)
5545 fm = ui.formatter('paths', opts)
5546 if fm:
5546 if fm:
5547 hidepassword = str
5547 hidepassword = str
5548 else:
5548 else:
5549 hidepassword = util.hidepassword
5549 hidepassword = util.hidepassword
5550 if ui.quiet:
5550 if ui.quiet:
5551 namefmt = '%s\n'
5551 namefmt = '%s\n'
5552 else:
5552 else:
5553 namefmt = '%s = '
5553 namefmt = '%s = '
5554 showsubopts = not search and not ui.quiet
5554 showsubopts = not search and not ui.quiet
5555
5555
5556 for name, path in pathitems:
5556 for name, path in pathitems:
5557 fm.startitem()
5557 fm.startitem()
5558 fm.condwrite(not search, 'name', namefmt, name)
5558 fm.condwrite(not search, 'name', namefmt, name)
5559 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5559 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5560 for subopt, value in sorted(path.suboptions.items()):
5560 for subopt, value in sorted(path.suboptions.items()):
5561 assert subopt not in ('name', 'url')
5561 assert subopt not in ('name', 'url')
5562 if showsubopts:
5562 if showsubopts:
5563 fm.plain('%s:%s = ' % (name, subopt))
5563 fm.plain('%s:%s = ' % (name, subopt))
5564 fm.condwrite(showsubopts, subopt, '%s\n', value)
5564 fm.condwrite(showsubopts, subopt, '%s\n', value)
5565
5565
5566 fm.end()
5566 fm.end()
5567
5567
5568 if search and not pathitems:
5568 if search and not pathitems:
5569 if not ui.quiet:
5569 if not ui.quiet:
5570 ui.warn(_("not found!\n"))
5570 ui.warn(_("not found!\n"))
5571 return 1
5571 return 1
5572 else:
5572 else:
5573 return 0
5573 return 0
5574
5574
5575 @command('phase',
5575 @command('phase',
5576 [('p', 'public', False, _('set changeset phase to public')),
5576 [('p', 'public', False, _('set changeset phase to public')),
5577 ('d', 'draft', False, _('set changeset phase to draft')),
5577 ('d', 'draft', False, _('set changeset phase to draft')),
5578 ('s', 'secret', False, _('set changeset phase to secret')),
5578 ('s', 'secret', False, _('set changeset phase to secret')),
5579 ('f', 'force', False, _('allow to move boundary backward')),
5579 ('f', 'force', False, _('allow to move boundary backward')),
5580 ('r', 'rev', [], _('target revision'), _('REV')),
5580 ('r', 'rev', [], _('target revision'), _('REV')),
5581 ],
5581 ],
5582 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5582 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5583 def phase(ui, repo, *revs, **opts):
5583 def phase(ui, repo, *revs, **opts):
5584 """set or show the current phase name
5584 """set or show the current phase name
5585
5585
5586 With no argument, show the phase name of the current revision(s).
5586 With no argument, show the phase name of the current revision(s).
5587
5587
5588 With one of -p/--public, -d/--draft or -s/--secret, change the
5588 With one of -p/--public, -d/--draft or -s/--secret, change the
5589 phase value of the specified revisions.
5589 phase value of the specified revisions.
5590
5590
5591 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5591 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5592 lower phase to an higher phase. Phases are ordered as follows::
5592 lower phase to an higher phase. Phases are ordered as follows::
5593
5593
5594 public < draft < secret
5594 public < draft < secret
5595
5595
5596 Returns 0 on success, 1 if some phases could not be changed.
5596 Returns 0 on success, 1 if some phases could not be changed.
5597
5597
5598 (For more information about the phases concept, see :hg:`help phases`.)
5598 (For more information about the phases concept, see :hg:`help phases`.)
5599 """
5599 """
5600 # search for a unique phase argument
5600 # search for a unique phase argument
5601 targetphase = None
5601 targetphase = None
5602 for idx, name in enumerate(phases.phasenames):
5602 for idx, name in enumerate(phases.phasenames):
5603 if opts[name]:
5603 if opts[name]:
5604 if targetphase is not None:
5604 if targetphase is not None:
5605 raise error.Abort(_('only one phase can be specified'))
5605 raise error.Abort(_('only one phase can be specified'))
5606 targetphase = idx
5606 targetphase = idx
5607
5607
5608 # look for specified revision
5608 # look for specified revision
5609 revs = list(revs)
5609 revs = list(revs)
5610 revs.extend(opts['rev'])
5610 revs.extend(opts['rev'])
5611 if not revs:
5611 if not revs:
5612 # display both parents as the second parent phase can influence
5612 # display both parents as the second parent phase can influence
5613 # the phase of a merge commit
5613 # the phase of a merge commit
5614 revs = [c.rev() for c in repo[None].parents()]
5614 revs = [c.rev() for c in repo[None].parents()]
5615
5615
5616 revs = scmutil.revrange(repo, revs)
5616 revs = scmutil.revrange(repo, revs)
5617
5617
5618 lock = None
5618 lock = None
5619 ret = 0
5619 ret = 0
5620 if targetphase is None:
5620 if targetphase is None:
5621 # display
5621 # display
5622 for r in revs:
5622 for r in revs:
5623 ctx = repo[r]
5623 ctx = repo[r]
5624 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5624 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5625 else:
5625 else:
5626 tr = None
5626 tr = None
5627 lock = repo.lock()
5627 lock = repo.lock()
5628 try:
5628 try:
5629 tr = repo.transaction("phase")
5629 tr = repo.transaction("phase")
5630 # set phase
5630 # set phase
5631 if not revs:
5631 if not revs:
5632 raise error.Abort(_('empty revision set'))
5632 raise error.Abort(_('empty revision set'))
5633 nodes = [repo[r].node() for r in revs]
5633 nodes = [repo[r].node() for r in revs]
5634 # moving revision from public to draft may hide them
5634 # moving revision from public to draft may hide them
5635 # We have to check result on an unfiltered repository
5635 # We have to check result on an unfiltered repository
5636 unfi = repo.unfiltered()
5636 unfi = repo.unfiltered()
5637 getphase = unfi._phasecache.phase
5637 getphase = unfi._phasecache.phase
5638 olddata = [getphase(unfi, r) for r in unfi]
5638 olddata = [getphase(unfi, r) for r in unfi]
5639 phases.advanceboundary(repo, tr, targetphase, nodes)
5639 phases.advanceboundary(repo, tr, targetphase, nodes)
5640 if opts['force']:
5640 if opts['force']:
5641 phases.retractboundary(repo, tr, targetphase, nodes)
5641 phases.retractboundary(repo, tr, targetphase, nodes)
5642 tr.close()
5642 tr.close()
5643 finally:
5643 finally:
5644 if tr is not None:
5644 if tr is not None:
5645 tr.release()
5645 tr.release()
5646 lock.release()
5646 lock.release()
5647 getphase = unfi._phasecache.phase
5647 getphase = unfi._phasecache.phase
5648 newdata = [getphase(unfi, r) for r in unfi]
5648 newdata = [getphase(unfi, r) for r in unfi]
5649 changes = sum(newdata[r] != olddata[r] for r in unfi)
5649 changes = sum(newdata[r] != olddata[r] for r in unfi)
5650 cl = unfi.changelog
5650 cl = unfi.changelog
5651 rejected = [n for n in nodes
5651 rejected = [n for n in nodes
5652 if newdata[cl.rev(n)] < targetphase]
5652 if newdata[cl.rev(n)] < targetphase]
5653 if rejected:
5653 if rejected:
5654 ui.warn(_('cannot move %i changesets to a higher '
5654 ui.warn(_('cannot move %i changesets to a higher '
5655 'phase, use --force\n') % len(rejected))
5655 'phase, use --force\n') % len(rejected))
5656 ret = 1
5656 ret = 1
5657 if changes:
5657 if changes:
5658 msg = _('phase changed for %i changesets\n') % changes
5658 msg = _('phase changed for %i changesets\n') % changes
5659 if ret:
5659 if ret:
5660 ui.status(msg)
5660 ui.status(msg)
5661 else:
5661 else:
5662 ui.note(msg)
5662 ui.note(msg)
5663 else:
5663 else:
5664 ui.warn(_('no phases changed\n'))
5664 ui.warn(_('no phases changed\n'))
5665 return ret
5665 return ret
5666
5666
5667 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5667 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5668 """Run after a changegroup has been added via pull/unbundle
5668 """Run after a changegroup has been added via pull/unbundle
5669
5669
5670 This takes arguments below:
5670 This takes arguments below:
5671
5671
5672 :modheads: change of heads by pull/unbundle
5672 :modheads: change of heads by pull/unbundle
5673 :optupdate: updating working directory is needed or not
5673 :optupdate: updating working directory is needed or not
5674 :checkout: update destination revision (or None to default destination)
5674 :checkout: update destination revision (or None to default destination)
5675 :brev: a name, which might be a bookmark to be activated after updating
5675 :brev: a name, which might be a bookmark to be activated after updating
5676 """
5676 """
5677 if modheads == 0:
5677 if modheads == 0:
5678 return
5678 return
5679 if optupdate:
5679 if optupdate:
5680 try:
5680 try:
5681 return hg.updatetotally(ui, repo, checkout, brev)
5681 return hg.updatetotally(ui, repo, checkout, brev)
5682 except error.UpdateAbort as inst:
5682 except error.UpdateAbort as inst:
5683 msg = _("not updating: %s") % str(inst)
5683 msg = _("not updating: %s") % str(inst)
5684 hint = inst.hint
5684 hint = inst.hint
5685 raise error.UpdateAbort(msg, hint=hint)
5685 raise error.UpdateAbort(msg, hint=hint)
5686 if modheads > 1:
5686 if modheads > 1:
5687 currentbranchheads = len(repo.branchheads())
5687 currentbranchheads = len(repo.branchheads())
5688 if currentbranchheads == modheads:
5688 if currentbranchheads == modheads:
5689 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5689 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5690 elif currentbranchheads > 1:
5690 elif currentbranchheads > 1:
5691 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5691 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5692 "merge)\n"))
5692 "merge)\n"))
5693 else:
5693 else:
5694 ui.status(_("(run 'hg heads' to see heads)\n"))
5694 ui.status(_("(run 'hg heads' to see heads)\n"))
5695 else:
5695 else:
5696 ui.status(_("(run 'hg update' to get a working copy)\n"))
5696 ui.status(_("(run 'hg update' to get a working copy)\n"))
5697
5697
5698 @command('^pull',
5698 @command('^pull',
5699 [('u', 'update', None,
5699 [('u', 'update', None,
5700 _('update to new branch head if changesets were pulled')),
5700 _('update to new branch head if changesets were pulled')),
5701 ('f', 'force', None, _('run even when remote repository is unrelated')),
5701 ('f', 'force', None, _('run even when remote repository is unrelated')),
5702 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5702 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5703 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5703 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5704 ('b', 'branch', [], _('a specific branch you would like to pull'),
5704 ('b', 'branch', [], _('a specific branch you would like to pull'),
5705 _('BRANCH')),
5705 _('BRANCH')),
5706 ] + remoteopts,
5706 ] + remoteopts,
5707 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5707 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5708 def pull(ui, repo, source="default", **opts):
5708 def pull(ui, repo, source="default", **opts):
5709 """pull changes from the specified source
5709 """pull changes from the specified source
5710
5710
5711 Pull changes from a remote repository to a local one.
5711 Pull changes from a remote repository to a local one.
5712
5712
5713 This finds all changes from the repository at the specified path
5713 This finds all changes from the repository at the specified path
5714 or URL and adds them to a local repository (the current one unless
5714 or URL and adds them to a local repository (the current one unless
5715 -R is specified). By default, this does not update the copy of the
5715 -R is specified). By default, this does not update the copy of the
5716 project in the working directory.
5716 project in the working directory.
5717
5717
5718 Use :hg:`incoming` if you want to see what would have been added
5718 Use :hg:`incoming` if you want to see what would have been added
5719 by a pull at the time you issued this command. If you then decide
5719 by a pull at the time you issued this command. If you then decide
5720 to add those changes to the repository, you should use :hg:`pull
5720 to add those changes to the repository, you should use :hg:`pull
5721 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5721 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5722
5722
5723 If SOURCE is omitted, the 'default' path will be used.
5723 If SOURCE is omitted, the 'default' path will be used.
5724 See :hg:`help urls` for more information.
5724 See :hg:`help urls` for more information.
5725
5725
5726 Returns 0 on success, 1 if an update had unresolved files.
5726 Returns 0 on success, 1 if an update had unresolved files.
5727 """
5727 """
5728 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5728 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5729 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5729 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5730 other = hg.peer(repo, opts, source)
5730 other = hg.peer(repo, opts, source)
5731 try:
5731 try:
5732 revs, checkout = hg.addbranchrevs(repo, other, branches,
5732 revs, checkout = hg.addbranchrevs(repo, other, branches,
5733 opts.get('rev'))
5733 opts.get('rev'))
5734
5734
5735
5735
5736 pullopargs = {}
5736 pullopargs = {}
5737 if opts.get('bookmark'):
5737 if opts.get('bookmark'):
5738 if not revs:
5738 if not revs:
5739 revs = []
5739 revs = []
5740 # The list of bookmark used here is not the one used to actually
5740 # The list of bookmark used here is not the one used to actually
5741 # update the bookmark name. This can result in the revision pulled
5741 # update the bookmark name. This can result in the revision pulled
5742 # not ending up with the name of the bookmark because of a race
5742 # not ending up with the name of the bookmark because of a race
5743 # condition on the server. (See issue 4689 for details)
5743 # condition on the server. (See issue 4689 for details)
5744 remotebookmarks = other.listkeys('bookmarks')
5744 remotebookmarks = other.listkeys('bookmarks')
5745 pullopargs['remotebookmarks'] = remotebookmarks
5745 pullopargs['remotebookmarks'] = remotebookmarks
5746 for b in opts['bookmark']:
5746 for b in opts['bookmark']:
5747 if b not in remotebookmarks:
5747 if b not in remotebookmarks:
5748 raise error.Abort(_('remote bookmark %s not found!') % b)
5748 raise error.Abort(_('remote bookmark %s not found!') % b)
5749 revs.append(remotebookmarks[b])
5749 revs.append(remotebookmarks[b])
5750
5750
5751 if revs:
5751 if revs:
5752 try:
5752 try:
5753 # When 'rev' is a bookmark name, we cannot guarantee that it
5753 # When 'rev' is a bookmark name, we cannot guarantee that it
5754 # will be updated with that name because of a race condition
5754 # will be updated with that name because of a race condition
5755 # server side. (See issue 4689 for details)
5755 # server side. (See issue 4689 for details)
5756 oldrevs = revs
5756 oldrevs = revs
5757 revs = [] # actually, nodes
5757 revs = [] # actually, nodes
5758 for r in oldrevs:
5758 for r in oldrevs:
5759 node = other.lookup(r)
5759 node = other.lookup(r)
5760 revs.append(node)
5760 revs.append(node)
5761 if r == checkout:
5761 if r == checkout:
5762 checkout = node
5762 checkout = node
5763 except error.CapabilityError:
5763 except error.CapabilityError:
5764 err = _("other repository doesn't support revision lookup, "
5764 err = _("other repository doesn't support revision lookup, "
5765 "so a rev cannot be specified.")
5765 "so a rev cannot be specified.")
5766 raise error.Abort(err)
5766 raise error.Abort(err)
5767
5767
5768 pullopargs.update(opts.get('opargs', {}))
5768 pullopargs.update(opts.get('opargs', {}))
5769 modheads = exchange.pull(repo, other, heads=revs,
5769 modheads = exchange.pull(repo, other, heads=revs,
5770 force=opts.get('force'),
5770 force=opts.get('force'),
5771 bookmarks=opts.get('bookmark', ()),
5771 bookmarks=opts.get('bookmark', ()),
5772 opargs=pullopargs).cgresult
5772 opargs=pullopargs).cgresult
5773
5773
5774 # brev is a name, which might be a bookmark to be activated at
5774 # brev is a name, which might be a bookmark to be activated at
5775 # the end of the update. In other words, it is an explicit
5775 # the end of the update. In other words, it is an explicit
5776 # destination of the update
5776 # destination of the update
5777 brev = None
5777 brev = None
5778
5778
5779 if checkout:
5779 if checkout:
5780 checkout = str(repo.changelog.rev(checkout))
5780 checkout = str(repo.changelog.rev(checkout))
5781
5781
5782 # order below depends on implementation of
5782 # order below depends on implementation of
5783 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5783 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5784 # because 'checkout' is determined without it.
5784 # because 'checkout' is determined without it.
5785 if opts.get('rev'):
5785 if opts.get('rev'):
5786 brev = opts['rev'][0]
5786 brev = opts['rev'][0]
5787 elif opts.get('branch'):
5787 elif opts.get('branch'):
5788 brev = opts['branch'][0]
5788 brev = opts['branch'][0]
5789 else:
5789 else:
5790 brev = branches[0]
5790 brev = branches[0]
5791 repo._subtoppath = source
5791 repo._subtoppath = source
5792 try:
5792 try:
5793 ret = postincoming(ui, repo, modheads, opts.get('update'),
5793 ret = postincoming(ui, repo, modheads, opts.get('update'),
5794 checkout, brev)
5794 checkout, brev)
5795
5795
5796 finally:
5796 finally:
5797 del repo._subtoppath
5797 del repo._subtoppath
5798
5798
5799 finally:
5799 finally:
5800 other.close()
5800 other.close()
5801 return ret
5801 return ret
5802
5802
5803 @command('^push',
5803 @command('^push',
5804 [('f', 'force', None, _('force push')),
5804 [('f', 'force', None, _('force push')),
5805 ('r', 'rev', [],
5805 ('r', 'rev', [],
5806 _('a changeset intended to be included in the destination'),
5806 _('a changeset intended to be included in the destination'),
5807 _('REV')),
5807 _('REV')),
5808 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5808 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5809 ('b', 'branch', [],
5809 ('b', 'branch', [],
5810 _('a specific branch you would like to push'), _('BRANCH')),
5810 _('a specific branch you would like to push'), _('BRANCH')),
5811 ('', 'new-branch', False, _('allow pushing a new branch')),
5811 ('', 'new-branch', False, _('allow pushing a new branch')),
5812 ] + remoteopts,
5812 ] + remoteopts,
5813 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5813 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5814 def push(ui, repo, dest=None, **opts):
5814 def push(ui, repo, dest=None, **opts):
5815 """push changes to the specified destination
5815 """push changes to the specified destination
5816
5816
5817 Push changesets from the local repository to the specified
5817 Push changesets from the local repository to the specified
5818 destination.
5818 destination.
5819
5819
5820 This operation is symmetrical to pull: it is identical to a pull
5820 This operation is symmetrical to pull: it is identical to a pull
5821 in the destination repository from the current one.
5821 in the destination repository from the current one.
5822
5822
5823 By default, push will not allow creation of new heads at the
5823 By default, push will not allow creation of new heads at the
5824 destination, since multiple heads would make it unclear which head
5824 destination, since multiple heads would make it unclear which head
5825 to use. In this situation, it is recommended to pull and merge
5825 to use. In this situation, it is recommended to pull and merge
5826 before pushing.
5826 before pushing.
5827
5827
5828 Use --new-branch if you want to allow push to create a new named
5828 Use --new-branch if you want to allow push to create a new named
5829 branch that is not present at the destination. This allows you to
5829 branch that is not present at the destination. This allows you to
5830 only create a new branch without forcing other changes.
5830 only create a new branch without forcing other changes.
5831
5831
5832 .. note::
5832 .. note::
5833
5833
5834 Extra care should be taken with the -f/--force option,
5834 Extra care should be taken with the -f/--force option,
5835 which will push all new heads on all branches, an action which will
5835 which will push all new heads on all branches, an action which will
5836 almost always cause confusion for collaborators.
5836 almost always cause confusion for collaborators.
5837
5837
5838 If -r/--rev is used, the specified revision and all its ancestors
5838 If -r/--rev is used, the specified revision and all its ancestors
5839 will be pushed to the remote repository.
5839 will be pushed to the remote repository.
5840
5840
5841 If -B/--bookmark is used, the specified bookmarked revision, its
5841 If -B/--bookmark is used, the specified bookmarked revision, its
5842 ancestors, and the bookmark will be pushed to the remote
5842 ancestors, and the bookmark will be pushed to the remote
5843 repository. Specifying ``.`` is equivalent to specifying the active
5843 repository. Specifying ``.`` is equivalent to specifying the active
5844 bookmark's name.
5844 bookmark's name.
5845
5845
5846 Please see :hg:`help urls` for important details about ``ssh://``
5846 Please see :hg:`help urls` for important details about ``ssh://``
5847 URLs. If DESTINATION is omitted, a default path will be used.
5847 URLs. If DESTINATION is omitted, a default path will be used.
5848
5848
5849 Returns 0 if push was successful, 1 if nothing to push.
5849 Returns 0 if push was successful, 1 if nothing to push.
5850 """
5850 """
5851
5851
5852 if opts.get('bookmark'):
5852 if opts.get('bookmark'):
5853 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5853 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5854 for b in opts['bookmark']:
5854 for b in opts['bookmark']:
5855 # translate -B options to -r so changesets get pushed
5855 # translate -B options to -r so changesets get pushed
5856 b = repo._bookmarks.expandname(b)
5856 b = repo._bookmarks.expandname(b)
5857 if b in repo._bookmarks:
5857 if b in repo._bookmarks:
5858 opts.setdefault('rev', []).append(b)
5858 opts.setdefault('rev', []).append(b)
5859 else:
5859 else:
5860 # if we try to push a deleted bookmark, translate it to null
5860 # if we try to push a deleted bookmark, translate it to null
5861 # this lets simultaneous -r, -b options continue working
5861 # this lets simultaneous -r, -b options continue working
5862 opts.setdefault('rev', []).append("null")
5862 opts.setdefault('rev', []).append("null")
5863
5863
5864 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5864 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5865 if not path:
5865 if not path:
5866 raise error.Abort(_('default repository not configured!'),
5866 raise error.Abort(_('default repository not configured!'),
5867 hint=_('see the "path" section in "hg help config"'))
5867 hint=_('see the "path" section in "hg help config"'))
5868 dest = path.pushloc or path.loc
5868 dest = path.pushloc or path.loc
5869 branches = (path.branch, opts.get('branch') or [])
5869 branches = (path.branch, opts.get('branch') or [])
5870 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5870 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5871 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5871 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5872 other = hg.peer(repo, opts, dest)
5872 other = hg.peer(repo, opts, dest)
5873
5873
5874 if revs:
5874 if revs:
5875 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5875 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5876 if not revs:
5876 if not revs:
5877 raise error.Abort(_("specified revisions evaluate to an empty set"),
5877 raise error.Abort(_("specified revisions evaluate to an empty set"),
5878 hint=_("use different revision arguments"))
5878 hint=_("use different revision arguments"))
5879
5879
5880 repo._subtoppath = dest
5880 repo._subtoppath = dest
5881 try:
5881 try:
5882 # push subrepos depth-first for coherent ordering
5882 # push subrepos depth-first for coherent ordering
5883 c = repo['']
5883 c = repo['']
5884 subs = c.substate # only repos that are committed
5884 subs = c.substate # only repos that are committed
5885 for s in sorted(subs):
5885 for s in sorted(subs):
5886 result = c.sub(s).push(opts)
5886 result = c.sub(s).push(opts)
5887 if result == 0:
5887 if result == 0:
5888 return not result
5888 return not result
5889 finally:
5889 finally:
5890 del repo._subtoppath
5890 del repo._subtoppath
5891 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5891 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5892 newbranch=opts.get('new_branch'),
5892 newbranch=opts.get('new_branch'),
5893 bookmarks=opts.get('bookmark', ()),
5893 bookmarks=opts.get('bookmark', ()),
5894 opargs=opts.get('opargs'))
5894 opargs=opts.get('opargs'))
5895
5895
5896 result = not pushop.cgresult
5896 result = not pushop.cgresult
5897
5897
5898 if pushop.bkresult is not None:
5898 if pushop.bkresult is not None:
5899 if pushop.bkresult == 2:
5899 if pushop.bkresult == 2:
5900 result = 2
5900 result = 2
5901 elif not result and pushop.bkresult:
5901 elif not result and pushop.bkresult:
5902 result = 2
5902 result = 2
5903
5903
5904 return result
5904 return result
5905
5905
5906 @command('recover', [])
5906 @command('recover', [])
5907 def recover(ui, repo):
5907 def recover(ui, repo):
5908 """roll back an interrupted transaction
5908 """roll back an interrupted transaction
5909
5909
5910 Recover from an interrupted commit or pull.
5910 Recover from an interrupted commit or pull.
5911
5911
5912 This command tries to fix the repository status after an
5912 This command tries to fix the repository status after an
5913 interrupted operation. It should only be necessary when Mercurial
5913 interrupted operation. It should only be necessary when Mercurial
5914 suggests it.
5914 suggests it.
5915
5915
5916 Returns 0 if successful, 1 if nothing to recover or verify fails.
5916 Returns 0 if successful, 1 if nothing to recover or verify fails.
5917 """
5917 """
5918 if repo.recover():
5918 if repo.recover():
5919 return hg.verify(repo)
5919 return hg.verify(repo)
5920 return 1
5920 return 1
5921
5921
5922 @command('^remove|rm',
5922 @command('^remove|rm',
5923 [('A', 'after', None, _('record delete for missing files')),
5923 [('A', 'after', None, _('record delete for missing files')),
5924 ('f', 'force', None,
5924 ('f', 'force', None,
5925 _('remove (and delete) file even if added or modified')),
5925 _('remove (and delete) file even if added or modified')),
5926 ] + subrepoopts + walkopts,
5926 ] + subrepoopts + walkopts,
5927 _('[OPTION]... FILE...'),
5927 _('[OPTION]... FILE...'),
5928 inferrepo=True)
5928 inferrepo=True)
5929 def remove(ui, repo, *pats, **opts):
5929 def remove(ui, repo, *pats, **opts):
5930 """remove the specified files on the next commit
5930 """remove the specified files on the next commit
5931
5931
5932 Schedule the indicated files for removal from the current branch.
5932 Schedule the indicated files for removal from the current branch.
5933
5933
5934 This command schedules the files to be removed at the next commit.
5934 This command schedules the files to be removed at the next commit.
5935 To undo a remove before that, see :hg:`revert`. To undo added
5935 To undo a remove before that, see :hg:`revert`. To undo added
5936 files, see :hg:`forget`.
5936 files, see :hg:`forget`.
5937
5937
5938 .. container:: verbose
5938 .. container:: verbose
5939
5939
5940 -A/--after can be used to remove only files that have already
5940 -A/--after can be used to remove only files that have already
5941 been deleted, -f/--force can be used to force deletion, and -Af
5941 been deleted, -f/--force can be used to force deletion, and -Af
5942 can be used to remove files from the next revision without
5942 can be used to remove files from the next revision without
5943 deleting them from the working directory.
5943 deleting them from the working directory.
5944
5944
5945 The following table details the behavior of remove for different
5945 The following table details the behavior of remove for different
5946 file states (columns) and option combinations (rows). The file
5946 file states (columns) and option combinations (rows). The file
5947 states are Added [A], Clean [C], Modified [M] and Missing [!]
5947 states are Added [A], Clean [C], Modified [M] and Missing [!]
5948 (as reported by :hg:`status`). The actions are Warn, Remove
5948 (as reported by :hg:`status`). The actions are Warn, Remove
5949 (from branch) and Delete (from disk):
5949 (from branch) and Delete (from disk):
5950
5950
5951 ========= == == == ==
5951 ========= == == == ==
5952 opt/state A C M !
5952 opt/state A C M !
5953 ========= == == == ==
5953 ========= == == == ==
5954 none W RD W R
5954 none W RD W R
5955 -f R RD RD R
5955 -f R RD RD R
5956 -A W W W R
5956 -A W W W R
5957 -Af R R R R
5957 -Af R R R R
5958 ========= == == == ==
5958 ========= == == == ==
5959
5959
5960 .. note::
5960 .. note::
5961
5961
5962 :hg:`remove` never deletes files in Added [A] state from the
5962 :hg:`remove` never deletes files in Added [A] state from the
5963 working directory, not even if ``--force`` is specified.
5963 working directory, not even if ``--force`` is specified.
5964
5964
5965 Returns 0 on success, 1 if any warnings encountered.
5965 Returns 0 on success, 1 if any warnings encountered.
5966 """
5966 """
5967
5967
5968 after, force = opts.get('after'), opts.get('force')
5968 after, force = opts.get('after'), opts.get('force')
5969 if not pats and not after:
5969 if not pats and not after:
5970 raise error.Abort(_('no files specified'))
5970 raise error.Abort(_('no files specified'))
5971
5971
5972 m = scmutil.match(repo[None], pats, opts)
5972 m = scmutil.match(repo[None], pats, opts)
5973 subrepos = opts.get('subrepos')
5973 subrepos = opts.get('subrepos')
5974 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5974 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5975
5975
5976 @command('rename|move|mv',
5976 @command('rename|move|mv',
5977 [('A', 'after', None, _('record a rename that has already occurred')),
5977 [('A', 'after', None, _('record a rename that has already occurred')),
5978 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5978 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5979 ] + walkopts + dryrunopts,
5979 ] + walkopts + dryrunopts,
5980 _('[OPTION]... SOURCE... DEST'))
5980 _('[OPTION]... SOURCE... DEST'))
5981 def rename(ui, repo, *pats, **opts):
5981 def rename(ui, repo, *pats, **opts):
5982 """rename files; equivalent of copy + remove
5982 """rename files; equivalent of copy + remove
5983
5983
5984 Mark dest as copies of sources; mark sources for deletion. If dest
5984 Mark dest as copies of sources; mark sources for deletion. If dest
5985 is a directory, copies are put in that directory. If dest is a
5985 is a directory, copies are put in that directory. If dest is a
5986 file, there can only be one source.
5986 file, there can only be one source.
5987
5987
5988 By default, this command copies the contents of files as they
5988 By default, this command copies the contents of files as they
5989 exist in the working directory. If invoked with -A/--after, the
5989 exist in the working directory. If invoked with -A/--after, the
5990 operation is recorded, but no copying is performed.
5990 operation is recorded, but no copying is performed.
5991
5991
5992 This command takes effect at the next commit. To undo a rename
5992 This command takes effect at the next commit. To undo a rename
5993 before that, see :hg:`revert`.
5993 before that, see :hg:`revert`.
5994
5994
5995 Returns 0 on success, 1 if errors are encountered.
5995 Returns 0 on success, 1 if errors are encountered.
5996 """
5996 """
5997 with repo.wlock(False):
5997 with repo.wlock(False):
5998 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5998 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5999
5999
6000 @command('resolve',
6000 @command('resolve',
6001 [('a', 'all', None, _('select all unresolved files')),
6001 [('a', 'all', None, _('select all unresolved files')),
6002 ('l', 'list', None, _('list state of files needing merge')),
6002 ('l', 'list', None, _('list state of files needing merge')),
6003 ('m', 'mark', None, _('mark files as resolved')),
6003 ('m', 'mark', None, _('mark files as resolved')),
6004 ('u', 'unmark', None, _('mark files as unresolved')),
6004 ('u', 'unmark', None, _('mark files as unresolved')),
6005 ('n', 'no-status', None, _('hide status prefix'))]
6005 ('n', 'no-status', None, _('hide status prefix'))]
6006 + mergetoolopts + walkopts + formatteropts,
6006 + mergetoolopts + walkopts + formatteropts,
6007 _('[OPTION]... [FILE]...'),
6007 _('[OPTION]... [FILE]...'),
6008 inferrepo=True)
6008 inferrepo=True)
6009 def resolve(ui, repo, *pats, **opts):
6009 def resolve(ui, repo, *pats, **opts):
6010 """redo merges or set/view the merge status of files
6010 """redo merges or set/view the merge status of files
6011
6011
6012 Merges with unresolved conflicts are often the result of
6012 Merges with unresolved conflicts are often the result of
6013 non-interactive merging using the ``internal:merge`` configuration
6013 non-interactive merging using the ``internal:merge`` configuration
6014 setting, or a command-line merge tool like ``diff3``. The resolve
6014 setting, or a command-line merge tool like ``diff3``. The resolve
6015 command is used to manage the files involved in a merge, after
6015 command is used to manage the files involved in a merge, after
6016 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6016 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6017 working directory must have two parents). See :hg:`help
6017 working directory must have two parents). See :hg:`help
6018 merge-tools` for information on configuring merge tools.
6018 merge-tools` for information on configuring merge tools.
6019
6019
6020 The resolve command can be used in the following ways:
6020 The resolve command can be used in the following ways:
6021
6021
6022 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6022 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6023 files, discarding any previous merge attempts. Re-merging is not
6023 files, discarding any previous merge attempts. Re-merging is not
6024 performed for files already marked as resolved. Use ``--all/-a``
6024 performed for files already marked as resolved. Use ``--all/-a``
6025 to select all unresolved files. ``--tool`` can be used to specify
6025 to select all unresolved files. ``--tool`` can be used to specify
6026 the merge tool used for the given files. It overrides the HGMERGE
6026 the merge tool used for the given files. It overrides the HGMERGE
6027 environment variable and your configuration files. Previous file
6027 environment variable and your configuration files. Previous file
6028 contents are saved with a ``.orig`` suffix.
6028 contents are saved with a ``.orig`` suffix.
6029
6029
6030 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6030 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6031 (e.g. after having manually fixed-up the files). The default is
6031 (e.g. after having manually fixed-up the files). The default is
6032 to mark all unresolved files.
6032 to mark all unresolved files.
6033
6033
6034 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6034 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6035 default is to mark all resolved files.
6035 default is to mark all resolved files.
6036
6036
6037 - :hg:`resolve -l`: list files which had or still have conflicts.
6037 - :hg:`resolve -l`: list files which had or still have conflicts.
6038 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6038 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6039
6039
6040 .. note::
6040 .. note::
6041
6041
6042 Mercurial will not let you commit files with unresolved merge
6042 Mercurial will not let you commit files with unresolved merge
6043 conflicts. You must use :hg:`resolve -m ...` before you can
6043 conflicts. You must use :hg:`resolve -m ...` before you can
6044 commit after a conflicting merge.
6044 commit after a conflicting merge.
6045
6045
6046 Returns 0 on success, 1 if any files fail a resolve attempt.
6046 Returns 0 on success, 1 if any files fail a resolve attempt.
6047 """
6047 """
6048
6048
6049 flaglist = 'all mark unmark list no_status'.split()
6049 flaglist = 'all mark unmark list no_status'.split()
6050 all, mark, unmark, show, nostatus = \
6050 all, mark, unmark, show, nostatus = \
6051 [opts.get(o) for o in flaglist]
6051 [opts.get(o) for o in flaglist]
6052
6052
6053 if (show and (mark or unmark)) or (mark and unmark):
6053 if (show and (mark or unmark)) or (mark and unmark):
6054 raise error.Abort(_("too many options specified"))
6054 raise error.Abort(_("too many options specified"))
6055 if pats and all:
6055 if pats and all:
6056 raise error.Abort(_("can't specify --all and patterns"))
6056 raise error.Abort(_("can't specify --all and patterns"))
6057 if not (all or pats or show or mark or unmark):
6057 if not (all or pats or show or mark or unmark):
6058 raise error.Abort(_('no files or directories specified'),
6058 raise error.Abort(_('no files or directories specified'),
6059 hint=('use --all to re-merge all unresolved files'))
6059 hint=('use --all to re-merge all unresolved files'))
6060
6060
6061 if show:
6061 if show:
6062 fm = ui.formatter('resolve', opts)
6062 fm = ui.formatter('resolve', opts)
6063 ms = mergemod.mergestate.read(repo)
6063 ms = mergemod.mergestate.read(repo)
6064 m = scmutil.match(repo[None], pats, opts)
6064 m = scmutil.match(repo[None], pats, opts)
6065 for f in ms:
6065 for f in ms:
6066 if not m(f):
6066 if not m(f):
6067 continue
6067 continue
6068 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6068 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6069 'd': 'driverresolved'}[ms[f]]
6069 'd': 'driverresolved'}[ms[f]]
6070 fm.startitem()
6070 fm.startitem()
6071 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6071 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6072 fm.write('path', '%s\n', f, label=l)
6072 fm.write('path', '%s\n', f, label=l)
6073 fm.end()
6073 fm.end()
6074 return 0
6074 return 0
6075
6075
6076 with repo.wlock():
6076 with repo.wlock():
6077 ms = mergemod.mergestate.read(repo)
6077 ms = mergemod.mergestate.read(repo)
6078
6078
6079 if not (ms.active() or repo.dirstate.p2() != nullid):
6079 if not (ms.active() or repo.dirstate.p2() != nullid):
6080 raise error.Abort(
6080 raise error.Abort(
6081 _('resolve command not applicable when not merging'))
6081 _('resolve command not applicable when not merging'))
6082
6082
6083 wctx = repo[None]
6083 wctx = repo[None]
6084
6084
6085 if ms.mergedriver and ms.mdstate() == 'u':
6085 if ms.mergedriver and ms.mdstate() == 'u':
6086 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6086 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6087 ms.commit()
6087 ms.commit()
6088 # allow mark and unmark to go through
6088 # allow mark and unmark to go through
6089 if not mark and not unmark and not proceed:
6089 if not mark and not unmark and not proceed:
6090 return 1
6090 return 1
6091
6091
6092 m = scmutil.match(wctx, pats, opts)
6092 m = scmutil.match(wctx, pats, opts)
6093 ret = 0
6093 ret = 0
6094 didwork = False
6094 didwork = False
6095 runconclude = False
6095 runconclude = False
6096
6096
6097 tocomplete = []
6097 tocomplete = []
6098 for f in ms:
6098 for f in ms:
6099 if not m(f):
6099 if not m(f):
6100 continue
6100 continue
6101
6101
6102 didwork = True
6102 didwork = True
6103
6103
6104 # don't let driver-resolved files be marked, and run the conclude
6104 # don't let driver-resolved files be marked, and run the conclude
6105 # step if asked to resolve
6105 # step if asked to resolve
6106 if ms[f] == "d":
6106 if ms[f] == "d":
6107 exact = m.exact(f)
6107 exact = m.exact(f)
6108 if mark:
6108 if mark:
6109 if exact:
6109 if exact:
6110 ui.warn(_('not marking %s as it is driver-resolved\n')
6110 ui.warn(_('not marking %s as it is driver-resolved\n')
6111 % f)
6111 % f)
6112 elif unmark:
6112 elif unmark:
6113 if exact:
6113 if exact:
6114 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6114 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6115 % f)
6115 % f)
6116 else:
6116 else:
6117 runconclude = True
6117 runconclude = True
6118 continue
6118 continue
6119
6119
6120 if mark:
6120 if mark:
6121 ms.mark(f, "r")
6121 ms.mark(f, "r")
6122 elif unmark:
6122 elif unmark:
6123 ms.mark(f, "u")
6123 ms.mark(f, "u")
6124 else:
6124 else:
6125 # backup pre-resolve (merge uses .orig for its own purposes)
6125 # backup pre-resolve (merge uses .orig for its own purposes)
6126 a = repo.wjoin(f)
6126 a = repo.wjoin(f)
6127 try:
6127 try:
6128 util.copyfile(a, a + ".resolve")
6128 util.copyfile(a, a + ".resolve")
6129 except (IOError, OSError) as inst:
6129 except (IOError, OSError) as inst:
6130 if inst.errno != errno.ENOENT:
6130 if inst.errno != errno.ENOENT:
6131 raise
6131 raise
6132
6132
6133 try:
6133 try:
6134 # preresolve file
6134 # preresolve file
6135 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6135 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6136 'resolve')
6136 'resolve')
6137 complete, r = ms.preresolve(f, wctx)
6137 complete, r = ms.preresolve(f, wctx)
6138 if not complete:
6138 if not complete:
6139 tocomplete.append(f)
6139 tocomplete.append(f)
6140 elif r:
6140 elif r:
6141 ret = 1
6141 ret = 1
6142 finally:
6142 finally:
6143 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6143 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6144 ms.commit()
6144 ms.commit()
6145
6145
6146 # replace filemerge's .orig file with our resolve file, but only
6146 # replace filemerge's .orig file with our resolve file, but only
6147 # for merges that are complete
6147 # for merges that are complete
6148 if complete:
6148 if complete:
6149 try:
6149 try:
6150 util.rename(a + ".resolve",
6150 util.rename(a + ".resolve",
6151 scmutil.origpath(ui, repo, a))
6151 scmutil.origpath(ui, repo, a))
6152 except OSError as inst:
6152 except OSError as inst:
6153 if inst.errno != errno.ENOENT:
6153 if inst.errno != errno.ENOENT:
6154 raise
6154 raise
6155
6155
6156 for f in tocomplete:
6156 for f in tocomplete:
6157 try:
6157 try:
6158 # resolve file
6158 # resolve file
6159 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6159 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6160 'resolve')
6160 'resolve')
6161 r = ms.resolve(f, wctx)
6161 r = ms.resolve(f, wctx)
6162 if r:
6162 if r:
6163 ret = 1
6163 ret = 1
6164 finally:
6164 finally:
6165 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6165 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6166 ms.commit()
6166 ms.commit()
6167
6167
6168 # replace filemerge's .orig file with our resolve file
6168 # replace filemerge's .orig file with our resolve file
6169 a = repo.wjoin(f)
6169 a = repo.wjoin(f)
6170 try:
6170 try:
6171 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6171 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6172 except OSError as inst:
6172 except OSError as inst:
6173 if inst.errno != errno.ENOENT:
6173 if inst.errno != errno.ENOENT:
6174 raise
6174 raise
6175
6175
6176 ms.commit()
6176 ms.commit()
6177 ms.recordactions()
6177 ms.recordactions()
6178
6178
6179 if not didwork and pats:
6179 if not didwork and pats:
6180 hint = None
6180 hint = None
6181 if not any([p for p in pats if p.find(':') >= 0]):
6181 if not any([p for p in pats if p.find(':') >= 0]):
6182 pats = ['path:%s' % p for p in pats]
6182 pats = ['path:%s' % p for p in pats]
6183 m = scmutil.match(wctx, pats, opts)
6183 m = scmutil.match(wctx, pats, opts)
6184 for f in ms:
6184 for f in ms:
6185 if not m(f):
6185 if not m(f):
6186 continue
6186 continue
6187 flags = ''.join(['-%s ' % o[0] for o in flaglist
6187 flags = ''.join(['-%s ' % o[0] for o in flaglist
6188 if opts.get(o)])
6188 if opts.get(o)])
6189 hint = _("(try: hg resolve %s%s)\n") % (
6189 hint = _("(try: hg resolve %s%s)\n") % (
6190 flags,
6190 flags,
6191 ' '.join(pats))
6191 ' '.join(pats))
6192 break
6192 break
6193 ui.warn(_("arguments do not match paths that need resolving\n"))
6193 ui.warn(_("arguments do not match paths that need resolving\n"))
6194 if hint:
6194 if hint:
6195 ui.warn(hint)
6195 ui.warn(hint)
6196 elif ms.mergedriver and ms.mdstate() != 's':
6196 elif ms.mergedriver and ms.mdstate() != 's':
6197 # run conclude step when either a driver-resolved file is requested
6197 # run conclude step when either a driver-resolved file is requested
6198 # or there are no driver-resolved files
6198 # or there are no driver-resolved files
6199 # we can't use 'ret' to determine whether any files are unresolved
6199 # we can't use 'ret' to determine whether any files are unresolved
6200 # because we might not have tried to resolve some
6200 # because we might not have tried to resolve some
6201 if ((runconclude or not list(ms.driverresolved()))
6201 if ((runconclude or not list(ms.driverresolved()))
6202 and not list(ms.unresolved())):
6202 and not list(ms.unresolved())):
6203 proceed = mergemod.driverconclude(repo, ms, wctx)
6203 proceed = mergemod.driverconclude(repo, ms, wctx)
6204 ms.commit()
6204 ms.commit()
6205 if not proceed:
6205 if not proceed:
6206 return 1
6206 return 1
6207
6207
6208 # Nudge users into finishing an unfinished operation
6208 # Nudge users into finishing an unfinished operation
6209 unresolvedf = list(ms.unresolved())
6209 unresolvedf = list(ms.unresolved())
6210 driverresolvedf = list(ms.driverresolved())
6210 driverresolvedf = list(ms.driverresolved())
6211 if not unresolvedf and not driverresolvedf:
6211 if not unresolvedf and not driverresolvedf:
6212 ui.status(_('(no more unresolved files)\n'))
6212 ui.status(_('(no more unresolved files)\n'))
6213 cmdutil.checkafterresolved(repo)
6213 cmdutil.checkafterresolved(repo)
6214 elif not unresolvedf:
6214 elif not unresolvedf:
6215 ui.status(_('(no more unresolved files -- '
6215 ui.status(_('(no more unresolved files -- '
6216 'run "hg resolve --all" to conclude)\n'))
6216 'run "hg resolve --all" to conclude)\n'))
6217
6217
6218 return ret
6218 return ret
6219
6219
6220 @command('revert',
6220 @command('revert',
6221 [('a', 'all', None, _('revert all changes when no arguments given')),
6221 [('a', 'all', None, _('revert all changes when no arguments given')),
6222 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6222 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6223 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6223 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6224 ('C', 'no-backup', None, _('do not save backup copies of files')),
6224 ('C', 'no-backup', None, _('do not save backup copies of files')),
6225 ('i', 'interactive', None,
6225 ('i', 'interactive', None,
6226 _('interactively select the changes (EXPERIMENTAL)')),
6226 _('interactively select the changes (EXPERIMENTAL)')),
6227 ] + walkopts + dryrunopts,
6227 ] + walkopts + dryrunopts,
6228 _('[OPTION]... [-r REV] [NAME]...'))
6228 _('[OPTION]... [-r REV] [NAME]...'))
6229 def revert(ui, repo, *pats, **opts):
6229 def revert(ui, repo, *pats, **opts):
6230 """restore files to their checkout state
6230 """restore files to their checkout state
6231
6231
6232 .. note::
6232 .. note::
6233
6233
6234 To check out earlier revisions, you should use :hg:`update REV`.
6234 To check out earlier revisions, you should use :hg:`update REV`.
6235 To cancel an uncommitted merge (and lose your changes),
6235 To cancel an uncommitted merge (and lose your changes),
6236 use :hg:`update --clean .`.
6236 use :hg:`update --clean .`.
6237
6237
6238 With no revision specified, revert the specified files or directories
6238 With no revision specified, revert the specified files or directories
6239 to the contents they had in the parent of the working directory.
6239 to the contents they had in the parent of the working directory.
6240 This restores the contents of files to an unmodified
6240 This restores the contents of files to an unmodified
6241 state and unschedules adds, removes, copies, and renames. If the
6241 state and unschedules adds, removes, copies, and renames. If the
6242 working directory has two parents, you must explicitly specify a
6242 working directory has two parents, you must explicitly specify a
6243 revision.
6243 revision.
6244
6244
6245 Using the -r/--rev or -d/--date options, revert the given files or
6245 Using the -r/--rev or -d/--date options, revert the given files or
6246 directories to their states as of a specific revision. Because
6246 directories to their states as of a specific revision. Because
6247 revert does not change the working directory parents, this will
6247 revert does not change the working directory parents, this will
6248 cause these files to appear modified. This can be helpful to "back
6248 cause these files to appear modified. This can be helpful to "back
6249 out" some or all of an earlier change. See :hg:`backout` for a
6249 out" some or all of an earlier change. See :hg:`backout` for a
6250 related method.
6250 related method.
6251
6251
6252 Modified files are saved with a .orig suffix before reverting.
6252 Modified files are saved with a .orig suffix before reverting.
6253 To disable these backups, use --no-backup.
6253 To disable these backups, use --no-backup.
6254
6254
6255 See :hg:`help dates` for a list of formats valid for -d/--date.
6255 See :hg:`help dates` for a list of formats valid for -d/--date.
6256
6256
6257 See :hg:`help backout` for a way to reverse the effect of an
6257 See :hg:`help backout` for a way to reverse the effect of an
6258 earlier changeset.
6258 earlier changeset.
6259
6259
6260 Returns 0 on success.
6260 Returns 0 on success.
6261 """
6261 """
6262
6262
6263 if opts.get("date"):
6263 if opts.get("date"):
6264 if opts.get("rev"):
6264 if opts.get("rev"):
6265 raise error.Abort(_("you can't specify a revision and a date"))
6265 raise error.Abort(_("you can't specify a revision and a date"))
6266 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6266 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6267
6267
6268 parent, p2 = repo.dirstate.parents()
6268 parent, p2 = repo.dirstate.parents()
6269 if not opts.get('rev') and p2 != nullid:
6269 if not opts.get('rev') and p2 != nullid:
6270 # revert after merge is a trap for new users (issue2915)
6270 # revert after merge is a trap for new users (issue2915)
6271 raise error.Abort(_('uncommitted merge with no revision specified'),
6271 raise error.Abort(_('uncommitted merge with no revision specified'),
6272 hint=_('use "hg update" or see "hg help revert"'))
6272 hint=_('use "hg update" or see "hg help revert"'))
6273
6273
6274 ctx = scmutil.revsingle(repo, opts.get('rev'))
6274 ctx = scmutil.revsingle(repo, opts.get('rev'))
6275
6275
6276 if (not (pats or opts.get('include') or opts.get('exclude') or
6276 if (not (pats or opts.get('include') or opts.get('exclude') or
6277 opts.get('all') or opts.get('interactive'))):
6277 opts.get('all') or opts.get('interactive'))):
6278 msg = _("no files or directories specified")
6278 msg = _("no files or directories specified")
6279 if p2 != nullid:
6279 if p2 != nullid:
6280 hint = _("uncommitted merge, use --all to discard all changes,"
6280 hint = _("uncommitted merge, use --all to discard all changes,"
6281 " or 'hg update -C .' to abort the merge")
6281 " or 'hg update -C .' to abort the merge")
6282 raise error.Abort(msg, hint=hint)
6282 raise error.Abort(msg, hint=hint)
6283 dirty = any(repo.status())
6283 dirty = any(repo.status())
6284 node = ctx.node()
6284 node = ctx.node()
6285 if node != parent:
6285 if node != parent:
6286 if dirty:
6286 if dirty:
6287 hint = _("uncommitted changes, use --all to discard all"
6287 hint = _("uncommitted changes, use --all to discard all"
6288 " changes, or 'hg update %s' to update") % ctx.rev()
6288 " changes, or 'hg update %s' to update") % ctx.rev()
6289 else:
6289 else:
6290 hint = _("use --all to revert all files,"
6290 hint = _("use --all to revert all files,"
6291 " or 'hg update %s' to update") % ctx.rev()
6291 " or 'hg update %s' to update") % ctx.rev()
6292 elif dirty:
6292 elif dirty:
6293 hint = _("uncommitted changes, use --all to discard all changes")
6293 hint = _("uncommitted changes, use --all to discard all changes")
6294 else:
6294 else:
6295 hint = _("use --all to revert all files")
6295 hint = _("use --all to revert all files")
6296 raise error.Abort(msg, hint=hint)
6296 raise error.Abort(msg, hint=hint)
6297
6297
6298 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6298 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6299
6299
6300 @command('rollback', dryrunopts +
6300 @command('rollback', dryrunopts +
6301 [('f', 'force', False, _('ignore safety measures'))])
6301 [('f', 'force', False, _('ignore safety measures'))])
6302 def rollback(ui, repo, **opts):
6302 def rollback(ui, repo, **opts):
6303 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6303 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6304
6304
6305 Please use :hg:`commit --amend` instead of rollback to correct
6305 Please use :hg:`commit --amend` instead of rollback to correct
6306 mistakes in the last commit.
6306 mistakes in the last commit.
6307
6307
6308 This command should be used with care. There is only one level of
6308 This command should be used with care. There is only one level of
6309 rollback, and there is no way to undo a rollback. It will also
6309 rollback, and there is no way to undo a rollback. It will also
6310 restore the dirstate at the time of the last transaction, losing
6310 restore the dirstate at the time of the last transaction, losing
6311 any dirstate changes since that time. This command does not alter
6311 any dirstate changes since that time. This command does not alter
6312 the working directory.
6312 the working directory.
6313
6313
6314 Transactions are used to encapsulate the effects of all commands
6314 Transactions are used to encapsulate the effects of all commands
6315 that create new changesets or propagate existing changesets into a
6315 that create new changesets or propagate existing changesets into a
6316 repository.
6316 repository.
6317
6317
6318 .. container:: verbose
6318 .. container:: verbose
6319
6319
6320 For example, the following commands are transactional, and their
6320 For example, the following commands are transactional, and their
6321 effects can be rolled back:
6321 effects can be rolled back:
6322
6322
6323 - commit
6323 - commit
6324 - import
6324 - import
6325 - pull
6325 - pull
6326 - push (with this repository as the destination)
6326 - push (with this repository as the destination)
6327 - unbundle
6327 - unbundle
6328
6328
6329 To avoid permanent data loss, rollback will refuse to rollback a
6329 To avoid permanent data loss, rollback will refuse to rollback a
6330 commit transaction if it isn't checked out. Use --force to
6330 commit transaction if it isn't checked out. Use --force to
6331 override this protection.
6331 override this protection.
6332
6332
6333 This command is not intended for use on public repositories. Once
6333 This command is not intended for use on public repositories. Once
6334 changes are visible for pull by other users, rolling a transaction
6334 changes are visible for pull by other users, rolling a transaction
6335 back locally is ineffective (someone else may already have pulled
6335 back locally is ineffective (someone else may already have pulled
6336 the changes). Furthermore, a race is possible with readers of the
6336 the changes). Furthermore, a race is possible with readers of the
6337 repository; for example an in-progress pull from the repository
6337 repository; for example an in-progress pull from the repository
6338 may fail if a rollback is performed.
6338 may fail if a rollback is performed.
6339
6339
6340 Returns 0 on success, 1 if no rollback data is available.
6340 Returns 0 on success, 1 if no rollback data is available.
6341 """
6341 """
6342 return repo.rollback(dryrun=opts.get('dry_run'),
6342 return repo.rollback(dryrun=opts.get('dry_run'),
6343 force=opts.get('force'))
6343 force=opts.get('force'))
6344
6344
6345 @command('root', [])
6345 @command('root', [])
6346 def root(ui, repo):
6346 def root(ui, repo):
6347 """print the root (top) of the current working directory
6347 """print the root (top) of the current working directory
6348
6348
6349 Print the root directory of the current repository.
6349 Print the root directory of the current repository.
6350
6350
6351 Returns 0 on success.
6351 Returns 0 on success.
6352 """
6352 """
6353 ui.write(repo.root + "\n")
6353 ui.write(repo.root + "\n")
6354
6354
6355 @command('^serve',
6355 @command('^serve',
6356 [('A', 'accesslog', '', _('name of access log file to write to'),
6356 [('A', 'accesslog', '', _('name of access log file to write to'),
6357 _('FILE')),
6357 _('FILE')),
6358 ('d', 'daemon', None, _('run server in background')),
6358 ('d', 'daemon', None, _('run server in background')),
6359 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6359 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6360 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6360 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6361 # use string type, then we can check if something was passed
6361 # use string type, then we can check if something was passed
6362 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6362 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6363 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6363 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6364 _('ADDR')),
6364 _('ADDR')),
6365 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6365 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6366 _('PREFIX')),
6366 _('PREFIX')),
6367 ('n', 'name', '',
6367 ('n', 'name', '',
6368 _('name to show in web pages (default: working directory)'), _('NAME')),
6368 _('name to show in web pages (default: working directory)'), _('NAME')),
6369 ('', 'web-conf', '',
6369 ('', 'web-conf', '',
6370 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6370 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6371 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6371 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6372 _('FILE')),
6372 _('FILE')),
6373 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6373 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6374 ('', 'stdio', None, _('for remote clients')),
6374 ('', 'stdio', None, _('for remote clients')),
6375 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6375 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6376 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6376 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6377 ('', 'style', '', _('template style to use'), _('STYLE')),
6377 ('', 'style', '', _('template style to use'), _('STYLE')),
6378 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6378 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6379 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6379 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6380 _('[OPTION]...'),
6380 _('[OPTION]...'),
6381 optionalrepo=True)
6381 optionalrepo=True)
6382 def serve(ui, repo, **opts):
6382 def serve(ui, repo, **opts):
6383 """start stand-alone webserver
6383 """start stand-alone webserver
6384
6384
6385 Start a local HTTP repository browser and pull server. You can use
6385 Start a local HTTP repository browser and pull server. You can use
6386 this for ad-hoc sharing and browsing of repositories. It is
6386 this for ad-hoc sharing and browsing of repositories. It is
6387 recommended to use a real web server to serve a repository for
6387 recommended to use a real web server to serve a repository for
6388 longer periods of time.
6388 longer periods of time.
6389
6389
6390 Please note that the server does not implement access control.
6390 Please note that the server does not implement access control.
6391 This means that, by default, anybody can read from the server and
6391 This means that, by default, anybody can read from the server and
6392 nobody can write to it by default. Set the ``web.allow_push``
6392 nobody can write to it by default. Set the ``web.allow_push``
6393 option to ``*`` to allow everybody to push to the server. You
6393 option to ``*`` to allow everybody to push to the server. You
6394 should use a real web server if you need to authenticate users.
6394 should use a real web server if you need to authenticate users.
6395
6395
6396 By default, the server logs accesses to stdout and errors to
6396 By default, the server logs accesses to stdout and errors to
6397 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6397 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6398 files.
6398 files.
6399
6399
6400 To have the server choose a free port number to listen on, specify
6400 To have the server choose a free port number to listen on, specify
6401 a port number of 0; in this case, the server will print the port
6401 a port number of 0; in this case, the server will print the port
6402 number it uses.
6402 number it uses.
6403
6403
6404 Returns 0 on success.
6404 Returns 0 on success.
6405 """
6405 """
6406
6406
6407 if opts["stdio"] and opts["cmdserver"]:
6407 if opts["stdio"] and opts["cmdserver"]:
6408 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6408 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6409
6409
6410 if opts["stdio"]:
6410 if opts["stdio"]:
6411 if repo is None:
6411 if repo is None:
6412 raise error.RepoError(_("there is no Mercurial repository here"
6412 raise error.RepoError(_("there is no Mercurial repository here"
6413 " (.hg not found)"))
6413 " (.hg not found)"))
6414 s = sshserver.sshserver(ui, repo)
6414 s = sshserver.sshserver(ui, repo)
6415 s.serve_forever()
6415 s.serve_forever()
6416
6416
6417 if opts["cmdserver"]:
6417 if opts["cmdserver"]:
6418 service = commandserver.createservice(ui, repo, opts)
6418 service = commandserver.createservice(ui, repo, opts)
6419 else:
6419 else:
6420 service = hgweb.createservice(ui, repo, opts)
6420 service = hgweb.createservice(ui, repo, opts)
6421 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6421 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6422
6422
6423 @command('^status|st',
6423 @command('^status|st',
6424 [('A', 'all', None, _('show status of all files')),
6424 [('A', 'all', None, _('show status of all files')),
6425 ('m', 'modified', None, _('show only modified files')),
6425 ('m', 'modified', None, _('show only modified files')),
6426 ('a', 'added', None, _('show only added files')),
6426 ('a', 'added', None, _('show only added files')),
6427 ('r', 'removed', None, _('show only removed files')),
6427 ('r', 'removed', None, _('show only removed files')),
6428 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6428 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6429 ('c', 'clean', None, _('show only files without changes')),
6429 ('c', 'clean', None, _('show only files without changes')),
6430 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6430 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6431 ('i', 'ignored', None, _('show only ignored files')),
6431 ('i', 'ignored', None, _('show only ignored files')),
6432 ('n', 'no-status', None, _('hide status prefix')),
6432 ('n', 'no-status', None, _('hide status prefix')),
6433 ('C', 'copies', None, _('show source of copied files')),
6433 ('C', 'copies', None, _('show source of copied files')),
6434 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6434 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6435 ('', 'rev', [], _('show difference from revision'), _('REV')),
6435 ('', 'rev', [], _('show difference from revision'), _('REV')),
6436 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6436 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6437 ] + walkopts + subrepoopts + formatteropts,
6437 ] + walkopts + subrepoopts + formatteropts,
6438 _('[OPTION]... [FILE]...'),
6438 _('[OPTION]... [FILE]...'),
6439 inferrepo=True)
6439 inferrepo=True)
6440 def status(ui, repo, *pats, **opts):
6440 def status(ui, repo, *pats, **opts):
6441 """show changed files in the working directory
6441 """show changed files in the working directory
6442
6442
6443 Show status of files in the repository. If names are given, only
6443 Show status of files in the repository. If names are given, only
6444 files that match are shown. Files that are clean or ignored or
6444 files that match are shown. Files that are clean or ignored or
6445 the source of a copy/move operation, are not listed unless
6445 the source of a copy/move operation, are not listed unless
6446 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6446 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6447 Unless options described with "show only ..." are given, the
6447 Unless options described with "show only ..." are given, the
6448 options -mardu are used.
6448 options -mardu are used.
6449
6449
6450 Option -q/--quiet hides untracked (unknown and ignored) files
6450 Option -q/--quiet hides untracked (unknown and ignored) files
6451 unless explicitly requested with -u/--unknown or -i/--ignored.
6451 unless explicitly requested with -u/--unknown or -i/--ignored.
6452
6452
6453 .. note::
6453 .. note::
6454
6454
6455 :hg:`status` may appear to disagree with diff if permissions have
6455 :hg:`status` may appear to disagree with diff if permissions have
6456 changed or a merge has occurred. The standard diff format does
6456 changed or a merge has occurred. The standard diff format does
6457 not report permission changes and diff only reports changes
6457 not report permission changes and diff only reports changes
6458 relative to one merge parent.
6458 relative to one merge parent.
6459
6459
6460 If one revision is given, it is used as the base revision.
6460 If one revision is given, it is used as the base revision.
6461 If two revisions are given, the differences between them are
6461 If two revisions are given, the differences between them are
6462 shown. The --change option can also be used as a shortcut to list
6462 shown. The --change option can also be used as a shortcut to list
6463 the changed files of a revision from its first parent.
6463 the changed files of a revision from its first parent.
6464
6464
6465 The codes used to show the status of files are::
6465 The codes used to show the status of files are::
6466
6466
6467 M = modified
6467 M = modified
6468 A = added
6468 A = added
6469 R = removed
6469 R = removed
6470 C = clean
6470 C = clean
6471 ! = missing (deleted by non-hg command, but still tracked)
6471 ! = missing (deleted by non-hg command, but still tracked)
6472 ? = not tracked
6472 ? = not tracked
6473 I = ignored
6473 I = ignored
6474 = origin of the previous file (with --copies)
6474 = origin of the previous file (with --copies)
6475
6475
6476 .. container:: verbose
6476 .. container:: verbose
6477
6477
6478 Examples:
6478 Examples:
6479
6479
6480 - show changes in the working directory relative to a
6480 - show changes in the working directory relative to a
6481 changeset::
6481 changeset::
6482
6482
6483 hg status --rev 9353
6483 hg status --rev 9353
6484
6484
6485 - show changes in the working directory relative to the
6485 - show changes in the working directory relative to the
6486 current directory (see :hg:`help patterns` for more information)::
6486 current directory (see :hg:`help patterns` for more information)::
6487
6487
6488 hg status re:
6488 hg status re:
6489
6489
6490 - show all changes including copies in an existing changeset::
6490 - show all changes including copies in an existing changeset::
6491
6491
6492 hg status --copies --change 9353
6492 hg status --copies --change 9353
6493
6493
6494 - get a NUL separated list of added files, suitable for xargs::
6494 - get a NUL separated list of added files, suitable for xargs::
6495
6495
6496 hg status -an0
6496 hg status -an0
6497
6497
6498 Returns 0 on success.
6498 Returns 0 on success.
6499 """
6499 """
6500
6500
6501 revs = opts.get('rev')
6501 revs = opts.get('rev')
6502 change = opts.get('change')
6502 change = opts.get('change')
6503
6503
6504 if revs and change:
6504 if revs and change:
6505 msg = _('cannot specify --rev and --change at the same time')
6505 msg = _('cannot specify --rev and --change at the same time')
6506 raise error.Abort(msg)
6506 raise error.Abort(msg)
6507 elif change:
6507 elif change:
6508 node2 = scmutil.revsingle(repo, change, None).node()
6508 node2 = scmutil.revsingle(repo, change, None).node()
6509 node1 = repo[node2].p1().node()
6509 node1 = repo[node2].p1().node()
6510 else:
6510 else:
6511 node1, node2 = scmutil.revpair(repo, revs)
6511 node1, node2 = scmutil.revpair(repo, revs)
6512
6512
6513 if pats:
6513 if pats:
6514 cwd = repo.getcwd()
6514 cwd = repo.getcwd()
6515 else:
6515 else:
6516 cwd = ''
6516 cwd = ''
6517
6517
6518 if opts.get('print0'):
6518 if opts.get('print0'):
6519 end = '\0'
6519 end = '\0'
6520 else:
6520 else:
6521 end = '\n'
6521 end = '\n'
6522 copy = {}
6522 copy = {}
6523 states = 'modified added removed deleted unknown ignored clean'.split()
6523 states = 'modified added removed deleted unknown ignored clean'.split()
6524 show = [k for k in states if opts.get(k)]
6524 show = [k for k in states if opts.get(k)]
6525 if opts.get('all'):
6525 if opts.get('all'):
6526 show += ui.quiet and (states[:4] + ['clean']) or states
6526 show += ui.quiet and (states[:4] + ['clean']) or states
6527 if not show:
6527 if not show:
6528 if ui.quiet:
6528 if ui.quiet:
6529 show = states[:4]
6529 show = states[:4]
6530 else:
6530 else:
6531 show = states[:5]
6531 show = states[:5]
6532
6532
6533 m = scmutil.match(repo[node2], pats, opts)
6533 m = scmutil.match(repo[node2], pats, opts)
6534 stat = repo.status(node1, node2, m,
6534 stat = repo.status(node1, node2, m,
6535 'ignored' in show, 'clean' in show, 'unknown' in show,
6535 'ignored' in show, 'clean' in show, 'unknown' in show,
6536 opts.get('subrepos'))
6536 opts.get('subrepos'))
6537 changestates = zip(states, 'MAR!?IC', stat)
6537 changestates = zip(states, 'MAR!?IC', stat)
6538
6538
6539 if (opts.get('all') or opts.get('copies')
6539 if (opts.get('all') or opts.get('copies')
6540 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6540 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6541 copy = copies.pathcopies(repo[node1], repo[node2], m)
6541 copy = copies.pathcopies(repo[node1], repo[node2], m)
6542
6542
6543 fm = ui.formatter('status', opts)
6543 fm = ui.formatter('status', opts)
6544 fmt = '%s' + end
6544 fmt = '%s' + end
6545 showchar = not opts.get('no_status')
6545 showchar = not opts.get('no_status')
6546
6546
6547 for state, char, files in changestates:
6547 for state, char, files in changestates:
6548 if state in show:
6548 if state in show:
6549 label = 'status.' + state
6549 label = 'status.' + state
6550 for f in files:
6550 for f in files:
6551 fm.startitem()
6551 fm.startitem()
6552 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6552 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6553 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6553 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6554 if f in copy:
6554 if f in copy:
6555 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6555 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6556 label='status.copied')
6556 label='status.copied')
6557 fm.end()
6557 fm.end()
6558
6558
6559 @command('^summary|sum',
6559 @command('^summary|sum',
6560 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6560 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6561 def summary(ui, repo, **opts):
6561 def summary(ui, repo, **opts):
6562 """summarize working directory state
6562 """summarize working directory state
6563
6563
6564 This generates a brief summary of the working directory state,
6564 This generates a brief summary of the working directory state,
6565 including parents, branch, commit status, phase and available updates.
6565 including parents, branch, commit status, phase and available updates.
6566
6566
6567 With the --remote option, this will check the default paths for
6567 With the --remote option, this will check the default paths for
6568 incoming and outgoing changes. This can be time-consuming.
6568 incoming and outgoing changes. This can be time-consuming.
6569
6569
6570 Returns 0 on success.
6570 Returns 0 on success.
6571 """
6571 """
6572
6572
6573 ctx = repo[None]
6573 ctx = repo[None]
6574 parents = ctx.parents()
6574 parents = ctx.parents()
6575 pnode = parents[0].node()
6575 pnode = parents[0].node()
6576 marks = []
6576 marks = []
6577
6577
6578 for p in parents:
6578 for p in parents:
6579 # label with log.changeset (instead of log.parent) since this
6579 # label with log.changeset (instead of log.parent) since this
6580 # shows a working directory parent *changeset*:
6580 # shows a working directory parent *changeset*:
6581 # i18n: column positioning for "hg summary"
6581 # i18n: column positioning for "hg summary"
6582 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6582 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6583 label='log.changeset changeset.%s' % p.phasestr())
6583 label='log.changeset changeset.%s' % p.phasestr())
6584 ui.write(' '.join(p.tags()), label='log.tag')
6584 ui.write(' '.join(p.tags()), label='log.tag')
6585 if p.bookmarks():
6585 if p.bookmarks():
6586 marks.extend(p.bookmarks())
6586 marks.extend(p.bookmarks())
6587 if p.rev() == -1:
6587 if p.rev() == -1:
6588 if not len(repo):
6588 if not len(repo):
6589 ui.write(_(' (empty repository)'))
6589 ui.write(_(' (empty repository)'))
6590 else:
6590 else:
6591 ui.write(_(' (no revision checked out)'))
6591 ui.write(_(' (no revision checked out)'))
6592 ui.write('\n')
6592 ui.write('\n')
6593 if p.description():
6593 if p.description():
6594 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6594 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6595 label='log.summary')
6595 label='log.summary')
6596
6596
6597 branch = ctx.branch()
6597 branch = ctx.branch()
6598 bheads = repo.branchheads(branch)
6598 bheads = repo.branchheads(branch)
6599 # i18n: column positioning for "hg summary"
6599 # i18n: column positioning for "hg summary"
6600 m = _('branch: %s\n') % branch
6600 m = _('branch: %s\n') % branch
6601 if branch != 'default':
6601 if branch != 'default':
6602 ui.write(m, label='log.branch')
6602 ui.write(m, label='log.branch')
6603 else:
6603 else:
6604 ui.status(m, label='log.branch')
6604 ui.status(m, label='log.branch')
6605
6605
6606 if marks:
6606 if marks:
6607 active = repo._activebookmark
6607 active = repo._activebookmark
6608 # i18n: column positioning for "hg summary"
6608 # i18n: column positioning for "hg summary"
6609 ui.write(_('bookmarks:'), label='log.bookmark')
6609 ui.write(_('bookmarks:'), label='log.bookmark')
6610 if active is not None:
6610 if active is not None:
6611 if active in marks:
6611 if active in marks:
6612 ui.write(' *' + active, label=activebookmarklabel)
6612 ui.write(' *' + active, label=activebookmarklabel)
6613 marks.remove(active)
6613 marks.remove(active)
6614 else:
6614 else:
6615 ui.write(' [%s]' % active, label=activebookmarklabel)
6615 ui.write(' [%s]' % active, label=activebookmarklabel)
6616 for m in marks:
6616 for m in marks:
6617 ui.write(' ' + m, label='log.bookmark')
6617 ui.write(' ' + m, label='log.bookmark')
6618 ui.write('\n', label='log.bookmark')
6618 ui.write('\n', label='log.bookmark')
6619
6619
6620 status = repo.status(unknown=True)
6620 status = repo.status(unknown=True)
6621
6621
6622 c = repo.dirstate.copies()
6622 c = repo.dirstate.copies()
6623 copied, renamed = [], []
6623 copied, renamed = [], []
6624 for d, s in c.iteritems():
6624 for d, s in c.iteritems():
6625 if s in status.removed:
6625 if s in status.removed:
6626 status.removed.remove(s)
6626 status.removed.remove(s)
6627 renamed.append(d)
6627 renamed.append(d)
6628 else:
6628 else:
6629 copied.append(d)
6629 copied.append(d)
6630 if d in status.added:
6630 if d in status.added:
6631 status.added.remove(d)
6631 status.added.remove(d)
6632
6632
6633 try:
6633 try:
6634 ms = mergemod.mergestate.read(repo)
6634 ms = mergemod.mergestate.read(repo)
6635 except error.UnsupportedMergeRecords as e:
6635 except error.UnsupportedMergeRecords as e:
6636 s = ' '.join(e.recordtypes)
6636 s = ' '.join(e.recordtypes)
6637 ui.warn(
6637 ui.warn(
6638 _('warning: merge state has unsupported record types: %s\n') % s)
6638 _('warning: merge state has unsupported record types: %s\n') % s)
6639 unresolved = 0
6639 unresolved = 0
6640 else:
6640 else:
6641 unresolved = [f for f in ms if ms[f] == 'u']
6641 unresolved = [f for f in ms if ms[f] == 'u']
6642
6642
6643 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6643 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6644
6644
6645 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6645 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6646 (ui.label(_('%d added'), 'status.added'), status.added),
6646 (ui.label(_('%d added'), 'status.added'), status.added),
6647 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6647 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6648 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6648 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6649 (ui.label(_('%d copied'), 'status.copied'), copied),
6649 (ui.label(_('%d copied'), 'status.copied'), copied),
6650 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6650 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6651 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6651 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6652 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6652 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6653 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6653 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6654 t = []
6654 t = []
6655 for l, s in labels:
6655 for l, s in labels:
6656 if s:
6656 if s:
6657 t.append(l % len(s))
6657 t.append(l % len(s))
6658
6658
6659 t = ', '.join(t)
6659 t = ', '.join(t)
6660 cleanworkdir = False
6660 cleanworkdir = False
6661
6661
6662 if repo.vfs.exists('graftstate'):
6662 if repo.vfs.exists('graftstate'):
6663 t += _(' (graft in progress)')
6663 t += _(' (graft in progress)')
6664 if repo.vfs.exists('updatestate'):
6664 if repo.vfs.exists('updatestate'):
6665 t += _(' (interrupted update)')
6665 t += _(' (interrupted update)')
6666 elif len(parents) > 1:
6666 elif len(parents) > 1:
6667 t += _(' (merge)')
6667 t += _(' (merge)')
6668 elif branch != parents[0].branch():
6668 elif branch != parents[0].branch():
6669 t += _(' (new branch)')
6669 t += _(' (new branch)')
6670 elif (parents[0].closesbranch() and
6670 elif (parents[0].closesbranch() and
6671 pnode in repo.branchheads(branch, closed=True)):
6671 pnode in repo.branchheads(branch, closed=True)):
6672 t += _(' (head closed)')
6672 t += _(' (head closed)')
6673 elif not (status.modified or status.added or status.removed or renamed or
6673 elif not (status.modified or status.added or status.removed or renamed or
6674 copied or subs):
6674 copied or subs):
6675 t += _(' (clean)')
6675 t += _(' (clean)')
6676 cleanworkdir = True
6676 cleanworkdir = True
6677 elif pnode not in bheads:
6677 elif pnode not in bheads:
6678 t += _(' (new branch head)')
6678 t += _(' (new branch head)')
6679
6679
6680 if parents:
6680 if parents:
6681 pendingphase = max(p.phase() for p in parents)
6681 pendingphase = max(p.phase() for p in parents)
6682 else:
6682 else:
6683 pendingphase = phases.public
6683 pendingphase = phases.public
6684
6684
6685 if pendingphase > phases.newcommitphase(ui):
6685 if pendingphase > phases.newcommitphase(ui):
6686 t += ' (%s)' % phases.phasenames[pendingphase]
6686 t += ' (%s)' % phases.phasenames[pendingphase]
6687
6687
6688 if cleanworkdir:
6688 if cleanworkdir:
6689 # i18n: column positioning for "hg summary"
6689 # i18n: column positioning for "hg summary"
6690 ui.status(_('commit: %s\n') % t.strip())
6690 ui.status(_('commit: %s\n') % t.strip())
6691 else:
6691 else:
6692 # i18n: column positioning for "hg summary"
6692 # i18n: column positioning for "hg summary"
6693 ui.write(_('commit: %s\n') % t.strip())
6693 ui.write(_('commit: %s\n') % t.strip())
6694
6694
6695 # all ancestors of branch heads - all ancestors of parent = new csets
6695 # all ancestors of branch heads - all ancestors of parent = new csets
6696 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6696 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6697 bheads))
6697 bheads))
6698
6698
6699 if new == 0:
6699 if new == 0:
6700 # i18n: column positioning for "hg summary"
6700 # i18n: column positioning for "hg summary"
6701 ui.status(_('update: (current)\n'))
6701 ui.status(_('update: (current)\n'))
6702 elif pnode not in bheads:
6702 elif pnode not in bheads:
6703 # i18n: column positioning for "hg summary"
6703 # i18n: column positioning for "hg summary"
6704 ui.write(_('update: %d new changesets (update)\n') % new)
6704 ui.write(_('update: %d new changesets (update)\n') % new)
6705 else:
6705 else:
6706 # i18n: column positioning for "hg summary"
6706 # i18n: column positioning for "hg summary"
6707 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6707 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6708 (new, len(bheads)))
6708 (new, len(bheads)))
6709
6709
6710 t = []
6710 t = []
6711 draft = len(repo.revs('draft()'))
6711 draft = len(repo.revs('draft()'))
6712 if draft:
6712 if draft:
6713 t.append(_('%d draft') % draft)
6713 t.append(_('%d draft') % draft)
6714 secret = len(repo.revs('secret()'))
6714 secret = len(repo.revs('secret()'))
6715 if secret:
6715 if secret:
6716 t.append(_('%d secret') % secret)
6716 t.append(_('%d secret') % secret)
6717
6717
6718 if draft or secret:
6718 if draft or secret:
6719 ui.status(_('phases: %s\n') % ', '.join(t))
6719 ui.status(_('phases: %s\n') % ', '.join(t))
6720
6720
6721 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6721 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6722 for trouble in ("unstable", "divergent", "bumped"):
6722 for trouble in ("unstable", "divergent", "bumped"):
6723 numtrouble = len(repo.revs(trouble + "()"))
6723 numtrouble = len(repo.revs(trouble + "()"))
6724 # We write all the possibilities to ease translation
6724 # We write all the possibilities to ease translation
6725 troublemsg = {
6725 troublemsg = {
6726 "unstable": _("unstable: %d changesets"),
6726 "unstable": _("unstable: %d changesets"),
6727 "divergent": _("divergent: %d changesets"),
6727 "divergent": _("divergent: %d changesets"),
6728 "bumped": _("bumped: %d changesets"),
6728 "bumped": _("bumped: %d changesets"),
6729 }
6729 }
6730 if numtrouble > 0:
6730 if numtrouble > 0:
6731 ui.status(troublemsg[trouble] % numtrouble + "\n")
6731 ui.status(troublemsg[trouble] % numtrouble + "\n")
6732
6732
6733 cmdutil.summaryhooks(ui, repo)
6733 cmdutil.summaryhooks(ui, repo)
6734
6734
6735 if opts.get('remote'):
6735 if opts.get('remote'):
6736 needsincoming, needsoutgoing = True, True
6736 needsincoming, needsoutgoing = True, True
6737 else:
6737 else:
6738 needsincoming, needsoutgoing = False, False
6738 needsincoming, needsoutgoing = False, False
6739 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6739 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6740 if i:
6740 if i:
6741 needsincoming = True
6741 needsincoming = True
6742 if o:
6742 if o:
6743 needsoutgoing = True
6743 needsoutgoing = True
6744 if not needsincoming and not needsoutgoing:
6744 if not needsincoming and not needsoutgoing:
6745 return
6745 return
6746
6746
6747 def getincoming():
6747 def getincoming():
6748 source, branches = hg.parseurl(ui.expandpath('default'))
6748 source, branches = hg.parseurl(ui.expandpath('default'))
6749 sbranch = branches[0]
6749 sbranch = branches[0]
6750 try:
6750 try:
6751 other = hg.peer(repo, {}, source)
6751 other = hg.peer(repo, {}, source)
6752 except error.RepoError:
6752 except error.RepoError:
6753 if opts.get('remote'):
6753 if opts.get('remote'):
6754 raise
6754 raise
6755 return source, sbranch, None, None, None
6755 return source, sbranch, None, None, None
6756 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6756 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6757 if revs:
6757 if revs:
6758 revs = [other.lookup(rev) for rev in revs]
6758 revs = [other.lookup(rev) for rev in revs]
6759 ui.debug('comparing with %s\n' % util.hidepassword(source))
6759 ui.debug('comparing with %s\n' % util.hidepassword(source))
6760 repo.ui.pushbuffer()
6760 repo.ui.pushbuffer()
6761 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6761 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6762 repo.ui.popbuffer()
6762 repo.ui.popbuffer()
6763 return source, sbranch, other, commoninc, commoninc[1]
6763 return source, sbranch, other, commoninc, commoninc[1]
6764
6764
6765 if needsincoming:
6765 if needsincoming:
6766 source, sbranch, sother, commoninc, incoming = getincoming()
6766 source, sbranch, sother, commoninc, incoming = getincoming()
6767 else:
6767 else:
6768 source = sbranch = sother = commoninc = incoming = None
6768 source = sbranch = sother = commoninc = incoming = None
6769
6769
6770 def getoutgoing():
6770 def getoutgoing():
6771 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6771 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6772 dbranch = branches[0]
6772 dbranch = branches[0]
6773 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6773 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6774 if source != dest:
6774 if source != dest:
6775 try:
6775 try:
6776 dother = hg.peer(repo, {}, dest)
6776 dother = hg.peer(repo, {}, dest)
6777 except error.RepoError:
6777 except error.RepoError:
6778 if opts.get('remote'):
6778 if opts.get('remote'):
6779 raise
6779 raise
6780 return dest, dbranch, None, None
6780 return dest, dbranch, None, None
6781 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6781 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6782 elif sother is None:
6782 elif sother is None:
6783 # there is no explicit destination peer, but source one is invalid
6783 # there is no explicit destination peer, but source one is invalid
6784 return dest, dbranch, None, None
6784 return dest, dbranch, None, None
6785 else:
6785 else:
6786 dother = sother
6786 dother = sother
6787 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6787 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6788 common = None
6788 common = None
6789 else:
6789 else:
6790 common = commoninc
6790 common = commoninc
6791 if revs:
6791 if revs:
6792 revs = [repo.lookup(rev) for rev in revs]
6792 revs = [repo.lookup(rev) for rev in revs]
6793 repo.ui.pushbuffer()
6793 repo.ui.pushbuffer()
6794 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6794 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6795 commoninc=common)
6795 commoninc=common)
6796 repo.ui.popbuffer()
6796 repo.ui.popbuffer()
6797 return dest, dbranch, dother, outgoing
6797 return dest, dbranch, dother, outgoing
6798
6798
6799 if needsoutgoing:
6799 if needsoutgoing:
6800 dest, dbranch, dother, outgoing = getoutgoing()
6800 dest, dbranch, dother, outgoing = getoutgoing()
6801 else:
6801 else:
6802 dest = dbranch = dother = outgoing = None
6802 dest = dbranch = dother = outgoing = None
6803
6803
6804 if opts.get('remote'):
6804 if opts.get('remote'):
6805 t = []
6805 t = []
6806 if incoming:
6806 if incoming:
6807 t.append(_('1 or more incoming'))
6807 t.append(_('1 or more incoming'))
6808 o = outgoing.missing
6808 o = outgoing.missing
6809 if o:
6809 if o:
6810 t.append(_('%d outgoing') % len(o))
6810 t.append(_('%d outgoing') % len(o))
6811 other = dother or sother
6811 other = dother or sother
6812 if 'bookmarks' in other.listkeys('namespaces'):
6812 if 'bookmarks' in other.listkeys('namespaces'):
6813 counts = bookmarks.summary(repo, other)
6813 counts = bookmarks.summary(repo, other)
6814 if counts[0] > 0:
6814 if counts[0] > 0:
6815 t.append(_('%d incoming bookmarks') % counts[0])
6815 t.append(_('%d incoming bookmarks') % counts[0])
6816 if counts[1] > 0:
6816 if counts[1] > 0:
6817 t.append(_('%d outgoing bookmarks') % counts[1])
6817 t.append(_('%d outgoing bookmarks') % counts[1])
6818
6818
6819 if t:
6819 if t:
6820 # i18n: column positioning for "hg summary"
6820 # i18n: column positioning for "hg summary"
6821 ui.write(_('remote: %s\n') % (', '.join(t)))
6821 ui.write(_('remote: %s\n') % (', '.join(t)))
6822 else:
6822 else:
6823 # i18n: column positioning for "hg summary"
6823 # i18n: column positioning for "hg summary"
6824 ui.status(_('remote: (synced)\n'))
6824 ui.status(_('remote: (synced)\n'))
6825
6825
6826 cmdutil.summaryremotehooks(ui, repo, opts,
6826 cmdutil.summaryremotehooks(ui, repo, opts,
6827 ((source, sbranch, sother, commoninc),
6827 ((source, sbranch, sother, commoninc),
6828 (dest, dbranch, dother, outgoing)))
6828 (dest, dbranch, dother, outgoing)))
6829
6829
6830 @command('tag',
6830 @command('tag',
6831 [('f', 'force', None, _('force tag')),
6831 [('f', 'force', None, _('force tag')),
6832 ('l', 'local', None, _('make the tag local')),
6832 ('l', 'local', None, _('make the tag local')),
6833 ('r', 'rev', '', _('revision to tag'), _('REV')),
6833 ('r', 'rev', '', _('revision to tag'), _('REV')),
6834 ('', 'remove', None, _('remove a tag')),
6834 ('', 'remove', None, _('remove a tag')),
6835 # -l/--local is already there, commitopts cannot be used
6835 # -l/--local is already there, commitopts cannot be used
6836 ('e', 'edit', None, _('invoke editor on commit messages')),
6836 ('e', 'edit', None, _('invoke editor on commit messages')),
6837 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6837 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6838 ] + commitopts2,
6838 ] + commitopts2,
6839 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6839 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6840 def tag(ui, repo, name1, *names, **opts):
6840 def tag(ui, repo, name1, *names, **opts):
6841 """add one or more tags for the current or given revision
6841 """add one or more tags for the current or given revision
6842
6842
6843 Name a particular revision using <name>.
6843 Name a particular revision using <name>.
6844
6844
6845 Tags are used to name particular revisions of the repository and are
6845 Tags are used to name particular revisions of the repository and are
6846 very useful to compare different revisions, to go back to significant
6846 very useful to compare different revisions, to go back to significant
6847 earlier versions or to mark branch points as releases, etc. Changing
6847 earlier versions or to mark branch points as releases, etc. Changing
6848 an existing tag is normally disallowed; use -f/--force to override.
6848 an existing tag is normally disallowed; use -f/--force to override.
6849
6849
6850 If no revision is given, the parent of the working directory is
6850 If no revision is given, the parent of the working directory is
6851 used.
6851 used.
6852
6852
6853 To facilitate version control, distribution, and merging of tags,
6853 To facilitate version control, distribution, and merging of tags,
6854 they are stored as a file named ".hgtags" which is managed similarly
6854 they are stored as a file named ".hgtags" which is managed similarly
6855 to other project files and can be hand-edited if necessary. This
6855 to other project files and can be hand-edited if necessary. This
6856 also means that tagging creates a new commit. The file
6856 also means that tagging creates a new commit. The file
6857 ".hg/localtags" is used for local tags (not shared among
6857 ".hg/localtags" is used for local tags (not shared among
6858 repositories).
6858 repositories).
6859
6859
6860 Tag commits are usually made at the head of a branch. If the parent
6860 Tag commits are usually made at the head of a branch. If the parent
6861 of the working directory is not a branch head, :hg:`tag` aborts; use
6861 of the working directory is not a branch head, :hg:`tag` aborts; use
6862 -f/--force to force the tag commit to be based on a non-head
6862 -f/--force to force the tag commit to be based on a non-head
6863 changeset.
6863 changeset.
6864
6864
6865 See :hg:`help dates` for a list of formats valid for -d/--date.
6865 See :hg:`help dates` for a list of formats valid for -d/--date.
6866
6866
6867 Since tag names have priority over branch names during revision
6867 Since tag names have priority over branch names during revision
6868 lookup, using an existing branch name as a tag name is discouraged.
6868 lookup, using an existing branch name as a tag name is discouraged.
6869
6869
6870 Returns 0 on success.
6870 Returns 0 on success.
6871 """
6871 """
6872 wlock = lock = None
6872 wlock = lock = None
6873 try:
6873 try:
6874 wlock = repo.wlock()
6874 wlock = repo.wlock()
6875 lock = repo.lock()
6875 lock = repo.lock()
6876 rev_ = "."
6876 rev_ = "."
6877 names = [t.strip() for t in (name1,) + names]
6877 names = [t.strip() for t in (name1,) + names]
6878 if len(names) != len(set(names)):
6878 if len(names) != len(set(names)):
6879 raise error.Abort(_('tag names must be unique'))
6879 raise error.Abort(_('tag names must be unique'))
6880 for n in names:
6880 for n in names:
6881 scmutil.checknewlabel(repo, n, 'tag')
6881 scmutil.checknewlabel(repo, n, 'tag')
6882 if not n:
6882 if not n:
6883 raise error.Abort(_('tag names cannot consist entirely of '
6883 raise error.Abort(_('tag names cannot consist entirely of '
6884 'whitespace'))
6884 'whitespace'))
6885 if opts.get('rev') and opts.get('remove'):
6885 if opts.get('rev') and opts.get('remove'):
6886 raise error.Abort(_("--rev and --remove are incompatible"))
6886 raise error.Abort(_("--rev and --remove are incompatible"))
6887 if opts.get('rev'):
6887 if opts.get('rev'):
6888 rev_ = opts['rev']
6888 rev_ = opts['rev']
6889 message = opts.get('message')
6889 message = opts.get('message')
6890 if opts.get('remove'):
6890 if opts.get('remove'):
6891 if opts.get('local'):
6891 if opts.get('local'):
6892 expectedtype = 'local'
6892 expectedtype = 'local'
6893 else:
6893 else:
6894 expectedtype = 'global'
6894 expectedtype = 'global'
6895
6895
6896 for n in names:
6896 for n in names:
6897 if not repo.tagtype(n):
6897 if not repo.tagtype(n):
6898 raise error.Abort(_("tag '%s' does not exist") % n)
6898 raise error.Abort(_("tag '%s' does not exist") % n)
6899 if repo.tagtype(n) != expectedtype:
6899 if repo.tagtype(n) != expectedtype:
6900 if expectedtype == 'global':
6900 if expectedtype == 'global':
6901 raise error.Abort(_("tag '%s' is not a global tag") % n)
6901 raise error.Abort(_("tag '%s' is not a global tag") % n)
6902 else:
6902 else:
6903 raise error.Abort(_("tag '%s' is not a local tag") % n)
6903 raise error.Abort(_("tag '%s' is not a local tag") % n)
6904 rev_ = 'null'
6904 rev_ = 'null'
6905 if not message:
6905 if not message:
6906 # we don't translate commit messages
6906 # we don't translate commit messages
6907 message = 'Removed tag %s' % ', '.join(names)
6907 message = 'Removed tag %s' % ', '.join(names)
6908 elif not opts.get('force'):
6908 elif not opts.get('force'):
6909 for n in names:
6909 for n in names:
6910 if n in repo.tags():
6910 if n in repo.tags():
6911 raise error.Abort(_("tag '%s' already exists "
6911 raise error.Abort(_("tag '%s' already exists "
6912 "(use -f to force)") % n)
6912 "(use -f to force)") % n)
6913 if not opts.get('local'):
6913 if not opts.get('local'):
6914 p1, p2 = repo.dirstate.parents()
6914 p1, p2 = repo.dirstate.parents()
6915 if p2 != nullid:
6915 if p2 != nullid:
6916 raise error.Abort(_('uncommitted merge'))
6916 raise error.Abort(_('uncommitted merge'))
6917 bheads = repo.branchheads()
6917 bheads = repo.branchheads()
6918 if not opts.get('force') and bheads and p1 not in bheads:
6918 if not opts.get('force') and bheads and p1 not in bheads:
6919 raise error.Abort(_('not at a branch head (use -f to force)'))
6919 raise error.Abort(_('not at a branch head (use -f to force)'))
6920 r = scmutil.revsingle(repo, rev_).node()
6920 r = scmutil.revsingle(repo, rev_).node()
6921
6921
6922 if not message:
6922 if not message:
6923 # we don't translate commit messages
6923 # we don't translate commit messages
6924 message = ('Added tag %s for changeset %s' %
6924 message = ('Added tag %s for changeset %s' %
6925 (', '.join(names), short(r)))
6925 (', '.join(names), short(r)))
6926
6926
6927 date = opts.get('date')
6927 date = opts.get('date')
6928 if date:
6928 if date:
6929 date = util.parsedate(date)
6929 date = util.parsedate(date)
6930
6930
6931 if opts.get('remove'):
6931 if opts.get('remove'):
6932 editform = 'tag.remove'
6932 editform = 'tag.remove'
6933 else:
6933 else:
6934 editform = 'tag.add'
6934 editform = 'tag.add'
6935 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6935 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6936
6936
6937 # don't allow tagging the null rev
6937 # don't allow tagging the null rev
6938 if (not opts.get('remove') and
6938 if (not opts.get('remove') and
6939 scmutil.revsingle(repo, rev_).rev() == nullrev):
6939 scmutil.revsingle(repo, rev_).rev() == nullrev):
6940 raise error.Abort(_("cannot tag null revision"))
6940 raise error.Abort(_("cannot tag null revision"))
6941
6941
6942 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6942 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6943 editor=editor)
6943 editor=editor)
6944 finally:
6944 finally:
6945 release(lock, wlock)
6945 release(lock, wlock)
6946
6946
6947 @command('tags', formatteropts, '')
6947 @command('tags', formatteropts, '')
6948 def tags(ui, repo, **opts):
6948 def tags(ui, repo, **opts):
6949 """list repository tags
6949 """list repository tags
6950
6950
6951 This lists both regular and local tags. When the -v/--verbose
6951 This lists both regular and local tags. When the -v/--verbose
6952 switch is used, a third column "local" is printed for local tags.
6952 switch is used, a third column "local" is printed for local tags.
6953 When the -q/--quiet switch is used, only the tag name is printed.
6953 When the -q/--quiet switch is used, only the tag name is printed.
6954
6954
6955 Returns 0 on success.
6955 Returns 0 on success.
6956 """
6956 """
6957
6957
6958 fm = ui.formatter('tags', opts)
6958 fm = ui.formatter('tags', opts)
6959 hexfunc = fm.hexfunc
6959 hexfunc = fm.hexfunc
6960 tagtype = ""
6960 tagtype = ""
6961
6961
6962 for t, n in reversed(repo.tagslist()):
6962 for t, n in reversed(repo.tagslist()):
6963 hn = hexfunc(n)
6963 hn = hexfunc(n)
6964 label = 'tags.normal'
6964 label = 'tags.normal'
6965 tagtype = ''
6965 tagtype = ''
6966 if repo.tagtype(t) == 'local':
6966 if repo.tagtype(t) == 'local':
6967 label = 'tags.local'
6967 label = 'tags.local'
6968 tagtype = 'local'
6968 tagtype = 'local'
6969
6969
6970 fm.startitem()
6970 fm.startitem()
6971 fm.write('tag', '%s', t, label=label)
6971 fm.write('tag', '%s', t, label=label)
6972 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6972 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6973 fm.condwrite(not ui.quiet, 'rev node', fmt,
6973 fm.condwrite(not ui.quiet, 'rev node', fmt,
6974 repo.changelog.rev(n), hn, label=label)
6974 repo.changelog.rev(n), hn, label=label)
6975 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6975 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6976 tagtype, label=label)
6976 tagtype, label=label)
6977 fm.plain('\n')
6977 fm.plain('\n')
6978 fm.end()
6978 fm.end()
6979
6979
6980 @command('tip',
6980 @command('tip',
6981 [('p', 'patch', None, _('show patch')),
6981 [('p', 'patch', None, _('show patch')),
6982 ('g', 'git', None, _('use git extended diff format')),
6982 ('g', 'git', None, _('use git extended diff format')),
6983 ] + templateopts,
6983 ] + templateopts,
6984 _('[-p] [-g]'))
6984 _('[-p] [-g]'))
6985 def tip(ui, repo, **opts):
6985 def tip(ui, repo, **opts):
6986 """show the tip revision (DEPRECATED)
6986 """show the tip revision (DEPRECATED)
6987
6987
6988 The tip revision (usually just called the tip) is the changeset
6988 The tip revision (usually just called the tip) is the changeset
6989 most recently added to the repository (and therefore the most
6989 most recently added to the repository (and therefore the most
6990 recently changed head).
6990 recently changed head).
6991
6991
6992 If you have just made a commit, that commit will be the tip. If
6992 If you have just made a commit, that commit will be the tip. If
6993 you have just pulled changes from another repository, the tip of
6993 you have just pulled changes from another repository, the tip of
6994 that repository becomes the current tip. The "tip" tag is special
6994 that repository becomes the current tip. The "tip" tag is special
6995 and cannot be renamed or assigned to a different changeset.
6995 and cannot be renamed or assigned to a different changeset.
6996
6996
6997 This command is deprecated, please use :hg:`heads` instead.
6997 This command is deprecated, please use :hg:`heads` instead.
6998
6998
6999 Returns 0 on success.
6999 Returns 0 on success.
7000 """
7000 """
7001 displayer = cmdutil.show_changeset(ui, repo, opts)
7001 displayer = cmdutil.show_changeset(ui, repo, opts)
7002 displayer.show(repo['tip'])
7002 displayer.show(repo['tip'])
7003 displayer.close()
7003 displayer.close()
7004
7004
7005 @command('unbundle',
7005 @command('unbundle',
7006 [('u', 'update', None,
7006 [('u', 'update', None,
7007 _('update to new branch head if changesets were unbundled'))],
7007 _('update to new branch head if changesets were unbundled'))],
7008 _('[-u] FILE...'))
7008 _('[-u] FILE...'))
7009 def unbundle(ui, repo, fname1, *fnames, **opts):
7009 def unbundle(ui, repo, fname1, *fnames, **opts):
7010 """apply one or more changegroup files
7010 """apply one or more changegroup files
7011
7011
7012 Apply one or more compressed changegroup files generated by the
7012 Apply one or more compressed changegroup files generated by the
7013 bundle command.
7013 bundle command.
7014
7014
7015 Returns 0 on success, 1 if an update has unresolved files.
7015 Returns 0 on success, 1 if an update has unresolved files.
7016 """
7016 """
7017 fnames = (fname1,) + fnames
7017 fnames = (fname1,) + fnames
7018
7018
7019 with repo.lock():
7019 with repo.lock():
7020 for fname in fnames:
7020 for fname in fnames:
7021 f = hg.openpath(ui, fname)
7021 f = hg.openpath(ui, fname)
7022 gen = exchange.readbundle(ui, f, fname)
7022 gen = exchange.readbundle(ui, f, fname)
7023 if isinstance(gen, bundle2.unbundle20):
7023 if isinstance(gen, bundle2.unbundle20):
7024 tr = repo.transaction('unbundle')
7024 tr = repo.transaction('unbundle')
7025 try:
7025 try:
7026 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7026 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7027 url='bundle:' + fname)
7027 url='bundle:' + fname)
7028 tr.close()
7028 tr.close()
7029 except error.BundleUnknownFeatureError as exc:
7029 except error.BundleUnknownFeatureError as exc:
7030 raise error.Abort(_('%s: unknown bundle feature, %s')
7030 raise error.Abort(_('%s: unknown bundle feature, %s')
7031 % (fname, exc),
7031 % (fname, exc),
7032 hint=_("see https://mercurial-scm.org/"
7032 hint=_("see https://mercurial-scm.org/"
7033 "wiki/BundleFeature for more "
7033 "wiki/BundleFeature for more "
7034 "information"))
7034 "information"))
7035 finally:
7035 finally:
7036 if tr:
7036 if tr:
7037 tr.release()
7037 tr.release()
7038 changes = [r.get('return', 0)
7038 changes = [r.get('return', 0)
7039 for r in op.records['changegroup']]
7039 for r in op.records['changegroup']]
7040 modheads = changegroup.combineresults(changes)
7040 modheads = changegroup.combineresults(changes)
7041 elif isinstance(gen, streamclone.streamcloneapplier):
7041 elif isinstance(gen, streamclone.streamcloneapplier):
7042 raise error.Abort(
7042 raise error.Abort(
7043 _('packed bundles cannot be applied with '
7043 _('packed bundles cannot be applied with '
7044 '"hg unbundle"'),
7044 '"hg unbundle"'),
7045 hint=_('use "hg debugapplystreamclonebundle"'))
7045 hint=_('use "hg debugapplystreamclonebundle"'))
7046 else:
7046 else:
7047 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7047 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7048
7048
7049 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7049 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7050
7050
7051 @command('^update|up|checkout|co',
7051 @command('^update|up|checkout|co',
7052 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7052 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7053 ('c', 'check', None,
7053 ('c', 'check', None,
7054 _('update across branches if no uncommitted changes')),
7054 _('update across branches if no uncommitted changes')),
7055 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7055 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7056 ('r', 'rev', '', _('revision'), _('REV'))
7056 ('r', 'rev', '', _('revision'), _('REV'))
7057 ] + mergetoolopts,
7057 ] + mergetoolopts,
7058 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7058 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7059 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7059 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7060 tool=None):
7060 tool=None):
7061 """update working directory (or switch revisions)
7061 """update working directory (or switch revisions)
7062
7062
7063 Update the repository's working directory to the specified
7063 Update the repository's working directory to the specified
7064 changeset. If no changeset is specified, update to the tip of the
7064 changeset. If no changeset is specified, update to the tip of the
7065 current named branch and move the active bookmark (see :hg:`help
7065 current named branch and move the active bookmark (see :hg:`help
7066 bookmarks`).
7066 bookmarks`).
7067
7067
7068 Update sets the working directory's parent revision to the specified
7068 Update sets the working directory's parent revision to the specified
7069 changeset (see :hg:`help parents`).
7069 changeset (see :hg:`help parents`).
7070
7070
7071 If the changeset is not a descendant or ancestor of the working
7071 If the changeset is not a descendant or ancestor of the working
7072 directory's parent, the update is aborted. With the -c/--check
7072 directory's parent, the update is aborted. With the -c/--check
7073 option, the working directory is checked for uncommitted changes; if
7073 option, the working directory is checked for uncommitted changes; if
7074 none are found, the working directory is updated to the specified
7074 none are found, the working directory is updated to the specified
7075 changeset.
7075 changeset.
7076
7076
7077 .. container:: verbose
7077 .. container:: verbose
7078
7078
7079 The following rules apply when the working directory contains
7079 The following rules apply when the working directory contains
7080 uncommitted changes:
7080 uncommitted changes:
7081
7081
7082 1. If neither -c/--check nor -C/--clean is specified, and if
7082 1. If neither -c/--check nor -C/--clean is specified, and if
7083 the requested changeset is an ancestor or descendant of
7083 the requested changeset is an ancestor or descendant of
7084 the working directory's parent, the uncommitted changes
7084 the working directory's parent, the uncommitted changes
7085 are merged into the requested changeset and the merged
7085 are merged into the requested changeset and the merged
7086 result is left uncommitted. If the requested changeset is
7086 result is left uncommitted. If the requested changeset is
7087 not an ancestor or descendant (that is, it is on another
7087 not an ancestor or descendant (that is, it is on another
7088 branch), the update is aborted and the uncommitted changes
7088 branch), the update is aborted and the uncommitted changes
7089 are preserved.
7089 are preserved.
7090
7090
7091 2. With the -c/--check option, the update is aborted and the
7091 2. With the -c/--check option, the update is aborted and the
7092 uncommitted changes are preserved.
7092 uncommitted changes are preserved.
7093
7093
7094 3. With the -C/--clean option, uncommitted changes are discarded and
7094 3. With the -C/--clean option, uncommitted changes are discarded and
7095 the working directory is updated to the requested changeset.
7095 the working directory is updated to the requested changeset.
7096
7096
7097 To cancel an uncommitted merge (and lose your changes), use
7097 To cancel an uncommitted merge (and lose your changes), use
7098 :hg:`update --clean .`.
7098 :hg:`update --clean .`.
7099
7099
7100 Use null as the changeset to remove the working directory (like
7100 Use null as the changeset to remove the working directory (like
7101 :hg:`clone -U`).
7101 :hg:`clone -U`).
7102
7102
7103 If you want to revert just one file to an older revision, use
7103 If you want to revert just one file to an older revision, use
7104 :hg:`revert [-r REV] NAME`.
7104 :hg:`revert [-r REV] NAME`.
7105
7105
7106 See :hg:`help dates` for a list of formats valid for -d/--date.
7106 See :hg:`help dates` for a list of formats valid for -d/--date.
7107
7107
7108 Returns 0 on success, 1 if there are unresolved files.
7108 Returns 0 on success, 1 if there are unresolved files.
7109 """
7109 """
7110 if rev and node:
7110 if rev and node:
7111 raise error.Abort(_("please specify just one revision"))
7111 raise error.Abort(_("please specify just one revision"))
7112
7112
7113 if rev is None or rev == '':
7113 if rev is None or rev == '':
7114 rev = node
7114 rev = node
7115
7115
7116 if date and rev is not None:
7116 if date and rev is not None:
7117 raise error.Abort(_("you can't specify a revision and a date"))
7117 raise error.Abort(_("you can't specify a revision and a date"))
7118
7118
7119 if check and clean:
7119 if check and clean:
7120 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7120 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7121
7121
7122 with repo.wlock():
7122 with repo.wlock():
7123 cmdutil.clearunfinished(repo)
7123 cmdutil.clearunfinished(repo)
7124
7124
7125 if date:
7125 if date:
7126 rev = cmdutil.finddate(ui, repo, date)
7126 rev = cmdutil.finddate(ui, repo, date)
7127
7127
7128 # if we defined a bookmark, we have to remember the original name
7128 # if we defined a bookmark, we have to remember the original name
7129 brev = rev
7129 brev = rev
7130 rev = scmutil.revsingle(repo, rev, rev).rev()
7130 rev = scmutil.revsingle(repo, rev, rev).rev()
7131
7131
7132 if check:
7132 if check:
7133 cmdutil.bailifchanged(repo, merge=False)
7133 cmdutil.bailifchanged(repo, merge=False)
7134
7134
7135 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7135 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7136
7136
7137 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7137 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7138
7138
7139 @command('verify', [])
7139 @command('verify', [])
7140 def verify(ui, repo):
7140 def verify(ui, repo):
7141 """verify the integrity of the repository
7141 """verify the integrity of the repository
7142
7142
7143 Verify the integrity of the current repository.
7143 Verify the integrity of the current repository.
7144
7144
7145 This will perform an extensive check of the repository's
7145 This will perform an extensive check of the repository's
7146 integrity, validating the hashes and checksums of each entry in
7146 integrity, validating the hashes and checksums of each entry in
7147 the changelog, manifest, and tracked files, as well as the
7147 the changelog, manifest, and tracked files, as well as the
7148 integrity of their crosslinks and indices.
7148 integrity of their crosslinks and indices.
7149
7149
7150 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7150 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7151 for more information about recovery from corruption of the
7151 for more information about recovery from corruption of the
7152 repository.
7152 repository.
7153
7153
7154 Returns 0 on success, 1 if errors are encountered.
7154 Returns 0 on success, 1 if errors are encountered.
7155 """
7155 """
7156 return hg.verify(repo)
7156 return hg.verify(repo)
7157
7157
7158 @command('version', [], norepo=True)
7158 @command('version', [], norepo=True)
7159 def version_(ui):
7159 def version_(ui):
7160 """output version and copyright information"""
7160 """output version and copyright information"""
7161 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7161 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7162 % util.version())
7162 % util.version())
7163 ui.status(_(
7163 ui.status(_(
7164 "(see https://mercurial-scm.org for more information)\n"
7164 "(see https://mercurial-scm.org for more information)\n"
7165 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7165 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7166 "This is free software; see the source for copying conditions. "
7166 "This is free software; see the source for copying conditions. "
7167 "There is NO\nwarranty; "
7167 "There is NO\nwarranty; "
7168 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7168 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7169 ))
7169 ))
7170
7170
7171 ui.note(_("\nEnabled extensions:\n\n"))
7171 ui.note(_("\nEnabled extensions:\n\n"))
7172 if ui.verbose:
7172 if ui.verbose:
7173 # format names and versions into columns
7173 # format names and versions into columns
7174 names = []
7174 names = []
7175 vers = []
7175 vers = []
7176 place = []
7176 place = []
7177 for name, module in extensions.extensions():
7177 for name, module in extensions.extensions():
7178 names.append(name)
7178 names.append(name)
7179 vers.append(extensions.moduleversion(module))
7179 vers.append(extensions.moduleversion(module))
7180 if extensions.ismoduleinternal(module):
7180 if extensions.ismoduleinternal(module):
7181 place.append(_("internal"))
7181 place.append(_("internal"))
7182 else:
7182 else:
7183 place.append(_("external"))
7183 place.append(_("external"))
7184 if names:
7184 if names:
7185 maxnamelen = max(len(n) for n in names)
7185 maxnamelen = max(len(n) for n in names)
7186 for i, name in enumerate(names):
7186 for i, name in enumerate(names):
7187 ui.write(" %-*s %s %s\n" %
7187 ui.write(" %-*s %s %s\n" %
7188 (maxnamelen, name, place[i], vers[i]))
7188 (maxnamelen, name, place[i], vers[i]))
7189
7189
7190 def loadcmdtable(ui, name, cmdtable):
7190 def loadcmdtable(ui, name, cmdtable):
7191 """Load command functions from specified cmdtable
7191 """Load command functions from specified cmdtable
7192 """
7192 """
7193 overrides = [cmd for cmd in cmdtable if cmd in table]
7193 overrides = [cmd for cmd in cmdtable if cmd in table]
7194 if overrides:
7194 if overrides:
7195 ui.warn(_("extension '%s' overrides commands: %s\n")
7195 ui.warn(_("extension '%s' overrides commands: %s\n")
7196 % (name, " ".join(overrides)))
7196 % (name, " ".join(overrides)))
7197 table.update(cmdtable)
7197 table.update(cmdtable)
@@ -1,2306 +1,2322 b''
1 $ HGENCODING=utf-8
1 $ HGENCODING=utf-8
2 $ export HGENCODING
2 $ export HGENCODING
3 $ cat > testrevset.py << EOF
3 $ cat > testrevset.py << EOF
4 > import mercurial.revset
4 > import mercurial.revset
5 >
5 >
6 > baseset = mercurial.revset.baseset
6 > baseset = mercurial.revset.baseset
7 >
7 >
8 > def r3232(repo, subset, x):
8 > def r3232(repo, subset, x):
9 > """"simple revset that return [3,2,3,2]
9 > """"simple revset that return [3,2,3,2]
10 >
10 >
11 > revisions duplicated on purpose.
11 > revisions duplicated on purpose.
12 > """
12 > """
13 > if 3 not in subset:
13 > if 3 not in subset:
14 > if 2 in subset:
14 > if 2 in subset:
15 > return baseset([2,2])
15 > return baseset([2,2])
16 > return baseset()
16 > return baseset()
17 > return baseset([3,3,2,2])
17 > return baseset([3,3,2,2])
18 >
18 >
19 > mercurial.revset.symbols['r3232'] = r3232
19 > mercurial.revset.symbols['r3232'] = r3232
20 > EOF
20 > EOF
21 $ cat >> $HGRCPATH << EOF
21 $ cat >> $HGRCPATH << EOF
22 > [extensions]
22 > [extensions]
23 > testrevset=$TESTTMP/testrevset.py
23 > testrevset=$TESTTMP/testrevset.py
24 > EOF
24 > EOF
25
25
26 $ try() {
26 $ try() {
27 > hg debugrevspec --debug "$@"
27 > hg debugrevspec --debug "$@"
28 > }
28 > }
29
29
30 $ log() {
30 $ log() {
31 > hg log --template '{rev}\n' -r "$1"
31 > hg log --template '{rev}\n' -r "$1"
32 > }
32 > }
33
33
34 $ hg init repo
34 $ hg init repo
35 $ cd repo
35 $ cd repo
36
36
37 $ echo a > a
37 $ echo a > a
38 $ hg branch a
38 $ hg branch a
39 marked working directory as branch a
39 marked working directory as branch a
40 (branches are permanent and global, did you want a bookmark?)
40 (branches are permanent and global, did you want a bookmark?)
41 $ hg ci -Aqm0
41 $ hg ci -Aqm0
42
42
43 $ echo b > b
43 $ echo b > b
44 $ hg branch b
44 $ hg branch b
45 marked working directory as branch b
45 marked working directory as branch b
46 $ hg ci -Aqm1
46 $ hg ci -Aqm1
47
47
48 $ rm a
48 $ rm a
49 $ hg branch a-b-c-
49 $ hg branch a-b-c-
50 marked working directory as branch a-b-c-
50 marked working directory as branch a-b-c-
51 $ hg ci -Aqm2 -u Bob
51 $ hg ci -Aqm2 -u Bob
52
52
53 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
53 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
54 2
54 2
55 $ hg log -r "extra('branch')" --template '{rev}\n'
55 $ hg log -r "extra('branch')" --template '{rev}\n'
56 0
56 0
57 1
57 1
58 2
58 2
59 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
59 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
60 0 a
60 0 a
61 2 a-b-c-
61 2 a-b-c-
62
62
63 $ hg co 1
63 $ hg co 1
64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 $ hg branch +a+b+c+
65 $ hg branch +a+b+c+
66 marked working directory as branch +a+b+c+
66 marked working directory as branch +a+b+c+
67 $ hg ci -Aqm3
67 $ hg ci -Aqm3
68
68
69 $ hg co 2 # interleave
69 $ hg co 2 # interleave
70 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
70 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
71 $ echo bb > b
71 $ echo bb > b
72 $ hg branch -- -a-b-c-
72 $ hg branch -- -a-b-c-
73 marked working directory as branch -a-b-c-
73 marked working directory as branch -a-b-c-
74 $ hg ci -Aqm4 -d "May 12 2005"
74 $ hg ci -Aqm4 -d "May 12 2005"
75
75
76 $ hg co 3
76 $ hg co 3
77 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 $ hg branch !a/b/c/
78 $ hg branch !a/b/c/
79 marked working directory as branch !a/b/c/
79 marked working directory as branch !a/b/c/
80 $ hg ci -Aqm"5 bug"
80 $ hg ci -Aqm"5 bug"
81
81
82 $ hg merge 4
82 $ hg merge 4
83 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
83 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
84 (branch merge, don't forget to commit)
84 (branch merge, don't forget to commit)
85 $ hg branch _a_b_c_
85 $ hg branch _a_b_c_
86 marked working directory as branch _a_b_c_
86 marked working directory as branch _a_b_c_
87 $ hg ci -Aqm"6 issue619"
87 $ hg ci -Aqm"6 issue619"
88
88
89 $ hg branch .a.b.c.
89 $ hg branch .a.b.c.
90 marked working directory as branch .a.b.c.
90 marked working directory as branch .a.b.c.
91 $ hg ci -Aqm7
91 $ hg ci -Aqm7
92
92
93 $ hg branch all
93 $ hg branch all
94 marked working directory as branch all
94 marked working directory as branch all
95
95
96 $ hg co 4
96 $ hg co 4
97 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 $ hg branch Γ©
98 $ hg branch Γ©
99 marked working directory as branch \xc3\xa9 (esc)
99 marked working directory as branch \xc3\xa9 (esc)
100 $ hg ci -Aqm9
100 $ hg ci -Aqm9
101
101
102 $ hg tag -r6 1.0
102 $ hg tag -r6 1.0
103 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
103 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
104
104
105 $ hg clone --quiet -U -r 7 . ../remote1
105 $ hg clone --quiet -U -r 7 . ../remote1
106 $ hg clone --quiet -U -r 8 . ../remote2
106 $ hg clone --quiet -U -r 8 . ../remote2
107 $ echo "[paths]" >> .hg/hgrc
107 $ echo "[paths]" >> .hg/hgrc
108 $ echo "default = ../remote1" >> .hg/hgrc
108 $ echo "default = ../remote1" >> .hg/hgrc
109
109
110 trivial
110 trivial
111
111
112 $ try 0:1
112 $ try 0:1
113 (range
113 (range
114 ('symbol', '0')
114 ('symbol', '0')
115 ('symbol', '1'))
115 ('symbol', '1'))
116 * set:
116 * set:
117 <spanset+ 0:1>
117 <spanset+ 0:1>
118 0
118 0
119 1
119 1
120 $ try --optimize :
120 $ try --optimize :
121 (rangeall
121 (rangeall
122 None)
122 None)
123 * optimized:
123 * optimized:
124 (range
124 (range
125 ('string', '0')
125 ('string', '0')
126 ('string', 'tip'))
126 ('string', 'tip'))
127 * set:
127 * set:
128 <spanset+ 0:9>
128 <spanset+ 0:9>
129 0
129 0
130 1
130 1
131 2
131 2
132 3
132 3
133 4
133 4
134 5
134 5
135 6
135 6
136 7
136 7
137 8
137 8
138 9
138 9
139 $ try 3::6
139 $ try 3::6
140 (dagrange
140 (dagrange
141 ('symbol', '3')
141 ('symbol', '3')
142 ('symbol', '6'))
142 ('symbol', '6'))
143 * set:
143 * set:
144 <baseset+ [3, 5, 6]>
144 <baseset+ [3, 5, 6]>
145 3
145 3
146 5
146 5
147 6
147 6
148 $ try '0|1|2'
148 $ try '0|1|2'
149 (or
149 (or
150 ('symbol', '0')
150 ('symbol', '0')
151 ('symbol', '1')
151 ('symbol', '1')
152 ('symbol', '2'))
152 ('symbol', '2'))
153 * set:
153 * set:
154 <baseset [0, 1, 2]>
154 <baseset [0, 1, 2]>
155 0
155 0
156 1
156 1
157 2
157 2
158
158
159 names that should work without quoting
159 names that should work without quoting
160
160
161 $ try a
161 $ try a
162 ('symbol', 'a')
162 ('symbol', 'a')
163 * set:
163 * set:
164 <baseset [0]>
164 <baseset [0]>
165 0
165 0
166 $ try b-a
166 $ try b-a
167 (minus
167 (minus
168 ('symbol', 'b')
168 ('symbol', 'b')
169 ('symbol', 'a'))
169 ('symbol', 'a'))
170 * set:
170 * set:
171 <filteredset
171 <filteredset
172 <baseset [1]>,
172 <baseset [1]>,
173 <not
173 <not
174 <baseset [0]>>>
174 <baseset [0]>>>
175 1
175 1
176 $ try _a_b_c_
176 $ try _a_b_c_
177 ('symbol', '_a_b_c_')
177 ('symbol', '_a_b_c_')
178 * set:
178 * set:
179 <baseset [6]>
179 <baseset [6]>
180 6
180 6
181 $ try _a_b_c_-a
181 $ try _a_b_c_-a
182 (minus
182 (minus
183 ('symbol', '_a_b_c_')
183 ('symbol', '_a_b_c_')
184 ('symbol', 'a'))
184 ('symbol', 'a'))
185 * set:
185 * set:
186 <filteredset
186 <filteredset
187 <baseset [6]>,
187 <baseset [6]>,
188 <not
188 <not
189 <baseset [0]>>>
189 <baseset [0]>>>
190 6
190 6
191 $ try .a.b.c.
191 $ try .a.b.c.
192 ('symbol', '.a.b.c.')
192 ('symbol', '.a.b.c.')
193 * set:
193 * set:
194 <baseset [7]>
194 <baseset [7]>
195 7
195 7
196 $ try .a.b.c.-a
196 $ try .a.b.c.-a
197 (minus
197 (minus
198 ('symbol', '.a.b.c.')
198 ('symbol', '.a.b.c.')
199 ('symbol', 'a'))
199 ('symbol', 'a'))
200 * set:
200 * set:
201 <filteredset
201 <filteredset
202 <baseset [7]>,
202 <baseset [7]>,
203 <not
203 <not
204 <baseset [0]>>>
204 <baseset [0]>>>
205 7
205 7
206
206
207 names that should be caught by fallback mechanism
207 names that should be caught by fallback mechanism
208
208
209 $ try -- '-a-b-c-'
209 $ try -- '-a-b-c-'
210 ('symbol', '-a-b-c-')
210 ('symbol', '-a-b-c-')
211 * set:
211 * set:
212 <baseset [4]>
212 <baseset [4]>
213 4
213 4
214 $ log -a-b-c-
214 $ log -a-b-c-
215 4
215 4
216 $ try '+a+b+c+'
216 $ try '+a+b+c+'
217 ('symbol', '+a+b+c+')
217 ('symbol', '+a+b+c+')
218 * set:
218 * set:
219 <baseset [3]>
219 <baseset [3]>
220 3
220 3
221 $ try '+a+b+c+:'
221 $ try '+a+b+c+:'
222 (rangepost
222 (rangepost
223 ('symbol', '+a+b+c+'))
223 ('symbol', '+a+b+c+'))
224 * set:
224 * set:
225 <spanset+ 3:9>
225 <spanset+ 3:9>
226 3
226 3
227 4
227 4
228 5
228 5
229 6
229 6
230 7
230 7
231 8
231 8
232 9
232 9
233 $ try ':+a+b+c+'
233 $ try ':+a+b+c+'
234 (rangepre
234 (rangepre
235 ('symbol', '+a+b+c+'))
235 ('symbol', '+a+b+c+'))
236 * set:
236 * set:
237 <spanset+ 0:3>
237 <spanset+ 0:3>
238 0
238 0
239 1
239 1
240 2
240 2
241 3
241 3
242 $ try -- '-a-b-c-:+a+b+c+'
242 $ try -- '-a-b-c-:+a+b+c+'
243 (range
243 (range
244 ('symbol', '-a-b-c-')
244 ('symbol', '-a-b-c-')
245 ('symbol', '+a+b+c+'))
245 ('symbol', '+a+b+c+'))
246 * set:
246 * set:
247 <spanset- 3:4>
247 <spanset- 3:4>
248 4
248 4
249 3
249 3
250 $ log '-a-b-c-:+a+b+c+'
250 $ log '-a-b-c-:+a+b+c+'
251 4
251 4
252 3
252 3
253
253
254 $ try -- -a-b-c--a # complains
254 $ try -- -a-b-c--a # complains
255 (minus
255 (minus
256 (minus
256 (minus
257 (minus
257 (minus
258 (negate
258 (negate
259 ('symbol', 'a'))
259 ('symbol', 'a'))
260 ('symbol', 'b'))
260 ('symbol', 'b'))
261 ('symbol', 'c'))
261 ('symbol', 'c'))
262 (negate
262 (negate
263 ('symbol', 'a')))
263 ('symbol', 'a')))
264 abort: unknown revision '-a'!
264 abort: unknown revision '-a'!
265 [255]
265 [255]
266 $ try Γ©
266 $ try Γ©
267 ('symbol', '\xc3\xa9')
267 ('symbol', '\xc3\xa9')
268 * set:
268 * set:
269 <baseset [9]>
269 <baseset [9]>
270 9
270 9
271
271
272 no quoting needed
272 no quoting needed
273
273
274 $ log ::a-b-c-
274 $ log ::a-b-c-
275 0
275 0
276 1
276 1
277 2
277 2
278
278
279 quoting needed
279 quoting needed
280
280
281 $ try '"-a-b-c-"-a'
281 $ try '"-a-b-c-"-a'
282 (minus
282 (minus
283 ('string', '-a-b-c-')
283 ('string', '-a-b-c-')
284 ('symbol', 'a'))
284 ('symbol', 'a'))
285 * set:
285 * set:
286 <filteredset
286 <filteredset
287 <baseset [4]>,
287 <baseset [4]>,
288 <not
288 <not
289 <baseset [0]>>>
289 <baseset [0]>>>
290 4
290 4
291
291
292 $ log '1 or 2'
292 $ log '1 or 2'
293 1
293 1
294 2
294 2
295 $ log '1|2'
295 $ log '1|2'
296 1
296 1
297 2
297 2
298 $ log '1 and 2'
298 $ log '1 and 2'
299 $ log '1&2'
299 $ log '1&2'
300 $ try '1&2|3' # precedence - and is higher
300 $ try '1&2|3' # precedence - and is higher
301 (or
301 (or
302 (and
302 (and
303 ('symbol', '1')
303 ('symbol', '1')
304 ('symbol', '2'))
304 ('symbol', '2'))
305 ('symbol', '3'))
305 ('symbol', '3'))
306 * set:
306 * set:
307 <addset
307 <addset
308 <baseset []>,
308 <baseset []>,
309 <baseset [3]>>
309 <baseset [3]>>
310 3
310 3
311 $ try '1|2&3'
311 $ try '1|2&3'
312 (or
312 (or
313 ('symbol', '1')
313 ('symbol', '1')
314 (and
314 (and
315 ('symbol', '2')
315 ('symbol', '2')
316 ('symbol', '3')))
316 ('symbol', '3')))
317 * set:
317 * set:
318 <addset
318 <addset
319 <baseset [1]>,
319 <baseset [1]>,
320 <baseset []>>
320 <baseset []>>
321 1
321 1
322 $ try '1&2&3' # associativity
322 $ try '1&2&3' # associativity
323 (and
323 (and
324 (and
324 (and
325 ('symbol', '1')
325 ('symbol', '1')
326 ('symbol', '2'))
326 ('symbol', '2'))
327 ('symbol', '3'))
327 ('symbol', '3'))
328 * set:
328 * set:
329 <baseset []>
329 <baseset []>
330 $ try '1|(2|3)'
330 $ try '1|(2|3)'
331 (or
331 (or
332 ('symbol', '1')
332 ('symbol', '1')
333 (group
333 (group
334 (or
334 (or
335 ('symbol', '2')
335 ('symbol', '2')
336 ('symbol', '3'))))
336 ('symbol', '3'))))
337 * set:
337 * set:
338 <addset
338 <addset
339 <baseset [1]>,
339 <baseset [1]>,
340 <baseset [2, 3]>>
340 <baseset [2, 3]>>
341 1
341 1
342 2
342 2
343 3
343 3
344 $ log '1.0' # tag
344 $ log '1.0' # tag
345 6
345 6
346 $ log 'a' # branch
346 $ log 'a' # branch
347 0
347 0
348 $ log '2785f51ee'
348 $ log '2785f51ee'
349 0
349 0
350 $ log 'date(2005)'
350 $ log 'date(2005)'
351 4
351 4
352 $ log 'date(this is a test)'
352 $ log 'date(this is a test)'
353 hg: parse error at 10: unexpected token: symbol
353 hg: parse error at 10: unexpected token: symbol
354 [255]
354 [255]
355 $ log 'date()'
355 $ log 'date()'
356 hg: parse error: date requires a string
356 hg: parse error: date requires a string
357 [255]
357 [255]
358 $ log 'date'
358 $ log 'date'
359 abort: unknown revision 'date'!
359 abort: unknown revision 'date'!
360 [255]
360 [255]
361 $ log 'date('
361 $ log 'date('
362 hg: parse error at 5: not a prefix: end
362 hg: parse error at 5: not a prefix: end
363 [255]
363 [255]
364 $ log 'date("\xy")'
364 $ log 'date("\xy")'
365 hg: parse error: invalid \x escape
365 hg: parse error: invalid \x escape
366 [255]
366 [255]
367 $ log 'date(tip)'
367 $ log 'date(tip)'
368 abort: invalid date: 'tip'
368 abort: invalid date: 'tip'
369 [255]
369 [255]
370 $ log '0:date'
370 $ log '0:date'
371 abort: unknown revision 'date'!
371 abort: unknown revision 'date'!
372 [255]
372 [255]
373 $ log '::"date"'
373 $ log '::"date"'
374 abort: unknown revision 'date'!
374 abort: unknown revision 'date'!
375 [255]
375 [255]
376 $ hg book date -r 4
376 $ hg book date -r 4
377 $ log '0:date'
377 $ log '0:date'
378 0
378 0
379 1
379 1
380 2
380 2
381 3
381 3
382 4
382 4
383 $ log '::date'
383 $ log '::date'
384 0
384 0
385 1
385 1
386 2
386 2
387 4
387 4
388 $ log '::"date"'
388 $ log '::"date"'
389 0
389 0
390 1
390 1
391 2
391 2
392 4
392 4
393 $ log 'date(2005) and 1::'
393 $ log 'date(2005) and 1::'
394 4
394 4
395 $ hg book -d date
395 $ hg book -d date
396
396
397 keyword arguments
397 keyword arguments
398
398
399 $ log 'extra(branch, value=a)'
399 $ log 'extra(branch, value=a)'
400 0
400 0
401
401
402 $ log 'extra(branch, a, b)'
402 $ log 'extra(branch, a, b)'
403 hg: parse error: extra takes at most 2 arguments
403 hg: parse error: extra takes at most 2 arguments
404 [255]
404 [255]
405 $ log 'extra(a, label=b)'
405 $ log 'extra(a, label=b)'
406 hg: parse error: extra got multiple values for keyword argument 'label'
406 hg: parse error: extra got multiple values for keyword argument 'label'
407 [255]
407 [255]
408 $ log 'extra(label=branch, default)'
408 $ log 'extra(label=branch, default)'
409 hg: parse error: extra got an invalid argument
409 hg: parse error: extra got an invalid argument
410 [255]
410 [255]
411 $ log 'extra(branch, foo+bar=baz)'
411 $ log 'extra(branch, foo+bar=baz)'
412 hg: parse error: extra got an invalid argument
412 hg: parse error: extra got an invalid argument
413 [255]
413 [255]
414 $ log 'extra(unknown=branch)'
414 $ log 'extra(unknown=branch)'
415 hg: parse error: extra got an unexpected keyword argument 'unknown'
415 hg: parse error: extra got an unexpected keyword argument 'unknown'
416 [255]
416 [255]
417
417
418 $ try 'foo=bar|baz'
418 $ try 'foo=bar|baz'
419 (keyvalue
419 (keyvalue
420 ('symbol', 'foo')
420 ('symbol', 'foo')
421 (or
421 (or
422 ('symbol', 'bar')
422 ('symbol', 'bar')
423 ('symbol', 'baz')))
423 ('symbol', 'baz')))
424 hg: parse error: can't use a key-value pair in this context
424 hg: parse error: can't use a key-value pair in this context
425 [255]
425 [255]
426
426
427 Test that symbols only get parsed as functions if there's an opening
427 Test that symbols only get parsed as functions if there's an opening
428 parenthesis.
428 parenthesis.
429
429
430 $ hg book only -r 9
430 $ hg book only -r 9
431 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
431 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
432 8
432 8
433 9
433 9
434
434
435 ancestor can accept 0 or more arguments
435 ancestor can accept 0 or more arguments
436
436
437 $ log 'ancestor()'
437 $ log 'ancestor()'
438 $ log 'ancestor(1)'
438 $ log 'ancestor(1)'
439 1
439 1
440 $ log 'ancestor(4,5)'
440 $ log 'ancestor(4,5)'
441 1
441 1
442 $ log 'ancestor(4,5) and 4'
442 $ log 'ancestor(4,5) and 4'
443 $ log 'ancestor(0,0,1,3)'
443 $ log 'ancestor(0,0,1,3)'
444 0
444 0
445 $ log 'ancestor(3,1,5,3,5,1)'
445 $ log 'ancestor(3,1,5,3,5,1)'
446 1
446 1
447 $ log 'ancestor(0,1,3,5)'
447 $ log 'ancestor(0,1,3,5)'
448 0
448 0
449 $ log 'ancestor(1,2,3,4,5)'
449 $ log 'ancestor(1,2,3,4,5)'
450 1
450 1
451
451
452 test ancestors
452 test ancestors
453
453
454 $ log 'ancestors(5)'
454 $ log 'ancestors(5)'
455 0
455 0
456 1
456 1
457 3
457 3
458 5
458 5
459 $ log 'ancestor(ancestors(5))'
459 $ log 'ancestor(ancestors(5))'
460 0
460 0
461 $ log '::r3232()'
461 $ log '::r3232()'
462 0
462 0
463 1
463 1
464 2
464 2
465 3
465 3
466
466
467 $ log 'author(bob)'
467 $ log 'author(bob)'
468 2
468 2
469 $ log 'author("re:bob|test")'
469 $ log 'author("re:bob|test")'
470 0
470 0
471 1
471 1
472 2
472 2
473 3
473 3
474 4
474 4
475 5
475 5
476 6
476 6
477 7
477 7
478 8
478 8
479 9
479 9
480 $ log 'branch(Γ©)'
480 $ log 'branch(Γ©)'
481 8
481 8
482 9
482 9
483 $ log 'branch(a)'
483 $ log 'branch(a)'
484 0
484 0
485 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
485 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
486 0 a
486 0 a
487 2 a-b-c-
487 2 a-b-c-
488 3 +a+b+c+
488 3 +a+b+c+
489 4 -a-b-c-
489 4 -a-b-c-
490 5 !a/b/c/
490 5 !a/b/c/
491 6 _a_b_c_
491 6 _a_b_c_
492 7 .a.b.c.
492 7 .a.b.c.
493 $ log 'children(ancestor(4,5))'
493 $ log 'children(ancestor(4,5))'
494 2
494 2
495 3
495 3
496 $ log 'closed()'
496 $ log 'closed()'
497 $ log 'contains(a)'
497 $ log 'contains(a)'
498 0
498 0
499 1
499 1
500 3
500 3
501 5
501 5
502 $ log 'contains("../repo/a")'
502 $ log 'contains("../repo/a")'
503 0
503 0
504 1
504 1
505 3
505 3
506 5
506 5
507 $ log 'desc(B)'
507 $ log 'desc(B)'
508 5
508 5
509 $ log 'descendants(2 or 3)'
509 $ log 'descendants(2 or 3)'
510 2
510 2
511 3
511 3
512 4
512 4
513 5
513 5
514 6
514 6
515 7
515 7
516 8
516 8
517 9
517 9
518 $ log 'file("b*")'
518 $ log 'file("b*")'
519 1
519 1
520 4
520 4
521 $ log 'filelog("b")'
521 $ log 'filelog("b")'
522 1
522 1
523 4
523 4
524 $ log 'filelog("../repo/b")'
524 $ log 'filelog("../repo/b")'
525 1
525 1
526 4
526 4
527 $ log 'follow()'
527 $ log 'follow()'
528 0
528 0
529 1
529 1
530 2
530 2
531 4
531 4
532 8
532 8
533 9
533 9
534 $ log 'grep("issue\d+")'
534 $ log 'grep("issue\d+")'
535 6
535 6
536 $ try 'grep("(")' # invalid regular expression
536 $ try 'grep("(")' # invalid regular expression
537 (func
537 (func
538 ('symbol', 'grep')
538 ('symbol', 'grep')
539 ('string', '('))
539 ('string', '('))
540 hg: parse error: invalid match pattern: unbalanced parenthesis
540 hg: parse error: invalid match pattern: unbalanced parenthesis
541 [255]
541 [255]
542 $ try 'grep("\bissue\d+")'
542 $ try 'grep("\bissue\d+")'
543 (func
543 (func
544 ('symbol', 'grep')
544 ('symbol', 'grep')
545 ('string', '\x08issue\\d+'))
545 ('string', '\x08issue\\d+'))
546 * set:
546 * set:
547 <filteredset
547 <filteredset
548 <fullreposet+ 0:9>,
548 <fullreposet+ 0:9>,
549 <grep '\x08issue\\d+'>>
549 <grep '\x08issue\\d+'>>
550 $ try 'grep(r"\bissue\d+")'
550 $ try 'grep(r"\bissue\d+")'
551 (func
551 (func
552 ('symbol', 'grep')
552 ('symbol', 'grep')
553 ('string', '\\bissue\\d+'))
553 ('string', '\\bissue\\d+'))
554 * set:
554 * set:
555 <filteredset
555 <filteredset
556 <fullreposet+ 0:9>,
556 <fullreposet+ 0:9>,
557 <grep '\\bissue\\d+'>>
557 <grep '\\bissue\\d+'>>
558 6
558 6
559 $ try 'grep(r"\")'
559 $ try 'grep(r"\")'
560 hg: parse error at 7: unterminated string
560 hg: parse error at 7: unterminated string
561 [255]
561 [255]
562 $ log 'head()'
562 $ log 'head()'
563 0
563 0
564 1
564 1
565 2
565 2
566 3
566 3
567 4
567 4
568 5
568 5
569 6
569 6
570 7
570 7
571 9
571 9
572 $ log 'heads(6::)'
572 $ log 'heads(6::)'
573 7
573 7
574 $ log 'keyword(issue)'
574 $ log 'keyword(issue)'
575 6
575 6
576 $ log 'keyword("test a")'
576 $ log 'keyword("test a")'
577 $ log 'limit(head(), 1)'
577 $ log 'limit(head(), 1)'
578 0
578 0
579 $ log 'limit(author("re:bob|test"), 3, 5)'
579 $ log 'limit(author("re:bob|test"), 3, 5)'
580 5
580 5
581 6
581 6
582 7
582 7
583 $ log 'limit(author("re:bob|test"), offset=6)'
583 $ log 'limit(author("re:bob|test"), offset=6)'
584 6
584 6
585 $ log 'limit(author("re:bob|test"), offset=10)'
585 $ log 'limit(author("re:bob|test"), offset=10)'
586 $ log 'limit(all(), 1, -1)'
586 $ log 'limit(all(), 1, -1)'
587 hg: parse error: negative offset
587 hg: parse error: negative offset
588 [255]
588 [255]
589 $ log 'matching(6)'
589 $ log 'matching(6)'
590 6
590 6
591 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
591 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
592 6
592 6
593 7
593 7
594
594
595 Testing min and max
595 Testing min and max
596
596
597 max: simple
597 max: simple
598
598
599 $ log 'max(contains(a))'
599 $ log 'max(contains(a))'
600 5
600 5
601
601
602 max: simple on unordered set)
602 max: simple on unordered set)
603
603
604 $ log 'max((4+0+2+5+7) and contains(a))'
604 $ log 'max((4+0+2+5+7) and contains(a))'
605 5
605 5
606
606
607 max: no result
607 max: no result
608
608
609 $ log 'max(contains(stringthatdoesnotappearanywhere))'
609 $ log 'max(contains(stringthatdoesnotappearanywhere))'
610
610
611 max: no result on unordered set
611 max: no result on unordered set
612
612
613 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
613 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
614
614
615 min: simple
615 min: simple
616
616
617 $ log 'min(contains(a))'
617 $ log 'min(contains(a))'
618 0
618 0
619
619
620 min: simple on unordered set
620 min: simple on unordered set
621
621
622 $ log 'min((4+0+2+5+7) and contains(a))'
622 $ log 'min((4+0+2+5+7) and contains(a))'
623 0
623 0
624
624
625 min: empty
625 min: empty
626
626
627 $ log 'min(contains(stringthatdoesnotappearanywhere))'
627 $ log 'min(contains(stringthatdoesnotappearanywhere))'
628
628
629 min: empty on unordered set
629 min: empty on unordered set
630
630
631 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
631 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
632
632
633
633
634 $ log 'merge()'
634 $ log 'merge()'
635 6
635 6
636 $ log 'branchpoint()'
636 $ log 'branchpoint()'
637 1
637 1
638 4
638 4
639 $ log 'modifies(b)'
639 $ log 'modifies(b)'
640 4
640 4
641 $ log 'modifies("path:b")'
641 $ log 'modifies("path:b")'
642 4
642 4
643 $ log 'modifies("*")'
643 $ log 'modifies("*")'
644 4
644 4
645 6
645 6
646 $ log 'modifies("set:modified()")'
646 $ log 'modifies("set:modified()")'
647 4
647 4
648 $ log 'id(5)'
648 $ log 'id(5)'
649 2
649 2
650 $ log 'only(9)'
650 $ log 'only(9)'
651 8
651 8
652 9
652 9
653 $ log 'only(8)'
653 $ log 'only(8)'
654 8
654 8
655 $ log 'only(9, 5)'
655 $ log 'only(9, 5)'
656 2
656 2
657 4
657 4
658 8
658 8
659 9
659 9
660 $ log 'only(7 + 9, 5 + 2)'
660 $ log 'only(7 + 9, 5 + 2)'
661 4
661 4
662 6
662 6
663 7
663 7
664 8
664 8
665 9
665 9
666
666
667 Test empty set input
667 Test empty set input
668 $ log 'only(p2())'
668 $ log 'only(p2())'
669 $ log 'only(p1(), p2())'
669 $ log 'only(p1(), p2())'
670 0
670 0
671 1
671 1
672 2
672 2
673 4
673 4
674 8
674 8
675 9
675 9
676
676
677 Test '%' operator
677 Test '%' operator
678
678
679 $ log '9%'
679 $ log '9%'
680 8
680 8
681 9
681 9
682 $ log '9%5'
682 $ log '9%5'
683 2
683 2
684 4
684 4
685 8
685 8
686 9
686 9
687 $ log '(7 + 9)%(5 + 2)'
687 $ log '(7 + 9)%(5 + 2)'
688 4
688 4
689 6
689 6
690 7
690 7
691 8
691 8
692 9
692 9
693
693
694 Test opreand of '%' is optimized recursively (issue4670)
694 Test opreand of '%' is optimized recursively (issue4670)
695
695
696 $ try --optimize '8:9-8%'
696 $ try --optimize '8:9-8%'
697 (onlypost
697 (onlypost
698 (minus
698 (minus
699 (range
699 (range
700 ('symbol', '8')
700 ('symbol', '8')
701 ('symbol', '9'))
701 ('symbol', '9'))
702 ('symbol', '8')))
702 ('symbol', '8')))
703 * optimized:
703 * optimized:
704 (func
704 (func
705 ('symbol', 'only')
705 ('symbol', 'only')
706 (difference
706 (difference
707 (range
707 (range
708 ('symbol', '8')
708 ('symbol', '8')
709 ('symbol', '9'))
709 ('symbol', '9'))
710 ('symbol', '8')))
710 ('symbol', '8')))
711 * set:
711 * set:
712 <baseset+ [8, 9]>
712 <baseset+ [8, 9]>
713 8
713 8
714 9
714 9
715 $ try --optimize '(9)%(5)'
715 $ try --optimize '(9)%(5)'
716 (only
716 (only
717 (group
717 (group
718 ('symbol', '9'))
718 ('symbol', '9'))
719 (group
719 (group
720 ('symbol', '5')))
720 ('symbol', '5')))
721 * optimized:
721 * optimized:
722 (func
722 (func
723 ('symbol', 'only')
723 ('symbol', 'only')
724 (list
724 (list
725 ('symbol', '9')
725 ('symbol', '9')
726 ('symbol', '5')))
726 ('symbol', '5')))
727 * set:
727 * set:
728 <baseset+ [8, 9, 2, 4]>
728 <baseset+ [8, 9, 2, 4]>
729 2
729 2
730 4
730 4
731 8
731 8
732 9
732 9
733
733
734 Test the order of operations
734 Test the order of operations
735
735
736 $ log '7 + 9%5 + 2'
736 $ log '7 + 9%5 + 2'
737 7
737 7
738 2
738 2
739 4
739 4
740 8
740 8
741 9
741 9
742
742
743 Test explicit numeric revision
743 Test explicit numeric revision
744 $ log 'rev(-2)'
744 $ log 'rev(-2)'
745 $ log 'rev(-1)'
745 $ log 'rev(-1)'
746 -1
746 -1
747 $ log 'rev(0)'
747 $ log 'rev(0)'
748 0
748 0
749 $ log 'rev(9)'
749 $ log 'rev(9)'
750 9
750 9
751 $ log 'rev(10)'
751 $ log 'rev(10)'
752 $ log 'rev(tip)'
752 $ log 'rev(tip)'
753 hg: parse error: rev expects a number
753 hg: parse error: rev expects a number
754 [255]
754 [255]
755
755
756 Test hexadecimal revision
756 Test hexadecimal revision
757 $ log 'id(2)'
757 $ log 'id(2)'
758 abort: 00changelog.i@2: ambiguous identifier!
758 abort: 00changelog.i@2: ambiguous identifier!
759 [255]
759 [255]
760 $ log 'id(23268)'
760 $ log 'id(23268)'
761 4
761 4
762 $ log 'id(2785f51eece)'
762 $ log 'id(2785f51eece)'
763 0
763 0
764 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
764 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
765 8
765 8
766 $ log 'id(d5d0dcbdc4a)'
766 $ log 'id(d5d0dcbdc4a)'
767 $ log 'id(d5d0dcbdc4w)'
767 $ log 'id(d5d0dcbdc4w)'
768 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
768 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
769 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
769 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
770 $ log 'id(1.0)'
770 $ log 'id(1.0)'
771 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
771 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
772
772
773 Test null revision
773 Test null revision
774 $ log '(null)'
774 $ log '(null)'
775 -1
775 -1
776 $ log '(null:0)'
776 $ log '(null:0)'
777 -1
777 -1
778 0
778 0
779 $ log '(0:null)'
779 $ log '(0:null)'
780 0
780 0
781 -1
781 -1
782 $ log 'null::0'
782 $ log 'null::0'
783 -1
783 -1
784 0
784 0
785 $ log 'null:tip - 0:'
785 $ log 'null:tip - 0:'
786 -1
786 -1
787 $ log 'null: and null::' | head -1
787 $ log 'null: and null::' | head -1
788 -1
788 -1
789 $ log 'null: or 0:' | head -2
789 $ log 'null: or 0:' | head -2
790 -1
790 -1
791 0
791 0
792 $ log 'ancestors(null)'
792 $ log 'ancestors(null)'
793 -1
793 -1
794 $ log 'reverse(null:)' | tail -2
794 $ log 'reverse(null:)' | tail -2
795 0
795 0
796 -1
796 -1
797 BROKEN: should be '-1'
797 BROKEN: should be '-1'
798 $ log 'first(null:)'
798 $ log 'first(null:)'
799 BROKEN: should be '-1'
799 BROKEN: should be '-1'
800 $ log 'min(null:)'
800 $ log 'min(null:)'
801 $ log 'tip:null and all()' | tail -2
801 $ log 'tip:null and all()' | tail -2
802 1
802 1
803 0
803 0
804
804
805 Test working-directory revision
805 Test working-directory revision
806 $ hg debugrevspec 'wdir()'
806 $ hg debugrevspec 'wdir()'
807 2147483647
807 2147483647
808 $ hg debugrevspec 'tip or wdir()'
808 $ hg debugrevspec 'tip or wdir()'
809 9
809 9
810 2147483647
810 2147483647
811 $ hg debugrevspec '0:tip and wdir()'
811 $ hg debugrevspec '0:tip and wdir()'
812 $ log '0:wdir()' | tail -3
812 $ log '0:wdir()' | tail -3
813 8
813 8
814 9
814 9
815 2147483647
815 2147483647
816 $ log 'wdir():0' | head -3
816 $ log 'wdir():0' | head -3
817 2147483647
817 2147483647
818 9
818 9
819 8
819 8
820 $ log 'wdir():wdir()'
820 $ log 'wdir():wdir()'
821 2147483647
821 2147483647
822 $ log '(all() + wdir()) & min(. + wdir())'
822 $ log '(all() + wdir()) & min(. + wdir())'
823 9
823 9
824 $ log '(all() + wdir()) & max(. + wdir())'
824 $ log '(all() + wdir()) & max(. + wdir())'
825 2147483647
825 2147483647
826 $ log '(all() + wdir()) & first(wdir() + .)'
826 $ log '(all() + wdir()) & first(wdir() + .)'
827 2147483647
827 2147483647
828 $ log '(all() + wdir()) & last(. + wdir())'
828 $ log '(all() + wdir()) & last(. + wdir())'
829 2147483647
829 2147483647
830
830
831 $ log 'outgoing()'
831 $ log 'outgoing()'
832 8
832 8
833 9
833 9
834 $ log 'outgoing("../remote1")'
834 $ log 'outgoing("../remote1")'
835 8
835 8
836 9
836 9
837 $ log 'outgoing("../remote2")'
837 $ log 'outgoing("../remote2")'
838 3
838 3
839 5
839 5
840 6
840 6
841 7
841 7
842 9
842 9
843 $ log 'p1(merge())'
843 $ log 'p1(merge())'
844 5
844 5
845 $ log 'p2(merge())'
845 $ log 'p2(merge())'
846 4
846 4
847 $ log 'parents(merge())'
847 $ log 'parents(merge())'
848 4
848 4
849 5
849 5
850 $ log 'p1(branchpoint())'
850 $ log 'p1(branchpoint())'
851 0
851 0
852 2
852 2
853 $ log 'p2(branchpoint())'
853 $ log 'p2(branchpoint())'
854 $ log 'parents(branchpoint())'
854 $ log 'parents(branchpoint())'
855 0
855 0
856 2
856 2
857 $ log 'removes(a)'
857 $ log 'removes(a)'
858 2
858 2
859 6
859 6
860 $ log 'roots(all())'
860 $ log 'roots(all())'
861 0
861 0
862 $ log 'reverse(2 or 3 or 4 or 5)'
862 $ log 'reverse(2 or 3 or 4 or 5)'
863 5
863 5
864 4
864 4
865 3
865 3
866 2
866 2
867 $ log 'reverse(all())'
867 $ log 'reverse(all())'
868 9
868 9
869 8
869 8
870 7
870 7
871 6
871 6
872 5
872 5
873 4
873 4
874 3
874 3
875 2
875 2
876 1
876 1
877 0
877 0
878 $ log 'reverse(all()) & filelog(b)'
878 $ log 'reverse(all()) & filelog(b)'
879 4
879 4
880 1
880 1
881 $ log 'rev(5)'
881 $ log 'rev(5)'
882 5
882 5
883 $ log 'sort(limit(reverse(all()), 3))'
883 $ log 'sort(limit(reverse(all()), 3))'
884 7
884 7
885 8
885 8
886 9
886 9
887 $ log 'sort(2 or 3 or 4 or 5, date)'
887 $ log 'sort(2 or 3 or 4 or 5, date)'
888 2
888 2
889 3
889 3
890 5
890 5
891 4
891 4
892 $ log 'tagged()'
892 $ log 'tagged()'
893 6
893 6
894 $ log 'tag()'
894 $ log 'tag()'
895 6
895 6
896 $ log 'tag(1.0)'
896 $ log 'tag(1.0)'
897 6
897 6
898 $ log 'tag(tip)'
898 $ log 'tag(tip)'
899 9
899 9
900
900
901 test sort revset
901 test sort revset
902 --------------------------------------------
902 --------------------------------------------
903
903
904 test when adding two unordered revsets
904 test when adding two unordered revsets
905
905
906 $ log 'sort(keyword(issue) or modifies(b))'
906 $ log 'sort(keyword(issue) or modifies(b))'
907 4
907 4
908 6
908 6
909
909
910 test when sorting a reversed collection in the same way it is
910 test when sorting a reversed collection in the same way it is
911
911
912 $ log 'sort(reverse(all()), -rev)'
912 $ log 'sort(reverse(all()), -rev)'
913 9
913 9
914 8
914 8
915 7
915 7
916 6
916 6
917 5
917 5
918 4
918 4
919 3
919 3
920 2
920 2
921 1
921 1
922 0
922 0
923
923
924 test when sorting a reversed collection
924 test when sorting a reversed collection
925
925
926 $ log 'sort(reverse(all()), rev)'
926 $ log 'sort(reverse(all()), rev)'
927 0
927 0
928 1
928 1
929 2
929 2
930 3
930 3
931 4
931 4
932 5
932 5
933 6
933 6
934 7
934 7
935 8
935 8
936 9
936 9
937
937
938
938
939 test sorting two sorted collections in different orders
939 test sorting two sorted collections in different orders
940
940
941 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
941 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
942 2
942 2
943 6
943 6
944 8
944 8
945 9
945 9
946
946
947 test sorting two sorted collections in different orders backwards
947 test sorting two sorted collections in different orders backwards
948
948
949 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
949 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
950 9
950 9
951 8
951 8
952 6
952 6
953 2
953 2
954
954
955 test subtracting something from an addset
955 test subtracting something from an addset
956
956
957 $ log '(outgoing() or removes(a)) - removes(a)'
957 $ log '(outgoing() or removes(a)) - removes(a)'
958 8
958 8
959 9
959 9
960
960
961 test intersecting something with an addset
961 test intersecting something with an addset
962
962
963 $ log 'parents(outgoing() or removes(a))'
963 $ log 'parents(outgoing() or removes(a))'
964 1
964 1
965 4
965 4
966 5
966 5
967 8
967 8
968
968
969 test that `or` operation combines elements in the right order:
969 test that `or` operation combines elements in the right order:
970
970
971 $ log '3:4 or 2:5'
971 $ log '3:4 or 2:5'
972 3
972 3
973 4
973 4
974 2
974 2
975 5
975 5
976 $ log '3:4 or 5:2'
976 $ log '3:4 or 5:2'
977 3
977 3
978 4
978 4
979 5
979 5
980 2
980 2
981 $ log 'sort(3:4 or 2:5)'
981 $ log 'sort(3:4 or 2:5)'
982 2
982 2
983 3
983 3
984 4
984 4
985 5
985 5
986 $ log 'sort(3:4 or 5:2)'
986 $ log 'sort(3:4 or 5:2)'
987 2
987 2
988 3
988 3
989 4
989 4
990 5
990 5
991
991
992 test that more than one `-r`s are combined in the right order and deduplicated:
992 test that more than one `-r`s are combined in the right order and deduplicated:
993
993
994 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
994 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
995 3
995 3
996 4
996 4
997 5
997 5
998 2
998 2
999 0
999 0
1000 1
1000 1
1001
1001
1002 test that `or` operation skips duplicated revisions from right-hand side
1002 test that `or` operation skips duplicated revisions from right-hand side
1003
1003
1004 $ try 'reverse(1::5) or ancestors(4)'
1004 $ try 'reverse(1::5) or ancestors(4)'
1005 (or
1005 (or
1006 (func
1006 (func
1007 ('symbol', 'reverse')
1007 ('symbol', 'reverse')
1008 (dagrange
1008 (dagrange
1009 ('symbol', '1')
1009 ('symbol', '1')
1010 ('symbol', '5')))
1010 ('symbol', '5')))
1011 (func
1011 (func
1012 ('symbol', 'ancestors')
1012 ('symbol', 'ancestors')
1013 ('symbol', '4')))
1013 ('symbol', '4')))
1014 * set:
1014 * set:
1015 <addset
1015 <addset
1016 <baseset- [1, 3, 5]>,
1016 <baseset- [1, 3, 5]>,
1017 <generatorset+>>
1017 <generatorset+>>
1018 5
1018 5
1019 3
1019 3
1020 1
1020 1
1021 0
1021 0
1022 2
1022 2
1023 4
1023 4
1024 $ try 'sort(ancestors(4) or reverse(1::5))'
1024 $ try 'sort(ancestors(4) or reverse(1::5))'
1025 (func
1025 (func
1026 ('symbol', 'sort')
1026 ('symbol', 'sort')
1027 (or
1027 (or
1028 (func
1028 (func
1029 ('symbol', 'ancestors')
1029 ('symbol', 'ancestors')
1030 ('symbol', '4'))
1030 ('symbol', '4'))
1031 (func
1031 (func
1032 ('symbol', 'reverse')
1032 ('symbol', 'reverse')
1033 (dagrange
1033 (dagrange
1034 ('symbol', '1')
1034 ('symbol', '1')
1035 ('symbol', '5')))))
1035 ('symbol', '5')))))
1036 * set:
1036 * set:
1037 <addset+
1037 <addset+
1038 <generatorset+>,
1038 <generatorset+>,
1039 <baseset- [1, 3, 5]>>
1039 <baseset- [1, 3, 5]>>
1040 0
1040 0
1041 1
1041 1
1042 2
1042 2
1043 3
1043 3
1044 4
1044 4
1045 5
1045 5
1046
1046
1047 test optimization of trivial `or` operation
1047 test optimization of trivial `or` operation
1048
1048
1049 $ try --optimize '0|(1)|"2"|-2|tip|null'
1049 $ try --optimize '0|(1)|"2"|-2|tip|null'
1050 (or
1050 (or
1051 ('symbol', '0')
1051 ('symbol', '0')
1052 (group
1052 (group
1053 ('symbol', '1'))
1053 ('symbol', '1'))
1054 ('string', '2')
1054 ('string', '2')
1055 (negate
1055 (negate
1056 ('symbol', '2'))
1056 ('symbol', '2'))
1057 ('symbol', 'tip')
1057 ('symbol', 'tip')
1058 ('symbol', 'null'))
1058 ('symbol', 'null'))
1059 * optimized:
1059 * optimized:
1060 (func
1060 (func
1061 ('symbol', '_list')
1061 ('symbol', '_list')
1062 ('string', '0\x001\x002\x00-2\x00tip\x00null'))
1062 ('string', '0\x001\x002\x00-2\x00tip\x00null'))
1063 * set:
1063 * set:
1064 <baseset [0, 1, 2, 8, 9, -1]>
1064 <baseset [0, 1, 2, 8, 9, -1]>
1065 0
1065 0
1066 1
1066 1
1067 2
1067 2
1068 8
1068 8
1069 9
1069 9
1070 -1
1070 -1
1071
1071
1072 $ try --optimize '0|1|2:3'
1072 $ try --optimize '0|1|2:3'
1073 (or
1073 (or
1074 ('symbol', '0')
1074 ('symbol', '0')
1075 ('symbol', '1')
1075 ('symbol', '1')
1076 (range
1076 (range
1077 ('symbol', '2')
1077 ('symbol', '2')
1078 ('symbol', '3')))
1078 ('symbol', '3')))
1079 * optimized:
1079 * optimized:
1080 (or
1080 (or
1081 (func
1081 (func
1082 ('symbol', '_list')
1082 ('symbol', '_list')
1083 ('string', '0\x001'))
1083 ('string', '0\x001'))
1084 (range
1084 (range
1085 ('symbol', '2')
1085 ('symbol', '2')
1086 ('symbol', '3')))
1086 ('symbol', '3')))
1087 * set:
1087 * set:
1088 <addset
1088 <addset
1089 <baseset [0, 1]>,
1089 <baseset [0, 1]>,
1090 <spanset+ 2:3>>
1090 <spanset+ 2:3>>
1091 0
1091 0
1092 1
1092 1
1093 2
1093 2
1094 3
1094 3
1095
1095
1096 $ try --optimize '0:1|2|3:4|5|6'
1096 $ try --optimize '0:1|2|3:4|5|6'
1097 (or
1097 (or
1098 (range
1098 (range
1099 ('symbol', '0')
1099 ('symbol', '0')
1100 ('symbol', '1'))
1100 ('symbol', '1'))
1101 ('symbol', '2')
1101 ('symbol', '2')
1102 (range
1102 (range
1103 ('symbol', '3')
1103 ('symbol', '3')
1104 ('symbol', '4'))
1104 ('symbol', '4'))
1105 ('symbol', '5')
1105 ('symbol', '5')
1106 ('symbol', '6'))
1106 ('symbol', '6'))
1107 * optimized:
1107 * optimized:
1108 (or
1108 (or
1109 (range
1109 (range
1110 ('symbol', '0')
1110 ('symbol', '0')
1111 ('symbol', '1'))
1111 ('symbol', '1'))
1112 ('symbol', '2')
1112 ('symbol', '2')
1113 (range
1113 (range
1114 ('symbol', '3')
1114 ('symbol', '3')
1115 ('symbol', '4'))
1115 ('symbol', '4'))
1116 (func
1116 (func
1117 ('symbol', '_list')
1117 ('symbol', '_list')
1118 ('string', '5\x006')))
1118 ('string', '5\x006')))
1119 * set:
1119 * set:
1120 <addset
1120 <addset
1121 <addset
1121 <addset
1122 <spanset+ 0:1>,
1122 <spanset+ 0:1>,
1123 <baseset [2]>>,
1123 <baseset [2]>>,
1124 <addset
1124 <addset
1125 <spanset+ 3:4>,
1125 <spanset+ 3:4>,
1126 <baseset [5, 6]>>>
1126 <baseset [5, 6]>>>
1127 0
1127 0
1128 1
1128 1
1129 2
1129 2
1130 3
1130 3
1131 4
1131 4
1132 5
1132 5
1133 6
1133 6
1134
1134
1135 test that `_list` should be narrowed by provided `subset`
1135 test that `_list` should be narrowed by provided `subset`
1136
1136
1137 $ log '0:2 and (null|1|2|3)'
1137 $ log '0:2 and (null|1|2|3)'
1138 1
1138 1
1139 2
1139 2
1140
1140
1141 test that `_list` should remove duplicates
1141 test that `_list` should remove duplicates
1142
1142
1143 $ log '0|1|2|1|2|-1|tip'
1143 $ log '0|1|2|1|2|-1|tip'
1144 0
1144 0
1145 1
1145 1
1146 2
1146 2
1147 9
1147 9
1148
1148
1149 test unknown revision in `_list`
1149 test unknown revision in `_list`
1150
1150
1151 $ log '0|unknown'
1151 $ log '0|unknown'
1152 abort: unknown revision 'unknown'!
1152 abort: unknown revision 'unknown'!
1153 [255]
1153 [255]
1154
1154
1155 test integer range in `_list`
1155 test integer range in `_list`
1156
1156
1157 $ log '-1|-10'
1157 $ log '-1|-10'
1158 9
1158 9
1159 0
1159 0
1160
1160
1161 $ log '-10|-11'
1161 $ log '-10|-11'
1162 abort: unknown revision '-11'!
1162 abort: unknown revision '-11'!
1163 [255]
1163 [255]
1164
1164
1165 $ log '9|10'
1165 $ log '9|10'
1166 abort: unknown revision '10'!
1166 abort: unknown revision '10'!
1167 [255]
1167 [255]
1168
1168
1169 test '0000' != '0' in `_list`
1169 test '0000' != '0' in `_list`
1170
1170
1171 $ log '0|0000'
1171 $ log '0|0000'
1172 0
1172 0
1173 -1
1173 -1
1174
1174
1175 test ',' in `_list`
1175 test ',' in `_list`
1176 $ log '0,1'
1176 $ log '0,1'
1177 hg: parse error: can't use a list in this context
1177 hg: parse error: can't use a list in this context
1178 (see hg help "revsets.x or y")
1178 (see hg help "revsets.x or y")
1179 [255]
1179 [255]
1180 $ try '0,1,2'
1180 $ try '0,1,2'
1181 (list
1181 (list
1182 ('symbol', '0')
1182 ('symbol', '0')
1183 ('symbol', '1')
1183 ('symbol', '1')
1184 ('symbol', '2'))
1184 ('symbol', '2'))
1185 hg: parse error: can't use a list in this context
1185 hg: parse error: can't use a list in this context
1186 (see hg help "revsets.x or y")
1186 (see hg help "revsets.x or y")
1187 [255]
1187 [255]
1188
1188
1189 test that chained `or` operations make balanced addsets
1189 test that chained `or` operations make balanced addsets
1190
1190
1191 $ try '0:1|1:2|2:3|3:4|4:5'
1191 $ try '0:1|1:2|2:3|3:4|4:5'
1192 (or
1192 (or
1193 (range
1193 (range
1194 ('symbol', '0')
1194 ('symbol', '0')
1195 ('symbol', '1'))
1195 ('symbol', '1'))
1196 (range
1196 (range
1197 ('symbol', '1')
1197 ('symbol', '1')
1198 ('symbol', '2'))
1198 ('symbol', '2'))
1199 (range
1199 (range
1200 ('symbol', '2')
1200 ('symbol', '2')
1201 ('symbol', '3'))
1201 ('symbol', '3'))
1202 (range
1202 (range
1203 ('symbol', '3')
1203 ('symbol', '3')
1204 ('symbol', '4'))
1204 ('symbol', '4'))
1205 (range
1205 (range
1206 ('symbol', '4')
1206 ('symbol', '4')
1207 ('symbol', '5')))
1207 ('symbol', '5')))
1208 * set:
1208 * set:
1209 <addset
1209 <addset
1210 <addset
1210 <addset
1211 <spanset+ 0:1>,
1211 <spanset+ 0:1>,
1212 <spanset+ 1:2>>,
1212 <spanset+ 1:2>>,
1213 <addset
1213 <addset
1214 <spanset+ 2:3>,
1214 <spanset+ 2:3>,
1215 <addset
1215 <addset
1216 <spanset+ 3:4>,
1216 <spanset+ 3:4>,
1217 <spanset+ 4:5>>>>
1217 <spanset+ 4:5>>>>
1218 0
1218 0
1219 1
1219 1
1220 2
1220 2
1221 3
1221 3
1222 4
1222 4
1223 5
1223 5
1224
1224
1225 no crash by empty group "()" while optimizing `or` operations
1225 no crash by empty group "()" while optimizing `or` operations
1226
1226
1227 $ try --optimize '0|()'
1227 $ try --optimize '0|()'
1228 (or
1228 (or
1229 ('symbol', '0')
1229 ('symbol', '0')
1230 (group
1230 (group
1231 None))
1231 None))
1232 * optimized:
1232 * optimized:
1233 (or
1233 (or
1234 ('symbol', '0')
1234 ('symbol', '0')
1235 None)
1235 None)
1236 hg: parse error: missing argument
1236 hg: parse error: missing argument
1237 [255]
1237 [255]
1238
1238
1239 test that chained `or` operations never eat up stack (issue4624)
1239 test that chained `or` operations never eat up stack (issue4624)
1240 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
1240 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
1241
1241
1242 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
1242 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
1243 0
1243 0
1244 1
1244 1
1245
1245
1246 test that repeated `-r` options never eat up stack (issue4565)
1246 test that repeated `-r` options never eat up stack (issue4565)
1247 (uses `-r 0::1` to avoid possible optimization at old-style parser)
1247 (uses `-r 0::1` to avoid possible optimization at old-style parser)
1248
1248
1249 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
1249 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
1250 0
1250 0
1251 1
1251 1
1252
1252
1253 check that conversion to only works
1253 check that conversion to only works
1254 $ try --optimize '::3 - ::1'
1254 $ try --optimize '::3 - ::1'
1255 (minus
1255 (minus
1256 (dagrangepre
1256 (dagrangepre
1257 ('symbol', '3'))
1257 ('symbol', '3'))
1258 (dagrangepre
1258 (dagrangepre
1259 ('symbol', '1')))
1259 ('symbol', '1')))
1260 * optimized:
1260 * optimized:
1261 (func
1261 (func
1262 ('symbol', 'only')
1262 ('symbol', 'only')
1263 (list
1263 (list
1264 ('symbol', '3')
1264 ('symbol', '3')
1265 ('symbol', '1')))
1265 ('symbol', '1')))
1266 * set:
1266 * set:
1267 <baseset+ [3]>
1267 <baseset+ [3]>
1268 3
1268 3
1269 $ try --optimize 'ancestors(1) - ancestors(3)'
1269 $ try --optimize 'ancestors(1) - ancestors(3)'
1270 (minus
1270 (minus
1271 (func
1271 (func
1272 ('symbol', 'ancestors')
1272 ('symbol', 'ancestors')
1273 ('symbol', '1'))
1273 ('symbol', '1'))
1274 (func
1274 (func
1275 ('symbol', 'ancestors')
1275 ('symbol', 'ancestors')
1276 ('symbol', '3')))
1276 ('symbol', '3')))
1277 * optimized:
1277 * optimized:
1278 (func
1278 (func
1279 ('symbol', 'only')
1279 ('symbol', 'only')
1280 (list
1280 (list
1281 ('symbol', '1')
1281 ('symbol', '1')
1282 ('symbol', '3')))
1282 ('symbol', '3')))
1283 * set:
1283 * set:
1284 <baseset+ []>
1284 <baseset+ []>
1285 $ try --optimize 'not ::2 and ::6'
1285 $ try --optimize 'not ::2 and ::6'
1286 (and
1286 (and
1287 (not
1287 (not
1288 (dagrangepre
1288 (dagrangepre
1289 ('symbol', '2')))
1289 ('symbol', '2')))
1290 (dagrangepre
1290 (dagrangepre
1291 ('symbol', '6')))
1291 ('symbol', '6')))
1292 * optimized:
1292 * optimized:
1293 (func
1293 (func
1294 ('symbol', 'only')
1294 ('symbol', 'only')
1295 (list
1295 (list
1296 ('symbol', '6')
1296 ('symbol', '6')
1297 ('symbol', '2')))
1297 ('symbol', '2')))
1298 * set:
1298 * set:
1299 <baseset+ [3, 4, 5, 6]>
1299 <baseset+ [3, 4, 5, 6]>
1300 3
1300 3
1301 4
1301 4
1302 5
1302 5
1303 6
1303 6
1304 $ try --optimize 'ancestors(6) and not ancestors(4)'
1304 $ try --optimize 'ancestors(6) and not ancestors(4)'
1305 (and
1305 (and
1306 (func
1306 (func
1307 ('symbol', 'ancestors')
1307 ('symbol', 'ancestors')
1308 ('symbol', '6'))
1308 ('symbol', '6'))
1309 (not
1309 (not
1310 (func
1310 (func
1311 ('symbol', 'ancestors')
1311 ('symbol', 'ancestors')
1312 ('symbol', '4'))))
1312 ('symbol', '4'))))
1313 * optimized:
1313 * optimized:
1314 (func
1314 (func
1315 ('symbol', 'only')
1315 ('symbol', 'only')
1316 (list
1316 (list
1317 ('symbol', '6')
1317 ('symbol', '6')
1318 ('symbol', '4')))
1318 ('symbol', '4')))
1319 * set:
1319 * set:
1320 <baseset+ [3, 5, 6]>
1320 <baseset+ [3, 5, 6]>
1321 3
1321 3
1322 5
1322 5
1323 6
1323 6
1324
1324
1325 no crash by empty group "()" while optimizing to "only()"
1325 no crash by empty group "()" while optimizing to "only()"
1326
1326
1327 $ try --optimize '::1 and ()'
1327 $ try --optimize '::1 and ()'
1328 (and
1328 (and
1329 (dagrangepre
1329 (dagrangepre
1330 ('symbol', '1'))
1330 ('symbol', '1'))
1331 (group
1331 (group
1332 None))
1332 None))
1333 * optimized:
1333 * optimized:
1334 (and
1334 (and
1335 None
1335 None
1336 (func
1336 (func
1337 ('symbol', 'ancestors')
1337 ('symbol', 'ancestors')
1338 ('symbol', '1')))
1338 ('symbol', '1')))
1339 hg: parse error: missing argument
1339 hg: parse error: missing argument
1340 [255]
1340 [255]
1341
1341
1342 we can use patterns when searching for tags
1342 we can use patterns when searching for tags
1343
1343
1344 $ log 'tag("1..*")'
1344 $ log 'tag("1..*")'
1345 abort: tag '1..*' does not exist!
1345 abort: tag '1..*' does not exist!
1346 [255]
1346 [255]
1347 $ log 'tag("re:1..*")'
1347 $ log 'tag("re:1..*")'
1348 6
1348 6
1349 $ log 'tag("re:[0-9].[0-9]")'
1349 $ log 'tag("re:[0-9].[0-9]")'
1350 6
1350 6
1351 $ log 'tag("literal:1.0")'
1351 $ log 'tag("literal:1.0")'
1352 6
1352 6
1353 $ log 'tag("re:0..*")'
1353 $ log 'tag("re:0..*")'
1354
1354
1355 $ log 'tag(unknown)'
1355 $ log 'tag(unknown)'
1356 abort: tag 'unknown' does not exist!
1356 abort: tag 'unknown' does not exist!
1357 [255]
1357 [255]
1358 $ log 'tag("re:unknown")'
1358 $ log 'tag("re:unknown")'
1359 $ log 'present(tag("unknown"))'
1359 $ log 'present(tag("unknown"))'
1360 $ log 'present(tag("re:unknown"))'
1360 $ log 'present(tag("re:unknown"))'
1361 $ log 'branch(unknown)'
1361 $ log 'branch(unknown)'
1362 abort: unknown revision 'unknown'!
1362 abort: unknown revision 'unknown'!
1363 [255]
1363 [255]
1364 $ log 'branch("literal:unknown")'
1364 $ log 'branch("literal:unknown")'
1365 abort: branch 'unknown' does not exist!
1365 abort: branch 'unknown' does not exist!
1366 [255]
1366 [255]
1367 $ log 'branch("re:unknown")'
1367 $ log 'branch("re:unknown")'
1368 $ log 'present(branch("unknown"))'
1368 $ log 'present(branch("unknown"))'
1369 $ log 'present(branch("re:unknown"))'
1369 $ log 'present(branch("re:unknown"))'
1370 $ log 'user(bob)'
1370 $ log 'user(bob)'
1371 2
1371 2
1372
1372
1373 $ log '4::8'
1373 $ log '4::8'
1374 4
1374 4
1375 8
1375 8
1376 $ log '4:8'
1376 $ log '4:8'
1377 4
1377 4
1378 5
1378 5
1379 6
1379 6
1380 7
1380 7
1381 8
1381 8
1382
1382
1383 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
1383 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
1384 4
1384 4
1385 2
1385 2
1386 5
1386 5
1387
1387
1388 $ log 'not 0 and 0:2'
1388 $ log 'not 0 and 0:2'
1389 1
1389 1
1390 2
1390 2
1391 $ log 'not 1 and 0:2'
1391 $ log 'not 1 and 0:2'
1392 0
1392 0
1393 2
1393 2
1394 $ log 'not 2 and 0:2'
1394 $ log 'not 2 and 0:2'
1395 0
1395 0
1396 1
1396 1
1397 $ log '(1 and 2)::'
1397 $ log '(1 and 2)::'
1398 $ log '(1 and 2):'
1398 $ log '(1 and 2):'
1399 $ log '(1 and 2):3'
1399 $ log '(1 and 2):3'
1400 $ log 'sort(head(), -rev)'
1400 $ log 'sort(head(), -rev)'
1401 9
1401 9
1402 7
1402 7
1403 6
1403 6
1404 5
1404 5
1405 4
1405 4
1406 3
1406 3
1407 2
1407 2
1408 1
1408 1
1409 0
1409 0
1410 $ log '4::8 - 8'
1410 $ log '4::8 - 8'
1411 4
1411 4
1412 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
1412 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
1413 2
1413 2
1414 3
1414 3
1415 1
1415 1
1416
1416
1417 $ log 'named("unknown")'
1417 $ log 'named("unknown")'
1418 abort: namespace 'unknown' does not exist!
1418 abort: namespace 'unknown' does not exist!
1419 [255]
1419 [255]
1420 $ log 'named("re:unknown")'
1420 $ log 'named("re:unknown")'
1421 abort: no namespace exists that match 'unknown'!
1421 abort: no namespace exists that match 'unknown'!
1422 [255]
1422 [255]
1423 $ log 'present(named("unknown"))'
1423 $ log 'present(named("unknown"))'
1424 $ log 'present(named("re:unknown"))'
1424 $ log 'present(named("re:unknown"))'
1425
1425
1426 $ log 'tag()'
1426 $ log 'tag()'
1427 6
1427 6
1428 $ log 'named("tags")'
1428 $ log 'named("tags")'
1429 6
1429 6
1430
1430
1431 issue2437
1431 issue2437
1432
1432
1433 $ log '3 and p1(5)'
1433 $ log '3 and p1(5)'
1434 3
1434 3
1435 $ log '4 and p2(6)'
1435 $ log '4 and p2(6)'
1436 4
1436 4
1437 $ log '1 and parents(:2)'
1437 $ log '1 and parents(:2)'
1438 1
1438 1
1439 $ log '2 and children(1:)'
1439 $ log '2 and children(1:)'
1440 2
1440 2
1441 $ log 'roots(all()) or roots(all())'
1441 $ log 'roots(all()) or roots(all())'
1442 0
1442 0
1443 $ hg debugrevspec 'roots(all()) or roots(all())'
1443 $ hg debugrevspec 'roots(all()) or roots(all())'
1444 0
1444 0
1445 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
1445 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
1446 9
1446 9
1447 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
1447 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
1448 4
1448 4
1449
1449
1450 issue2654: report a parse error if the revset was not completely parsed
1450 issue2654: report a parse error if the revset was not completely parsed
1451
1451
1452 $ log '1 OR 2'
1452 $ log '1 OR 2'
1453 hg: parse error at 2: invalid token
1453 hg: parse error at 2: invalid token
1454 [255]
1454 [255]
1455
1455
1456 or operator should preserve ordering:
1456 or operator should preserve ordering:
1457 $ log 'reverse(2::4) or tip'
1457 $ log 'reverse(2::4) or tip'
1458 4
1458 4
1459 2
1459 2
1460 9
1460 9
1461
1461
1462 parentrevspec
1462 parentrevspec
1463
1463
1464 $ log 'merge()^0'
1464 $ log 'merge()^0'
1465 6
1465 6
1466 $ log 'merge()^'
1466 $ log 'merge()^'
1467 5
1467 5
1468 $ log 'merge()^1'
1468 $ log 'merge()^1'
1469 5
1469 5
1470 $ log 'merge()^2'
1470 $ log 'merge()^2'
1471 4
1471 4
1472 $ log 'merge()^^'
1472 $ log 'merge()^^'
1473 3
1473 3
1474 $ log 'merge()^1^'
1474 $ log 'merge()^1^'
1475 3
1475 3
1476 $ log 'merge()^^^'
1476 $ log 'merge()^^^'
1477 1
1477 1
1478
1478
1479 $ log 'merge()~0'
1479 $ log 'merge()~0'
1480 6
1480 6
1481 $ log 'merge()~1'
1481 $ log 'merge()~1'
1482 5
1482 5
1483 $ log 'merge()~2'
1483 $ log 'merge()~2'
1484 3
1484 3
1485 $ log 'merge()~2^1'
1485 $ log 'merge()~2^1'
1486 1
1486 1
1487 $ log 'merge()~3'
1487 $ log 'merge()~3'
1488 1
1488 1
1489
1489
1490 $ log '(-3:tip)^'
1490 $ log '(-3:tip)^'
1491 4
1491 4
1492 6
1492 6
1493 8
1493 8
1494
1494
1495 $ log 'tip^foo'
1495 $ log 'tip^foo'
1496 hg: parse error: ^ expects a number 0, 1, or 2
1496 hg: parse error: ^ expects a number 0, 1, or 2
1497 [255]
1497 [255]
1498
1498
1499 Bogus function gets suggestions
1499 Bogus function gets suggestions
1500 $ log 'add()'
1500 $ log 'add()'
1501 hg: parse error: unknown identifier: add
1501 hg: parse error: unknown identifier: add
1502 (did you mean adds?)
1502 (did you mean adds?)
1503 [255]
1503 [255]
1504 $ log 'added()'
1504 $ log 'added()'
1505 hg: parse error: unknown identifier: added
1505 hg: parse error: unknown identifier: added
1506 (did you mean adds?)
1506 (did you mean adds?)
1507 [255]
1507 [255]
1508 $ log 'remo()'
1508 $ log 'remo()'
1509 hg: parse error: unknown identifier: remo
1509 hg: parse error: unknown identifier: remo
1510 (did you mean one of remote, removes?)
1510 (did you mean one of remote, removes?)
1511 [255]
1511 [255]
1512 $ log 'babar()'
1512 $ log 'babar()'
1513 hg: parse error: unknown identifier: babar
1513 hg: parse error: unknown identifier: babar
1514 [255]
1514 [255]
1515
1515
1516 Bogus function with a similar internal name doesn't suggest the internal name
1516 Bogus function with a similar internal name doesn't suggest the internal name
1517 $ log 'matches()'
1517 $ log 'matches()'
1518 hg: parse error: unknown identifier: matches
1518 hg: parse error: unknown identifier: matches
1519 (did you mean matching?)
1519 (did you mean matching?)
1520 [255]
1520 [255]
1521
1521
1522 Undocumented functions aren't suggested as similar either
1522 Undocumented functions aren't suggested as similar either
1523 $ log 'wdir2()'
1523 $ log 'wdir2()'
1524 hg: parse error: unknown identifier: wdir2
1524 hg: parse error: unknown identifier: wdir2
1525 [255]
1525 [255]
1526
1526
1527 multiple revspecs
1527 multiple revspecs
1528
1528
1529 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
1529 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
1530 8
1530 8
1531 9
1531 9
1532 4
1532 4
1533 5
1533 5
1534 6
1534 6
1535 7
1535 7
1536
1536
1537 test usage in revpair (with "+")
1537 test usage in revpair (with "+")
1538
1538
1539 (real pair)
1539 (real pair)
1540
1540
1541 $ hg diff -r 'tip^^' -r 'tip'
1541 $ hg diff -r 'tip^^' -r 'tip'
1542 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1542 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1543 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1543 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1544 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1544 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1545 @@ -0,0 +1,1 @@
1545 @@ -0,0 +1,1 @@
1546 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1546 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1547 $ hg diff -r 'tip^^::tip'
1547 $ hg diff -r 'tip^^::tip'
1548 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1548 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1549 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1549 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1550 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1550 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1551 @@ -0,0 +1,1 @@
1551 @@ -0,0 +1,1 @@
1552 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1552 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1553
1553
1554 (single rev)
1554 (single rev)
1555
1555
1556 $ hg diff -r 'tip^' -r 'tip^'
1556 $ hg diff -r 'tip^' -r 'tip^'
1557 $ hg diff -r 'tip^:tip^'
1557 $ hg diff -r 'tip^:tip^'
1558
1558
1559 (single rev that does not looks like a range)
1559 (single rev that does not looks like a range)
1560
1560
1561 $ hg diff -r 'tip^::tip^ or tip^'
1561 $ hg diff -r 'tip^::tip^ or tip^'
1562 diff -r d5d0dcbdc4d9 .hgtags
1562 diff -r d5d0dcbdc4d9 .hgtags
1563 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1563 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1564 +++ b/.hgtags * (glob)
1564 +++ b/.hgtags * (glob)
1565 @@ -0,0 +1,1 @@
1565 @@ -0,0 +1,1 @@
1566 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1566 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1567 $ hg diff -r 'tip^ or tip^'
1567 $ hg diff -r 'tip^ or tip^'
1568 diff -r d5d0dcbdc4d9 .hgtags
1568 diff -r d5d0dcbdc4d9 .hgtags
1569 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1569 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1570 +++ b/.hgtags * (glob)
1570 +++ b/.hgtags * (glob)
1571 @@ -0,0 +1,1 @@
1571 @@ -0,0 +1,1 @@
1572 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1572 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1573
1573
1574 (no rev)
1574 (no rev)
1575
1575
1576 $ hg diff -r 'author("babar") or author("celeste")'
1576 $ hg diff -r 'author("babar") or author("celeste")'
1577 abort: empty revision range
1577 abort: empty revision range
1578 [255]
1578 [255]
1579
1579
1580 aliases:
1580 aliases:
1581
1581
1582 $ echo '[revsetalias]' >> .hg/hgrc
1582 $ echo '[revsetalias]' >> .hg/hgrc
1583 $ echo 'm = merge()' >> .hg/hgrc
1583 $ echo 'm = merge()' >> .hg/hgrc
1584 (revset aliases can override builtin revsets)
1584 (revset aliases can override builtin revsets)
1585 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
1585 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
1586 $ echo 'sincem = descendants(m)' >> .hg/hgrc
1586 $ echo 'sincem = descendants(m)' >> .hg/hgrc
1587 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
1587 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
1588 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1588 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1589 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1589 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1590
1590
1591 $ try m
1591 $ try m
1592 ('symbol', 'm')
1592 ('symbol', 'm')
1593 * expanded:
1593 (func
1594 (func
1594 ('symbol', 'merge')
1595 ('symbol', 'merge')
1595 None)
1596 None)
1596 * set:
1597 * set:
1597 <filteredset
1598 <filteredset
1598 <fullreposet+ 0:9>,
1599 <fullreposet+ 0:9>,
1599 <merge>>
1600 <merge>>
1600 6
1601 6
1601
1602
1602 $ HGPLAIN=1
1603 $ HGPLAIN=1
1603 $ export HGPLAIN
1604 $ export HGPLAIN
1604 $ try m
1605 $ try m
1605 ('symbol', 'm')
1606 ('symbol', 'm')
1606 abort: unknown revision 'm'!
1607 abort: unknown revision 'm'!
1607 [255]
1608 [255]
1608
1609
1609 $ HGPLAINEXCEPT=revsetalias
1610 $ HGPLAINEXCEPT=revsetalias
1610 $ export HGPLAINEXCEPT
1611 $ export HGPLAINEXCEPT
1611 $ try m
1612 $ try m
1612 ('symbol', 'm')
1613 ('symbol', 'm')
1614 * expanded:
1613 (func
1615 (func
1614 ('symbol', 'merge')
1616 ('symbol', 'merge')
1615 None)
1617 None)
1616 * set:
1618 * set:
1617 <filteredset
1619 <filteredset
1618 <fullreposet+ 0:9>,
1620 <fullreposet+ 0:9>,
1619 <merge>>
1621 <merge>>
1620 6
1622 6
1621
1623
1622 $ unset HGPLAIN
1624 $ unset HGPLAIN
1623 $ unset HGPLAINEXCEPT
1625 $ unset HGPLAINEXCEPT
1624
1626
1625 $ try 'p2(.)'
1627 $ try 'p2(.)'
1626 (func
1628 (func
1627 ('symbol', 'p2')
1629 ('symbol', 'p2')
1628 ('symbol', '.'))
1630 ('symbol', '.'))
1631 * expanded:
1629 (func
1632 (func
1630 ('symbol', 'p1')
1633 ('symbol', 'p1')
1631 ('symbol', '.'))
1634 ('symbol', '.'))
1632 * set:
1635 * set:
1633 <baseset+ [8]>
1636 <baseset+ [8]>
1634 8
1637 8
1635
1638
1636 $ HGPLAIN=1
1639 $ HGPLAIN=1
1637 $ export HGPLAIN
1640 $ export HGPLAIN
1638 $ try 'p2(.)'
1641 $ try 'p2(.)'
1639 (func
1642 (func
1640 ('symbol', 'p2')
1643 ('symbol', 'p2')
1641 ('symbol', '.'))
1644 ('symbol', '.'))
1642 * set:
1645 * set:
1643 <baseset+ []>
1646 <baseset+ []>
1644
1647
1645 $ HGPLAINEXCEPT=revsetalias
1648 $ HGPLAINEXCEPT=revsetalias
1646 $ export HGPLAINEXCEPT
1649 $ export HGPLAINEXCEPT
1647 $ try 'p2(.)'
1650 $ try 'p2(.)'
1648 (func
1651 (func
1649 ('symbol', 'p2')
1652 ('symbol', 'p2')
1650 ('symbol', '.'))
1653 ('symbol', '.'))
1654 * expanded:
1651 (func
1655 (func
1652 ('symbol', 'p1')
1656 ('symbol', 'p1')
1653 ('symbol', '.'))
1657 ('symbol', '.'))
1654 * set:
1658 * set:
1655 <baseset+ [8]>
1659 <baseset+ [8]>
1656 8
1660 8
1657
1661
1658 $ unset HGPLAIN
1662 $ unset HGPLAIN
1659 $ unset HGPLAINEXCEPT
1663 $ unset HGPLAINEXCEPT
1660
1664
1661 test alias recursion
1665 test alias recursion
1662
1666
1663 $ try sincem
1667 $ try sincem
1664 ('symbol', 'sincem')
1668 ('symbol', 'sincem')
1669 * expanded:
1665 (func
1670 (func
1666 ('symbol', 'descendants')
1671 ('symbol', 'descendants')
1667 (func
1672 (func
1668 ('symbol', 'merge')
1673 ('symbol', 'merge')
1669 None))
1674 None))
1670 * set:
1675 * set:
1671 <addset+
1676 <addset+
1672 <filteredset
1677 <filteredset
1673 <fullreposet+ 0:9>,
1678 <fullreposet+ 0:9>,
1674 <merge>>,
1679 <merge>>,
1675 <generatorset+>>
1680 <generatorset+>>
1676 6
1681 6
1677 7
1682 7
1678
1683
1679 test infinite recursion
1684 test infinite recursion
1680
1685
1681 $ echo 'recurse1 = recurse2' >> .hg/hgrc
1686 $ echo 'recurse1 = recurse2' >> .hg/hgrc
1682 $ echo 'recurse2 = recurse1' >> .hg/hgrc
1687 $ echo 'recurse2 = recurse1' >> .hg/hgrc
1683 $ try recurse1
1688 $ try recurse1
1684 ('symbol', 'recurse1')
1689 ('symbol', 'recurse1')
1685 hg: parse error: infinite expansion of revset alias "recurse1" detected
1690 hg: parse error: infinite expansion of revset alias "recurse1" detected
1686 [255]
1691 [255]
1687
1692
1688 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
1693 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
1689 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
1694 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
1690 $ try "level2(level1(1, 2), 3)"
1695 $ try "level2(level1(1, 2), 3)"
1691 (func
1696 (func
1692 ('symbol', 'level2')
1697 ('symbol', 'level2')
1693 (list
1698 (list
1694 (func
1699 (func
1695 ('symbol', 'level1')
1700 ('symbol', 'level1')
1696 (list
1701 (list
1697 ('symbol', '1')
1702 ('symbol', '1')
1698 ('symbol', '2')))
1703 ('symbol', '2')))
1699 ('symbol', '3')))
1704 ('symbol', '3')))
1705 * expanded:
1700 (or
1706 (or
1701 ('symbol', '3')
1707 ('symbol', '3')
1702 (or
1708 (or
1703 ('symbol', '1')
1709 ('symbol', '1')
1704 ('symbol', '2')))
1710 ('symbol', '2')))
1705 * set:
1711 * set:
1706 <addset
1712 <addset
1707 <baseset [3]>,
1713 <baseset [3]>,
1708 <baseset [1, 2]>>
1714 <baseset [1, 2]>>
1709 3
1715 3
1710 1
1716 1
1711 2
1717 2
1712
1718
1713 test nesting and variable passing
1719 test nesting and variable passing
1714
1720
1715 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1721 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1716 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1722 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1717 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1723 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1718 $ try 'nested(2:5)'
1724 $ try 'nested(2:5)'
1719 (func
1725 (func
1720 ('symbol', 'nested')
1726 ('symbol', 'nested')
1721 (range
1727 (range
1722 ('symbol', '2')
1728 ('symbol', '2')
1723 ('symbol', '5')))
1729 ('symbol', '5')))
1730 * expanded:
1724 (func
1731 (func
1725 ('symbol', 'max')
1732 ('symbol', 'max')
1726 (range
1733 (range
1727 ('symbol', '2')
1734 ('symbol', '2')
1728 ('symbol', '5')))
1735 ('symbol', '5')))
1729 * set:
1736 * set:
1730 <baseset
1737 <baseset
1731 <max
1738 <max
1732 <fullreposet+ 0:9>,
1739 <fullreposet+ 0:9>,
1733 <spanset+ 2:5>>>
1740 <spanset+ 2:5>>>
1734 5
1741 5
1735
1742
1736 test chained `or` operations are flattened at parsing phase
1743 test chained `or` operations are flattened at parsing phase
1737
1744
1738 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
1745 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
1739 $ try 'chainedorops(0:1, 1:2, 2:3)'
1746 $ try 'chainedorops(0:1, 1:2, 2:3)'
1740 (func
1747 (func
1741 ('symbol', 'chainedorops')
1748 ('symbol', 'chainedorops')
1742 (list
1749 (list
1743 (range
1750 (range
1744 ('symbol', '0')
1751 ('symbol', '0')
1745 ('symbol', '1'))
1752 ('symbol', '1'))
1746 (range
1753 (range
1747 ('symbol', '1')
1754 ('symbol', '1')
1748 ('symbol', '2'))
1755 ('symbol', '2'))
1749 (range
1756 (range
1750 ('symbol', '2')
1757 ('symbol', '2')
1751 ('symbol', '3'))))
1758 ('symbol', '3'))))
1759 * expanded:
1752 (or
1760 (or
1753 (range
1761 (range
1754 ('symbol', '0')
1762 ('symbol', '0')
1755 ('symbol', '1'))
1763 ('symbol', '1'))
1756 (range
1764 (range
1757 ('symbol', '1')
1765 ('symbol', '1')
1758 ('symbol', '2'))
1766 ('symbol', '2'))
1759 (range
1767 (range
1760 ('symbol', '2')
1768 ('symbol', '2')
1761 ('symbol', '3')))
1769 ('symbol', '3')))
1762 * set:
1770 * set:
1763 <addset
1771 <addset
1764 <spanset+ 0:1>,
1772 <spanset+ 0:1>,
1765 <addset
1773 <addset
1766 <spanset+ 1:2>,
1774 <spanset+ 1:2>,
1767 <spanset+ 2:3>>>
1775 <spanset+ 2:3>>>
1768 0
1776 0
1769 1
1777 1
1770 2
1778 2
1771 3
1779 3
1772
1780
1773 test variable isolation, variable placeholders are rewritten as string
1781 test variable isolation, variable placeholders are rewritten as string
1774 then parsed and matched again as string. Check they do not leak too
1782 then parsed and matched again as string. Check they do not leak too
1775 far away.
1783 far away.
1776
1784
1777 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1785 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1778 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1786 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1779 $ try 'callinjection(2:5)'
1787 $ try 'callinjection(2:5)'
1780 (func
1788 (func
1781 ('symbol', 'callinjection')
1789 ('symbol', 'callinjection')
1782 (range
1790 (range
1783 ('symbol', '2')
1791 ('symbol', '2')
1784 ('symbol', '5')))
1792 ('symbol', '5')))
1793 * expanded:
1785 (func
1794 (func
1786 ('symbol', 'descendants')
1795 ('symbol', 'descendants')
1787 (func
1796 (func
1788 ('symbol', 'max')
1797 ('symbol', 'max')
1789 ('string', '$1')))
1798 ('string', '$1')))
1790 abort: unknown revision '$1'!
1799 abort: unknown revision '$1'!
1791 [255]
1800 [255]
1792
1801
1793 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1802 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1794 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1803 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1795 $ try 'callinjection2(2:5)'
1804 $ try 'callinjection2(2:5)'
1796 (func
1805 (func
1797 ('symbol', 'callinjection2')
1806 ('symbol', 'callinjection2')
1798 (range
1807 (range
1799 ('symbol', '2')
1808 ('symbol', '2')
1800 ('symbol', '5')))
1809 ('symbol', '5')))
1801 abort: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1810 abort: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1802 [255]
1811 [255]
1803 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1812 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1804 ('symbol', 'tip')
1813 ('symbol', 'tip')
1805 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1814 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1806 warning: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1815 warning: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1807 * set:
1816 * set:
1808 <baseset [9]>
1817 <baseset [9]>
1809 9
1818 9
1810 >>> data = file('.hg/hgrc', 'rb').read()
1819 >>> data = file('.hg/hgrc', 'rb').read()
1811 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1820 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1812
1821
1813 $ try 'tip'
1822 $ try 'tip'
1814 ('symbol', 'tip')
1823 ('symbol', 'tip')
1815 * set:
1824 * set:
1816 <baseset [9]>
1825 <baseset [9]>
1817 9
1826 9
1818
1827
1819 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1828 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1820 ('symbol', 'tip')
1829 ('symbol', 'tip')
1821 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1830 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1822 * set:
1831 * set:
1823 <baseset [9]>
1832 <baseset [9]>
1824 9
1833 9
1825 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1834 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1826 $ try 'strictreplacing("foo", tip)'
1835 $ try 'strictreplacing("foo", tip)'
1827 (func
1836 (func
1828 ('symbol', 'strictreplacing')
1837 ('symbol', 'strictreplacing')
1829 (list
1838 (list
1830 ('string', 'foo')
1839 ('string', 'foo')
1831 ('symbol', 'tip')))
1840 ('symbol', 'tip')))
1841 * expanded:
1832 (or
1842 (or
1833 ('symbol', 'tip')
1843 ('symbol', 'tip')
1834 (func
1844 (func
1835 ('symbol', 'desc')
1845 ('symbol', 'desc')
1836 ('string', '$1')))
1846 ('string', '$1')))
1837 * set:
1847 * set:
1838 <addset
1848 <addset
1839 <baseset [9]>,
1849 <baseset [9]>,
1840 <filteredset
1850 <filteredset
1841 <fullreposet+ 0:9>,
1851 <fullreposet+ 0:9>,
1842 <desc '$1'>>>
1852 <desc '$1'>>>
1843 9
1853 9
1844
1854
1845 $ try 'd(2:5)'
1855 $ try 'd(2:5)'
1846 (func
1856 (func
1847 ('symbol', 'd')
1857 ('symbol', 'd')
1848 (range
1858 (range
1849 ('symbol', '2')
1859 ('symbol', '2')
1850 ('symbol', '5')))
1860 ('symbol', '5')))
1861 * expanded:
1851 (func
1862 (func
1852 ('symbol', 'reverse')
1863 ('symbol', 'reverse')
1853 (func
1864 (func
1854 ('symbol', 'sort')
1865 ('symbol', 'sort')
1855 (list
1866 (list
1856 (range
1867 (range
1857 ('symbol', '2')
1868 ('symbol', '2')
1858 ('symbol', '5'))
1869 ('symbol', '5'))
1859 ('symbol', 'date'))))
1870 ('symbol', 'date'))))
1860 * set:
1871 * set:
1861 <baseset [4, 5, 3, 2]>
1872 <baseset [4, 5, 3, 2]>
1862 4
1873 4
1863 5
1874 5
1864 3
1875 3
1865 2
1876 2
1866 $ try 'rs(2 or 3, date)'
1877 $ try 'rs(2 or 3, date)'
1867 (func
1878 (func
1868 ('symbol', 'rs')
1879 ('symbol', 'rs')
1869 (list
1880 (list
1870 (or
1881 (or
1871 ('symbol', '2')
1882 ('symbol', '2')
1872 ('symbol', '3'))
1883 ('symbol', '3'))
1873 ('symbol', 'date')))
1884 ('symbol', 'date')))
1885 * expanded:
1874 (func
1886 (func
1875 ('symbol', 'reverse')
1887 ('symbol', 'reverse')
1876 (func
1888 (func
1877 ('symbol', 'sort')
1889 ('symbol', 'sort')
1878 (list
1890 (list
1879 (or
1891 (or
1880 ('symbol', '2')
1892 ('symbol', '2')
1881 ('symbol', '3'))
1893 ('symbol', '3'))
1882 ('symbol', 'date'))))
1894 ('symbol', 'date'))))
1883 * set:
1895 * set:
1884 <baseset [3, 2]>
1896 <baseset [3, 2]>
1885 3
1897 3
1886 2
1898 2
1887 $ try 'rs()'
1899 $ try 'rs()'
1888 (func
1900 (func
1889 ('symbol', 'rs')
1901 ('symbol', 'rs')
1890 None)
1902 None)
1891 hg: parse error: invalid number of arguments: 0
1903 hg: parse error: invalid number of arguments: 0
1892 [255]
1904 [255]
1893 $ try 'rs(2)'
1905 $ try 'rs(2)'
1894 (func
1906 (func
1895 ('symbol', 'rs')
1907 ('symbol', 'rs')
1896 ('symbol', '2'))
1908 ('symbol', '2'))
1897 hg: parse error: invalid number of arguments: 1
1909 hg: parse error: invalid number of arguments: 1
1898 [255]
1910 [255]
1899 $ try 'rs(2, data, 7)'
1911 $ try 'rs(2, data, 7)'
1900 (func
1912 (func
1901 ('symbol', 'rs')
1913 ('symbol', 'rs')
1902 (list
1914 (list
1903 ('symbol', '2')
1915 ('symbol', '2')
1904 ('symbol', 'data')
1916 ('symbol', 'data')
1905 ('symbol', '7')))
1917 ('symbol', '7')))
1906 hg: parse error: invalid number of arguments: 3
1918 hg: parse error: invalid number of arguments: 3
1907 [255]
1919 [255]
1908 $ try 'rs4(2 or 3, x, x, date)'
1920 $ try 'rs4(2 or 3, x, x, date)'
1909 (func
1921 (func
1910 ('symbol', 'rs4')
1922 ('symbol', 'rs4')
1911 (list
1923 (list
1912 (or
1924 (or
1913 ('symbol', '2')
1925 ('symbol', '2')
1914 ('symbol', '3'))
1926 ('symbol', '3'))
1915 ('symbol', 'x')
1927 ('symbol', 'x')
1916 ('symbol', 'x')
1928 ('symbol', 'x')
1917 ('symbol', 'date')))
1929 ('symbol', 'date')))
1930 * expanded:
1918 (func
1931 (func
1919 ('symbol', 'reverse')
1932 ('symbol', 'reverse')
1920 (func
1933 (func
1921 ('symbol', 'sort')
1934 ('symbol', 'sort')
1922 (list
1935 (list
1923 (or
1936 (or
1924 ('symbol', '2')
1937 ('symbol', '2')
1925 ('symbol', '3'))
1938 ('symbol', '3'))
1926 ('symbol', 'date'))))
1939 ('symbol', 'date'))))
1927 * set:
1940 * set:
1928 <baseset [3, 2]>
1941 <baseset [3, 2]>
1929 3
1942 3
1930 2
1943 2
1931
1944
1932 issue4553: check that revset aliases override existing hash prefix
1945 issue4553: check that revset aliases override existing hash prefix
1933
1946
1934 $ hg log -qr e
1947 $ hg log -qr e
1935 6:e0cc66ef77e8
1948 6:e0cc66ef77e8
1936
1949
1937 $ hg log -qr e --config revsetalias.e="all()"
1950 $ hg log -qr e --config revsetalias.e="all()"
1938 0:2785f51eece5
1951 0:2785f51eece5
1939 1:d75937da8da0
1952 1:d75937da8da0
1940 2:5ed5505e9f1c
1953 2:5ed5505e9f1c
1941 3:8528aa5637f2
1954 3:8528aa5637f2
1942 4:2326846efdab
1955 4:2326846efdab
1943 5:904fa392b941
1956 5:904fa392b941
1944 6:e0cc66ef77e8
1957 6:e0cc66ef77e8
1945 7:013af1973af4
1958 7:013af1973af4
1946 8:d5d0dcbdc4d9
1959 8:d5d0dcbdc4d9
1947 9:24286f4ae135
1960 9:24286f4ae135
1948
1961
1949 $ hg log -qr e: --config revsetalias.e="0"
1962 $ hg log -qr e: --config revsetalias.e="0"
1950 0:2785f51eece5
1963 0:2785f51eece5
1951 1:d75937da8da0
1964 1:d75937da8da0
1952 2:5ed5505e9f1c
1965 2:5ed5505e9f1c
1953 3:8528aa5637f2
1966 3:8528aa5637f2
1954 4:2326846efdab
1967 4:2326846efdab
1955 5:904fa392b941
1968 5:904fa392b941
1956 6:e0cc66ef77e8
1969 6:e0cc66ef77e8
1957 7:013af1973af4
1970 7:013af1973af4
1958 8:d5d0dcbdc4d9
1971 8:d5d0dcbdc4d9
1959 9:24286f4ae135
1972 9:24286f4ae135
1960
1973
1961 $ hg log -qr :e --config revsetalias.e="9"
1974 $ hg log -qr :e --config revsetalias.e="9"
1962 0:2785f51eece5
1975 0:2785f51eece5
1963 1:d75937da8da0
1976 1:d75937da8da0
1964 2:5ed5505e9f1c
1977 2:5ed5505e9f1c
1965 3:8528aa5637f2
1978 3:8528aa5637f2
1966 4:2326846efdab
1979 4:2326846efdab
1967 5:904fa392b941
1980 5:904fa392b941
1968 6:e0cc66ef77e8
1981 6:e0cc66ef77e8
1969 7:013af1973af4
1982 7:013af1973af4
1970 8:d5d0dcbdc4d9
1983 8:d5d0dcbdc4d9
1971 9:24286f4ae135
1984 9:24286f4ae135
1972
1985
1973 $ hg log -qr e:
1986 $ hg log -qr e:
1974 6:e0cc66ef77e8
1987 6:e0cc66ef77e8
1975 7:013af1973af4
1988 7:013af1973af4
1976 8:d5d0dcbdc4d9
1989 8:d5d0dcbdc4d9
1977 9:24286f4ae135
1990 9:24286f4ae135
1978
1991
1979 $ hg log -qr :e
1992 $ hg log -qr :e
1980 0:2785f51eece5
1993 0:2785f51eece5
1981 1:d75937da8da0
1994 1:d75937da8da0
1982 2:5ed5505e9f1c
1995 2:5ed5505e9f1c
1983 3:8528aa5637f2
1996 3:8528aa5637f2
1984 4:2326846efdab
1997 4:2326846efdab
1985 5:904fa392b941
1998 5:904fa392b941
1986 6:e0cc66ef77e8
1999 6:e0cc66ef77e8
1987
2000
1988 issue2549 - correct optimizations
2001 issue2549 - correct optimizations
1989
2002
1990 $ try 'limit(1 or 2 or 3, 2) and not 2'
2003 $ try 'limit(1 or 2 or 3, 2) and not 2'
1991 (and
2004 (and
1992 (func
2005 (func
1993 ('symbol', 'limit')
2006 ('symbol', 'limit')
1994 (list
2007 (list
1995 (or
2008 (or
1996 ('symbol', '1')
2009 ('symbol', '1')
1997 ('symbol', '2')
2010 ('symbol', '2')
1998 ('symbol', '3'))
2011 ('symbol', '3'))
1999 ('symbol', '2')))
2012 ('symbol', '2')))
2000 (not
2013 (not
2001 ('symbol', '2')))
2014 ('symbol', '2')))
2002 * set:
2015 * set:
2003 <filteredset
2016 <filteredset
2004 <baseset
2017 <baseset
2005 <limit n=2, offset=0,
2018 <limit n=2, offset=0,
2006 <fullreposet+ 0:9>,
2019 <fullreposet+ 0:9>,
2007 <baseset [1, 2, 3]>>>,
2020 <baseset [1, 2, 3]>>>,
2008 <not
2021 <not
2009 <baseset [2]>>>
2022 <baseset [2]>>>
2010 1
2023 1
2011 $ try 'max(1 or 2) and not 2'
2024 $ try 'max(1 or 2) and not 2'
2012 (and
2025 (and
2013 (func
2026 (func
2014 ('symbol', 'max')
2027 ('symbol', 'max')
2015 (or
2028 (or
2016 ('symbol', '1')
2029 ('symbol', '1')
2017 ('symbol', '2')))
2030 ('symbol', '2')))
2018 (not
2031 (not
2019 ('symbol', '2')))
2032 ('symbol', '2')))
2020 * set:
2033 * set:
2021 <filteredset
2034 <filteredset
2022 <baseset
2035 <baseset
2023 <max
2036 <max
2024 <fullreposet+ 0:9>,
2037 <fullreposet+ 0:9>,
2025 <baseset [1, 2]>>>,
2038 <baseset [1, 2]>>>,
2026 <not
2039 <not
2027 <baseset [2]>>>
2040 <baseset [2]>>>
2028 $ try 'min(1 or 2) and not 1'
2041 $ try 'min(1 or 2) and not 1'
2029 (and
2042 (and
2030 (func
2043 (func
2031 ('symbol', 'min')
2044 ('symbol', 'min')
2032 (or
2045 (or
2033 ('symbol', '1')
2046 ('symbol', '1')
2034 ('symbol', '2')))
2047 ('symbol', '2')))
2035 (not
2048 (not
2036 ('symbol', '1')))
2049 ('symbol', '1')))
2037 * set:
2050 * set:
2038 <filteredset
2051 <filteredset
2039 <baseset
2052 <baseset
2040 <min
2053 <min
2041 <fullreposet+ 0:9>,
2054 <fullreposet+ 0:9>,
2042 <baseset [1, 2]>>>,
2055 <baseset [1, 2]>>>,
2043 <not
2056 <not
2044 <baseset [1]>>>
2057 <baseset [1]>>>
2045 $ try 'last(1 or 2, 1) and not 2'
2058 $ try 'last(1 or 2, 1) and not 2'
2046 (and
2059 (and
2047 (func
2060 (func
2048 ('symbol', 'last')
2061 ('symbol', 'last')
2049 (list
2062 (list
2050 (or
2063 (or
2051 ('symbol', '1')
2064 ('symbol', '1')
2052 ('symbol', '2'))
2065 ('symbol', '2'))
2053 ('symbol', '1')))
2066 ('symbol', '1')))
2054 (not
2067 (not
2055 ('symbol', '2')))
2068 ('symbol', '2')))
2056 * set:
2069 * set:
2057 <filteredset
2070 <filteredset
2058 <baseset
2071 <baseset
2059 <last n=1,
2072 <last n=1,
2060 <fullreposet+ 0:9>,
2073 <fullreposet+ 0:9>,
2061 <baseset [2, 1]>>>,
2074 <baseset [2, 1]>>>,
2062 <not
2075 <not
2063 <baseset [2]>>>
2076 <baseset [2]>>>
2064
2077
2065 issue4289 - ordering of built-ins
2078 issue4289 - ordering of built-ins
2066 $ hg log -M -q -r 3:2
2079 $ hg log -M -q -r 3:2
2067 3:8528aa5637f2
2080 3:8528aa5637f2
2068 2:5ed5505e9f1c
2081 2:5ed5505e9f1c
2069
2082
2070 test revsets started with 40-chars hash (issue3669)
2083 test revsets started with 40-chars hash (issue3669)
2071
2084
2072 $ ISSUE3669_TIP=`hg tip --template '{node}'`
2085 $ ISSUE3669_TIP=`hg tip --template '{node}'`
2073 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
2086 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
2074 9
2087 9
2075 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
2088 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
2076 8
2089 8
2077
2090
2078 test or-ed indirect predicates (issue3775)
2091 test or-ed indirect predicates (issue3775)
2079
2092
2080 $ log '6 or 6^1' | sort
2093 $ log '6 or 6^1' | sort
2081 5
2094 5
2082 6
2095 6
2083 $ log '6^1 or 6' | sort
2096 $ log '6^1 or 6' | sort
2084 5
2097 5
2085 6
2098 6
2086 $ log '4 or 4~1' | sort
2099 $ log '4 or 4~1' | sort
2087 2
2100 2
2088 4
2101 4
2089 $ log '4~1 or 4' | sort
2102 $ log '4~1 or 4' | sort
2090 2
2103 2
2091 4
2104 4
2092 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
2105 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
2093 0
2106 0
2094 1
2107 1
2095 2
2108 2
2096 3
2109 3
2097 4
2110 4
2098 5
2111 5
2099 6
2112 6
2100 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
2113 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
2101 0
2114 0
2102 1
2115 1
2103 2
2116 2
2104 3
2117 3
2105 4
2118 4
2106 5
2119 5
2107 6
2120 6
2108
2121
2109 tests for 'remote()' predicate:
2122 tests for 'remote()' predicate:
2110 #. (csets in remote) (id) (remote)
2123 #. (csets in remote) (id) (remote)
2111 1. less than local current branch "default"
2124 1. less than local current branch "default"
2112 2. same with local specified "default"
2125 2. same with local specified "default"
2113 3. more than local specified specified
2126 3. more than local specified specified
2114
2127
2115 $ hg clone --quiet -U . ../remote3
2128 $ hg clone --quiet -U . ../remote3
2116 $ cd ../remote3
2129 $ cd ../remote3
2117 $ hg update -q 7
2130 $ hg update -q 7
2118 $ echo r > r
2131 $ echo r > r
2119 $ hg ci -Aqm 10
2132 $ hg ci -Aqm 10
2120 $ log 'remote()'
2133 $ log 'remote()'
2121 7
2134 7
2122 $ log 'remote("a-b-c-")'
2135 $ log 'remote("a-b-c-")'
2123 2
2136 2
2124 $ cd ../repo
2137 $ cd ../repo
2125 $ log 'remote(".a.b.c.", "../remote3")'
2138 $ log 'remote(".a.b.c.", "../remote3")'
2126
2139
2127 tests for concatenation of strings/symbols by "##"
2140 tests for concatenation of strings/symbols by "##"
2128
2141
2129 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
2142 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
2130 (_concat
2143 (_concat
2131 (_concat
2144 (_concat
2132 (_concat
2145 (_concat
2133 ('symbol', '278')
2146 ('symbol', '278')
2134 ('string', '5f5'))
2147 ('string', '5f5'))
2135 ('symbol', '1ee'))
2148 ('symbol', '1ee'))
2136 ('string', 'ce5'))
2149 ('string', 'ce5'))
2150 * concatenated:
2137 ('string', '2785f51eece5')
2151 ('string', '2785f51eece5')
2138 * set:
2152 * set:
2139 <baseset [0]>
2153 <baseset [0]>
2140 0
2154 0
2141
2155
2142 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
2156 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
2143 $ try "cat4(278, '5f5', 1ee, 'ce5')"
2157 $ try "cat4(278, '5f5', 1ee, 'ce5')"
2144 (func
2158 (func
2145 ('symbol', 'cat4')
2159 ('symbol', 'cat4')
2146 (list
2160 (list
2147 ('symbol', '278')
2161 ('symbol', '278')
2148 ('string', '5f5')
2162 ('string', '5f5')
2149 ('symbol', '1ee')
2163 ('symbol', '1ee')
2150 ('string', 'ce5')))
2164 ('string', 'ce5')))
2165 * expanded:
2151 (_concat
2166 (_concat
2152 (_concat
2167 (_concat
2153 (_concat
2168 (_concat
2154 ('symbol', '278')
2169 ('symbol', '278')
2155 ('string', '5f5'))
2170 ('string', '5f5'))
2156 ('symbol', '1ee'))
2171 ('symbol', '1ee'))
2157 ('string', 'ce5'))
2172 ('string', 'ce5'))
2173 * concatenated:
2158 ('string', '2785f51eece5')
2174 ('string', '2785f51eece5')
2159 * set:
2175 * set:
2160 <baseset [0]>
2176 <baseset [0]>
2161 0
2177 0
2162
2178
2163 (check concatenation in alias nesting)
2179 (check concatenation in alias nesting)
2164
2180
2165 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
2181 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
2166 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
2182 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
2167 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
2183 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
2168 0
2184 0
2169
2185
2170 (check operator priority)
2186 (check operator priority)
2171
2187
2172 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
2188 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
2173 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
2189 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
2174 0
2190 0
2175 4
2191 4
2176
2192
2177 $ cd ..
2193 $ cd ..
2178
2194
2179 prepare repository that has "default" branches of multiple roots
2195 prepare repository that has "default" branches of multiple roots
2180
2196
2181 $ hg init namedbranch
2197 $ hg init namedbranch
2182 $ cd namedbranch
2198 $ cd namedbranch
2183
2199
2184 $ echo default0 >> a
2200 $ echo default0 >> a
2185 $ hg ci -Aqm0
2201 $ hg ci -Aqm0
2186 $ echo default1 >> a
2202 $ echo default1 >> a
2187 $ hg ci -m1
2203 $ hg ci -m1
2188
2204
2189 $ hg branch -q stable
2205 $ hg branch -q stable
2190 $ echo stable2 >> a
2206 $ echo stable2 >> a
2191 $ hg ci -m2
2207 $ hg ci -m2
2192 $ echo stable3 >> a
2208 $ echo stable3 >> a
2193 $ hg ci -m3
2209 $ hg ci -m3
2194
2210
2195 $ hg update -q null
2211 $ hg update -q null
2196 $ echo default4 >> a
2212 $ echo default4 >> a
2197 $ hg ci -Aqm4
2213 $ hg ci -Aqm4
2198 $ echo default5 >> a
2214 $ echo default5 >> a
2199 $ hg ci -m5
2215 $ hg ci -m5
2200
2216
2201 "null" revision belongs to "default" branch (issue4683)
2217 "null" revision belongs to "default" branch (issue4683)
2202
2218
2203 $ log 'branch(null)'
2219 $ log 'branch(null)'
2204 0
2220 0
2205 1
2221 1
2206 4
2222 4
2207 5
2223 5
2208
2224
2209 "null" revision belongs to "default" branch, but it shouldn't appear in set
2225 "null" revision belongs to "default" branch, but it shouldn't appear in set
2210 unless explicitly specified (issue4682)
2226 unless explicitly specified (issue4682)
2211
2227
2212 $ log 'children(branch(default))'
2228 $ log 'children(branch(default))'
2213 1
2229 1
2214 2
2230 2
2215 5
2231 5
2216
2232
2217 $ cd ..
2233 $ cd ..
2218
2234
2219 test author/desc/keyword in problematic encoding
2235 test author/desc/keyword in problematic encoding
2220 # unicode: cp932:
2236 # unicode: cp932:
2221 # u30A2 0x83 0x41(= 'A')
2237 # u30A2 0x83 0x41(= 'A')
2222 # u30C2 0x83 0x61(= 'a')
2238 # u30C2 0x83 0x61(= 'a')
2223
2239
2224 $ hg init problematicencoding
2240 $ hg init problematicencoding
2225 $ cd problematicencoding
2241 $ cd problematicencoding
2226
2242
2227 $ python > setup.sh <<EOF
2243 $ python > setup.sh <<EOF
2228 > print u'''
2244 > print u'''
2229 > echo a > text
2245 > echo a > text
2230 > hg add text
2246 > hg add text
2231 > hg --encoding utf-8 commit -u '\u30A2' -m none
2247 > hg --encoding utf-8 commit -u '\u30A2' -m none
2232 > echo b > text
2248 > echo b > text
2233 > hg --encoding utf-8 commit -u '\u30C2' -m none
2249 > hg --encoding utf-8 commit -u '\u30C2' -m none
2234 > echo c > text
2250 > echo c > text
2235 > hg --encoding utf-8 commit -u none -m '\u30A2'
2251 > hg --encoding utf-8 commit -u none -m '\u30A2'
2236 > echo d > text
2252 > echo d > text
2237 > hg --encoding utf-8 commit -u none -m '\u30C2'
2253 > hg --encoding utf-8 commit -u none -m '\u30C2'
2238 > '''.encode('utf-8')
2254 > '''.encode('utf-8')
2239 > EOF
2255 > EOF
2240 $ sh < setup.sh
2256 $ sh < setup.sh
2241
2257
2242 test in problematic encoding
2258 test in problematic encoding
2243 $ python > test.sh <<EOF
2259 $ python > test.sh <<EOF
2244 > print u'''
2260 > print u'''
2245 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
2261 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
2246 > echo ====
2262 > echo ====
2247 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
2263 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
2248 > echo ====
2264 > echo ====
2249 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
2265 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
2250 > echo ====
2266 > echo ====
2251 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
2267 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
2252 > echo ====
2268 > echo ====
2253 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
2269 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
2254 > echo ====
2270 > echo ====
2255 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
2271 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
2256 > '''.encode('cp932')
2272 > '''.encode('cp932')
2257 > EOF
2273 > EOF
2258 $ sh < test.sh
2274 $ sh < test.sh
2259 0
2275 0
2260 ====
2276 ====
2261 1
2277 1
2262 ====
2278 ====
2263 2
2279 2
2264 ====
2280 ====
2265 3
2281 3
2266 ====
2282 ====
2267 0
2283 0
2268 2
2284 2
2269 ====
2285 ====
2270 1
2286 1
2271 3
2287 3
2272
2288
2273 test error message of bad revset
2289 test error message of bad revset
2274 $ hg log -r 'foo\\'
2290 $ hg log -r 'foo\\'
2275 hg: parse error at 3: syntax error in revset 'foo\\'
2291 hg: parse error at 3: syntax error in revset 'foo\\'
2276 [255]
2292 [255]
2277
2293
2278 $ cd ..
2294 $ cd ..
2279
2295
2280 Test that revset predicate of extension isn't loaded at failure of
2296 Test that revset predicate of extension isn't loaded at failure of
2281 loading it
2297 loading it
2282
2298
2283 $ cd repo
2299 $ cd repo
2284
2300
2285 $ cat <<EOF > $TESTTMP/custompredicate.py
2301 $ cat <<EOF > $TESTTMP/custompredicate.py
2286 > from mercurial import error, registrar, revset
2302 > from mercurial import error, registrar, revset
2287 >
2303 >
2288 > revsetpredicate = registrar.revsetpredicate()
2304 > revsetpredicate = registrar.revsetpredicate()
2289 >
2305 >
2290 > @revsetpredicate('custom1()')
2306 > @revsetpredicate('custom1()')
2291 > def custom1(repo, subset, x):
2307 > def custom1(repo, subset, x):
2292 > return revset.baseset([1])
2308 > return revset.baseset([1])
2293 >
2309 >
2294 > raise error.Abort('intentional failure of loading extension')
2310 > raise error.Abort('intentional failure of loading extension')
2295 > EOF
2311 > EOF
2296 $ cat <<EOF > .hg/hgrc
2312 $ cat <<EOF > .hg/hgrc
2297 > [extensions]
2313 > [extensions]
2298 > custompredicate = $TESTTMP/custompredicate.py
2314 > custompredicate = $TESTTMP/custompredicate.py
2299 > EOF
2315 > EOF
2300
2316
2301 $ hg debugrevspec "custom1()"
2317 $ hg debugrevspec "custom1()"
2302 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
2318 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
2303 hg: parse error: unknown identifier: custom1
2319 hg: parse error: unknown identifier: custom1
2304 [255]
2320 [255]
2305
2321
2306 $ cd ..
2322 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now