##// END OF EJS Templates
server: add public function to select either cmdserver or hgweb
Yuya Nishihara -
r30510:a0878bc8 default
parent child Browse files
Show More
@@ -1,7091 +1,7088 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 string
18 import string
19 import sys
19 import sys
20 import tempfile
20 import tempfile
21 import time
21 import time
22
22
23 from .i18n import _
23 from .i18n import _
24 from .node import (
24 from .node import (
25 bin,
25 bin,
26 hex,
26 hex,
27 nullhex,
27 nullhex,
28 nullid,
28 nullid,
29 nullrev,
29 nullrev,
30 short,
30 short,
31 )
31 )
32 from . import (
32 from . import (
33 archival,
33 archival,
34 bookmarks,
34 bookmarks,
35 bundle2,
35 bundle2,
36 changegroup,
36 changegroup,
37 cmdutil,
37 cmdutil,
38 copies,
38 copies,
39 dagparser,
39 dagparser,
40 dagutil,
40 dagutil,
41 destutil,
41 destutil,
42 dirstateguard,
42 dirstateguard,
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 formatter,
49 formatter,
50 graphmod,
50 graphmod,
51 hbisect,
51 hbisect,
52 help,
52 help,
53 hg,
53 hg,
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 policy,
61 policy,
62 pvec,
62 pvec,
63 pycompat,
63 pycompat,
64 repair,
64 repair,
65 revlog,
65 revlog,
66 revset,
66 revset,
67 scmutil,
67 scmutil,
68 server,
68 server,
69 setdiscovery,
69 setdiscovery,
70 sshserver,
70 sshserver,
71 sslutil,
71 sslutil,
72 streamclone,
72 streamclone,
73 templatekw,
73 templatekw,
74 templater,
74 templater,
75 treediscovery,
75 treediscovery,
76 ui as uimod,
76 ui as uimod,
77 util,
77 util,
78 )
78 )
79
79
80 release = lockmod.release
80 release = lockmod.release
81
81
82 table = {}
82 table = {}
83
83
84 command = cmdutil.command(table)
84 command = cmdutil.command(table)
85
85
86 # label constants
86 # label constants
87 # until 3.5, bookmarks.current was the advertised name, not
87 # until 3.5, bookmarks.current was the advertised name, not
88 # bookmarks.active, so we must use both to avoid breaking old
88 # bookmarks.active, so we must use both to avoid breaking old
89 # custom styles
89 # custom styles
90 activebookmarklabel = 'bookmarks.active bookmarks.current'
90 activebookmarklabel = 'bookmarks.active bookmarks.current'
91
91
92 # common command options
92 # common command options
93
93
94 globalopts = [
94 globalopts = [
95 ('R', 'repository', '',
95 ('R', 'repository', '',
96 _('repository root directory or name of overlay bundle file'),
96 _('repository root directory or name of overlay bundle file'),
97 _('REPO')),
97 _('REPO')),
98 ('', 'cwd', '',
98 ('', 'cwd', '',
99 _('change working directory'), _('DIR')),
99 _('change working directory'), _('DIR')),
100 ('y', 'noninteractive', None,
100 ('y', 'noninteractive', None,
101 _('do not prompt, automatically pick the first choice for all prompts')),
101 _('do not prompt, automatically pick the first choice for all prompts')),
102 ('q', 'quiet', None, _('suppress output')),
102 ('q', 'quiet', None, _('suppress output')),
103 ('v', 'verbose', None, _('enable additional output')),
103 ('v', 'verbose', None, _('enable additional output')),
104 ('', 'config', [],
104 ('', 'config', [],
105 _('set/override config option (use \'section.name=value\')'),
105 _('set/override config option (use \'section.name=value\')'),
106 _('CONFIG')),
106 _('CONFIG')),
107 ('', 'debug', None, _('enable debugging output')),
107 ('', 'debug', None, _('enable debugging output')),
108 ('', 'debugger', None, _('start debugger')),
108 ('', 'debugger', None, _('start debugger')),
109 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
109 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
110 _('ENCODE')),
110 _('ENCODE')),
111 ('', 'encodingmode', encoding.encodingmode,
111 ('', 'encodingmode', encoding.encodingmode,
112 _('set the charset encoding mode'), _('MODE')),
112 _('set the charset encoding mode'), _('MODE')),
113 ('', 'traceback', None, _('always print a traceback on exception')),
113 ('', 'traceback', None, _('always print a traceback on exception')),
114 ('', 'time', None, _('time how long the command takes')),
114 ('', 'time', None, _('time how long the command takes')),
115 ('', 'profile', None, _('print command execution profile')),
115 ('', 'profile', None, _('print command execution profile')),
116 ('', 'version', None, _('output version information and exit')),
116 ('', 'version', None, _('output version information and exit')),
117 ('h', 'help', None, _('display help and exit')),
117 ('h', 'help', None, _('display help and exit')),
118 ('', 'hidden', False, _('consider hidden changesets')),
118 ('', 'hidden', False, _('consider hidden changesets')),
119 ]
119 ]
120
120
121 dryrunopts = [('n', 'dry-run', None,
121 dryrunopts = [('n', 'dry-run', None,
122 _('do not perform actions, just print output'))]
122 _('do not perform actions, just print output'))]
123
123
124 remoteopts = [
124 remoteopts = [
125 ('e', 'ssh', '',
125 ('e', 'ssh', '',
126 _('specify ssh command to use'), _('CMD')),
126 _('specify ssh command to use'), _('CMD')),
127 ('', 'remotecmd', '',
127 ('', 'remotecmd', '',
128 _('specify hg command to run on the remote side'), _('CMD')),
128 _('specify hg command to run on the remote side'), _('CMD')),
129 ('', 'insecure', None,
129 ('', 'insecure', None,
130 _('do not verify server certificate (ignoring web.cacerts config)')),
130 _('do not verify server certificate (ignoring web.cacerts config)')),
131 ]
131 ]
132
132
133 walkopts = [
133 walkopts = [
134 ('I', 'include', [],
134 ('I', 'include', [],
135 _('include names matching the given patterns'), _('PATTERN')),
135 _('include names matching the given patterns'), _('PATTERN')),
136 ('X', 'exclude', [],
136 ('X', 'exclude', [],
137 _('exclude names matching the given patterns'), _('PATTERN')),
137 _('exclude names matching the given patterns'), _('PATTERN')),
138 ]
138 ]
139
139
140 commitopts = [
140 commitopts = [
141 ('m', 'message', '',
141 ('m', 'message', '',
142 _('use text as commit message'), _('TEXT')),
142 _('use text as commit message'), _('TEXT')),
143 ('l', 'logfile', '',
143 ('l', 'logfile', '',
144 _('read commit message from file'), _('FILE')),
144 _('read commit message from file'), _('FILE')),
145 ]
145 ]
146
146
147 commitopts2 = [
147 commitopts2 = [
148 ('d', 'date', '',
148 ('d', 'date', '',
149 _('record the specified date as commit date'), _('DATE')),
149 _('record the specified date as commit date'), _('DATE')),
150 ('u', 'user', '',
150 ('u', 'user', '',
151 _('record the specified user as committer'), _('USER')),
151 _('record the specified user as committer'), _('USER')),
152 ]
152 ]
153
153
154 # hidden for now
154 # hidden for now
155 formatteropts = [
155 formatteropts = [
156 ('T', 'template', '',
156 ('T', 'template', '',
157 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
157 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
158 ]
158 ]
159
159
160 templateopts = [
160 templateopts = [
161 ('', 'style', '',
161 ('', 'style', '',
162 _('display using template map file (DEPRECATED)'), _('STYLE')),
162 _('display using template map file (DEPRECATED)'), _('STYLE')),
163 ('T', 'template', '',
163 ('T', 'template', '',
164 _('display with template'), _('TEMPLATE')),
164 _('display with template'), _('TEMPLATE')),
165 ]
165 ]
166
166
167 logopts = [
167 logopts = [
168 ('p', 'patch', None, _('show patch')),
168 ('p', 'patch', None, _('show patch')),
169 ('g', 'git', None, _('use git extended diff format')),
169 ('g', 'git', None, _('use git extended diff format')),
170 ('l', 'limit', '',
170 ('l', 'limit', '',
171 _('limit number of changes displayed'), _('NUM')),
171 _('limit number of changes displayed'), _('NUM')),
172 ('M', 'no-merges', None, _('do not show merges')),
172 ('M', 'no-merges', None, _('do not show merges')),
173 ('', 'stat', None, _('output diffstat-style summary of changes')),
173 ('', 'stat', None, _('output diffstat-style summary of changes')),
174 ('G', 'graph', None, _("show the revision DAG")),
174 ('G', 'graph', None, _("show the revision DAG")),
175 ] + templateopts
175 ] + templateopts
176
176
177 diffopts = [
177 diffopts = [
178 ('a', 'text', None, _('treat all files as text')),
178 ('a', 'text', None, _('treat all files as text')),
179 ('g', 'git', None, _('use git extended diff format')),
179 ('g', 'git', None, _('use git extended diff format')),
180 ('', 'nodates', None, _('omit dates from diff headers'))
180 ('', 'nodates', None, _('omit dates from diff headers'))
181 ]
181 ]
182
182
183 diffwsopts = [
183 diffwsopts = [
184 ('w', 'ignore-all-space', None,
184 ('w', 'ignore-all-space', None,
185 _('ignore white space when comparing lines')),
185 _('ignore white space when comparing lines')),
186 ('b', 'ignore-space-change', None,
186 ('b', 'ignore-space-change', None,
187 _('ignore changes in the amount of white space')),
187 _('ignore changes in the amount of white space')),
188 ('B', 'ignore-blank-lines', None,
188 ('B', 'ignore-blank-lines', None,
189 _('ignore changes whose lines are all blank')),
189 _('ignore changes whose lines are all blank')),
190 ]
190 ]
191
191
192 diffopts2 = [
192 diffopts2 = [
193 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
193 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
194 ('p', 'show-function', None, _('show which function each change is in')),
194 ('p', 'show-function', None, _('show which function each change is in')),
195 ('', 'reverse', None, _('produce a diff that undoes the changes')),
195 ('', 'reverse', None, _('produce a diff that undoes the changes')),
196 ] + diffwsopts + [
196 ] + diffwsopts + [
197 ('U', 'unified', '',
197 ('U', 'unified', '',
198 _('number of lines of context to show'), _('NUM')),
198 _('number of lines of context to show'), _('NUM')),
199 ('', 'stat', None, _('output diffstat-style summary of changes')),
199 ('', 'stat', None, _('output diffstat-style summary of changes')),
200 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
200 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
201 ]
201 ]
202
202
203 mergetoolopts = [
203 mergetoolopts = [
204 ('t', 'tool', '', _('specify merge tool')),
204 ('t', 'tool', '', _('specify merge tool')),
205 ]
205 ]
206
206
207 similarityopts = [
207 similarityopts = [
208 ('s', 'similarity', '',
208 ('s', 'similarity', '',
209 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
209 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
210 ]
210 ]
211
211
212 subrepoopts = [
212 subrepoopts = [
213 ('S', 'subrepos', None,
213 ('S', 'subrepos', None,
214 _('recurse into subrepositories'))
214 _('recurse into subrepositories'))
215 ]
215 ]
216
216
217 debugrevlogopts = [
217 debugrevlogopts = [
218 ('c', 'changelog', False, _('open changelog')),
218 ('c', 'changelog', False, _('open changelog')),
219 ('m', 'manifest', False, _('open manifest')),
219 ('m', 'manifest', False, _('open manifest')),
220 ('', 'dir', '', _('open directory manifest')),
220 ('', 'dir', '', _('open directory manifest')),
221 ]
221 ]
222
222
223 # Commands start here, listed alphabetically
223 # Commands start here, listed alphabetically
224
224
225 @command('^add',
225 @command('^add',
226 walkopts + subrepoopts + dryrunopts,
226 walkopts + subrepoopts + dryrunopts,
227 _('[OPTION]... [FILE]...'),
227 _('[OPTION]... [FILE]...'),
228 inferrepo=True)
228 inferrepo=True)
229 def add(ui, repo, *pats, **opts):
229 def add(ui, repo, *pats, **opts):
230 """add the specified files on the next commit
230 """add the specified files on the next commit
231
231
232 Schedule files to be version controlled and added to the
232 Schedule files to be version controlled and added to the
233 repository.
233 repository.
234
234
235 The files will be added to the repository at the next commit. To
235 The files will be added to the repository at the next commit. To
236 undo an add before that, see :hg:`forget`.
236 undo an add before that, see :hg:`forget`.
237
237
238 If no names are given, add all files to the repository (except
238 If no names are given, add all files to the repository (except
239 files matching ``.hgignore``).
239 files matching ``.hgignore``).
240
240
241 .. container:: verbose
241 .. container:: verbose
242
242
243 Examples:
243 Examples:
244
244
245 - New (unknown) files are added
245 - New (unknown) files are added
246 automatically by :hg:`add`::
246 automatically by :hg:`add`::
247
247
248 $ ls
248 $ ls
249 foo.c
249 foo.c
250 $ hg status
250 $ hg status
251 ? foo.c
251 ? foo.c
252 $ hg add
252 $ hg add
253 adding foo.c
253 adding foo.c
254 $ hg status
254 $ hg status
255 A foo.c
255 A foo.c
256
256
257 - Specific files to be added can be specified::
257 - Specific files to be added can be specified::
258
258
259 $ ls
259 $ ls
260 bar.c foo.c
260 bar.c foo.c
261 $ hg status
261 $ hg status
262 ? bar.c
262 ? bar.c
263 ? foo.c
263 ? foo.c
264 $ hg add bar.c
264 $ hg add bar.c
265 $ hg status
265 $ hg status
266 A bar.c
266 A bar.c
267 ? foo.c
267 ? foo.c
268
268
269 Returns 0 if all files are successfully added.
269 Returns 0 if all files are successfully added.
270 """
270 """
271
271
272 m = scmutil.match(repo[None], pats, opts)
272 m = scmutil.match(repo[None], pats, opts)
273 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
273 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
274 return rejected and 1 or 0
274 return rejected and 1 or 0
275
275
276 @command('addremove',
276 @command('addremove',
277 similarityopts + subrepoopts + walkopts + dryrunopts,
277 similarityopts + subrepoopts + walkopts + dryrunopts,
278 _('[OPTION]... [FILE]...'),
278 _('[OPTION]... [FILE]...'),
279 inferrepo=True)
279 inferrepo=True)
280 def addremove(ui, repo, *pats, **opts):
280 def addremove(ui, repo, *pats, **opts):
281 """add all new files, delete all missing files
281 """add all new files, delete all missing files
282
282
283 Add all new files and remove all missing files from the
283 Add all new files and remove all missing files from the
284 repository.
284 repository.
285
285
286 Unless names are given, new files are ignored if they match any of
286 Unless names are given, new files are ignored if they match any of
287 the patterns in ``.hgignore``. As with add, these changes take
287 the patterns in ``.hgignore``. As with add, these changes take
288 effect at the next commit.
288 effect at the next commit.
289
289
290 Use the -s/--similarity option to detect renamed files. This
290 Use the -s/--similarity option to detect renamed files. This
291 option takes a percentage between 0 (disabled) and 100 (files must
291 option takes a percentage between 0 (disabled) and 100 (files must
292 be identical) as its parameter. With a parameter greater than 0,
292 be identical) as its parameter. With a parameter greater than 0,
293 this compares every removed file with every added file and records
293 this compares every removed file with every added file and records
294 those similar enough as renames. Detecting renamed files this way
294 those similar enough as renames. Detecting renamed files this way
295 can be expensive. After using this option, :hg:`status -C` can be
295 can be expensive. After using this option, :hg:`status -C` can be
296 used to check which files were identified as moved or renamed. If
296 used to check which files were identified as moved or renamed. If
297 not specified, -s/--similarity defaults to 100 and only renames of
297 not specified, -s/--similarity defaults to 100 and only renames of
298 identical files are detected.
298 identical files are detected.
299
299
300 .. container:: verbose
300 .. container:: verbose
301
301
302 Examples:
302 Examples:
303
303
304 - A number of files (bar.c and foo.c) are new,
304 - A number of files (bar.c and foo.c) are new,
305 while foobar.c has been removed (without using :hg:`remove`)
305 while foobar.c has been removed (without using :hg:`remove`)
306 from the repository::
306 from the repository::
307
307
308 $ ls
308 $ ls
309 bar.c foo.c
309 bar.c foo.c
310 $ hg status
310 $ hg status
311 ! foobar.c
311 ! foobar.c
312 ? bar.c
312 ? bar.c
313 ? foo.c
313 ? foo.c
314 $ hg addremove
314 $ hg addremove
315 adding bar.c
315 adding bar.c
316 adding foo.c
316 adding foo.c
317 removing foobar.c
317 removing foobar.c
318 $ hg status
318 $ hg status
319 A bar.c
319 A bar.c
320 A foo.c
320 A foo.c
321 R foobar.c
321 R foobar.c
322
322
323 - A file foobar.c was moved to foo.c without using :hg:`rename`.
323 - A file foobar.c was moved to foo.c without using :hg:`rename`.
324 Afterwards, it was edited slightly::
324 Afterwards, it was edited slightly::
325
325
326 $ ls
326 $ ls
327 foo.c
327 foo.c
328 $ hg status
328 $ hg status
329 ! foobar.c
329 ! foobar.c
330 ? foo.c
330 ? foo.c
331 $ hg addremove --similarity 90
331 $ hg addremove --similarity 90
332 removing foobar.c
332 removing foobar.c
333 adding foo.c
333 adding foo.c
334 recording removal of foobar.c as rename to foo.c (94% similar)
334 recording removal of foobar.c as rename to foo.c (94% similar)
335 $ hg status -C
335 $ hg status -C
336 A foo.c
336 A foo.c
337 foobar.c
337 foobar.c
338 R foobar.c
338 R foobar.c
339
339
340 Returns 0 if all files are successfully added.
340 Returns 0 if all files are successfully added.
341 """
341 """
342 try:
342 try:
343 sim = float(opts.get('similarity') or 100)
343 sim = float(opts.get('similarity') or 100)
344 except ValueError:
344 except ValueError:
345 raise error.Abort(_('similarity must be a number'))
345 raise error.Abort(_('similarity must be a number'))
346 if sim < 0 or sim > 100:
346 if sim < 0 or sim > 100:
347 raise error.Abort(_('similarity must be between 0 and 100'))
347 raise error.Abort(_('similarity must be between 0 and 100'))
348 matcher = scmutil.match(repo[None], pats, opts)
348 matcher = scmutil.match(repo[None], pats, opts)
349 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
349 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
350
350
351 @command('^annotate|blame',
351 @command('^annotate|blame',
352 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
352 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
353 ('', 'follow', None,
353 ('', 'follow', None,
354 _('follow copies/renames and list the filename (DEPRECATED)')),
354 _('follow copies/renames and list the filename (DEPRECATED)')),
355 ('', 'no-follow', None, _("don't follow copies and renames")),
355 ('', 'no-follow', None, _("don't follow copies and renames")),
356 ('a', 'text', None, _('treat all files as text')),
356 ('a', 'text', None, _('treat all files as text')),
357 ('u', 'user', None, _('list the author (long with -v)')),
357 ('u', 'user', None, _('list the author (long with -v)')),
358 ('f', 'file', None, _('list the filename')),
358 ('f', 'file', None, _('list the filename')),
359 ('d', 'date', None, _('list the date (short with -q)')),
359 ('d', 'date', None, _('list the date (short with -q)')),
360 ('n', 'number', None, _('list the revision number (default)')),
360 ('n', 'number', None, _('list the revision number (default)')),
361 ('c', 'changeset', None, _('list the changeset')),
361 ('c', 'changeset', None, _('list the changeset')),
362 ('l', 'line-number', None, _('show line number at the first appearance'))
362 ('l', 'line-number', None, _('show line number at the first appearance'))
363 ] + diffwsopts + walkopts + formatteropts,
363 ] + diffwsopts + walkopts + formatteropts,
364 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
364 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
365 inferrepo=True)
365 inferrepo=True)
366 def annotate(ui, repo, *pats, **opts):
366 def annotate(ui, repo, *pats, **opts):
367 """show changeset information by line for each file
367 """show changeset information by line for each file
368
368
369 List changes in files, showing the revision id responsible for
369 List changes in files, showing the revision id responsible for
370 each line.
370 each line.
371
371
372 This command is useful for discovering when a change was made and
372 This command is useful for discovering when a change was made and
373 by whom.
373 by whom.
374
374
375 If you include --file, --user, or --date, the revision number is
375 If you include --file, --user, or --date, the revision number is
376 suppressed unless you also include --number.
376 suppressed unless you also include --number.
377
377
378 Without the -a/--text option, annotate will avoid processing files
378 Without the -a/--text option, annotate will avoid processing files
379 it detects as binary. With -a, annotate will annotate the file
379 it detects as binary. With -a, annotate will annotate the file
380 anyway, although the results will probably be neither useful
380 anyway, although the results will probably be neither useful
381 nor desirable.
381 nor desirable.
382
382
383 Returns 0 on success.
383 Returns 0 on success.
384 """
384 """
385 if not pats:
385 if not pats:
386 raise error.Abort(_('at least one filename or pattern is required'))
386 raise error.Abort(_('at least one filename or pattern is required'))
387
387
388 if opts.get('follow'):
388 if opts.get('follow'):
389 # --follow is deprecated and now just an alias for -f/--file
389 # --follow is deprecated and now just an alias for -f/--file
390 # to mimic the behavior of Mercurial before version 1.5
390 # to mimic the behavior of Mercurial before version 1.5
391 opts['file'] = True
391 opts['file'] = True
392
392
393 ctx = scmutil.revsingle(repo, opts.get('rev'))
393 ctx = scmutil.revsingle(repo, opts.get('rev'))
394
394
395 fm = ui.formatter('annotate', opts)
395 fm = ui.formatter('annotate', opts)
396 if ui.quiet:
396 if ui.quiet:
397 datefunc = util.shortdate
397 datefunc = util.shortdate
398 else:
398 else:
399 datefunc = util.datestr
399 datefunc = util.datestr
400 if ctx.rev() is None:
400 if ctx.rev() is None:
401 def hexfn(node):
401 def hexfn(node):
402 if node is None:
402 if node is None:
403 return None
403 return None
404 else:
404 else:
405 return fm.hexfunc(node)
405 return fm.hexfunc(node)
406 if opts.get('changeset'):
406 if opts.get('changeset'):
407 # omit "+" suffix which is appended to node hex
407 # omit "+" suffix which is appended to node hex
408 def formatrev(rev):
408 def formatrev(rev):
409 if rev is None:
409 if rev is None:
410 return '%d' % ctx.p1().rev()
410 return '%d' % ctx.p1().rev()
411 else:
411 else:
412 return '%d' % rev
412 return '%d' % rev
413 else:
413 else:
414 def formatrev(rev):
414 def formatrev(rev):
415 if rev is None:
415 if rev is None:
416 return '%d+' % ctx.p1().rev()
416 return '%d+' % ctx.p1().rev()
417 else:
417 else:
418 return '%d ' % rev
418 return '%d ' % rev
419 def formathex(hex):
419 def formathex(hex):
420 if hex is None:
420 if hex is None:
421 return '%s+' % fm.hexfunc(ctx.p1().node())
421 return '%s+' % fm.hexfunc(ctx.p1().node())
422 else:
422 else:
423 return '%s ' % hex
423 return '%s ' % hex
424 else:
424 else:
425 hexfn = fm.hexfunc
425 hexfn = fm.hexfunc
426 formatrev = formathex = str
426 formatrev = formathex = str
427
427
428 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
428 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
429 ('number', ' ', lambda x: x[0].rev(), formatrev),
429 ('number', ' ', lambda x: x[0].rev(), formatrev),
430 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
430 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
431 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
431 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
432 ('file', ' ', lambda x: x[0].path(), str),
432 ('file', ' ', lambda x: x[0].path(), str),
433 ('line_number', ':', lambda x: x[1], str),
433 ('line_number', ':', lambda x: x[1], str),
434 ]
434 ]
435 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
435 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
436
436
437 if (not opts.get('user') and not opts.get('changeset')
437 if (not opts.get('user') and not opts.get('changeset')
438 and not opts.get('date') and not opts.get('file')):
438 and not opts.get('date') and not opts.get('file')):
439 opts['number'] = True
439 opts['number'] = True
440
440
441 linenumber = opts.get('line_number') is not None
441 linenumber = opts.get('line_number') is not None
442 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
442 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
443 raise error.Abort(_('at least one of -n/-c is required for -l'))
443 raise error.Abort(_('at least one of -n/-c is required for -l'))
444
444
445 if fm.isplain():
445 if fm.isplain():
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 else:
448 else:
449 def makefunc(get, fmt):
449 def makefunc(get, fmt):
450 return get
450 return get
451 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
451 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
452 if opts.get(op)]
452 if opts.get(op)]
453 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
453 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
454 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
454 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
455 if opts.get(op))
455 if opts.get(op))
456
456
457 def bad(x, y):
457 def bad(x, y):
458 raise error.Abort("%s: %s" % (x, y))
458 raise error.Abort("%s: %s" % (x, y))
459
459
460 m = scmutil.match(ctx, pats, opts, badfn=bad)
460 m = scmutil.match(ctx, pats, opts, badfn=bad)
461
461
462 follow = not opts.get('no_follow')
462 follow = not opts.get('no_follow')
463 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
463 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
464 whitespace=True)
464 whitespace=True)
465 for abs in ctx.walk(m):
465 for abs in ctx.walk(m):
466 fctx = ctx[abs]
466 fctx = ctx[abs]
467 if not opts.get('text') and util.binary(fctx.data()):
467 if not opts.get('text') and util.binary(fctx.data()):
468 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
468 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
469 continue
469 continue
470
470
471 lines = fctx.annotate(follow=follow, linenumber=linenumber,
471 lines = fctx.annotate(follow=follow, linenumber=linenumber,
472 diffopts=diffopts)
472 diffopts=diffopts)
473 if not lines:
473 if not lines:
474 continue
474 continue
475 formats = []
475 formats = []
476 pieces = []
476 pieces = []
477
477
478 for f, sep in funcmap:
478 for f, sep in funcmap:
479 l = [f(n) for n, dummy in lines]
479 l = [f(n) for n, dummy in lines]
480 if fm.isplain():
480 if fm.isplain():
481 sizes = [encoding.colwidth(x) for x in l]
481 sizes = [encoding.colwidth(x) for x in l]
482 ml = max(sizes)
482 ml = max(sizes)
483 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
483 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
484 else:
484 else:
485 formats.append(['%s' for x in l])
485 formats.append(['%s' for x in l])
486 pieces.append(l)
486 pieces.append(l)
487
487
488 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
488 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
489 fm.startitem()
489 fm.startitem()
490 fm.write(fields, "".join(f), *p)
490 fm.write(fields, "".join(f), *p)
491 fm.write('line', ": %s", l[1])
491 fm.write('line', ": %s", l[1])
492
492
493 if not lines[-1][1].endswith('\n'):
493 if not lines[-1][1].endswith('\n'):
494 fm.plain('\n')
494 fm.plain('\n')
495
495
496 fm.end()
496 fm.end()
497
497
498 @command('archive',
498 @command('archive',
499 [('', 'no-decode', None, _('do not pass files through decoders')),
499 [('', 'no-decode', None, _('do not pass files through decoders')),
500 ('p', 'prefix', '', _('directory prefix for files in archive'),
500 ('p', 'prefix', '', _('directory prefix for files in archive'),
501 _('PREFIX')),
501 _('PREFIX')),
502 ('r', 'rev', '', _('revision to distribute'), _('REV')),
502 ('r', 'rev', '', _('revision to distribute'), _('REV')),
503 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
503 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
504 ] + subrepoopts + walkopts,
504 ] + subrepoopts + walkopts,
505 _('[OPTION]... DEST'))
505 _('[OPTION]... DEST'))
506 def archive(ui, repo, dest, **opts):
506 def archive(ui, repo, dest, **opts):
507 '''create an unversioned archive of a repository revision
507 '''create an unversioned archive of a repository revision
508
508
509 By default, the revision used is the parent of the working
509 By default, the revision used is the parent of the working
510 directory; use -r/--rev to specify a different revision.
510 directory; use -r/--rev to specify a different revision.
511
511
512 The archive type is automatically detected based on file
512 The archive type is automatically detected based on file
513 extension (to override, use -t/--type).
513 extension (to override, use -t/--type).
514
514
515 .. container:: verbose
515 .. container:: verbose
516
516
517 Examples:
517 Examples:
518
518
519 - create a zip file containing the 1.0 release::
519 - create a zip file containing the 1.0 release::
520
520
521 hg archive -r 1.0 project-1.0.zip
521 hg archive -r 1.0 project-1.0.zip
522
522
523 - create a tarball excluding .hg files::
523 - create a tarball excluding .hg files::
524
524
525 hg archive project.tar.gz -X ".hg*"
525 hg archive project.tar.gz -X ".hg*"
526
526
527 Valid types are:
527 Valid types are:
528
528
529 :``files``: a directory full of files (default)
529 :``files``: a directory full of files (default)
530 :``tar``: tar archive, uncompressed
530 :``tar``: tar archive, uncompressed
531 :``tbz2``: tar archive, compressed using bzip2
531 :``tbz2``: tar archive, compressed using bzip2
532 :``tgz``: tar archive, compressed using gzip
532 :``tgz``: tar archive, compressed using gzip
533 :``uzip``: zip archive, uncompressed
533 :``uzip``: zip archive, uncompressed
534 :``zip``: zip archive, compressed using deflate
534 :``zip``: zip archive, compressed using deflate
535
535
536 The exact name of the destination archive or directory is given
536 The exact name of the destination archive or directory is given
537 using a format string; see :hg:`help export` for details.
537 using a format string; see :hg:`help export` for details.
538
538
539 Each member added to an archive file has a directory prefix
539 Each member added to an archive file has a directory prefix
540 prepended. Use -p/--prefix to specify a format string for the
540 prepended. Use -p/--prefix to specify a format string for the
541 prefix. The default is the basename of the archive, with suffixes
541 prefix. The default is the basename of the archive, with suffixes
542 removed.
542 removed.
543
543
544 Returns 0 on success.
544 Returns 0 on success.
545 '''
545 '''
546
546
547 ctx = scmutil.revsingle(repo, opts.get('rev'))
547 ctx = scmutil.revsingle(repo, opts.get('rev'))
548 if not ctx:
548 if not ctx:
549 raise error.Abort(_('no working directory: please specify a revision'))
549 raise error.Abort(_('no working directory: please specify a revision'))
550 node = ctx.node()
550 node = ctx.node()
551 dest = cmdutil.makefilename(repo, dest, node)
551 dest = cmdutil.makefilename(repo, dest, node)
552 if os.path.realpath(dest) == repo.root:
552 if os.path.realpath(dest) == repo.root:
553 raise error.Abort(_('repository root cannot be destination'))
553 raise error.Abort(_('repository root cannot be destination'))
554
554
555 kind = opts.get('type') or archival.guesskind(dest) or 'files'
555 kind = opts.get('type') or archival.guesskind(dest) or 'files'
556 prefix = opts.get('prefix')
556 prefix = opts.get('prefix')
557
557
558 if dest == '-':
558 if dest == '-':
559 if kind == 'files':
559 if kind == 'files':
560 raise error.Abort(_('cannot archive plain files to stdout'))
560 raise error.Abort(_('cannot archive plain files to stdout'))
561 dest = cmdutil.makefileobj(repo, dest)
561 dest = cmdutil.makefileobj(repo, dest)
562 if not prefix:
562 if not prefix:
563 prefix = os.path.basename(repo.root) + '-%h'
563 prefix = os.path.basename(repo.root) + '-%h'
564
564
565 prefix = cmdutil.makefilename(repo, prefix, node)
565 prefix = cmdutil.makefilename(repo, prefix, node)
566 matchfn = scmutil.match(ctx, [], opts)
566 matchfn = scmutil.match(ctx, [], opts)
567 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
567 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
568 matchfn, prefix, subrepos=opts.get('subrepos'))
568 matchfn, prefix, subrepos=opts.get('subrepos'))
569
569
570 @command('backout',
570 @command('backout',
571 [('', 'merge', None, _('merge with old dirstate parent after backout')),
571 [('', 'merge', None, _('merge with old dirstate parent after backout')),
572 ('', 'commit', None,
572 ('', 'commit', None,
573 _('commit if no conflicts were encountered (DEPRECATED)')),
573 _('commit if no conflicts were encountered (DEPRECATED)')),
574 ('', 'no-commit', None, _('do not commit')),
574 ('', 'no-commit', None, _('do not commit')),
575 ('', 'parent', '',
575 ('', 'parent', '',
576 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
576 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
577 ('r', 'rev', '', _('revision to backout'), _('REV')),
577 ('r', 'rev', '', _('revision to backout'), _('REV')),
578 ('e', 'edit', False, _('invoke editor on commit messages')),
578 ('e', 'edit', False, _('invoke editor on commit messages')),
579 ] + mergetoolopts + walkopts + commitopts + commitopts2,
579 ] + mergetoolopts + walkopts + commitopts + commitopts2,
580 _('[OPTION]... [-r] REV'))
580 _('[OPTION]... [-r] REV'))
581 def backout(ui, repo, node=None, rev=None, **opts):
581 def backout(ui, repo, node=None, rev=None, **opts):
582 '''reverse effect of earlier changeset
582 '''reverse effect of earlier changeset
583
583
584 Prepare a new changeset with the effect of REV undone in the
584 Prepare a new changeset with the effect of REV undone in the
585 current working directory. If no conflicts were encountered,
585 current working directory. If no conflicts were encountered,
586 it will be committed immediately.
586 it will be committed immediately.
587
587
588 If REV is the parent of the working directory, then this new changeset
588 If REV is the parent of the working directory, then this new changeset
589 is committed automatically (unless --no-commit is specified).
589 is committed automatically (unless --no-commit is specified).
590
590
591 .. note::
591 .. note::
592
592
593 :hg:`backout` cannot be used to fix either an unwanted or
593 :hg:`backout` cannot be used to fix either an unwanted or
594 incorrect merge.
594 incorrect merge.
595
595
596 .. container:: verbose
596 .. container:: verbose
597
597
598 Examples:
598 Examples:
599
599
600 - Reverse the effect of the parent of the working directory.
600 - Reverse the effect of the parent of the working directory.
601 This backout will be committed immediately::
601 This backout will be committed immediately::
602
602
603 hg backout -r .
603 hg backout -r .
604
604
605 - Reverse the effect of previous bad revision 23::
605 - Reverse the effect of previous bad revision 23::
606
606
607 hg backout -r 23
607 hg backout -r 23
608
608
609 - Reverse the effect of previous bad revision 23 and
609 - Reverse the effect of previous bad revision 23 and
610 leave changes uncommitted::
610 leave changes uncommitted::
611
611
612 hg backout -r 23 --no-commit
612 hg backout -r 23 --no-commit
613 hg commit -m "Backout revision 23"
613 hg commit -m "Backout revision 23"
614
614
615 By default, the pending changeset will have one parent,
615 By default, the pending changeset will have one parent,
616 maintaining a linear history. With --merge, the pending
616 maintaining a linear history. With --merge, the pending
617 changeset will instead have two parents: the old parent of the
617 changeset will instead have two parents: the old parent of the
618 working directory and a new child of REV that simply undoes REV.
618 working directory and a new child of REV that simply undoes REV.
619
619
620 Before version 1.7, the behavior without --merge was equivalent
620 Before version 1.7, the behavior without --merge was equivalent
621 to specifying --merge followed by :hg:`update --clean .` to
621 to specifying --merge followed by :hg:`update --clean .` to
622 cancel the merge and leave the child of REV as a head to be
622 cancel the merge and leave the child of REV as a head to be
623 merged separately.
623 merged separately.
624
624
625 See :hg:`help dates` for a list of formats valid for -d/--date.
625 See :hg:`help dates` for a list of formats valid for -d/--date.
626
626
627 See :hg:`help revert` for a way to restore files to the state
627 See :hg:`help revert` for a way to restore files to the state
628 of another revision.
628 of another revision.
629
629
630 Returns 0 on success, 1 if nothing to backout or there are unresolved
630 Returns 0 on success, 1 if nothing to backout or there are unresolved
631 files.
631 files.
632 '''
632 '''
633 wlock = lock = None
633 wlock = lock = None
634 try:
634 try:
635 wlock = repo.wlock()
635 wlock = repo.wlock()
636 lock = repo.lock()
636 lock = repo.lock()
637 return _dobackout(ui, repo, node, rev, **opts)
637 return _dobackout(ui, repo, node, rev, **opts)
638 finally:
638 finally:
639 release(lock, wlock)
639 release(lock, wlock)
640
640
641 def _dobackout(ui, repo, node=None, rev=None, **opts):
641 def _dobackout(ui, repo, node=None, rev=None, **opts):
642 if opts.get('commit') and opts.get('no_commit'):
642 if opts.get('commit') and opts.get('no_commit'):
643 raise error.Abort(_("cannot use --commit with --no-commit"))
643 raise error.Abort(_("cannot use --commit with --no-commit"))
644 if opts.get('merge') and opts.get('no_commit'):
644 if opts.get('merge') and opts.get('no_commit'):
645 raise error.Abort(_("cannot use --merge with --no-commit"))
645 raise error.Abort(_("cannot use --merge with --no-commit"))
646
646
647 if rev and node:
647 if rev and node:
648 raise error.Abort(_("please specify just one revision"))
648 raise error.Abort(_("please specify just one revision"))
649
649
650 if not rev:
650 if not rev:
651 rev = node
651 rev = node
652
652
653 if not rev:
653 if not rev:
654 raise error.Abort(_("please specify a revision to backout"))
654 raise error.Abort(_("please specify a revision to backout"))
655
655
656 date = opts.get('date')
656 date = opts.get('date')
657 if date:
657 if date:
658 opts['date'] = util.parsedate(date)
658 opts['date'] = util.parsedate(date)
659
659
660 cmdutil.checkunfinished(repo)
660 cmdutil.checkunfinished(repo)
661 cmdutil.bailifchanged(repo)
661 cmdutil.bailifchanged(repo)
662 node = scmutil.revsingle(repo, rev).node()
662 node = scmutil.revsingle(repo, rev).node()
663
663
664 op1, op2 = repo.dirstate.parents()
664 op1, op2 = repo.dirstate.parents()
665 if not repo.changelog.isancestor(node, op1):
665 if not repo.changelog.isancestor(node, op1):
666 raise error.Abort(_('cannot backout change that is not an ancestor'))
666 raise error.Abort(_('cannot backout change that is not an ancestor'))
667
667
668 p1, p2 = repo.changelog.parents(node)
668 p1, p2 = repo.changelog.parents(node)
669 if p1 == nullid:
669 if p1 == nullid:
670 raise error.Abort(_('cannot backout a change with no parents'))
670 raise error.Abort(_('cannot backout a change with no parents'))
671 if p2 != nullid:
671 if p2 != nullid:
672 if not opts.get('parent'):
672 if not opts.get('parent'):
673 raise error.Abort(_('cannot backout a merge changeset'))
673 raise error.Abort(_('cannot backout a merge changeset'))
674 p = repo.lookup(opts['parent'])
674 p = repo.lookup(opts['parent'])
675 if p not in (p1, p2):
675 if p not in (p1, p2):
676 raise error.Abort(_('%s is not a parent of %s') %
676 raise error.Abort(_('%s is not a parent of %s') %
677 (short(p), short(node)))
677 (short(p), short(node)))
678 parent = p
678 parent = p
679 else:
679 else:
680 if opts.get('parent'):
680 if opts.get('parent'):
681 raise error.Abort(_('cannot use --parent on non-merge changeset'))
681 raise error.Abort(_('cannot use --parent on non-merge changeset'))
682 parent = p1
682 parent = p1
683
683
684 # the backout should appear on the same branch
684 # the backout should appear on the same branch
685 branch = repo.dirstate.branch()
685 branch = repo.dirstate.branch()
686 bheads = repo.branchheads(branch)
686 bheads = repo.branchheads(branch)
687 rctx = scmutil.revsingle(repo, hex(parent))
687 rctx = scmutil.revsingle(repo, hex(parent))
688 if not opts.get('merge') and op1 != node:
688 if not opts.get('merge') and op1 != node:
689 dsguard = dirstateguard.dirstateguard(repo, 'backout')
689 dsguard = dirstateguard.dirstateguard(repo, 'backout')
690 try:
690 try:
691 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
691 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
692 'backout')
692 'backout')
693 stats = mergemod.update(repo, parent, True, True, node, False)
693 stats = mergemod.update(repo, parent, True, True, node, False)
694 repo.setparents(op1, op2)
694 repo.setparents(op1, op2)
695 dsguard.close()
695 dsguard.close()
696 hg._showstats(repo, stats)
696 hg._showstats(repo, stats)
697 if stats[3]:
697 if stats[3]:
698 repo.ui.status(_("use 'hg resolve' to retry unresolved "
698 repo.ui.status(_("use 'hg resolve' to retry unresolved "
699 "file merges\n"))
699 "file merges\n"))
700 return 1
700 return 1
701 finally:
701 finally:
702 ui.setconfig('ui', 'forcemerge', '', '')
702 ui.setconfig('ui', 'forcemerge', '', '')
703 lockmod.release(dsguard)
703 lockmod.release(dsguard)
704 else:
704 else:
705 hg.clean(repo, node, show_stats=False)
705 hg.clean(repo, node, show_stats=False)
706 repo.dirstate.setbranch(branch)
706 repo.dirstate.setbranch(branch)
707 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
707 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
708
708
709 if opts.get('no_commit'):
709 if opts.get('no_commit'):
710 msg = _("changeset %s backed out, "
710 msg = _("changeset %s backed out, "
711 "don't forget to commit.\n")
711 "don't forget to commit.\n")
712 ui.status(msg % short(node))
712 ui.status(msg % short(node))
713 return 0
713 return 0
714
714
715 def commitfunc(ui, repo, message, match, opts):
715 def commitfunc(ui, repo, message, match, opts):
716 editform = 'backout'
716 editform = 'backout'
717 e = cmdutil.getcommiteditor(editform=editform, **opts)
717 e = cmdutil.getcommiteditor(editform=editform, **opts)
718 if not message:
718 if not message:
719 # we don't translate commit messages
719 # we don't translate commit messages
720 message = "Backed out changeset %s" % short(node)
720 message = "Backed out changeset %s" % short(node)
721 e = cmdutil.getcommiteditor(edit=True, editform=editform)
721 e = cmdutil.getcommiteditor(edit=True, editform=editform)
722 return repo.commit(message, opts.get('user'), opts.get('date'),
722 return repo.commit(message, opts.get('user'), opts.get('date'),
723 match, editor=e)
723 match, editor=e)
724 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
724 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
725 if not newnode:
725 if not newnode:
726 ui.status(_("nothing changed\n"))
726 ui.status(_("nothing changed\n"))
727 return 1
727 return 1
728 cmdutil.commitstatus(repo, newnode, branch, bheads)
728 cmdutil.commitstatus(repo, newnode, branch, bheads)
729
729
730 def nice(node):
730 def nice(node):
731 return '%d:%s' % (repo.changelog.rev(node), short(node))
731 return '%d:%s' % (repo.changelog.rev(node), short(node))
732 ui.status(_('changeset %s backs out changeset %s\n') %
732 ui.status(_('changeset %s backs out changeset %s\n') %
733 (nice(repo.changelog.tip()), nice(node)))
733 (nice(repo.changelog.tip()), nice(node)))
734 if opts.get('merge') and op1 != node:
734 if opts.get('merge') and op1 != node:
735 hg.clean(repo, op1, show_stats=False)
735 hg.clean(repo, op1, show_stats=False)
736 ui.status(_('merging with changeset %s\n')
736 ui.status(_('merging with changeset %s\n')
737 % nice(repo.changelog.tip()))
737 % nice(repo.changelog.tip()))
738 try:
738 try:
739 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
739 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
740 'backout')
740 'backout')
741 return hg.merge(repo, hex(repo.changelog.tip()))
741 return hg.merge(repo, hex(repo.changelog.tip()))
742 finally:
742 finally:
743 ui.setconfig('ui', 'forcemerge', '', '')
743 ui.setconfig('ui', 'forcemerge', '', '')
744 return 0
744 return 0
745
745
746 @command('bisect',
746 @command('bisect',
747 [('r', 'reset', False, _('reset bisect state')),
747 [('r', 'reset', False, _('reset bisect state')),
748 ('g', 'good', False, _('mark changeset good')),
748 ('g', 'good', False, _('mark changeset good')),
749 ('b', 'bad', False, _('mark changeset bad')),
749 ('b', 'bad', False, _('mark changeset bad')),
750 ('s', 'skip', False, _('skip testing changeset')),
750 ('s', 'skip', False, _('skip testing changeset')),
751 ('e', 'extend', False, _('extend the bisect range')),
751 ('e', 'extend', False, _('extend the bisect range')),
752 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
752 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
753 ('U', 'noupdate', False, _('do not update to target'))],
753 ('U', 'noupdate', False, _('do not update to target'))],
754 _("[-gbsr] [-U] [-c CMD] [REV]"))
754 _("[-gbsr] [-U] [-c CMD] [REV]"))
755 def bisect(ui, repo, rev=None, extra=None, command=None,
755 def bisect(ui, repo, rev=None, extra=None, command=None,
756 reset=None, good=None, bad=None, skip=None, extend=None,
756 reset=None, good=None, bad=None, skip=None, extend=None,
757 noupdate=None):
757 noupdate=None):
758 """subdivision search of changesets
758 """subdivision search of changesets
759
759
760 This command helps to find changesets which introduce problems. To
760 This command helps to find changesets which introduce problems. To
761 use, mark the earliest changeset you know exhibits the problem as
761 use, mark the earliest changeset you know exhibits the problem as
762 bad, then mark the latest changeset which is free from the problem
762 bad, then mark the latest changeset which is free from the problem
763 as good. Bisect will update your working directory to a revision
763 as good. Bisect will update your working directory to a revision
764 for testing (unless the -U/--noupdate option is specified). Once
764 for testing (unless the -U/--noupdate option is specified). Once
765 you have performed tests, mark the working directory as good or
765 you have performed tests, mark the working directory as good or
766 bad, and bisect will either update to another candidate changeset
766 bad, and bisect will either update to another candidate changeset
767 or announce that it has found the bad revision.
767 or announce that it has found the bad revision.
768
768
769 As a shortcut, you can also use the revision argument to mark a
769 As a shortcut, you can also use the revision argument to mark a
770 revision as good or bad without checking it out first.
770 revision as good or bad without checking it out first.
771
771
772 If you supply a command, it will be used for automatic bisection.
772 If you supply a command, it will be used for automatic bisection.
773 The environment variable HG_NODE will contain the ID of the
773 The environment variable HG_NODE will contain the ID of the
774 changeset being tested. The exit status of the command will be
774 changeset being tested. The exit status of the command will be
775 used to mark revisions as good or bad: status 0 means good, 125
775 used to mark revisions as good or bad: status 0 means good, 125
776 means to skip the revision, 127 (command not found) will abort the
776 means to skip the revision, 127 (command not found) will abort the
777 bisection, and any other non-zero exit status means the revision
777 bisection, and any other non-zero exit status means the revision
778 is bad.
778 is bad.
779
779
780 .. container:: verbose
780 .. container:: verbose
781
781
782 Some examples:
782 Some examples:
783
783
784 - start a bisection with known bad revision 34, and good revision 12::
784 - start a bisection with known bad revision 34, and good revision 12::
785
785
786 hg bisect --bad 34
786 hg bisect --bad 34
787 hg bisect --good 12
787 hg bisect --good 12
788
788
789 - advance the current bisection by marking current revision as good or
789 - advance the current bisection by marking current revision as good or
790 bad::
790 bad::
791
791
792 hg bisect --good
792 hg bisect --good
793 hg bisect --bad
793 hg bisect --bad
794
794
795 - mark the current revision, or a known revision, to be skipped (e.g. if
795 - mark the current revision, or a known revision, to be skipped (e.g. if
796 that revision is not usable because of another issue)::
796 that revision is not usable because of another issue)::
797
797
798 hg bisect --skip
798 hg bisect --skip
799 hg bisect --skip 23
799 hg bisect --skip 23
800
800
801 - skip all revisions that do not touch directories ``foo`` or ``bar``::
801 - skip all revisions that do not touch directories ``foo`` or ``bar``::
802
802
803 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
803 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
804
804
805 - forget the current bisection::
805 - forget the current bisection::
806
806
807 hg bisect --reset
807 hg bisect --reset
808
808
809 - use 'make && make tests' to automatically find the first broken
809 - use 'make && make tests' to automatically find the first broken
810 revision::
810 revision::
811
811
812 hg bisect --reset
812 hg bisect --reset
813 hg bisect --bad 34
813 hg bisect --bad 34
814 hg bisect --good 12
814 hg bisect --good 12
815 hg bisect --command "make && make tests"
815 hg bisect --command "make && make tests"
816
816
817 - see all changesets whose states are already known in the current
817 - see all changesets whose states are already known in the current
818 bisection::
818 bisection::
819
819
820 hg log -r "bisect(pruned)"
820 hg log -r "bisect(pruned)"
821
821
822 - see the changeset currently being bisected (especially useful
822 - see the changeset currently being bisected (especially useful
823 if running with -U/--noupdate)::
823 if running with -U/--noupdate)::
824
824
825 hg log -r "bisect(current)"
825 hg log -r "bisect(current)"
826
826
827 - see all changesets that took part in the current bisection::
827 - see all changesets that took part in the current bisection::
828
828
829 hg log -r "bisect(range)"
829 hg log -r "bisect(range)"
830
830
831 - you can even get a nice graph::
831 - you can even get a nice graph::
832
832
833 hg log --graph -r "bisect(range)"
833 hg log --graph -r "bisect(range)"
834
834
835 See :hg:`help revsets` for more about the `bisect()` keyword.
835 See :hg:`help revsets` for more about the `bisect()` keyword.
836
836
837 Returns 0 on success.
837 Returns 0 on success.
838 """
838 """
839 # backward compatibility
839 # backward compatibility
840 if rev in "good bad reset init".split():
840 if rev in "good bad reset init".split():
841 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
841 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
842 cmd, rev, extra = rev, extra, None
842 cmd, rev, extra = rev, extra, None
843 if cmd == "good":
843 if cmd == "good":
844 good = True
844 good = True
845 elif cmd == "bad":
845 elif cmd == "bad":
846 bad = True
846 bad = True
847 else:
847 else:
848 reset = True
848 reset = True
849 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
849 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
850 raise error.Abort(_('incompatible arguments'))
850 raise error.Abort(_('incompatible arguments'))
851
851
852 cmdutil.checkunfinished(repo)
852 cmdutil.checkunfinished(repo)
853
853
854 if reset:
854 if reset:
855 hbisect.resetstate(repo)
855 hbisect.resetstate(repo)
856 return
856 return
857
857
858 state = hbisect.load_state(repo)
858 state = hbisect.load_state(repo)
859
859
860 # update state
860 # update state
861 if good or bad or skip:
861 if good or bad or skip:
862 if rev:
862 if rev:
863 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
863 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
864 else:
864 else:
865 nodes = [repo.lookup('.')]
865 nodes = [repo.lookup('.')]
866 if good:
866 if good:
867 state['good'] += nodes
867 state['good'] += nodes
868 elif bad:
868 elif bad:
869 state['bad'] += nodes
869 state['bad'] += nodes
870 elif skip:
870 elif skip:
871 state['skip'] += nodes
871 state['skip'] += nodes
872 hbisect.save_state(repo, state)
872 hbisect.save_state(repo, state)
873 if not (state['good'] and state['bad']):
873 if not (state['good'] and state['bad']):
874 return
874 return
875
875
876 def mayupdate(repo, node, show_stats=True):
876 def mayupdate(repo, node, show_stats=True):
877 """common used update sequence"""
877 """common used update sequence"""
878 if noupdate:
878 if noupdate:
879 return
879 return
880 cmdutil.bailifchanged(repo)
880 cmdutil.bailifchanged(repo)
881 return hg.clean(repo, node, show_stats=show_stats)
881 return hg.clean(repo, node, show_stats=show_stats)
882
882
883 displayer = cmdutil.show_changeset(ui, repo, {})
883 displayer = cmdutil.show_changeset(ui, repo, {})
884
884
885 if command:
885 if command:
886 changesets = 1
886 changesets = 1
887 if noupdate:
887 if noupdate:
888 try:
888 try:
889 node = state['current'][0]
889 node = state['current'][0]
890 except LookupError:
890 except LookupError:
891 raise error.Abort(_('current bisect revision is unknown - '
891 raise error.Abort(_('current bisect revision is unknown - '
892 'start a new bisect to fix'))
892 'start a new bisect to fix'))
893 else:
893 else:
894 node, p2 = repo.dirstate.parents()
894 node, p2 = repo.dirstate.parents()
895 if p2 != nullid:
895 if p2 != nullid:
896 raise error.Abort(_('current bisect revision is a merge'))
896 raise error.Abort(_('current bisect revision is a merge'))
897 if rev:
897 if rev:
898 node = repo[scmutil.revsingle(repo, rev, node)].node()
898 node = repo[scmutil.revsingle(repo, rev, node)].node()
899 try:
899 try:
900 while changesets:
900 while changesets:
901 # update state
901 # update state
902 state['current'] = [node]
902 state['current'] = [node]
903 hbisect.save_state(repo, state)
903 hbisect.save_state(repo, state)
904 status = ui.system(command, environ={'HG_NODE': hex(node)})
904 status = ui.system(command, environ={'HG_NODE': hex(node)})
905 if status == 125:
905 if status == 125:
906 transition = "skip"
906 transition = "skip"
907 elif status == 0:
907 elif status == 0:
908 transition = "good"
908 transition = "good"
909 # status < 0 means process was killed
909 # status < 0 means process was killed
910 elif status == 127:
910 elif status == 127:
911 raise error.Abort(_("failed to execute %s") % command)
911 raise error.Abort(_("failed to execute %s") % command)
912 elif status < 0:
912 elif status < 0:
913 raise error.Abort(_("%s killed") % command)
913 raise error.Abort(_("%s killed") % command)
914 else:
914 else:
915 transition = "bad"
915 transition = "bad"
916 state[transition].append(node)
916 state[transition].append(node)
917 ctx = repo[node]
917 ctx = repo[node]
918 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
918 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
919 hbisect.checkstate(state)
919 hbisect.checkstate(state)
920 # bisect
920 # bisect
921 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
921 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
922 # update to next check
922 # update to next check
923 node = nodes[0]
923 node = nodes[0]
924 mayupdate(repo, node, show_stats=False)
924 mayupdate(repo, node, show_stats=False)
925 finally:
925 finally:
926 state['current'] = [node]
926 state['current'] = [node]
927 hbisect.save_state(repo, state)
927 hbisect.save_state(repo, state)
928 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
928 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
929 return
929 return
930
930
931 hbisect.checkstate(state)
931 hbisect.checkstate(state)
932
932
933 # actually bisect
933 # actually bisect
934 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
934 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
935 if extend:
935 if extend:
936 if not changesets:
936 if not changesets:
937 extendnode = hbisect.extendrange(repo, state, nodes, good)
937 extendnode = hbisect.extendrange(repo, state, nodes, good)
938 if extendnode is not None:
938 if extendnode is not None:
939 ui.write(_("Extending search to changeset %d:%s\n")
939 ui.write(_("Extending search to changeset %d:%s\n")
940 % (extendnode.rev(), extendnode))
940 % (extendnode.rev(), extendnode))
941 state['current'] = [extendnode.node()]
941 state['current'] = [extendnode.node()]
942 hbisect.save_state(repo, state)
942 hbisect.save_state(repo, state)
943 return mayupdate(repo, extendnode.node())
943 return mayupdate(repo, extendnode.node())
944 raise error.Abort(_("nothing to extend"))
944 raise error.Abort(_("nothing to extend"))
945
945
946 if changesets == 0:
946 if changesets == 0:
947 hbisect.printresult(ui, repo, state, displayer, nodes, good)
947 hbisect.printresult(ui, repo, state, displayer, nodes, good)
948 else:
948 else:
949 assert len(nodes) == 1 # only a single node can be tested next
949 assert len(nodes) == 1 # only a single node can be tested next
950 node = nodes[0]
950 node = nodes[0]
951 # compute the approximate number of remaining tests
951 # compute the approximate number of remaining tests
952 tests, size = 0, 2
952 tests, size = 0, 2
953 while size <= changesets:
953 while size <= changesets:
954 tests, size = tests + 1, size * 2
954 tests, size = tests + 1, size * 2
955 rev = repo.changelog.rev(node)
955 rev = repo.changelog.rev(node)
956 ui.write(_("Testing changeset %d:%s "
956 ui.write(_("Testing changeset %d:%s "
957 "(%d changesets remaining, ~%d tests)\n")
957 "(%d changesets remaining, ~%d tests)\n")
958 % (rev, short(node), changesets, tests))
958 % (rev, short(node), changesets, tests))
959 state['current'] = [node]
959 state['current'] = [node]
960 hbisect.save_state(repo, state)
960 hbisect.save_state(repo, state)
961 return mayupdate(repo, node)
961 return mayupdate(repo, node)
962
962
963 @command('bookmarks|bookmark',
963 @command('bookmarks|bookmark',
964 [('f', 'force', False, _('force')),
964 [('f', 'force', False, _('force')),
965 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
965 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
966 ('d', 'delete', False, _('delete a given bookmark')),
966 ('d', 'delete', False, _('delete a given bookmark')),
967 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
967 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
968 ('i', 'inactive', False, _('mark a bookmark inactive')),
968 ('i', 'inactive', False, _('mark a bookmark inactive')),
969 ] + formatteropts,
969 ] + formatteropts,
970 _('hg bookmarks [OPTIONS]... [NAME]...'))
970 _('hg bookmarks [OPTIONS]... [NAME]...'))
971 def bookmark(ui, repo, *names, **opts):
971 def bookmark(ui, repo, *names, **opts):
972 '''create a new bookmark or list existing bookmarks
972 '''create a new bookmark or list existing bookmarks
973
973
974 Bookmarks are labels on changesets to help track lines of development.
974 Bookmarks are labels on changesets to help track lines of development.
975 Bookmarks are unversioned and can be moved, renamed and deleted.
975 Bookmarks are unversioned and can be moved, renamed and deleted.
976 Deleting or moving a bookmark has no effect on the associated changesets.
976 Deleting or moving a bookmark has no effect on the associated changesets.
977
977
978 Creating or updating to a bookmark causes it to be marked as 'active'.
978 Creating or updating to a bookmark causes it to be marked as 'active'.
979 The active bookmark is indicated with a '*'.
979 The active bookmark is indicated with a '*'.
980 When a commit is made, the active bookmark will advance to the new commit.
980 When a commit is made, the active bookmark will advance to the new commit.
981 A plain :hg:`update` will also advance an active bookmark, if possible.
981 A plain :hg:`update` will also advance an active bookmark, if possible.
982 Updating away from a bookmark will cause it to be deactivated.
982 Updating away from a bookmark will cause it to be deactivated.
983
983
984 Bookmarks can be pushed and pulled between repositories (see
984 Bookmarks can be pushed and pulled between repositories (see
985 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
985 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
986 diverged, a new 'divergent bookmark' of the form 'name@path' will
986 diverged, a new 'divergent bookmark' of the form 'name@path' will
987 be created. Using :hg:`merge` will resolve the divergence.
987 be created. Using :hg:`merge` will resolve the divergence.
988
988
989 A bookmark named '@' has the special property that :hg:`clone` will
989 A bookmark named '@' has the special property that :hg:`clone` will
990 check it out by default if it exists.
990 check it out by default if it exists.
991
991
992 .. container:: verbose
992 .. container:: verbose
993
993
994 Examples:
994 Examples:
995
995
996 - create an active bookmark for a new line of development::
996 - create an active bookmark for a new line of development::
997
997
998 hg book new-feature
998 hg book new-feature
999
999
1000 - create an inactive bookmark as a place marker::
1000 - create an inactive bookmark as a place marker::
1001
1001
1002 hg book -i reviewed
1002 hg book -i reviewed
1003
1003
1004 - create an inactive bookmark on another changeset::
1004 - create an inactive bookmark on another changeset::
1005
1005
1006 hg book -r .^ tested
1006 hg book -r .^ tested
1007
1007
1008 - rename bookmark turkey to dinner::
1008 - rename bookmark turkey to dinner::
1009
1009
1010 hg book -m turkey dinner
1010 hg book -m turkey dinner
1011
1011
1012 - move the '@' bookmark from another branch::
1012 - move the '@' bookmark from another branch::
1013
1013
1014 hg book -f @
1014 hg book -f @
1015 '''
1015 '''
1016 force = opts.get('force')
1016 force = opts.get('force')
1017 rev = opts.get('rev')
1017 rev = opts.get('rev')
1018 delete = opts.get('delete')
1018 delete = opts.get('delete')
1019 rename = opts.get('rename')
1019 rename = opts.get('rename')
1020 inactive = opts.get('inactive')
1020 inactive = opts.get('inactive')
1021
1021
1022 def checkformat(mark):
1022 def checkformat(mark):
1023 mark = mark.strip()
1023 mark = mark.strip()
1024 if not mark:
1024 if not mark:
1025 raise error.Abort(_("bookmark names cannot consist entirely of "
1025 raise error.Abort(_("bookmark names cannot consist entirely of "
1026 "whitespace"))
1026 "whitespace"))
1027 scmutil.checknewlabel(repo, mark, 'bookmark')
1027 scmutil.checknewlabel(repo, mark, 'bookmark')
1028 return mark
1028 return mark
1029
1029
1030 def checkconflict(repo, mark, cur, force=False, target=None):
1030 def checkconflict(repo, mark, cur, force=False, target=None):
1031 if mark in marks and not force:
1031 if mark in marks and not force:
1032 if target:
1032 if target:
1033 if marks[mark] == target and target == cur:
1033 if marks[mark] == target and target == cur:
1034 # re-activating a bookmark
1034 # re-activating a bookmark
1035 return
1035 return
1036 anc = repo.changelog.ancestors([repo[target].rev()])
1036 anc = repo.changelog.ancestors([repo[target].rev()])
1037 bmctx = repo[marks[mark]]
1037 bmctx = repo[marks[mark]]
1038 divs = [repo[b].node() for b in marks
1038 divs = [repo[b].node() for b in marks
1039 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1039 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1040
1040
1041 # allow resolving a single divergent bookmark even if moving
1041 # allow resolving a single divergent bookmark even if moving
1042 # the bookmark across branches when a revision is specified
1042 # the bookmark across branches when a revision is specified
1043 # that contains a divergent bookmark
1043 # that contains a divergent bookmark
1044 if bmctx.rev() not in anc and target in divs:
1044 if bmctx.rev() not in anc and target in divs:
1045 bookmarks.deletedivergent(repo, [target], mark)
1045 bookmarks.deletedivergent(repo, [target], mark)
1046 return
1046 return
1047
1047
1048 deletefrom = [b for b in divs
1048 deletefrom = [b for b in divs
1049 if repo[b].rev() in anc or b == target]
1049 if repo[b].rev() in anc or b == target]
1050 bookmarks.deletedivergent(repo, deletefrom, mark)
1050 bookmarks.deletedivergent(repo, deletefrom, mark)
1051 if bookmarks.validdest(repo, bmctx, repo[target]):
1051 if bookmarks.validdest(repo, bmctx, repo[target]):
1052 ui.status(_("moving bookmark '%s' forward from %s\n") %
1052 ui.status(_("moving bookmark '%s' forward from %s\n") %
1053 (mark, short(bmctx.node())))
1053 (mark, short(bmctx.node())))
1054 return
1054 return
1055 raise error.Abort(_("bookmark '%s' already exists "
1055 raise error.Abort(_("bookmark '%s' already exists "
1056 "(use -f to force)") % mark)
1056 "(use -f to force)") % mark)
1057 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1057 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1058 and not force):
1058 and not force):
1059 raise error.Abort(
1059 raise error.Abort(
1060 _("a bookmark cannot have the name of an existing branch"))
1060 _("a bookmark cannot have the name of an existing branch"))
1061
1061
1062 if delete and rename:
1062 if delete and rename:
1063 raise error.Abort(_("--delete and --rename are incompatible"))
1063 raise error.Abort(_("--delete and --rename are incompatible"))
1064 if delete and rev:
1064 if delete and rev:
1065 raise error.Abort(_("--rev is incompatible with --delete"))
1065 raise error.Abort(_("--rev is incompatible with --delete"))
1066 if rename and rev:
1066 if rename and rev:
1067 raise error.Abort(_("--rev is incompatible with --rename"))
1067 raise error.Abort(_("--rev is incompatible with --rename"))
1068 if not names and (delete or rev):
1068 if not names and (delete or rev):
1069 raise error.Abort(_("bookmark name required"))
1069 raise error.Abort(_("bookmark name required"))
1070
1070
1071 if delete or rename or names or inactive:
1071 if delete or rename or names or inactive:
1072 wlock = lock = tr = None
1072 wlock = lock = tr = None
1073 try:
1073 try:
1074 wlock = repo.wlock()
1074 wlock = repo.wlock()
1075 lock = repo.lock()
1075 lock = repo.lock()
1076 cur = repo.changectx('.').node()
1076 cur = repo.changectx('.').node()
1077 marks = repo._bookmarks
1077 marks = repo._bookmarks
1078 if delete:
1078 if delete:
1079 tr = repo.transaction('bookmark')
1079 tr = repo.transaction('bookmark')
1080 for mark in names:
1080 for mark in names:
1081 if mark not in marks:
1081 if mark not in marks:
1082 raise error.Abort(_("bookmark '%s' does not exist") %
1082 raise error.Abort(_("bookmark '%s' does not exist") %
1083 mark)
1083 mark)
1084 if mark == repo._activebookmark:
1084 if mark == repo._activebookmark:
1085 bookmarks.deactivate(repo)
1085 bookmarks.deactivate(repo)
1086 del marks[mark]
1086 del marks[mark]
1087
1087
1088 elif rename:
1088 elif rename:
1089 tr = repo.transaction('bookmark')
1089 tr = repo.transaction('bookmark')
1090 if not names:
1090 if not names:
1091 raise error.Abort(_("new bookmark name required"))
1091 raise error.Abort(_("new bookmark name required"))
1092 elif len(names) > 1:
1092 elif len(names) > 1:
1093 raise error.Abort(_("only one new bookmark name allowed"))
1093 raise error.Abort(_("only one new bookmark name allowed"))
1094 mark = checkformat(names[0])
1094 mark = checkformat(names[0])
1095 if rename not in marks:
1095 if rename not in marks:
1096 raise error.Abort(_("bookmark '%s' does not exist")
1096 raise error.Abort(_("bookmark '%s' does not exist")
1097 % rename)
1097 % rename)
1098 checkconflict(repo, mark, cur, force)
1098 checkconflict(repo, mark, cur, force)
1099 marks[mark] = marks[rename]
1099 marks[mark] = marks[rename]
1100 if repo._activebookmark == rename and not inactive:
1100 if repo._activebookmark == rename and not inactive:
1101 bookmarks.activate(repo, mark)
1101 bookmarks.activate(repo, mark)
1102 del marks[rename]
1102 del marks[rename]
1103 elif names:
1103 elif names:
1104 tr = repo.transaction('bookmark')
1104 tr = repo.transaction('bookmark')
1105 newact = None
1105 newact = None
1106 for mark in names:
1106 for mark in names:
1107 mark = checkformat(mark)
1107 mark = checkformat(mark)
1108 if newact is None:
1108 if newact is None:
1109 newact = mark
1109 newact = mark
1110 if inactive and mark == repo._activebookmark:
1110 if inactive and mark == repo._activebookmark:
1111 bookmarks.deactivate(repo)
1111 bookmarks.deactivate(repo)
1112 return
1112 return
1113 tgt = cur
1113 tgt = cur
1114 if rev:
1114 if rev:
1115 tgt = scmutil.revsingle(repo, rev).node()
1115 tgt = scmutil.revsingle(repo, rev).node()
1116 checkconflict(repo, mark, cur, force, tgt)
1116 checkconflict(repo, mark, cur, force, tgt)
1117 marks[mark] = tgt
1117 marks[mark] = tgt
1118 if not inactive and cur == marks[newact] and not rev:
1118 if not inactive and cur == marks[newact] and not rev:
1119 bookmarks.activate(repo, newact)
1119 bookmarks.activate(repo, newact)
1120 elif cur != tgt and newact == repo._activebookmark:
1120 elif cur != tgt and newact == repo._activebookmark:
1121 bookmarks.deactivate(repo)
1121 bookmarks.deactivate(repo)
1122 elif inactive:
1122 elif inactive:
1123 if len(marks) == 0:
1123 if len(marks) == 0:
1124 ui.status(_("no bookmarks set\n"))
1124 ui.status(_("no bookmarks set\n"))
1125 elif not repo._activebookmark:
1125 elif not repo._activebookmark:
1126 ui.status(_("no active bookmark\n"))
1126 ui.status(_("no active bookmark\n"))
1127 else:
1127 else:
1128 bookmarks.deactivate(repo)
1128 bookmarks.deactivate(repo)
1129 if tr is not None:
1129 if tr is not None:
1130 marks.recordchange(tr)
1130 marks.recordchange(tr)
1131 tr.close()
1131 tr.close()
1132 finally:
1132 finally:
1133 lockmod.release(tr, lock, wlock)
1133 lockmod.release(tr, lock, wlock)
1134 else: # show bookmarks
1134 else: # show bookmarks
1135 fm = ui.formatter('bookmarks', opts)
1135 fm = ui.formatter('bookmarks', opts)
1136 hexfn = fm.hexfunc
1136 hexfn = fm.hexfunc
1137 marks = repo._bookmarks
1137 marks = repo._bookmarks
1138 if len(marks) == 0 and fm.isplain():
1138 if len(marks) == 0 and fm.isplain():
1139 ui.status(_("no bookmarks set\n"))
1139 ui.status(_("no bookmarks set\n"))
1140 for bmark, n in sorted(marks.iteritems()):
1140 for bmark, n in sorted(marks.iteritems()):
1141 active = repo._activebookmark
1141 active = repo._activebookmark
1142 if bmark == active:
1142 if bmark == active:
1143 prefix, label = '*', activebookmarklabel
1143 prefix, label = '*', activebookmarklabel
1144 else:
1144 else:
1145 prefix, label = ' ', ''
1145 prefix, label = ' ', ''
1146
1146
1147 fm.startitem()
1147 fm.startitem()
1148 if not ui.quiet:
1148 if not ui.quiet:
1149 fm.plain(' %s ' % prefix, label=label)
1149 fm.plain(' %s ' % prefix, label=label)
1150 fm.write('bookmark', '%s', bmark, label=label)
1150 fm.write('bookmark', '%s', bmark, label=label)
1151 pad = " " * (25 - encoding.colwidth(bmark))
1151 pad = " " * (25 - encoding.colwidth(bmark))
1152 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1152 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1153 repo.changelog.rev(n), hexfn(n), label=label)
1153 repo.changelog.rev(n), hexfn(n), label=label)
1154 fm.data(active=(bmark == active))
1154 fm.data(active=(bmark == active))
1155 fm.plain('\n')
1155 fm.plain('\n')
1156 fm.end()
1156 fm.end()
1157
1157
1158 @command('branch',
1158 @command('branch',
1159 [('f', 'force', None,
1159 [('f', 'force', None,
1160 _('set branch name even if it shadows an existing branch')),
1160 _('set branch name even if it shadows an existing branch')),
1161 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1161 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1162 _('[-fC] [NAME]'))
1162 _('[-fC] [NAME]'))
1163 def branch(ui, repo, label=None, **opts):
1163 def branch(ui, repo, label=None, **opts):
1164 """set or show the current branch name
1164 """set or show the current branch name
1165
1165
1166 .. note::
1166 .. note::
1167
1167
1168 Branch names are permanent and global. Use :hg:`bookmark` to create a
1168 Branch names are permanent and global. Use :hg:`bookmark` to create a
1169 light-weight bookmark instead. See :hg:`help glossary` for more
1169 light-weight bookmark instead. See :hg:`help glossary` for more
1170 information about named branches and bookmarks.
1170 information about named branches and bookmarks.
1171
1171
1172 With no argument, show the current branch name. With one argument,
1172 With no argument, show the current branch name. With one argument,
1173 set the working directory branch name (the branch will not exist
1173 set the working directory branch name (the branch will not exist
1174 in the repository until the next commit). Standard practice
1174 in the repository until the next commit). Standard practice
1175 recommends that primary development take place on the 'default'
1175 recommends that primary development take place on the 'default'
1176 branch.
1176 branch.
1177
1177
1178 Unless -f/--force is specified, branch will not let you set a
1178 Unless -f/--force is specified, branch will not let you set a
1179 branch name that already exists.
1179 branch name that already exists.
1180
1180
1181 Use -C/--clean to reset the working directory branch to that of
1181 Use -C/--clean to reset the working directory branch to that of
1182 the parent of the working directory, negating a previous branch
1182 the parent of the working directory, negating a previous branch
1183 change.
1183 change.
1184
1184
1185 Use the command :hg:`update` to switch to an existing branch. Use
1185 Use the command :hg:`update` to switch to an existing branch. Use
1186 :hg:`commit --close-branch` to mark this branch head as closed.
1186 :hg:`commit --close-branch` to mark this branch head as closed.
1187 When all heads of a branch are closed, the branch will be
1187 When all heads of a branch are closed, the branch will be
1188 considered closed.
1188 considered closed.
1189
1189
1190 Returns 0 on success.
1190 Returns 0 on success.
1191 """
1191 """
1192 if label:
1192 if label:
1193 label = label.strip()
1193 label = label.strip()
1194
1194
1195 if not opts.get('clean') and not label:
1195 if not opts.get('clean') and not label:
1196 ui.write("%s\n" % repo.dirstate.branch())
1196 ui.write("%s\n" % repo.dirstate.branch())
1197 return
1197 return
1198
1198
1199 with repo.wlock():
1199 with repo.wlock():
1200 if opts.get('clean'):
1200 if opts.get('clean'):
1201 label = repo[None].p1().branch()
1201 label = repo[None].p1().branch()
1202 repo.dirstate.setbranch(label)
1202 repo.dirstate.setbranch(label)
1203 ui.status(_('reset working directory to branch %s\n') % label)
1203 ui.status(_('reset working directory to branch %s\n') % label)
1204 elif label:
1204 elif label:
1205 if not opts.get('force') and label in repo.branchmap():
1205 if not opts.get('force') and label in repo.branchmap():
1206 if label not in [p.branch() for p in repo[None].parents()]:
1206 if label not in [p.branch() for p in repo[None].parents()]:
1207 raise error.Abort(_('a branch of the same name already'
1207 raise error.Abort(_('a branch of the same name already'
1208 ' exists'),
1208 ' exists'),
1209 # i18n: "it" refers to an existing branch
1209 # i18n: "it" refers to an existing branch
1210 hint=_("use 'hg update' to switch to it"))
1210 hint=_("use 'hg update' to switch to it"))
1211 scmutil.checknewlabel(repo, label, 'branch')
1211 scmutil.checknewlabel(repo, label, 'branch')
1212 repo.dirstate.setbranch(label)
1212 repo.dirstate.setbranch(label)
1213 ui.status(_('marked working directory as branch %s\n') % label)
1213 ui.status(_('marked working directory as branch %s\n') % label)
1214
1214
1215 # find any open named branches aside from default
1215 # find any open named branches aside from default
1216 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1216 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1217 if n != "default" and not c]
1217 if n != "default" and not c]
1218 if not others:
1218 if not others:
1219 ui.status(_('(branches are permanent and global, '
1219 ui.status(_('(branches are permanent and global, '
1220 'did you want a bookmark?)\n'))
1220 'did you want a bookmark?)\n'))
1221
1221
1222 @command('branches',
1222 @command('branches',
1223 [('a', 'active', False,
1223 [('a', 'active', False,
1224 _('show only branches that have unmerged heads (DEPRECATED)')),
1224 _('show only branches that have unmerged heads (DEPRECATED)')),
1225 ('c', 'closed', False, _('show normal and closed branches')),
1225 ('c', 'closed', False, _('show normal and closed branches')),
1226 ] + formatteropts,
1226 ] + formatteropts,
1227 _('[-c]'))
1227 _('[-c]'))
1228 def branches(ui, repo, active=False, closed=False, **opts):
1228 def branches(ui, repo, active=False, closed=False, **opts):
1229 """list repository named branches
1229 """list repository named branches
1230
1230
1231 List the repository's named branches, indicating which ones are
1231 List the repository's named branches, indicating which ones are
1232 inactive. If -c/--closed is specified, also list branches which have
1232 inactive. If -c/--closed is specified, also list branches which have
1233 been marked closed (see :hg:`commit --close-branch`).
1233 been marked closed (see :hg:`commit --close-branch`).
1234
1234
1235 Use the command :hg:`update` to switch to an existing branch.
1235 Use the command :hg:`update` to switch to an existing branch.
1236
1236
1237 Returns 0.
1237 Returns 0.
1238 """
1238 """
1239
1239
1240 fm = ui.formatter('branches', opts)
1240 fm = ui.formatter('branches', opts)
1241 hexfunc = fm.hexfunc
1241 hexfunc = fm.hexfunc
1242
1242
1243 allheads = set(repo.heads())
1243 allheads = set(repo.heads())
1244 branches = []
1244 branches = []
1245 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1245 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1246 isactive = not isclosed and bool(set(heads) & allheads)
1246 isactive = not isclosed and bool(set(heads) & allheads)
1247 branches.append((tag, repo[tip], isactive, not isclosed))
1247 branches.append((tag, repo[tip], isactive, not isclosed))
1248 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1248 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1249 reverse=True)
1249 reverse=True)
1250
1250
1251 for tag, ctx, isactive, isopen in branches:
1251 for tag, ctx, isactive, isopen in branches:
1252 if active and not isactive:
1252 if active and not isactive:
1253 continue
1253 continue
1254 if isactive:
1254 if isactive:
1255 label = 'branches.active'
1255 label = 'branches.active'
1256 notice = ''
1256 notice = ''
1257 elif not isopen:
1257 elif not isopen:
1258 if not closed:
1258 if not closed:
1259 continue
1259 continue
1260 label = 'branches.closed'
1260 label = 'branches.closed'
1261 notice = _(' (closed)')
1261 notice = _(' (closed)')
1262 else:
1262 else:
1263 label = 'branches.inactive'
1263 label = 'branches.inactive'
1264 notice = _(' (inactive)')
1264 notice = _(' (inactive)')
1265 current = (tag == repo.dirstate.branch())
1265 current = (tag == repo.dirstate.branch())
1266 if current:
1266 if current:
1267 label = 'branches.current'
1267 label = 'branches.current'
1268
1268
1269 fm.startitem()
1269 fm.startitem()
1270 fm.write('branch', '%s', tag, label=label)
1270 fm.write('branch', '%s', tag, label=label)
1271 rev = ctx.rev()
1271 rev = ctx.rev()
1272 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1272 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1273 fmt = ' ' * padsize + ' %d:%s'
1273 fmt = ' ' * padsize + ' %d:%s'
1274 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1274 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1275 label='log.changeset changeset.%s' % ctx.phasestr())
1275 label='log.changeset changeset.%s' % ctx.phasestr())
1276 fm.data(active=isactive, closed=not isopen, current=current)
1276 fm.data(active=isactive, closed=not isopen, current=current)
1277 if not ui.quiet:
1277 if not ui.quiet:
1278 fm.plain(notice)
1278 fm.plain(notice)
1279 fm.plain('\n')
1279 fm.plain('\n')
1280 fm.end()
1280 fm.end()
1281
1281
1282 @command('bundle',
1282 @command('bundle',
1283 [('f', 'force', None, _('run even when the destination is unrelated')),
1283 [('f', 'force', None, _('run even when the destination is unrelated')),
1284 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1284 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1285 _('REV')),
1285 _('REV')),
1286 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1286 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1287 _('BRANCH')),
1287 _('BRANCH')),
1288 ('', 'base', [],
1288 ('', 'base', [],
1289 _('a base changeset assumed to be available at the destination'),
1289 _('a base changeset assumed to be available at the destination'),
1290 _('REV')),
1290 _('REV')),
1291 ('a', 'all', None, _('bundle all changesets in the repository')),
1291 ('a', 'all', None, _('bundle all changesets in the repository')),
1292 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1292 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1293 ] + remoteopts,
1293 ] + remoteopts,
1294 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1294 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1295 def bundle(ui, repo, fname, dest=None, **opts):
1295 def bundle(ui, repo, fname, dest=None, **opts):
1296 """create a changegroup file
1296 """create a changegroup file
1297
1297
1298 Generate a changegroup file collecting changesets to be added
1298 Generate a changegroup file collecting changesets to be added
1299 to a repository.
1299 to a repository.
1300
1300
1301 To create a bundle containing all changesets, use -a/--all
1301 To create a bundle containing all changesets, use -a/--all
1302 (or --base null). Otherwise, hg assumes the destination will have
1302 (or --base null). Otherwise, hg assumes the destination will have
1303 all the nodes you specify with --base parameters. Otherwise, hg
1303 all the nodes you specify with --base parameters. Otherwise, hg
1304 will assume the repository has all the nodes in destination, or
1304 will assume the repository has all the nodes in destination, or
1305 default-push/default if no destination is specified.
1305 default-push/default if no destination is specified.
1306
1306
1307 You can change bundle format with the -t/--type option. You can
1307 You can change bundle format with the -t/--type option. You can
1308 specify a compression, a bundle version or both using a dash
1308 specify a compression, a bundle version or both using a dash
1309 (comp-version). The available compression methods are: none, bzip2,
1309 (comp-version). The available compression methods are: none, bzip2,
1310 and gzip (by default, bundles are compressed using bzip2). The
1310 and gzip (by default, bundles are compressed using bzip2). The
1311 available formats are: v1, v2 (default to most suitable).
1311 available formats are: v1, v2 (default to most suitable).
1312
1312
1313 The bundle file can then be transferred using conventional means
1313 The bundle file can then be transferred using conventional means
1314 and applied to another repository with the unbundle or pull
1314 and applied to another repository with the unbundle or pull
1315 command. This is useful when direct push and pull are not
1315 command. This is useful when direct push and pull are not
1316 available or when exporting an entire repository is undesirable.
1316 available or when exporting an entire repository is undesirable.
1317
1317
1318 Applying bundles preserves all changeset contents including
1318 Applying bundles preserves all changeset contents including
1319 permissions, copy/rename information, and revision history.
1319 permissions, copy/rename information, and revision history.
1320
1320
1321 Returns 0 on success, 1 if no changes found.
1321 Returns 0 on success, 1 if no changes found.
1322 """
1322 """
1323 revs = None
1323 revs = None
1324 if 'rev' in opts:
1324 if 'rev' in opts:
1325 revstrings = opts['rev']
1325 revstrings = opts['rev']
1326 revs = scmutil.revrange(repo, revstrings)
1326 revs = scmutil.revrange(repo, revstrings)
1327 if revstrings and not revs:
1327 if revstrings and not revs:
1328 raise error.Abort(_('no commits to bundle'))
1328 raise error.Abort(_('no commits to bundle'))
1329
1329
1330 bundletype = opts.get('type', 'bzip2').lower()
1330 bundletype = opts.get('type', 'bzip2').lower()
1331 try:
1331 try:
1332 bcompression, cgversion, params = exchange.parsebundlespec(
1332 bcompression, cgversion, params = exchange.parsebundlespec(
1333 repo, bundletype, strict=False)
1333 repo, bundletype, strict=False)
1334 except error.UnsupportedBundleSpecification as e:
1334 except error.UnsupportedBundleSpecification as e:
1335 raise error.Abort(str(e),
1335 raise error.Abort(str(e),
1336 hint=_("see 'hg help bundle' for supported "
1336 hint=_("see 'hg help bundle' for supported "
1337 "values for --type"))
1337 "values for --type"))
1338
1338
1339 # Packed bundles are a pseudo bundle format for now.
1339 # Packed bundles are a pseudo bundle format for now.
1340 if cgversion == 's1':
1340 if cgversion == 's1':
1341 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1341 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1342 hint=_("use 'hg debugcreatestreamclonebundle'"))
1342 hint=_("use 'hg debugcreatestreamclonebundle'"))
1343
1343
1344 if opts.get('all'):
1344 if opts.get('all'):
1345 if dest:
1345 if dest:
1346 raise error.Abort(_("--all is incompatible with specifying "
1346 raise error.Abort(_("--all is incompatible with specifying "
1347 "a destination"))
1347 "a destination"))
1348 if opts.get('base'):
1348 if opts.get('base'):
1349 ui.warn(_("ignoring --base because --all was specified\n"))
1349 ui.warn(_("ignoring --base because --all was specified\n"))
1350 base = ['null']
1350 base = ['null']
1351 else:
1351 else:
1352 base = scmutil.revrange(repo, opts.get('base'))
1352 base = scmutil.revrange(repo, opts.get('base'))
1353 # TODO: get desired bundlecaps from command line.
1353 # TODO: get desired bundlecaps from command line.
1354 bundlecaps = None
1354 bundlecaps = None
1355 if cgversion not in changegroup.supportedoutgoingversions(repo):
1355 if cgversion not in changegroup.supportedoutgoingversions(repo):
1356 raise error.Abort(_("repository does not support bundle version %s") %
1356 raise error.Abort(_("repository does not support bundle version %s") %
1357 cgversion)
1357 cgversion)
1358
1358
1359 if base:
1359 if base:
1360 if dest:
1360 if dest:
1361 raise error.Abort(_("--base is incompatible with specifying "
1361 raise error.Abort(_("--base is incompatible with specifying "
1362 "a destination"))
1362 "a destination"))
1363 common = [repo.lookup(rev) for rev in base]
1363 common = [repo.lookup(rev) for rev in base]
1364 heads = revs and map(repo.lookup, revs) or None
1364 heads = revs and map(repo.lookup, revs) or None
1365 outgoing = discovery.outgoing(repo, common, heads)
1365 outgoing = discovery.outgoing(repo, common, heads)
1366 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1366 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1367 bundlecaps=bundlecaps,
1367 bundlecaps=bundlecaps,
1368 version=cgversion)
1368 version=cgversion)
1369 outgoing = None
1369 outgoing = None
1370 else:
1370 else:
1371 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1371 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1372 dest, branches = hg.parseurl(dest, opts.get('branch'))
1372 dest, branches = hg.parseurl(dest, opts.get('branch'))
1373 other = hg.peer(repo, opts, dest)
1373 other = hg.peer(repo, opts, dest)
1374 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1374 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1375 heads = revs and map(repo.lookup, revs) or revs
1375 heads = revs and map(repo.lookup, revs) or revs
1376 outgoing = discovery.findcommonoutgoing(repo, other,
1376 outgoing = discovery.findcommonoutgoing(repo, other,
1377 onlyheads=heads,
1377 onlyheads=heads,
1378 force=opts.get('force'),
1378 force=opts.get('force'),
1379 portable=True)
1379 portable=True)
1380 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1380 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1381 bundlecaps, version=cgversion)
1381 bundlecaps, version=cgversion)
1382 if not cg:
1382 if not cg:
1383 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1383 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1384 return 1
1384 return 1
1385
1385
1386 if cgversion == '01': #bundle1
1386 if cgversion == '01': #bundle1
1387 if bcompression is None:
1387 if bcompression is None:
1388 bcompression = 'UN'
1388 bcompression = 'UN'
1389 bversion = 'HG10' + bcompression
1389 bversion = 'HG10' + bcompression
1390 bcompression = None
1390 bcompression = None
1391 else:
1391 else:
1392 assert cgversion == '02'
1392 assert cgversion == '02'
1393 bversion = 'HG20'
1393 bversion = 'HG20'
1394
1394
1395 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1395 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1396
1396
1397 @command('cat',
1397 @command('cat',
1398 [('o', 'output', '',
1398 [('o', 'output', '',
1399 _('print output to file with formatted name'), _('FORMAT')),
1399 _('print output to file with formatted name'), _('FORMAT')),
1400 ('r', 'rev', '', _('print the given revision'), _('REV')),
1400 ('r', 'rev', '', _('print the given revision'), _('REV')),
1401 ('', 'decode', None, _('apply any matching decode filter')),
1401 ('', 'decode', None, _('apply any matching decode filter')),
1402 ] + walkopts,
1402 ] + walkopts,
1403 _('[OPTION]... FILE...'),
1403 _('[OPTION]... FILE...'),
1404 inferrepo=True)
1404 inferrepo=True)
1405 def cat(ui, repo, file1, *pats, **opts):
1405 def cat(ui, repo, file1, *pats, **opts):
1406 """output the current or given revision of files
1406 """output the current or given revision of files
1407
1407
1408 Print the specified files as they were at the given revision. If
1408 Print the specified files as they were at the given revision. If
1409 no revision is given, the parent of the working directory is used.
1409 no revision is given, the parent of the working directory is used.
1410
1410
1411 Output may be to a file, in which case the name of the file is
1411 Output may be to a file, in which case the name of the file is
1412 given using a format string. The formatting rules as follows:
1412 given using a format string. The formatting rules as follows:
1413
1413
1414 :``%%``: literal "%" character
1414 :``%%``: literal "%" character
1415 :``%s``: basename of file being printed
1415 :``%s``: basename of file being printed
1416 :``%d``: dirname of file being printed, or '.' if in repository root
1416 :``%d``: dirname of file being printed, or '.' if in repository root
1417 :``%p``: root-relative path name of file being printed
1417 :``%p``: root-relative path name of file being printed
1418 :``%H``: changeset hash (40 hexadecimal digits)
1418 :``%H``: changeset hash (40 hexadecimal digits)
1419 :``%R``: changeset revision number
1419 :``%R``: changeset revision number
1420 :``%h``: short-form changeset hash (12 hexadecimal digits)
1420 :``%h``: short-form changeset hash (12 hexadecimal digits)
1421 :``%r``: zero-padded changeset revision number
1421 :``%r``: zero-padded changeset revision number
1422 :``%b``: basename of the exporting repository
1422 :``%b``: basename of the exporting repository
1423
1423
1424 Returns 0 on success.
1424 Returns 0 on success.
1425 """
1425 """
1426 ctx = scmutil.revsingle(repo, opts.get('rev'))
1426 ctx = scmutil.revsingle(repo, opts.get('rev'))
1427 m = scmutil.match(ctx, (file1,) + pats, opts)
1427 m = scmutil.match(ctx, (file1,) + pats, opts)
1428
1428
1429 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1429 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1430
1430
1431 @command('^clone',
1431 @command('^clone',
1432 [('U', 'noupdate', None, _('the clone will include an empty working '
1432 [('U', 'noupdate', None, _('the clone will include an empty working '
1433 'directory (only a repository)')),
1433 'directory (only a repository)')),
1434 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1434 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1435 _('REV')),
1435 _('REV')),
1436 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1436 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1437 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1437 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1438 ('', 'pull', None, _('use pull protocol to copy metadata')),
1438 ('', 'pull', None, _('use pull protocol to copy metadata')),
1439 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1439 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1440 ] + remoteopts,
1440 ] + remoteopts,
1441 _('[OPTION]... SOURCE [DEST]'),
1441 _('[OPTION]... SOURCE [DEST]'),
1442 norepo=True)
1442 norepo=True)
1443 def clone(ui, source, dest=None, **opts):
1443 def clone(ui, source, dest=None, **opts):
1444 """make a copy of an existing repository
1444 """make a copy of an existing repository
1445
1445
1446 Create a copy of an existing repository in a new directory.
1446 Create a copy of an existing repository in a new directory.
1447
1447
1448 If no destination directory name is specified, it defaults to the
1448 If no destination directory name is specified, it defaults to the
1449 basename of the source.
1449 basename of the source.
1450
1450
1451 The location of the source is added to the new repository's
1451 The location of the source is added to the new repository's
1452 ``.hg/hgrc`` file, as the default to be used for future pulls.
1452 ``.hg/hgrc`` file, as the default to be used for future pulls.
1453
1453
1454 Only local paths and ``ssh://`` URLs are supported as
1454 Only local paths and ``ssh://`` URLs are supported as
1455 destinations. For ``ssh://`` destinations, no working directory or
1455 destinations. For ``ssh://`` destinations, no working directory or
1456 ``.hg/hgrc`` will be created on the remote side.
1456 ``.hg/hgrc`` will be created on the remote side.
1457
1457
1458 If the source repository has a bookmark called '@' set, that
1458 If the source repository has a bookmark called '@' set, that
1459 revision will be checked out in the new repository by default.
1459 revision will be checked out in the new repository by default.
1460
1460
1461 To check out a particular version, use -u/--update, or
1461 To check out a particular version, use -u/--update, or
1462 -U/--noupdate to create a clone with no working directory.
1462 -U/--noupdate to create a clone with no working directory.
1463
1463
1464 To pull only a subset of changesets, specify one or more revisions
1464 To pull only a subset of changesets, specify one or more revisions
1465 identifiers with -r/--rev or branches with -b/--branch. The
1465 identifiers with -r/--rev or branches with -b/--branch. The
1466 resulting clone will contain only the specified changesets and
1466 resulting clone will contain only the specified changesets and
1467 their ancestors. These options (or 'clone src#rev dest') imply
1467 their ancestors. These options (or 'clone src#rev dest') imply
1468 --pull, even for local source repositories.
1468 --pull, even for local source repositories.
1469
1469
1470 .. note::
1470 .. note::
1471
1471
1472 Specifying a tag will include the tagged changeset but not the
1472 Specifying a tag will include the tagged changeset but not the
1473 changeset containing the tag.
1473 changeset containing the tag.
1474
1474
1475 .. container:: verbose
1475 .. container:: verbose
1476
1476
1477 For efficiency, hardlinks are used for cloning whenever the
1477 For efficiency, hardlinks are used for cloning whenever the
1478 source and destination are on the same filesystem (note this
1478 source and destination are on the same filesystem (note this
1479 applies only to the repository data, not to the working
1479 applies only to the repository data, not to the working
1480 directory). Some filesystems, such as AFS, implement hardlinking
1480 directory). Some filesystems, such as AFS, implement hardlinking
1481 incorrectly, but do not report errors. In these cases, use the
1481 incorrectly, but do not report errors. In these cases, use the
1482 --pull option to avoid hardlinking.
1482 --pull option to avoid hardlinking.
1483
1483
1484 In some cases, you can clone repositories and the working
1484 In some cases, you can clone repositories and the working
1485 directory using full hardlinks with ::
1485 directory using full hardlinks with ::
1486
1486
1487 $ cp -al REPO REPOCLONE
1487 $ cp -al REPO REPOCLONE
1488
1488
1489 This is the fastest way to clone, but it is not always safe. The
1489 This is the fastest way to clone, but it is not always safe. The
1490 operation is not atomic (making sure REPO is not modified during
1490 operation is not atomic (making sure REPO is not modified during
1491 the operation is up to you) and you have to make sure your
1491 the operation is up to you) and you have to make sure your
1492 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1492 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1493 so). Also, this is not compatible with certain extensions that
1493 so). Also, this is not compatible with certain extensions that
1494 place their metadata under the .hg directory, such as mq.
1494 place their metadata under the .hg directory, such as mq.
1495
1495
1496 Mercurial will update the working directory to the first applicable
1496 Mercurial will update the working directory to the first applicable
1497 revision from this list:
1497 revision from this list:
1498
1498
1499 a) null if -U or the source repository has no changesets
1499 a) null if -U or the source repository has no changesets
1500 b) if -u . and the source repository is local, the first parent of
1500 b) if -u . and the source repository is local, the first parent of
1501 the source repository's working directory
1501 the source repository's working directory
1502 c) the changeset specified with -u (if a branch name, this means the
1502 c) the changeset specified with -u (if a branch name, this means the
1503 latest head of that branch)
1503 latest head of that branch)
1504 d) the changeset specified with -r
1504 d) the changeset specified with -r
1505 e) the tipmost head specified with -b
1505 e) the tipmost head specified with -b
1506 f) the tipmost head specified with the url#branch source syntax
1506 f) the tipmost head specified with the url#branch source syntax
1507 g) the revision marked with the '@' bookmark, if present
1507 g) the revision marked with the '@' bookmark, if present
1508 h) the tipmost head of the default branch
1508 h) the tipmost head of the default branch
1509 i) tip
1509 i) tip
1510
1510
1511 When cloning from servers that support it, Mercurial may fetch
1511 When cloning from servers that support it, Mercurial may fetch
1512 pre-generated data from a server-advertised URL. When this is done,
1512 pre-generated data from a server-advertised URL. When this is done,
1513 hooks operating on incoming changesets and changegroups may fire twice,
1513 hooks operating on incoming changesets and changegroups may fire twice,
1514 once for the bundle fetched from the URL and another for any additional
1514 once for the bundle fetched from the URL and another for any additional
1515 data not fetched from this URL. In addition, if an error occurs, the
1515 data not fetched from this URL. In addition, if an error occurs, the
1516 repository may be rolled back to a partial clone. This behavior may
1516 repository may be rolled back to a partial clone. This behavior may
1517 change in future releases. See :hg:`help -e clonebundles` for more.
1517 change in future releases. See :hg:`help -e clonebundles` for more.
1518
1518
1519 Examples:
1519 Examples:
1520
1520
1521 - clone a remote repository to a new directory named hg/::
1521 - clone a remote repository to a new directory named hg/::
1522
1522
1523 hg clone https://www.mercurial-scm.org/repo/hg/
1523 hg clone https://www.mercurial-scm.org/repo/hg/
1524
1524
1525 - create a lightweight local clone::
1525 - create a lightweight local clone::
1526
1526
1527 hg clone project/ project-feature/
1527 hg clone project/ project-feature/
1528
1528
1529 - clone from an absolute path on an ssh server (note double-slash)::
1529 - clone from an absolute path on an ssh server (note double-slash)::
1530
1530
1531 hg clone ssh://user@server//home/projects/alpha/
1531 hg clone ssh://user@server//home/projects/alpha/
1532
1532
1533 - do a high-speed clone over a LAN while checking out a
1533 - do a high-speed clone over a LAN while checking out a
1534 specified version::
1534 specified version::
1535
1535
1536 hg clone --uncompressed http://server/repo -u 1.5
1536 hg clone --uncompressed http://server/repo -u 1.5
1537
1537
1538 - create a repository without changesets after a particular revision::
1538 - create a repository without changesets after a particular revision::
1539
1539
1540 hg clone -r 04e544 experimental/ good/
1540 hg clone -r 04e544 experimental/ good/
1541
1541
1542 - clone (and track) a particular named branch::
1542 - clone (and track) a particular named branch::
1543
1543
1544 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1544 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1545
1545
1546 See :hg:`help urls` for details on specifying URLs.
1546 See :hg:`help urls` for details on specifying URLs.
1547
1547
1548 Returns 0 on success.
1548 Returns 0 on success.
1549 """
1549 """
1550 if opts.get('noupdate') and opts.get('updaterev'):
1550 if opts.get('noupdate') and opts.get('updaterev'):
1551 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1551 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1552
1552
1553 r = hg.clone(ui, opts, source, dest,
1553 r = hg.clone(ui, opts, source, dest,
1554 pull=opts.get('pull'),
1554 pull=opts.get('pull'),
1555 stream=opts.get('uncompressed'),
1555 stream=opts.get('uncompressed'),
1556 rev=opts.get('rev'),
1556 rev=opts.get('rev'),
1557 update=opts.get('updaterev') or not opts.get('noupdate'),
1557 update=opts.get('updaterev') or not opts.get('noupdate'),
1558 branch=opts.get('branch'),
1558 branch=opts.get('branch'),
1559 shareopts=opts.get('shareopts'))
1559 shareopts=opts.get('shareopts'))
1560
1560
1561 return r is None
1561 return r is None
1562
1562
1563 @command('^commit|ci',
1563 @command('^commit|ci',
1564 [('A', 'addremove', None,
1564 [('A', 'addremove', None,
1565 _('mark new/missing files as added/removed before committing')),
1565 _('mark new/missing files as added/removed before committing')),
1566 ('', 'close-branch', None,
1566 ('', 'close-branch', None,
1567 _('mark a branch head as closed')),
1567 _('mark a branch head as closed')),
1568 ('', 'amend', None, _('amend the parent of the working directory')),
1568 ('', 'amend', None, _('amend the parent of the working directory')),
1569 ('s', 'secret', None, _('use the secret phase for committing')),
1569 ('s', 'secret', None, _('use the secret phase for committing')),
1570 ('e', 'edit', None, _('invoke editor on commit messages')),
1570 ('e', 'edit', None, _('invoke editor on commit messages')),
1571 ('i', 'interactive', None, _('use interactive mode')),
1571 ('i', 'interactive', None, _('use interactive mode')),
1572 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1572 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1573 _('[OPTION]... [FILE]...'),
1573 _('[OPTION]... [FILE]...'),
1574 inferrepo=True)
1574 inferrepo=True)
1575 def commit(ui, repo, *pats, **opts):
1575 def commit(ui, repo, *pats, **opts):
1576 """commit the specified files or all outstanding changes
1576 """commit the specified files or all outstanding changes
1577
1577
1578 Commit changes to the given files into the repository. Unlike a
1578 Commit changes to the given files into the repository. Unlike a
1579 centralized SCM, this operation is a local operation. See
1579 centralized SCM, this operation is a local operation. See
1580 :hg:`push` for a way to actively distribute your changes.
1580 :hg:`push` for a way to actively distribute your changes.
1581
1581
1582 If a list of files is omitted, all changes reported by :hg:`status`
1582 If a list of files is omitted, all changes reported by :hg:`status`
1583 will be committed.
1583 will be committed.
1584
1584
1585 If you are committing the result of a merge, do not provide any
1585 If you are committing the result of a merge, do not provide any
1586 filenames or -I/-X filters.
1586 filenames or -I/-X filters.
1587
1587
1588 If no commit message is specified, Mercurial starts your
1588 If no commit message is specified, Mercurial starts your
1589 configured editor where you can enter a message. In case your
1589 configured editor where you can enter a message. In case your
1590 commit fails, you will find a backup of your message in
1590 commit fails, you will find a backup of your message in
1591 ``.hg/last-message.txt``.
1591 ``.hg/last-message.txt``.
1592
1592
1593 The --close-branch flag can be used to mark the current branch
1593 The --close-branch flag can be used to mark the current branch
1594 head closed. When all heads of a branch are closed, the branch
1594 head closed. When all heads of a branch are closed, the branch
1595 will be considered closed and no longer listed.
1595 will be considered closed and no longer listed.
1596
1596
1597 The --amend flag can be used to amend the parent of the
1597 The --amend flag can be used to amend the parent of the
1598 working directory with a new commit that contains the changes
1598 working directory with a new commit that contains the changes
1599 in the parent in addition to those currently reported by :hg:`status`,
1599 in the parent in addition to those currently reported by :hg:`status`,
1600 if there are any. The old commit is stored in a backup bundle in
1600 if there are any. The old commit is stored in a backup bundle in
1601 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1601 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1602 on how to restore it).
1602 on how to restore it).
1603
1603
1604 Message, user and date are taken from the amended commit unless
1604 Message, user and date are taken from the amended commit unless
1605 specified. When a message isn't specified on the command line,
1605 specified. When a message isn't specified on the command line,
1606 the editor will open with the message of the amended commit.
1606 the editor will open with the message of the amended commit.
1607
1607
1608 It is not possible to amend public changesets (see :hg:`help phases`)
1608 It is not possible to amend public changesets (see :hg:`help phases`)
1609 or changesets that have children.
1609 or changesets that have children.
1610
1610
1611 See :hg:`help dates` for a list of formats valid for -d/--date.
1611 See :hg:`help dates` for a list of formats valid for -d/--date.
1612
1612
1613 Returns 0 on success, 1 if nothing changed.
1613 Returns 0 on success, 1 if nothing changed.
1614
1614
1615 .. container:: verbose
1615 .. container:: verbose
1616
1616
1617 Examples:
1617 Examples:
1618
1618
1619 - commit all files ending in .py::
1619 - commit all files ending in .py::
1620
1620
1621 hg commit --include "set:**.py"
1621 hg commit --include "set:**.py"
1622
1622
1623 - commit all non-binary files::
1623 - commit all non-binary files::
1624
1624
1625 hg commit --exclude "set:binary()"
1625 hg commit --exclude "set:binary()"
1626
1626
1627 - amend the current commit and set the date to now::
1627 - amend the current commit and set the date to now::
1628
1628
1629 hg commit --amend --date now
1629 hg commit --amend --date now
1630 """
1630 """
1631 wlock = lock = None
1631 wlock = lock = None
1632 try:
1632 try:
1633 wlock = repo.wlock()
1633 wlock = repo.wlock()
1634 lock = repo.lock()
1634 lock = repo.lock()
1635 return _docommit(ui, repo, *pats, **opts)
1635 return _docommit(ui, repo, *pats, **opts)
1636 finally:
1636 finally:
1637 release(lock, wlock)
1637 release(lock, wlock)
1638
1638
1639 def _docommit(ui, repo, *pats, **opts):
1639 def _docommit(ui, repo, *pats, **opts):
1640 if opts.get('interactive'):
1640 if opts.get('interactive'):
1641 opts.pop('interactive')
1641 opts.pop('interactive')
1642 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1642 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1643 cmdutil.recordfilter, *pats, **opts)
1643 cmdutil.recordfilter, *pats, **opts)
1644 # ret can be 0 (no changes to record) or the value returned by
1644 # ret can be 0 (no changes to record) or the value returned by
1645 # commit(), 1 if nothing changed or None on success.
1645 # commit(), 1 if nothing changed or None on success.
1646 return 1 if ret == 0 else ret
1646 return 1 if ret == 0 else ret
1647
1647
1648 if opts.get('subrepos'):
1648 if opts.get('subrepos'):
1649 if opts.get('amend'):
1649 if opts.get('amend'):
1650 raise error.Abort(_('cannot amend with --subrepos'))
1650 raise error.Abort(_('cannot amend with --subrepos'))
1651 # Let --subrepos on the command line override config setting.
1651 # Let --subrepos on the command line override config setting.
1652 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1652 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1653
1653
1654 cmdutil.checkunfinished(repo, commit=True)
1654 cmdutil.checkunfinished(repo, commit=True)
1655
1655
1656 branch = repo[None].branch()
1656 branch = repo[None].branch()
1657 bheads = repo.branchheads(branch)
1657 bheads = repo.branchheads(branch)
1658
1658
1659 extra = {}
1659 extra = {}
1660 if opts.get('close_branch'):
1660 if opts.get('close_branch'):
1661 extra['close'] = 1
1661 extra['close'] = 1
1662
1662
1663 if not bheads:
1663 if not bheads:
1664 raise error.Abort(_('can only close branch heads'))
1664 raise error.Abort(_('can only close branch heads'))
1665 elif opts.get('amend'):
1665 elif opts.get('amend'):
1666 if repo[None].parents()[0].p1().branch() != branch and \
1666 if repo[None].parents()[0].p1().branch() != branch and \
1667 repo[None].parents()[0].p2().branch() != branch:
1667 repo[None].parents()[0].p2().branch() != branch:
1668 raise error.Abort(_('can only close branch heads'))
1668 raise error.Abort(_('can only close branch heads'))
1669
1669
1670 if opts.get('amend'):
1670 if opts.get('amend'):
1671 if ui.configbool('ui', 'commitsubrepos'):
1671 if ui.configbool('ui', 'commitsubrepos'):
1672 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1672 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1673
1673
1674 old = repo['.']
1674 old = repo['.']
1675 if not old.mutable():
1675 if not old.mutable():
1676 raise error.Abort(_('cannot amend public changesets'))
1676 raise error.Abort(_('cannot amend public changesets'))
1677 if len(repo[None].parents()) > 1:
1677 if len(repo[None].parents()) > 1:
1678 raise error.Abort(_('cannot amend while merging'))
1678 raise error.Abort(_('cannot amend while merging'))
1679 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1679 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1680 if not allowunstable and old.children():
1680 if not allowunstable and old.children():
1681 raise error.Abort(_('cannot amend changeset with children'))
1681 raise error.Abort(_('cannot amend changeset with children'))
1682
1682
1683 # Currently histedit gets confused if an amend happens while histedit
1683 # Currently histedit gets confused if an amend happens while histedit
1684 # is in progress. Since we have a checkunfinished command, we are
1684 # is in progress. Since we have a checkunfinished command, we are
1685 # temporarily honoring it.
1685 # temporarily honoring it.
1686 #
1686 #
1687 # Note: eventually this guard will be removed. Please do not expect
1687 # Note: eventually this guard will be removed. Please do not expect
1688 # this behavior to remain.
1688 # this behavior to remain.
1689 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1689 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1690 cmdutil.checkunfinished(repo)
1690 cmdutil.checkunfinished(repo)
1691
1691
1692 # commitfunc is used only for temporary amend commit by cmdutil.amend
1692 # commitfunc is used only for temporary amend commit by cmdutil.amend
1693 def commitfunc(ui, repo, message, match, opts):
1693 def commitfunc(ui, repo, message, match, opts):
1694 return repo.commit(message,
1694 return repo.commit(message,
1695 opts.get('user') or old.user(),
1695 opts.get('user') or old.user(),
1696 opts.get('date') or old.date(),
1696 opts.get('date') or old.date(),
1697 match,
1697 match,
1698 extra=extra)
1698 extra=extra)
1699
1699
1700 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1700 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1701 if node == old.node():
1701 if node == old.node():
1702 ui.status(_("nothing changed\n"))
1702 ui.status(_("nothing changed\n"))
1703 return 1
1703 return 1
1704 else:
1704 else:
1705 def commitfunc(ui, repo, message, match, opts):
1705 def commitfunc(ui, repo, message, match, opts):
1706 backup = ui.backupconfig('phases', 'new-commit')
1706 backup = ui.backupconfig('phases', 'new-commit')
1707 baseui = repo.baseui
1707 baseui = repo.baseui
1708 basebackup = baseui.backupconfig('phases', 'new-commit')
1708 basebackup = baseui.backupconfig('phases', 'new-commit')
1709 try:
1709 try:
1710 if opts.get('secret'):
1710 if opts.get('secret'):
1711 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1711 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1712 # Propagate to subrepos
1712 # Propagate to subrepos
1713 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1713 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1714
1714
1715 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1715 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1716 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1716 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1717 return repo.commit(message, opts.get('user'), opts.get('date'),
1717 return repo.commit(message, opts.get('user'), opts.get('date'),
1718 match,
1718 match,
1719 editor=editor,
1719 editor=editor,
1720 extra=extra)
1720 extra=extra)
1721 finally:
1721 finally:
1722 ui.restoreconfig(backup)
1722 ui.restoreconfig(backup)
1723 repo.baseui.restoreconfig(basebackup)
1723 repo.baseui.restoreconfig(basebackup)
1724
1724
1725
1725
1726 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1726 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1727
1727
1728 if not node:
1728 if not node:
1729 stat = cmdutil.postcommitstatus(repo, pats, opts)
1729 stat = cmdutil.postcommitstatus(repo, pats, opts)
1730 if stat[3]:
1730 if stat[3]:
1731 ui.status(_("nothing changed (%d missing files, see "
1731 ui.status(_("nothing changed (%d missing files, see "
1732 "'hg status')\n") % len(stat[3]))
1732 "'hg status')\n") % len(stat[3]))
1733 else:
1733 else:
1734 ui.status(_("nothing changed\n"))
1734 ui.status(_("nothing changed\n"))
1735 return 1
1735 return 1
1736
1736
1737 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1737 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1738
1738
1739 @command('config|showconfig|debugconfig',
1739 @command('config|showconfig|debugconfig',
1740 [('u', 'untrusted', None, _('show untrusted configuration options')),
1740 [('u', 'untrusted', None, _('show untrusted configuration options')),
1741 ('e', 'edit', None, _('edit user config')),
1741 ('e', 'edit', None, _('edit user config')),
1742 ('l', 'local', None, _('edit repository config')),
1742 ('l', 'local', None, _('edit repository config')),
1743 ('g', 'global', None, _('edit global config'))] + formatteropts,
1743 ('g', 'global', None, _('edit global config'))] + formatteropts,
1744 _('[-u] [NAME]...'),
1744 _('[-u] [NAME]...'),
1745 optionalrepo=True)
1745 optionalrepo=True)
1746 def config(ui, repo, *values, **opts):
1746 def config(ui, repo, *values, **opts):
1747 """show combined config settings from all hgrc files
1747 """show combined config settings from all hgrc files
1748
1748
1749 With no arguments, print names and values of all config items.
1749 With no arguments, print names and values of all config items.
1750
1750
1751 With one argument of the form section.name, print just the value
1751 With one argument of the form section.name, print just the value
1752 of that config item.
1752 of that config item.
1753
1753
1754 With multiple arguments, print names and values of all config
1754 With multiple arguments, print names and values of all config
1755 items with matching section names.
1755 items with matching section names.
1756
1756
1757 With --edit, start an editor on the user-level config file. With
1757 With --edit, start an editor on the user-level config file. With
1758 --global, edit the system-wide config file. With --local, edit the
1758 --global, edit the system-wide config file. With --local, edit the
1759 repository-level config file.
1759 repository-level config file.
1760
1760
1761 With --debug, the source (filename and line number) is printed
1761 With --debug, the source (filename and line number) is printed
1762 for each config item.
1762 for each config item.
1763
1763
1764 See :hg:`help config` for more information about config files.
1764 See :hg:`help config` for more information about config files.
1765
1765
1766 Returns 0 on success, 1 if NAME does not exist.
1766 Returns 0 on success, 1 if NAME does not exist.
1767
1767
1768 """
1768 """
1769
1769
1770 if opts.get('edit') or opts.get('local') or opts.get('global'):
1770 if opts.get('edit') or opts.get('local') or opts.get('global'):
1771 if opts.get('local') and opts.get('global'):
1771 if opts.get('local') and opts.get('global'):
1772 raise error.Abort(_("can't use --local and --global together"))
1772 raise error.Abort(_("can't use --local and --global together"))
1773
1773
1774 if opts.get('local'):
1774 if opts.get('local'):
1775 if not repo:
1775 if not repo:
1776 raise error.Abort(_("can't use --local outside a repository"))
1776 raise error.Abort(_("can't use --local outside a repository"))
1777 paths = [repo.join('hgrc')]
1777 paths = [repo.join('hgrc')]
1778 elif opts.get('global'):
1778 elif opts.get('global'):
1779 paths = scmutil.systemrcpath()
1779 paths = scmutil.systemrcpath()
1780 else:
1780 else:
1781 paths = scmutil.userrcpath()
1781 paths = scmutil.userrcpath()
1782
1782
1783 for f in paths:
1783 for f in paths:
1784 if os.path.exists(f):
1784 if os.path.exists(f):
1785 break
1785 break
1786 else:
1786 else:
1787 if opts.get('global'):
1787 if opts.get('global'):
1788 samplehgrc = uimod.samplehgrcs['global']
1788 samplehgrc = uimod.samplehgrcs['global']
1789 elif opts.get('local'):
1789 elif opts.get('local'):
1790 samplehgrc = uimod.samplehgrcs['local']
1790 samplehgrc = uimod.samplehgrcs['local']
1791 else:
1791 else:
1792 samplehgrc = uimod.samplehgrcs['user']
1792 samplehgrc = uimod.samplehgrcs['user']
1793
1793
1794 f = paths[0]
1794 f = paths[0]
1795 fp = open(f, "w")
1795 fp = open(f, "w")
1796 fp.write(samplehgrc)
1796 fp.write(samplehgrc)
1797 fp.close()
1797 fp.close()
1798
1798
1799 editor = ui.geteditor()
1799 editor = ui.geteditor()
1800 ui.system("%s \"%s\"" % (editor, f),
1800 ui.system("%s \"%s\"" % (editor, f),
1801 onerr=error.Abort, errprefix=_("edit failed"))
1801 onerr=error.Abort, errprefix=_("edit failed"))
1802 return
1802 return
1803
1803
1804 fm = ui.formatter('config', opts)
1804 fm = ui.formatter('config', opts)
1805 for f in scmutil.rcpath():
1805 for f in scmutil.rcpath():
1806 ui.debug('read config from: %s\n' % f)
1806 ui.debug('read config from: %s\n' % f)
1807 untrusted = bool(opts.get('untrusted'))
1807 untrusted = bool(opts.get('untrusted'))
1808 if values:
1808 if values:
1809 sections = [v for v in values if '.' not in v]
1809 sections = [v for v in values if '.' not in v]
1810 items = [v for v in values if '.' in v]
1810 items = [v for v in values if '.' in v]
1811 if len(items) > 1 or items and sections:
1811 if len(items) > 1 or items and sections:
1812 raise error.Abort(_('only one config item permitted'))
1812 raise error.Abort(_('only one config item permitted'))
1813 matched = False
1813 matched = False
1814 for section, name, value in ui.walkconfig(untrusted=untrusted):
1814 for section, name, value in ui.walkconfig(untrusted=untrusted):
1815 value = str(value)
1815 value = str(value)
1816 if fm.isplain():
1816 if fm.isplain():
1817 value = value.replace('\n', '\\n')
1817 value = value.replace('\n', '\\n')
1818 entryname = section + '.' + name
1818 entryname = section + '.' + name
1819 if values:
1819 if values:
1820 for v in values:
1820 for v in values:
1821 if v == section:
1821 if v == section:
1822 fm.startitem()
1822 fm.startitem()
1823 fm.condwrite(ui.debugflag, 'source', '%s: ',
1823 fm.condwrite(ui.debugflag, 'source', '%s: ',
1824 ui.configsource(section, name, untrusted))
1824 ui.configsource(section, name, untrusted))
1825 fm.write('name value', '%s=%s\n', entryname, value)
1825 fm.write('name value', '%s=%s\n', entryname, value)
1826 matched = True
1826 matched = True
1827 elif v == entryname:
1827 elif v == entryname:
1828 fm.startitem()
1828 fm.startitem()
1829 fm.condwrite(ui.debugflag, 'source', '%s: ',
1829 fm.condwrite(ui.debugflag, 'source', '%s: ',
1830 ui.configsource(section, name, untrusted))
1830 ui.configsource(section, name, untrusted))
1831 fm.write('value', '%s\n', value)
1831 fm.write('value', '%s\n', value)
1832 fm.data(name=entryname)
1832 fm.data(name=entryname)
1833 matched = True
1833 matched = True
1834 else:
1834 else:
1835 fm.startitem()
1835 fm.startitem()
1836 fm.condwrite(ui.debugflag, 'source', '%s: ',
1836 fm.condwrite(ui.debugflag, 'source', '%s: ',
1837 ui.configsource(section, name, untrusted))
1837 ui.configsource(section, name, untrusted))
1838 fm.write('name value', '%s=%s\n', entryname, value)
1838 fm.write('name value', '%s=%s\n', entryname, value)
1839 matched = True
1839 matched = True
1840 fm.end()
1840 fm.end()
1841 if matched:
1841 if matched:
1842 return 0
1842 return 0
1843 return 1
1843 return 1
1844
1844
1845 @command('copy|cp',
1845 @command('copy|cp',
1846 [('A', 'after', None, _('record a copy that has already occurred')),
1846 [('A', 'after', None, _('record a copy that has already occurred')),
1847 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1847 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1848 ] + walkopts + dryrunopts,
1848 ] + walkopts + dryrunopts,
1849 _('[OPTION]... [SOURCE]... DEST'))
1849 _('[OPTION]... [SOURCE]... DEST'))
1850 def copy(ui, repo, *pats, **opts):
1850 def copy(ui, repo, *pats, **opts):
1851 """mark files as copied for the next commit
1851 """mark files as copied for the next commit
1852
1852
1853 Mark dest as having copies of source files. If dest is a
1853 Mark dest as having copies of source files. If dest is a
1854 directory, copies are put in that directory. If dest is a file,
1854 directory, copies are put in that directory. If dest is a file,
1855 the source must be a single file.
1855 the source must be a single file.
1856
1856
1857 By default, this command copies the contents of files as they
1857 By default, this command copies the contents of files as they
1858 exist in the working directory. If invoked with -A/--after, the
1858 exist in the working directory. If invoked with -A/--after, the
1859 operation is recorded, but no copying is performed.
1859 operation is recorded, but no copying is performed.
1860
1860
1861 This command takes effect with the next commit. To undo a copy
1861 This command takes effect with the next commit. To undo a copy
1862 before that, see :hg:`revert`.
1862 before that, see :hg:`revert`.
1863
1863
1864 Returns 0 on success, 1 if errors are encountered.
1864 Returns 0 on success, 1 if errors are encountered.
1865 """
1865 """
1866 with repo.wlock(False):
1866 with repo.wlock(False):
1867 return cmdutil.copy(ui, repo, pats, opts)
1867 return cmdutil.copy(ui, repo, pats, opts)
1868
1868
1869 @command('debugdag',
1869 @command('debugdag',
1870 [('t', 'tags', None, _('use tags as labels')),
1870 [('t', 'tags', None, _('use tags as labels')),
1871 ('b', 'branches', None, _('annotate with branch names')),
1871 ('b', 'branches', None, _('annotate with branch names')),
1872 ('', 'dots', None, _('use dots for runs')),
1872 ('', 'dots', None, _('use dots for runs')),
1873 ('s', 'spaces', None, _('separate elements by spaces'))],
1873 ('s', 'spaces', None, _('separate elements by spaces'))],
1874 _('[OPTION]... [FILE [REV]...]'),
1874 _('[OPTION]... [FILE [REV]...]'),
1875 optionalrepo=True)
1875 optionalrepo=True)
1876 def debugdag(ui, repo, file_=None, *revs, **opts):
1876 def debugdag(ui, repo, file_=None, *revs, **opts):
1877 """format the changelog or an index DAG as a concise textual description
1877 """format the changelog or an index DAG as a concise textual description
1878
1878
1879 If you pass a revlog index, the revlog's DAG is emitted. If you list
1879 If you pass a revlog index, the revlog's DAG is emitted. If you list
1880 revision numbers, they get labeled in the output as rN.
1880 revision numbers, they get labeled in the output as rN.
1881
1881
1882 Otherwise, the changelog DAG of the current repo is emitted.
1882 Otherwise, the changelog DAG of the current repo is emitted.
1883 """
1883 """
1884 spaces = opts.get('spaces')
1884 spaces = opts.get('spaces')
1885 dots = opts.get('dots')
1885 dots = opts.get('dots')
1886 if file_:
1886 if file_:
1887 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1887 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1888 revs = set((int(r) for r in revs))
1888 revs = set((int(r) for r in revs))
1889 def events():
1889 def events():
1890 for r in rlog:
1890 for r in rlog:
1891 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1891 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1892 if p != -1))
1892 if p != -1))
1893 if r in revs:
1893 if r in revs:
1894 yield 'l', (r, "r%i" % r)
1894 yield 'l', (r, "r%i" % r)
1895 elif repo:
1895 elif repo:
1896 cl = repo.changelog
1896 cl = repo.changelog
1897 tags = opts.get('tags')
1897 tags = opts.get('tags')
1898 branches = opts.get('branches')
1898 branches = opts.get('branches')
1899 if tags:
1899 if tags:
1900 labels = {}
1900 labels = {}
1901 for l, n in repo.tags().items():
1901 for l, n in repo.tags().items():
1902 labels.setdefault(cl.rev(n), []).append(l)
1902 labels.setdefault(cl.rev(n), []).append(l)
1903 def events():
1903 def events():
1904 b = "default"
1904 b = "default"
1905 for r in cl:
1905 for r in cl:
1906 if branches:
1906 if branches:
1907 newb = cl.read(cl.node(r))[5]['branch']
1907 newb = cl.read(cl.node(r))[5]['branch']
1908 if newb != b:
1908 if newb != b:
1909 yield 'a', newb
1909 yield 'a', newb
1910 b = newb
1910 b = newb
1911 yield 'n', (r, list(p for p in cl.parentrevs(r)
1911 yield 'n', (r, list(p for p in cl.parentrevs(r)
1912 if p != -1))
1912 if p != -1))
1913 if tags:
1913 if tags:
1914 ls = labels.get(r)
1914 ls = labels.get(r)
1915 if ls:
1915 if ls:
1916 for l in ls:
1916 for l in ls:
1917 yield 'l', (r, l)
1917 yield 'l', (r, l)
1918 else:
1918 else:
1919 raise error.Abort(_('need repo for changelog dag'))
1919 raise error.Abort(_('need repo for changelog dag'))
1920
1920
1921 for line in dagparser.dagtextlines(events(),
1921 for line in dagparser.dagtextlines(events(),
1922 addspaces=spaces,
1922 addspaces=spaces,
1923 wraplabels=True,
1923 wraplabels=True,
1924 wrapannotations=True,
1924 wrapannotations=True,
1925 wrapnonlinear=dots,
1925 wrapnonlinear=dots,
1926 usedots=dots,
1926 usedots=dots,
1927 maxlinewidth=70):
1927 maxlinewidth=70):
1928 ui.write(line)
1928 ui.write(line)
1929 ui.write("\n")
1929 ui.write("\n")
1930
1930
1931 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
1931 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
1932 def debugdata(ui, repo, file_, rev=None, **opts):
1932 def debugdata(ui, repo, file_, rev=None, **opts):
1933 """dump the contents of a data file revision"""
1933 """dump the contents of a data file revision"""
1934 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
1934 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
1935 if rev is not None:
1935 if rev is not None:
1936 raise error.CommandError('debugdata', _('invalid arguments'))
1936 raise error.CommandError('debugdata', _('invalid arguments'))
1937 file_, rev = None, file_
1937 file_, rev = None, file_
1938 elif rev is None:
1938 elif rev is None:
1939 raise error.CommandError('debugdata', _('invalid arguments'))
1939 raise error.CommandError('debugdata', _('invalid arguments'))
1940 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1940 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1941 try:
1941 try:
1942 ui.write(r.revision(r.lookup(rev)))
1942 ui.write(r.revision(r.lookup(rev)))
1943 except KeyError:
1943 except KeyError:
1944 raise error.Abort(_('invalid revision identifier %s') % rev)
1944 raise error.Abort(_('invalid revision identifier %s') % rev)
1945
1945
1946 @command('debugdate',
1946 @command('debugdate',
1947 [('e', 'extended', None, _('try extended date formats'))],
1947 [('e', 'extended', None, _('try extended date formats'))],
1948 _('[-e] DATE [RANGE]'),
1948 _('[-e] DATE [RANGE]'),
1949 norepo=True, optionalrepo=True)
1949 norepo=True, optionalrepo=True)
1950 def debugdate(ui, date, range=None, **opts):
1950 def debugdate(ui, date, range=None, **opts):
1951 """parse and display a date"""
1951 """parse and display a date"""
1952 if opts["extended"]:
1952 if opts["extended"]:
1953 d = util.parsedate(date, util.extendeddateformats)
1953 d = util.parsedate(date, util.extendeddateformats)
1954 else:
1954 else:
1955 d = util.parsedate(date)
1955 d = util.parsedate(date)
1956 ui.write(("internal: %s %s\n") % d)
1956 ui.write(("internal: %s %s\n") % d)
1957 ui.write(("standard: %s\n") % util.datestr(d))
1957 ui.write(("standard: %s\n") % util.datestr(d))
1958 if range:
1958 if range:
1959 m = util.matchdate(range)
1959 m = util.matchdate(range)
1960 ui.write(("match: %s\n") % m(d[0]))
1960 ui.write(("match: %s\n") % m(d[0]))
1961
1961
1962 @command('debugdiscovery',
1962 @command('debugdiscovery',
1963 [('', 'old', None, _('use old-style discovery')),
1963 [('', 'old', None, _('use old-style discovery')),
1964 ('', 'nonheads', None,
1964 ('', 'nonheads', None,
1965 _('use old-style discovery with non-heads included')),
1965 _('use old-style discovery with non-heads included')),
1966 ] + remoteopts,
1966 ] + remoteopts,
1967 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1967 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1968 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1968 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1969 """runs the changeset discovery protocol in isolation"""
1969 """runs the changeset discovery protocol in isolation"""
1970 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1970 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1971 opts.get('branch'))
1971 opts.get('branch'))
1972 remote = hg.peer(repo, opts, remoteurl)
1972 remote = hg.peer(repo, opts, remoteurl)
1973 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1973 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1974
1974
1975 # make sure tests are repeatable
1975 # make sure tests are repeatable
1976 random.seed(12323)
1976 random.seed(12323)
1977
1977
1978 def doit(localheads, remoteheads, remote=remote):
1978 def doit(localheads, remoteheads, remote=remote):
1979 if opts.get('old'):
1979 if opts.get('old'):
1980 if localheads:
1980 if localheads:
1981 raise error.Abort('cannot use localheads with old style '
1981 raise error.Abort('cannot use localheads with old style '
1982 'discovery')
1982 'discovery')
1983 if not util.safehasattr(remote, 'branches'):
1983 if not util.safehasattr(remote, 'branches'):
1984 # enable in-client legacy support
1984 # enable in-client legacy support
1985 remote = localrepo.locallegacypeer(remote.local())
1985 remote = localrepo.locallegacypeer(remote.local())
1986 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1986 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1987 force=True)
1987 force=True)
1988 common = set(common)
1988 common = set(common)
1989 if not opts.get('nonheads'):
1989 if not opts.get('nonheads'):
1990 ui.write(("unpruned common: %s\n") %
1990 ui.write(("unpruned common: %s\n") %
1991 " ".join(sorted(short(n) for n in common)))
1991 " ".join(sorted(short(n) for n in common)))
1992 dag = dagutil.revlogdag(repo.changelog)
1992 dag = dagutil.revlogdag(repo.changelog)
1993 all = dag.ancestorset(dag.internalizeall(common))
1993 all = dag.ancestorset(dag.internalizeall(common))
1994 common = dag.externalizeall(dag.headsetofconnecteds(all))
1994 common = dag.externalizeall(dag.headsetofconnecteds(all))
1995 else:
1995 else:
1996 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1996 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1997 common = set(common)
1997 common = set(common)
1998 rheads = set(hds)
1998 rheads = set(hds)
1999 lheads = set(repo.heads())
1999 lheads = set(repo.heads())
2000 ui.write(("common heads: %s\n") %
2000 ui.write(("common heads: %s\n") %
2001 " ".join(sorted(short(n) for n in common)))
2001 " ".join(sorted(short(n) for n in common)))
2002 if lheads <= common:
2002 if lheads <= common:
2003 ui.write(("local is subset\n"))
2003 ui.write(("local is subset\n"))
2004 elif rheads <= common:
2004 elif rheads <= common:
2005 ui.write(("remote is subset\n"))
2005 ui.write(("remote is subset\n"))
2006
2006
2007 serverlogs = opts.get('serverlog')
2007 serverlogs = opts.get('serverlog')
2008 if serverlogs:
2008 if serverlogs:
2009 for filename in serverlogs:
2009 for filename in serverlogs:
2010 with open(filename, 'r') as logfile:
2010 with open(filename, 'r') as logfile:
2011 line = logfile.readline()
2011 line = logfile.readline()
2012 while line:
2012 while line:
2013 parts = line.strip().split(';')
2013 parts = line.strip().split(';')
2014 op = parts[1]
2014 op = parts[1]
2015 if op == 'cg':
2015 if op == 'cg':
2016 pass
2016 pass
2017 elif op == 'cgss':
2017 elif op == 'cgss':
2018 doit(parts[2].split(' '), parts[3].split(' '))
2018 doit(parts[2].split(' '), parts[3].split(' '))
2019 elif op == 'unb':
2019 elif op == 'unb':
2020 doit(parts[3].split(' '), parts[2].split(' '))
2020 doit(parts[3].split(' '), parts[2].split(' '))
2021 line = logfile.readline()
2021 line = logfile.readline()
2022 else:
2022 else:
2023 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2023 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2024 opts.get('remote_head'))
2024 opts.get('remote_head'))
2025 localrevs = opts.get('local_head')
2025 localrevs = opts.get('local_head')
2026 doit(localrevs, remoterevs)
2026 doit(localrevs, remoterevs)
2027
2027
2028 @command('debugextensions', formatteropts, [], norepo=True)
2028 @command('debugextensions', formatteropts, [], norepo=True)
2029 def debugextensions(ui, **opts):
2029 def debugextensions(ui, **opts):
2030 '''show information about active extensions'''
2030 '''show information about active extensions'''
2031 exts = extensions.extensions(ui)
2031 exts = extensions.extensions(ui)
2032 hgver = util.version()
2032 hgver = util.version()
2033 fm = ui.formatter('debugextensions', opts)
2033 fm = ui.formatter('debugextensions', opts)
2034 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2034 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2035 isinternal = extensions.ismoduleinternal(extmod)
2035 isinternal = extensions.ismoduleinternal(extmod)
2036 extsource = extmod.__file__
2036 extsource = extmod.__file__
2037 if isinternal:
2037 if isinternal:
2038 exttestedwith = [] # never expose magic string to users
2038 exttestedwith = [] # never expose magic string to users
2039 else:
2039 else:
2040 exttestedwith = getattr(extmod, 'testedwith', '').split()
2040 exttestedwith = getattr(extmod, 'testedwith', '').split()
2041 extbuglink = getattr(extmod, 'buglink', None)
2041 extbuglink = getattr(extmod, 'buglink', None)
2042
2042
2043 fm.startitem()
2043 fm.startitem()
2044
2044
2045 if ui.quiet or ui.verbose:
2045 if ui.quiet or ui.verbose:
2046 fm.write('name', '%s\n', extname)
2046 fm.write('name', '%s\n', extname)
2047 else:
2047 else:
2048 fm.write('name', '%s', extname)
2048 fm.write('name', '%s', extname)
2049 if isinternal or hgver in exttestedwith:
2049 if isinternal or hgver in exttestedwith:
2050 fm.plain('\n')
2050 fm.plain('\n')
2051 elif not exttestedwith:
2051 elif not exttestedwith:
2052 fm.plain(_(' (untested!)\n'))
2052 fm.plain(_(' (untested!)\n'))
2053 else:
2053 else:
2054 lasttestedversion = exttestedwith[-1]
2054 lasttestedversion = exttestedwith[-1]
2055 fm.plain(' (%s!)\n' % lasttestedversion)
2055 fm.plain(' (%s!)\n' % lasttestedversion)
2056
2056
2057 fm.condwrite(ui.verbose and extsource, 'source',
2057 fm.condwrite(ui.verbose and extsource, 'source',
2058 _(' location: %s\n'), extsource or "")
2058 _(' location: %s\n'), extsource or "")
2059
2059
2060 if ui.verbose:
2060 if ui.verbose:
2061 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2061 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2062 fm.data(bundled=isinternal)
2062 fm.data(bundled=isinternal)
2063
2063
2064 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2064 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2065 _(' tested with: %s\n'),
2065 _(' tested with: %s\n'),
2066 fm.formatlist(exttestedwith, name='ver'))
2066 fm.formatlist(exttestedwith, name='ver'))
2067
2067
2068 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2068 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2069 _(' bug reporting: %s\n'), extbuglink or "")
2069 _(' bug reporting: %s\n'), extbuglink or "")
2070
2070
2071 fm.end()
2071 fm.end()
2072
2072
2073 @command('debugfileset',
2073 @command('debugfileset',
2074 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2074 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2075 _('[-r REV] FILESPEC'))
2075 _('[-r REV] FILESPEC'))
2076 def debugfileset(ui, repo, expr, **opts):
2076 def debugfileset(ui, repo, expr, **opts):
2077 '''parse and apply a fileset specification'''
2077 '''parse and apply a fileset specification'''
2078 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2078 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2079 if ui.verbose:
2079 if ui.verbose:
2080 tree = fileset.parse(expr)
2080 tree = fileset.parse(expr)
2081 ui.note(fileset.prettyformat(tree), "\n")
2081 ui.note(fileset.prettyformat(tree), "\n")
2082
2082
2083 for f in ctx.getfileset(expr):
2083 for f in ctx.getfileset(expr):
2084 ui.write("%s\n" % f)
2084 ui.write("%s\n" % f)
2085
2085
2086 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2086 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2087 def debugfsinfo(ui, path="."):
2087 def debugfsinfo(ui, path="."):
2088 """show information detected about current filesystem"""
2088 """show information detected about current filesystem"""
2089 util.writefile('.debugfsinfo', '')
2089 util.writefile('.debugfsinfo', '')
2090 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2090 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2091 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2091 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2092 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2092 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2093 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2093 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2094 and 'yes' or 'no'))
2094 and 'yes' or 'no'))
2095 os.unlink('.debugfsinfo')
2095 os.unlink('.debugfsinfo')
2096
2096
2097 @command('debuggetbundle',
2097 @command('debuggetbundle',
2098 [('H', 'head', [], _('id of head node'), _('ID')),
2098 [('H', 'head', [], _('id of head node'), _('ID')),
2099 ('C', 'common', [], _('id of common node'), _('ID')),
2099 ('C', 'common', [], _('id of common node'), _('ID')),
2100 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2100 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2101 _('REPO FILE [-H|-C ID]...'),
2101 _('REPO FILE [-H|-C ID]...'),
2102 norepo=True)
2102 norepo=True)
2103 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2103 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2104 """retrieves a bundle from a repo
2104 """retrieves a bundle from a repo
2105
2105
2106 Every ID must be a full-length hex node id string. Saves the bundle to the
2106 Every ID must be a full-length hex node id string. Saves the bundle to the
2107 given file.
2107 given file.
2108 """
2108 """
2109 repo = hg.peer(ui, opts, repopath)
2109 repo = hg.peer(ui, opts, repopath)
2110 if not repo.capable('getbundle'):
2110 if not repo.capable('getbundle'):
2111 raise error.Abort("getbundle() not supported by target repository")
2111 raise error.Abort("getbundle() not supported by target repository")
2112 args = {}
2112 args = {}
2113 if common:
2113 if common:
2114 args['common'] = [bin(s) for s in common]
2114 args['common'] = [bin(s) for s in common]
2115 if head:
2115 if head:
2116 args['heads'] = [bin(s) for s in head]
2116 args['heads'] = [bin(s) for s in head]
2117 # TODO: get desired bundlecaps from command line.
2117 # TODO: get desired bundlecaps from command line.
2118 args['bundlecaps'] = None
2118 args['bundlecaps'] = None
2119 bundle = repo.getbundle('debug', **args)
2119 bundle = repo.getbundle('debug', **args)
2120
2120
2121 bundletype = opts.get('type', 'bzip2').lower()
2121 bundletype = opts.get('type', 'bzip2').lower()
2122 btypes = {'none': 'HG10UN',
2122 btypes = {'none': 'HG10UN',
2123 'bzip2': 'HG10BZ',
2123 'bzip2': 'HG10BZ',
2124 'gzip': 'HG10GZ',
2124 'gzip': 'HG10GZ',
2125 'bundle2': 'HG20'}
2125 'bundle2': 'HG20'}
2126 bundletype = btypes.get(bundletype)
2126 bundletype = btypes.get(bundletype)
2127 if bundletype not in bundle2.bundletypes:
2127 if bundletype not in bundle2.bundletypes:
2128 raise error.Abort(_('unknown bundle type specified with --type'))
2128 raise error.Abort(_('unknown bundle type specified with --type'))
2129 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2129 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2130
2130
2131 @command('debugignore', [], '[FILE]')
2131 @command('debugignore', [], '[FILE]')
2132 def debugignore(ui, repo, *files, **opts):
2132 def debugignore(ui, repo, *files, **opts):
2133 """display the combined ignore pattern and information about ignored files
2133 """display the combined ignore pattern and information about ignored files
2134
2134
2135 With no argument display the combined ignore pattern.
2135 With no argument display the combined ignore pattern.
2136
2136
2137 Given space separated file names, shows if the given file is ignored and
2137 Given space separated file names, shows if the given file is ignored and
2138 if so, show the ignore rule (file and line number) that matched it.
2138 if so, show the ignore rule (file and line number) that matched it.
2139 """
2139 """
2140 ignore = repo.dirstate._ignore
2140 ignore = repo.dirstate._ignore
2141 if not files:
2141 if not files:
2142 # Show all the patterns
2142 # Show all the patterns
2143 includepat = getattr(ignore, 'includepat', None)
2143 includepat = getattr(ignore, 'includepat', None)
2144 if includepat is not None:
2144 if includepat is not None:
2145 ui.write("%s\n" % includepat)
2145 ui.write("%s\n" % includepat)
2146 else:
2146 else:
2147 raise error.Abort(_("no ignore patterns found"))
2147 raise error.Abort(_("no ignore patterns found"))
2148 else:
2148 else:
2149 for f in files:
2149 for f in files:
2150 nf = util.normpath(f)
2150 nf = util.normpath(f)
2151 ignored = None
2151 ignored = None
2152 ignoredata = None
2152 ignoredata = None
2153 if nf != '.':
2153 if nf != '.':
2154 if ignore(nf):
2154 if ignore(nf):
2155 ignored = nf
2155 ignored = nf
2156 ignoredata = repo.dirstate._ignorefileandline(nf)
2156 ignoredata = repo.dirstate._ignorefileandline(nf)
2157 else:
2157 else:
2158 for p in util.finddirs(nf):
2158 for p in util.finddirs(nf):
2159 if ignore(p):
2159 if ignore(p):
2160 ignored = p
2160 ignored = p
2161 ignoredata = repo.dirstate._ignorefileandline(p)
2161 ignoredata = repo.dirstate._ignorefileandline(p)
2162 break
2162 break
2163 if ignored:
2163 if ignored:
2164 if ignored == nf:
2164 if ignored == nf:
2165 ui.write(_("%s is ignored\n") % f)
2165 ui.write(_("%s is ignored\n") % f)
2166 else:
2166 else:
2167 ui.write(_("%s is ignored because of "
2167 ui.write(_("%s is ignored because of "
2168 "containing folder %s\n")
2168 "containing folder %s\n")
2169 % (f, ignored))
2169 % (f, ignored))
2170 ignorefile, lineno, line = ignoredata
2170 ignorefile, lineno, line = ignoredata
2171 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2171 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2172 % (ignorefile, lineno, line))
2172 % (ignorefile, lineno, line))
2173 else:
2173 else:
2174 ui.write(_("%s is not ignored\n") % f)
2174 ui.write(_("%s is not ignored\n") % f)
2175
2175
2176 @command('debugindex', debugrevlogopts +
2176 @command('debugindex', debugrevlogopts +
2177 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2177 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2178 _('[-f FORMAT] -c|-m|FILE'),
2178 _('[-f FORMAT] -c|-m|FILE'),
2179 optionalrepo=True)
2179 optionalrepo=True)
2180 def debugindex(ui, repo, file_=None, **opts):
2180 def debugindex(ui, repo, file_=None, **opts):
2181 """dump the contents of an index file"""
2181 """dump the contents of an index file"""
2182 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2182 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2183 format = opts.get('format', 0)
2183 format = opts.get('format', 0)
2184 if format not in (0, 1):
2184 if format not in (0, 1):
2185 raise error.Abort(_("unknown format %d") % format)
2185 raise error.Abort(_("unknown format %d") % format)
2186
2186
2187 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2187 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2188 if generaldelta:
2188 if generaldelta:
2189 basehdr = ' delta'
2189 basehdr = ' delta'
2190 else:
2190 else:
2191 basehdr = ' base'
2191 basehdr = ' base'
2192
2192
2193 if ui.debugflag:
2193 if ui.debugflag:
2194 shortfn = hex
2194 shortfn = hex
2195 else:
2195 else:
2196 shortfn = short
2196 shortfn = short
2197
2197
2198 # There might not be anything in r, so have a sane default
2198 # There might not be anything in r, so have a sane default
2199 idlen = 12
2199 idlen = 12
2200 for i in r:
2200 for i in r:
2201 idlen = len(shortfn(r.node(i)))
2201 idlen = len(shortfn(r.node(i)))
2202 break
2202 break
2203
2203
2204 if format == 0:
2204 if format == 0:
2205 ui.write((" rev offset length " + basehdr + " linkrev"
2205 ui.write((" rev offset length " + basehdr + " linkrev"
2206 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2206 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2207 elif format == 1:
2207 elif format == 1:
2208 ui.write((" rev flag offset length"
2208 ui.write((" rev flag offset length"
2209 " size " + basehdr + " link p1 p2"
2209 " size " + basehdr + " link p1 p2"
2210 " %s\n") % "nodeid".rjust(idlen))
2210 " %s\n") % "nodeid".rjust(idlen))
2211
2211
2212 for i in r:
2212 for i in r:
2213 node = r.node(i)
2213 node = r.node(i)
2214 if generaldelta:
2214 if generaldelta:
2215 base = r.deltaparent(i)
2215 base = r.deltaparent(i)
2216 else:
2216 else:
2217 base = r.chainbase(i)
2217 base = r.chainbase(i)
2218 if format == 0:
2218 if format == 0:
2219 try:
2219 try:
2220 pp = r.parents(node)
2220 pp = r.parents(node)
2221 except Exception:
2221 except Exception:
2222 pp = [nullid, nullid]
2222 pp = [nullid, nullid]
2223 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2223 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2224 i, r.start(i), r.length(i), base, r.linkrev(i),
2224 i, r.start(i), r.length(i), base, r.linkrev(i),
2225 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2225 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2226 elif format == 1:
2226 elif format == 1:
2227 pr = r.parentrevs(i)
2227 pr = r.parentrevs(i)
2228 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2228 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2229 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2229 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2230 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2230 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2231
2231
2232 @command('debugindexdot', debugrevlogopts,
2232 @command('debugindexdot', debugrevlogopts,
2233 _('-c|-m|FILE'), optionalrepo=True)
2233 _('-c|-m|FILE'), optionalrepo=True)
2234 def debugindexdot(ui, repo, file_=None, **opts):
2234 def debugindexdot(ui, repo, file_=None, **opts):
2235 """dump an index DAG as a graphviz dot file"""
2235 """dump an index DAG as a graphviz dot file"""
2236 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2236 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2237 ui.write(("digraph G {\n"))
2237 ui.write(("digraph G {\n"))
2238 for i in r:
2238 for i in r:
2239 node = r.node(i)
2239 node = r.node(i)
2240 pp = r.parents(node)
2240 pp = r.parents(node)
2241 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2241 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2242 if pp[1] != nullid:
2242 if pp[1] != nullid:
2243 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2243 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2244 ui.write("}\n")
2244 ui.write("}\n")
2245
2245
2246 @command('debugdeltachain',
2246 @command('debugdeltachain',
2247 debugrevlogopts + formatteropts,
2247 debugrevlogopts + formatteropts,
2248 _('-c|-m|FILE'),
2248 _('-c|-m|FILE'),
2249 optionalrepo=True)
2249 optionalrepo=True)
2250 def debugdeltachain(ui, repo, file_=None, **opts):
2250 def debugdeltachain(ui, repo, file_=None, **opts):
2251 """dump information about delta chains in a revlog
2251 """dump information about delta chains in a revlog
2252
2252
2253 Output can be templatized. Available template keywords are:
2253 Output can be templatized. Available template keywords are:
2254
2254
2255 :``rev``: revision number
2255 :``rev``: revision number
2256 :``chainid``: delta chain identifier (numbered by unique base)
2256 :``chainid``: delta chain identifier (numbered by unique base)
2257 :``chainlen``: delta chain length to this revision
2257 :``chainlen``: delta chain length to this revision
2258 :``prevrev``: previous revision in delta chain
2258 :``prevrev``: previous revision in delta chain
2259 :``deltatype``: role of delta / how it was computed
2259 :``deltatype``: role of delta / how it was computed
2260 :``compsize``: compressed size of revision
2260 :``compsize``: compressed size of revision
2261 :``uncompsize``: uncompressed size of revision
2261 :``uncompsize``: uncompressed size of revision
2262 :``chainsize``: total size of compressed revisions in chain
2262 :``chainsize``: total size of compressed revisions in chain
2263 :``chainratio``: total chain size divided by uncompressed revision size
2263 :``chainratio``: total chain size divided by uncompressed revision size
2264 (new delta chains typically start at ratio 2.00)
2264 (new delta chains typically start at ratio 2.00)
2265 :``lindist``: linear distance from base revision in delta chain to end
2265 :``lindist``: linear distance from base revision in delta chain to end
2266 of this revision
2266 of this revision
2267 :``extradist``: total size of revisions not part of this delta chain from
2267 :``extradist``: total size of revisions not part of this delta chain from
2268 base of delta chain to end of this revision; a measurement
2268 base of delta chain to end of this revision; a measurement
2269 of how much extra data we need to read/seek across to read
2269 of how much extra data we need to read/seek across to read
2270 the delta chain for this revision
2270 the delta chain for this revision
2271 :``extraratio``: extradist divided by chainsize; another representation of
2271 :``extraratio``: extradist divided by chainsize; another representation of
2272 how much unrelated data is needed to load this delta chain
2272 how much unrelated data is needed to load this delta chain
2273 """
2273 """
2274 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2274 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2275 index = r.index
2275 index = r.index
2276 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2276 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2277
2277
2278 def revinfo(rev):
2278 def revinfo(rev):
2279 e = index[rev]
2279 e = index[rev]
2280 compsize = e[1]
2280 compsize = e[1]
2281 uncompsize = e[2]
2281 uncompsize = e[2]
2282 chainsize = 0
2282 chainsize = 0
2283
2283
2284 if generaldelta:
2284 if generaldelta:
2285 if e[3] == e[5]:
2285 if e[3] == e[5]:
2286 deltatype = 'p1'
2286 deltatype = 'p1'
2287 elif e[3] == e[6]:
2287 elif e[3] == e[6]:
2288 deltatype = 'p2'
2288 deltatype = 'p2'
2289 elif e[3] == rev - 1:
2289 elif e[3] == rev - 1:
2290 deltatype = 'prev'
2290 deltatype = 'prev'
2291 elif e[3] == rev:
2291 elif e[3] == rev:
2292 deltatype = 'base'
2292 deltatype = 'base'
2293 else:
2293 else:
2294 deltatype = 'other'
2294 deltatype = 'other'
2295 else:
2295 else:
2296 if e[3] == rev:
2296 if e[3] == rev:
2297 deltatype = 'base'
2297 deltatype = 'base'
2298 else:
2298 else:
2299 deltatype = 'prev'
2299 deltatype = 'prev'
2300
2300
2301 chain = r._deltachain(rev)[0]
2301 chain = r._deltachain(rev)[0]
2302 for iterrev in chain:
2302 for iterrev in chain:
2303 e = index[iterrev]
2303 e = index[iterrev]
2304 chainsize += e[1]
2304 chainsize += e[1]
2305
2305
2306 return compsize, uncompsize, deltatype, chain, chainsize
2306 return compsize, uncompsize, deltatype, chain, chainsize
2307
2307
2308 fm = ui.formatter('debugdeltachain', opts)
2308 fm = ui.formatter('debugdeltachain', opts)
2309
2309
2310 fm.plain(' rev chain# chainlen prev delta '
2310 fm.plain(' rev chain# chainlen prev delta '
2311 'size rawsize chainsize ratio lindist extradist '
2311 'size rawsize chainsize ratio lindist extradist '
2312 'extraratio\n')
2312 'extraratio\n')
2313
2313
2314 chainbases = {}
2314 chainbases = {}
2315 for rev in r:
2315 for rev in r:
2316 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2316 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2317 chainbase = chain[0]
2317 chainbase = chain[0]
2318 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2318 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2319 basestart = r.start(chainbase)
2319 basestart = r.start(chainbase)
2320 revstart = r.start(rev)
2320 revstart = r.start(rev)
2321 lineardist = revstart + comp - basestart
2321 lineardist = revstart + comp - basestart
2322 extradist = lineardist - chainsize
2322 extradist = lineardist - chainsize
2323 try:
2323 try:
2324 prevrev = chain[-2]
2324 prevrev = chain[-2]
2325 except IndexError:
2325 except IndexError:
2326 prevrev = -1
2326 prevrev = -1
2327
2327
2328 chainratio = float(chainsize) / float(uncomp)
2328 chainratio = float(chainsize) / float(uncomp)
2329 extraratio = float(extradist) / float(chainsize)
2329 extraratio = float(extradist) / float(chainsize)
2330
2330
2331 fm.startitem()
2331 fm.startitem()
2332 fm.write('rev chainid chainlen prevrev deltatype compsize '
2332 fm.write('rev chainid chainlen prevrev deltatype compsize '
2333 'uncompsize chainsize chainratio lindist extradist '
2333 'uncompsize chainsize chainratio lindist extradist '
2334 'extraratio',
2334 'extraratio',
2335 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2335 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2336 rev, chainid, len(chain), prevrev, deltatype, comp,
2336 rev, chainid, len(chain), prevrev, deltatype, comp,
2337 uncomp, chainsize, chainratio, lineardist, extradist,
2337 uncomp, chainsize, chainratio, lineardist, extradist,
2338 extraratio,
2338 extraratio,
2339 rev=rev, chainid=chainid, chainlen=len(chain),
2339 rev=rev, chainid=chainid, chainlen=len(chain),
2340 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2340 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2341 uncompsize=uncomp, chainsize=chainsize,
2341 uncompsize=uncomp, chainsize=chainsize,
2342 chainratio=chainratio, lindist=lineardist,
2342 chainratio=chainratio, lindist=lineardist,
2343 extradist=extradist, extraratio=extraratio)
2343 extradist=extradist, extraratio=extraratio)
2344
2344
2345 fm.end()
2345 fm.end()
2346
2346
2347 @command('debuginstall', [] + formatteropts, '', norepo=True)
2347 @command('debuginstall', [] + formatteropts, '', norepo=True)
2348 def debuginstall(ui, **opts):
2348 def debuginstall(ui, **opts):
2349 '''test Mercurial installation
2349 '''test Mercurial installation
2350
2350
2351 Returns 0 on success.
2351 Returns 0 on success.
2352 '''
2352 '''
2353
2353
2354 def writetemp(contents):
2354 def writetemp(contents):
2355 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2355 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2356 f = os.fdopen(fd, "wb")
2356 f = os.fdopen(fd, "wb")
2357 f.write(contents)
2357 f.write(contents)
2358 f.close()
2358 f.close()
2359 return name
2359 return name
2360
2360
2361 problems = 0
2361 problems = 0
2362
2362
2363 fm = ui.formatter('debuginstall', opts)
2363 fm = ui.formatter('debuginstall', opts)
2364 fm.startitem()
2364 fm.startitem()
2365
2365
2366 # encoding
2366 # encoding
2367 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2367 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2368 err = None
2368 err = None
2369 try:
2369 try:
2370 encoding.fromlocal("test")
2370 encoding.fromlocal("test")
2371 except error.Abort as inst:
2371 except error.Abort as inst:
2372 err = inst
2372 err = inst
2373 problems += 1
2373 problems += 1
2374 fm.condwrite(err, 'encodingerror', _(" %s\n"
2374 fm.condwrite(err, 'encodingerror', _(" %s\n"
2375 " (check that your locale is properly set)\n"), err)
2375 " (check that your locale is properly set)\n"), err)
2376
2376
2377 # Python
2377 # Python
2378 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2378 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2379 sys.executable)
2379 sys.executable)
2380 fm.write('pythonver', _("checking Python version (%s)\n"),
2380 fm.write('pythonver', _("checking Python version (%s)\n"),
2381 ("%s.%s.%s" % sys.version_info[:3]))
2381 ("%s.%s.%s" % sys.version_info[:3]))
2382 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2382 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2383 os.path.dirname(os.__file__))
2383 os.path.dirname(os.__file__))
2384
2384
2385 security = set(sslutil.supportedprotocols)
2385 security = set(sslutil.supportedprotocols)
2386 if sslutil.hassni:
2386 if sslutil.hassni:
2387 security.add('sni')
2387 security.add('sni')
2388
2388
2389 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
2389 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
2390 fm.formatlist(sorted(security), name='protocol',
2390 fm.formatlist(sorted(security), name='protocol',
2391 fmt='%s', sep=','))
2391 fmt='%s', sep=','))
2392
2392
2393 # These are warnings, not errors. So don't increment problem count. This
2393 # These are warnings, not errors. So don't increment problem count. This
2394 # may change in the future.
2394 # may change in the future.
2395 if 'tls1.2' not in security:
2395 if 'tls1.2' not in security:
2396 fm.plain(_(' TLS 1.2 not supported by Python install; '
2396 fm.plain(_(' TLS 1.2 not supported by Python install; '
2397 'network connections lack modern security\n'))
2397 'network connections lack modern security\n'))
2398 if 'sni' not in security:
2398 if 'sni' not in security:
2399 fm.plain(_(' SNI not supported by Python install; may have '
2399 fm.plain(_(' SNI not supported by Python install; may have '
2400 'connectivity issues with some servers\n'))
2400 'connectivity issues with some servers\n'))
2401
2401
2402 # TODO print CA cert info
2402 # TODO print CA cert info
2403
2403
2404 # hg version
2404 # hg version
2405 hgver = util.version()
2405 hgver = util.version()
2406 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2406 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2407 hgver.split('+')[0])
2407 hgver.split('+')[0])
2408 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2408 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2409 '+'.join(hgver.split('+')[1:]))
2409 '+'.join(hgver.split('+')[1:]))
2410
2410
2411 # compiled modules
2411 # compiled modules
2412 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2412 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2413 policy.policy)
2413 policy.policy)
2414 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2414 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2415 os.path.dirname(__file__))
2415 os.path.dirname(__file__))
2416
2416
2417 err = None
2417 err = None
2418 try:
2418 try:
2419 from . import (
2419 from . import (
2420 base85,
2420 base85,
2421 bdiff,
2421 bdiff,
2422 mpatch,
2422 mpatch,
2423 osutil,
2423 osutil,
2424 )
2424 )
2425 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2425 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2426 except Exception as inst:
2426 except Exception as inst:
2427 err = inst
2427 err = inst
2428 problems += 1
2428 problems += 1
2429 fm.condwrite(err, 'extensionserror', " %s\n", err)
2429 fm.condwrite(err, 'extensionserror', " %s\n", err)
2430
2430
2431 compengines = util.compengines._engines.values()
2431 compengines = util.compengines._engines.values()
2432 fm.write('compengines', _('checking registered compression engines (%s)\n'),
2432 fm.write('compengines', _('checking registered compression engines (%s)\n'),
2433 fm.formatlist(sorted(e.name() for e in compengines),
2433 fm.formatlist(sorted(e.name() for e in compengines),
2434 name='compengine', fmt='%s', sep=', '))
2434 name='compengine', fmt='%s', sep=', '))
2435 fm.write('compenginesavail', _('checking available compression engines '
2435 fm.write('compenginesavail', _('checking available compression engines '
2436 '(%s)\n'),
2436 '(%s)\n'),
2437 fm.formatlist(sorted(e.name() for e in compengines
2437 fm.formatlist(sorted(e.name() for e in compengines
2438 if e.available()),
2438 if e.available()),
2439 name='compengine', fmt='%s', sep=', '))
2439 name='compengine', fmt='%s', sep=', '))
2440
2440
2441 # templates
2441 # templates
2442 p = templater.templatepaths()
2442 p = templater.templatepaths()
2443 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2443 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2444 fm.condwrite(not p, '', _(" no template directories found\n"))
2444 fm.condwrite(not p, '', _(" no template directories found\n"))
2445 if p:
2445 if p:
2446 m = templater.templatepath("map-cmdline.default")
2446 m = templater.templatepath("map-cmdline.default")
2447 if m:
2447 if m:
2448 # template found, check if it is working
2448 # template found, check if it is working
2449 err = None
2449 err = None
2450 try:
2450 try:
2451 templater.templater.frommapfile(m)
2451 templater.templater.frommapfile(m)
2452 except Exception as inst:
2452 except Exception as inst:
2453 err = inst
2453 err = inst
2454 p = None
2454 p = None
2455 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2455 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2456 else:
2456 else:
2457 p = None
2457 p = None
2458 fm.condwrite(p, 'defaulttemplate',
2458 fm.condwrite(p, 'defaulttemplate',
2459 _("checking default template (%s)\n"), m)
2459 _("checking default template (%s)\n"), m)
2460 fm.condwrite(not m, 'defaulttemplatenotfound',
2460 fm.condwrite(not m, 'defaulttemplatenotfound',
2461 _(" template '%s' not found\n"), "default")
2461 _(" template '%s' not found\n"), "default")
2462 if not p:
2462 if not p:
2463 problems += 1
2463 problems += 1
2464 fm.condwrite(not p, '',
2464 fm.condwrite(not p, '',
2465 _(" (templates seem to have been installed incorrectly)\n"))
2465 _(" (templates seem to have been installed incorrectly)\n"))
2466
2466
2467 # editor
2467 # editor
2468 editor = ui.geteditor()
2468 editor = ui.geteditor()
2469 editor = util.expandpath(editor)
2469 editor = util.expandpath(editor)
2470 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2470 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2471 cmdpath = util.findexe(shlex.split(editor)[0])
2471 cmdpath = util.findexe(shlex.split(editor)[0])
2472 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2472 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2473 _(" No commit editor set and can't find %s in PATH\n"
2473 _(" No commit editor set and can't find %s in PATH\n"
2474 " (specify a commit editor in your configuration"
2474 " (specify a commit editor in your configuration"
2475 " file)\n"), not cmdpath and editor == 'vi' and editor)
2475 " file)\n"), not cmdpath and editor == 'vi' and editor)
2476 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2476 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2477 _(" Can't find editor '%s' in PATH\n"
2477 _(" Can't find editor '%s' in PATH\n"
2478 " (specify a commit editor in your configuration"
2478 " (specify a commit editor in your configuration"
2479 " file)\n"), not cmdpath and editor)
2479 " file)\n"), not cmdpath and editor)
2480 if not cmdpath and editor != 'vi':
2480 if not cmdpath and editor != 'vi':
2481 problems += 1
2481 problems += 1
2482
2482
2483 # check username
2483 # check username
2484 username = None
2484 username = None
2485 err = None
2485 err = None
2486 try:
2486 try:
2487 username = ui.username()
2487 username = ui.username()
2488 except error.Abort as e:
2488 except error.Abort as e:
2489 err = e
2489 err = e
2490 problems += 1
2490 problems += 1
2491
2491
2492 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2492 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2493 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2493 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2494 " (specify a username in your configuration file)\n"), err)
2494 " (specify a username in your configuration file)\n"), err)
2495
2495
2496 fm.condwrite(not problems, '',
2496 fm.condwrite(not problems, '',
2497 _("no problems detected\n"))
2497 _("no problems detected\n"))
2498 if not problems:
2498 if not problems:
2499 fm.data(problems=problems)
2499 fm.data(problems=problems)
2500 fm.condwrite(problems, 'problems',
2500 fm.condwrite(problems, 'problems',
2501 _("%d problems detected,"
2501 _("%d problems detected,"
2502 " please check your install!\n"), problems)
2502 " please check your install!\n"), problems)
2503 fm.end()
2503 fm.end()
2504
2504
2505 return problems
2505 return problems
2506
2506
2507 @command('debugknown', [], _('REPO ID...'), norepo=True)
2507 @command('debugknown', [], _('REPO ID...'), norepo=True)
2508 def debugknown(ui, repopath, *ids, **opts):
2508 def debugknown(ui, repopath, *ids, **opts):
2509 """test whether node ids are known to a repo
2509 """test whether node ids are known to a repo
2510
2510
2511 Every ID must be a full-length hex node id string. Returns a list of 0s
2511 Every ID must be a full-length hex node id string. Returns a list of 0s
2512 and 1s indicating unknown/known.
2512 and 1s indicating unknown/known.
2513 """
2513 """
2514 repo = hg.peer(ui, opts, repopath)
2514 repo = hg.peer(ui, opts, repopath)
2515 if not repo.capable('known'):
2515 if not repo.capable('known'):
2516 raise error.Abort("known() not supported by target repository")
2516 raise error.Abort("known() not supported by target repository")
2517 flags = repo.known([bin(s) for s in ids])
2517 flags = repo.known([bin(s) for s in ids])
2518 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2518 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2519
2519
2520 @command('debuglabelcomplete', [], _('LABEL...'))
2520 @command('debuglabelcomplete', [], _('LABEL...'))
2521 def debuglabelcomplete(ui, repo, *args):
2521 def debuglabelcomplete(ui, repo, *args):
2522 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2522 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2523 debugnamecomplete(ui, repo, *args)
2523 debugnamecomplete(ui, repo, *args)
2524
2524
2525 @command('debugmergestate', [], '')
2525 @command('debugmergestate', [], '')
2526 def debugmergestate(ui, repo, *args):
2526 def debugmergestate(ui, repo, *args):
2527 """print merge state
2527 """print merge state
2528
2528
2529 Use --verbose to print out information about whether v1 or v2 merge state
2529 Use --verbose to print out information about whether v1 or v2 merge state
2530 was chosen."""
2530 was chosen."""
2531 def _hashornull(h):
2531 def _hashornull(h):
2532 if h == nullhex:
2532 if h == nullhex:
2533 return 'null'
2533 return 'null'
2534 else:
2534 else:
2535 return h
2535 return h
2536
2536
2537 def printrecords(version):
2537 def printrecords(version):
2538 ui.write(('* version %s records\n') % version)
2538 ui.write(('* version %s records\n') % version)
2539 if version == 1:
2539 if version == 1:
2540 records = v1records
2540 records = v1records
2541 else:
2541 else:
2542 records = v2records
2542 records = v2records
2543
2543
2544 for rtype, record in records:
2544 for rtype, record in records:
2545 # pretty print some record types
2545 # pretty print some record types
2546 if rtype == 'L':
2546 if rtype == 'L':
2547 ui.write(('local: %s\n') % record)
2547 ui.write(('local: %s\n') % record)
2548 elif rtype == 'O':
2548 elif rtype == 'O':
2549 ui.write(('other: %s\n') % record)
2549 ui.write(('other: %s\n') % record)
2550 elif rtype == 'm':
2550 elif rtype == 'm':
2551 driver, mdstate = record.split('\0', 1)
2551 driver, mdstate = record.split('\0', 1)
2552 ui.write(('merge driver: %s (state "%s")\n')
2552 ui.write(('merge driver: %s (state "%s")\n')
2553 % (driver, mdstate))
2553 % (driver, mdstate))
2554 elif rtype in 'FDC':
2554 elif rtype in 'FDC':
2555 r = record.split('\0')
2555 r = record.split('\0')
2556 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2556 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2557 if version == 1:
2557 if version == 1:
2558 onode = 'not stored in v1 format'
2558 onode = 'not stored in v1 format'
2559 flags = r[7]
2559 flags = r[7]
2560 else:
2560 else:
2561 onode, flags = r[7:9]
2561 onode, flags = r[7:9]
2562 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2562 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2563 % (f, rtype, state, _hashornull(hash)))
2563 % (f, rtype, state, _hashornull(hash)))
2564 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2564 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2565 ui.write((' ancestor path: %s (node %s)\n')
2565 ui.write((' ancestor path: %s (node %s)\n')
2566 % (afile, _hashornull(anode)))
2566 % (afile, _hashornull(anode)))
2567 ui.write((' other path: %s (node %s)\n')
2567 ui.write((' other path: %s (node %s)\n')
2568 % (ofile, _hashornull(onode)))
2568 % (ofile, _hashornull(onode)))
2569 elif rtype == 'f':
2569 elif rtype == 'f':
2570 filename, rawextras = record.split('\0', 1)
2570 filename, rawextras = record.split('\0', 1)
2571 extras = rawextras.split('\0')
2571 extras = rawextras.split('\0')
2572 i = 0
2572 i = 0
2573 extrastrings = []
2573 extrastrings = []
2574 while i < len(extras):
2574 while i < len(extras):
2575 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2575 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2576 i += 2
2576 i += 2
2577
2577
2578 ui.write(('file extras: %s (%s)\n')
2578 ui.write(('file extras: %s (%s)\n')
2579 % (filename, ', '.join(extrastrings)))
2579 % (filename, ', '.join(extrastrings)))
2580 elif rtype == 'l':
2580 elif rtype == 'l':
2581 labels = record.split('\0', 2)
2581 labels = record.split('\0', 2)
2582 labels = [l for l in labels if len(l) > 0]
2582 labels = [l for l in labels if len(l) > 0]
2583 ui.write(('labels:\n'))
2583 ui.write(('labels:\n'))
2584 ui.write((' local: %s\n' % labels[0]))
2584 ui.write((' local: %s\n' % labels[0]))
2585 ui.write((' other: %s\n' % labels[1]))
2585 ui.write((' other: %s\n' % labels[1]))
2586 if len(labels) > 2:
2586 if len(labels) > 2:
2587 ui.write((' base: %s\n' % labels[2]))
2587 ui.write((' base: %s\n' % labels[2]))
2588 else:
2588 else:
2589 ui.write(('unrecognized entry: %s\t%s\n')
2589 ui.write(('unrecognized entry: %s\t%s\n')
2590 % (rtype, record.replace('\0', '\t')))
2590 % (rtype, record.replace('\0', '\t')))
2591
2591
2592 # Avoid mergestate.read() since it may raise an exception for unsupported
2592 # Avoid mergestate.read() since it may raise an exception for unsupported
2593 # merge state records. We shouldn't be doing this, but this is OK since this
2593 # merge state records. We shouldn't be doing this, but this is OK since this
2594 # command is pretty low-level.
2594 # command is pretty low-level.
2595 ms = mergemod.mergestate(repo)
2595 ms = mergemod.mergestate(repo)
2596
2596
2597 # sort so that reasonable information is on top
2597 # sort so that reasonable information is on top
2598 v1records = ms._readrecordsv1()
2598 v1records = ms._readrecordsv1()
2599 v2records = ms._readrecordsv2()
2599 v2records = ms._readrecordsv2()
2600 order = 'LOml'
2600 order = 'LOml'
2601 def key(r):
2601 def key(r):
2602 idx = order.find(r[0])
2602 idx = order.find(r[0])
2603 if idx == -1:
2603 if idx == -1:
2604 return (1, r[1])
2604 return (1, r[1])
2605 else:
2605 else:
2606 return (0, idx)
2606 return (0, idx)
2607 v1records.sort(key=key)
2607 v1records.sort(key=key)
2608 v2records.sort(key=key)
2608 v2records.sort(key=key)
2609
2609
2610 if not v1records and not v2records:
2610 if not v1records and not v2records:
2611 ui.write(('no merge state found\n'))
2611 ui.write(('no merge state found\n'))
2612 elif not v2records:
2612 elif not v2records:
2613 ui.note(('no version 2 merge state\n'))
2613 ui.note(('no version 2 merge state\n'))
2614 printrecords(1)
2614 printrecords(1)
2615 elif ms._v1v2match(v1records, v2records):
2615 elif ms._v1v2match(v1records, v2records):
2616 ui.note(('v1 and v2 states match: using v2\n'))
2616 ui.note(('v1 and v2 states match: using v2\n'))
2617 printrecords(2)
2617 printrecords(2)
2618 else:
2618 else:
2619 ui.note(('v1 and v2 states mismatch: using v1\n'))
2619 ui.note(('v1 and v2 states mismatch: using v1\n'))
2620 printrecords(1)
2620 printrecords(1)
2621 if ui.verbose:
2621 if ui.verbose:
2622 printrecords(2)
2622 printrecords(2)
2623
2623
2624 @command('debugnamecomplete', [], _('NAME...'))
2624 @command('debugnamecomplete', [], _('NAME...'))
2625 def debugnamecomplete(ui, repo, *args):
2625 def debugnamecomplete(ui, repo, *args):
2626 '''complete "names" - tags, open branch names, bookmark names'''
2626 '''complete "names" - tags, open branch names, bookmark names'''
2627
2627
2628 names = set()
2628 names = set()
2629 # since we previously only listed open branches, we will handle that
2629 # since we previously only listed open branches, we will handle that
2630 # specially (after this for loop)
2630 # specially (after this for loop)
2631 for name, ns in repo.names.iteritems():
2631 for name, ns in repo.names.iteritems():
2632 if name != 'branches':
2632 if name != 'branches':
2633 names.update(ns.listnames(repo))
2633 names.update(ns.listnames(repo))
2634 names.update(tag for (tag, heads, tip, closed)
2634 names.update(tag for (tag, heads, tip, closed)
2635 in repo.branchmap().iterbranches() if not closed)
2635 in repo.branchmap().iterbranches() if not closed)
2636 completions = set()
2636 completions = set()
2637 if not args:
2637 if not args:
2638 args = ['']
2638 args = ['']
2639 for a in args:
2639 for a in args:
2640 completions.update(n for n in names if n.startswith(a))
2640 completions.update(n for n in names if n.startswith(a))
2641 ui.write('\n'.join(sorted(completions)))
2641 ui.write('\n'.join(sorted(completions)))
2642 ui.write('\n')
2642 ui.write('\n')
2643
2643
2644 @command('debuglocks',
2644 @command('debuglocks',
2645 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2645 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2646 ('W', 'force-wlock', None,
2646 ('W', 'force-wlock', None,
2647 _('free the working state lock (DANGEROUS)'))],
2647 _('free the working state lock (DANGEROUS)'))],
2648 _('[OPTION]...'))
2648 _('[OPTION]...'))
2649 def debuglocks(ui, repo, **opts):
2649 def debuglocks(ui, repo, **opts):
2650 """show or modify state of locks
2650 """show or modify state of locks
2651
2651
2652 By default, this command will show which locks are held. This
2652 By default, this command will show which locks are held. This
2653 includes the user and process holding the lock, the amount of time
2653 includes the user and process holding the lock, the amount of time
2654 the lock has been held, and the machine name where the process is
2654 the lock has been held, and the machine name where the process is
2655 running if it's not local.
2655 running if it's not local.
2656
2656
2657 Locks protect the integrity of Mercurial's data, so should be
2657 Locks protect the integrity of Mercurial's data, so should be
2658 treated with care. System crashes or other interruptions may cause
2658 treated with care. System crashes or other interruptions may cause
2659 locks to not be properly released, though Mercurial will usually
2659 locks to not be properly released, though Mercurial will usually
2660 detect and remove such stale locks automatically.
2660 detect and remove such stale locks automatically.
2661
2661
2662 However, detecting stale locks may not always be possible (for
2662 However, detecting stale locks may not always be possible (for
2663 instance, on a shared filesystem). Removing locks may also be
2663 instance, on a shared filesystem). Removing locks may also be
2664 blocked by filesystem permissions.
2664 blocked by filesystem permissions.
2665
2665
2666 Returns 0 if no locks are held.
2666 Returns 0 if no locks are held.
2667
2667
2668 """
2668 """
2669
2669
2670 if opts.get('force_lock'):
2670 if opts.get('force_lock'):
2671 repo.svfs.unlink('lock')
2671 repo.svfs.unlink('lock')
2672 if opts.get('force_wlock'):
2672 if opts.get('force_wlock'):
2673 repo.vfs.unlink('wlock')
2673 repo.vfs.unlink('wlock')
2674 if opts.get('force_lock') or opts.get('force_lock'):
2674 if opts.get('force_lock') or opts.get('force_lock'):
2675 return 0
2675 return 0
2676
2676
2677 now = time.time()
2677 now = time.time()
2678 held = 0
2678 held = 0
2679
2679
2680 def report(vfs, name, method):
2680 def report(vfs, name, method):
2681 # this causes stale locks to get reaped for more accurate reporting
2681 # this causes stale locks to get reaped for more accurate reporting
2682 try:
2682 try:
2683 l = method(False)
2683 l = method(False)
2684 except error.LockHeld:
2684 except error.LockHeld:
2685 l = None
2685 l = None
2686
2686
2687 if l:
2687 if l:
2688 l.release()
2688 l.release()
2689 else:
2689 else:
2690 try:
2690 try:
2691 stat = vfs.lstat(name)
2691 stat = vfs.lstat(name)
2692 age = now - stat.st_mtime
2692 age = now - stat.st_mtime
2693 user = util.username(stat.st_uid)
2693 user = util.username(stat.st_uid)
2694 locker = vfs.readlock(name)
2694 locker = vfs.readlock(name)
2695 if ":" in locker:
2695 if ":" in locker:
2696 host, pid = locker.split(':')
2696 host, pid = locker.split(':')
2697 if host == socket.gethostname():
2697 if host == socket.gethostname():
2698 locker = 'user %s, process %s' % (user, pid)
2698 locker = 'user %s, process %s' % (user, pid)
2699 else:
2699 else:
2700 locker = 'user %s, process %s, host %s' \
2700 locker = 'user %s, process %s, host %s' \
2701 % (user, pid, host)
2701 % (user, pid, host)
2702 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2702 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2703 return 1
2703 return 1
2704 except OSError as e:
2704 except OSError as e:
2705 if e.errno != errno.ENOENT:
2705 if e.errno != errno.ENOENT:
2706 raise
2706 raise
2707
2707
2708 ui.write(("%-6s free\n") % (name + ":"))
2708 ui.write(("%-6s free\n") % (name + ":"))
2709 return 0
2709 return 0
2710
2710
2711 held += report(repo.svfs, "lock", repo.lock)
2711 held += report(repo.svfs, "lock", repo.lock)
2712 held += report(repo.vfs, "wlock", repo.wlock)
2712 held += report(repo.vfs, "wlock", repo.wlock)
2713
2713
2714 return held
2714 return held
2715
2715
2716 @command('debugobsolete',
2716 @command('debugobsolete',
2717 [('', 'flags', 0, _('markers flag')),
2717 [('', 'flags', 0, _('markers flag')),
2718 ('', 'record-parents', False,
2718 ('', 'record-parents', False,
2719 _('record parent information for the precursor')),
2719 _('record parent information for the precursor')),
2720 ('r', 'rev', [], _('display markers relevant to REV')),
2720 ('r', 'rev', [], _('display markers relevant to REV')),
2721 ('', 'index', False, _('display index of the marker')),
2721 ('', 'index', False, _('display index of the marker')),
2722 ('', 'delete', [], _('delete markers specified by indices')),
2722 ('', 'delete', [], _('delete markers specified by indices')),
2723 ] + commitopts2 + formatteropts,
2723 ] + commitopts2 + formatteropts,
2724 _('[OBSOLETED [REPLACEMENT ...]]'))
2724 _('[OBSOLETED [REPLACEMENT ...]]'))
2725 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2725 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2726 """create arbitrary obsolete marker
2726 """create arbitrary obsolete marker
2727
2727
2728 With no arguments, displays the list of obsolescence markers."""
2728 With no arguments, displays the list of obsolescence markers."""
2729
2729
2730 def parsenodeid(s):
2730 def parsenodeid(s):
2731 try:
2731 try:
2732 # We do not use revsingle/revrange functions here to accept
2732 # We do not use revsingle/revrange functions here to accept
2733 # arbitrary node identifiers, possibly not present in the
2733 # arbitrary node identifiers, possibly not present in the
2734 # local repository.
2734 # local repository.
2735 n = bin(s)
2735 n = bin(s)
2736 if len(n) != len(nullid):
2736 if len(n) != len(nullid):
2737 raise TypeError()
2737 raise TypeError()
2738 return n
2738 return n
2739 except TypeError:
2739 except TypeError:
2740 raise error.Abort('changeset references must be full hexadecimal '
2740 raise error.Abort('changeset references must be full hexadecimal '
2741 'node identifiers')
2741 'node identifiers')
2742
2742
2743 if opts.get('delete'):
2743 if opts.get('delete'):
2744 indices = []
2744 indices = []
2745 for v in opts.get('delete'):
2745 for v in opts.get('delete'):
2746 try:
2746 try:
2747 indices.append(int(v))
2747 indices.append(int(v))
2748 except ValueError:
2748 except ValueError:
2749 raise error.Abort(_('invalid index value: %r') % v,
2749 raise error.Abort(_('invalid index value: %r') % v,
2750 hint=_('use integers for indices'))
2750 hint=_('use integers for indices'))
2751
2751
2752 if repo.currenttransaction():
2752 if repo.currenttransaction():
2753 raise error.Abort(_('cannot delete obsmarkers in the middle '
2753 raise error.Abort(_('cannot delete obsmarkers in the middle '
2754 'of transaction.'))
2754 'of transaction.'))
2755
2755
2756 with repo.lock():
2756 with repo.lock():
2757 n = repair.deleteobsmarkers(repo.obsstore, indices)
2757 n = repair.deleteobsmarkers(repo.obsstore, indices)
2758 ui.write(_('deleted %i obsolescence markers\n') % n)
2758 ui.write(_('deleted %i obsolescence markers\n') % n)
2759
2759
2760 return
2760 return
2761
2761
2762 if precursor is not None:
2762 if precursor is not None:
2763 if opts['rev']:
2763 if opts['rev']:
2764 raise error.Abort('cannot select revision when creating marker')
2764 raise error.Abort('cannot select revision when creating marker')
2765 metadata = {}
2765 metadata = {}
2766 metadata['user'] = opts['user'] or ui.username()
2766 metadata['user'] = opts['user'] or ui.username()
2767 succs = tuple(parsenodeid(succ) for succ in successors)
2767 succs = tuple(parsenodeid(succ) for succ in successors)
2768 l = repo.lock()
2768 l = repo.lock()
2769 try:
2769 try:
2770 tr = repo.transaction('debugobsolete')
2770 tr = repo.transaction('debugobsolete')
2771 try:
2771 try:
2772 date = opts.get('date')
2772 date = opts.get('date')
2773 if date:
2773 if date:
2774 date = util.parsedate(date)
2774 date = util.parsedate(date)
2775 else:
2775 else:
2776 date = None
2776 date = None
2777 prec = parsenodeid(precursor)
2777 prec = parsenodeid(precursor)
2778 parents = None
2778 parents = None
2779 if opts['record_parents']:
2779 if opts['record_parents']:
2780 if prec not in repo.unfiltered():
2780 if prec not in repo.unfiltered():
2781 raise error.Abort('cannot used --record-parents on '
2781 raise error.Abort('cannot used --record-parents on '
2782 'unknown changesets')
2782 'unknown changesets')
2783 parents = repo.unfiltered()[prec].parents()
2783 parents = repo.unfiltered()[prec].parents()
2784 parents = tuple(p.node() for p in parents)
2784 parents = tuple(p.node() for p in parents)
2785 repo.obsstore.create(tr, prec, succs, opts['flags'],
2785 repo.obsstore.create(tr, prec, succs, opts['flags'],
2786 parents=parents, date=date,
2786 parents=parents, date=date,
2787 metadata=metadata)
2787 metadata=metadata)
2788 tr.close()
2788 tr.close()
2789 except ValueError as exc:
2789 except ValueError as exc:
2790 raise error.Abort(_('bad obsmarker input: %s') % exc)
2790 raise error.Abort(_('bad obsmarker input: %s') % exc)
2791 finally:
2791 finally:
2792 tr.release()
2792 tr.release()
2793 finally:
2793 finally:
2794 l.release()
2794 l.release()
2795 else:
2795 else:
2796 if opts['rev']:
2796 if opts['rev']:
2797 revs = scmutil.revrange(repo, opts['rev'])
2797 revs = scmutil.revrange(repo, opts['rev'])
2798 nodes = [repo[r].node() for r in revs]
2798 nodes = [repo[r].node() for r in revs]
2799 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2799 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2800 markers.sort(key=lambda x: x._data)
2800 markers.sort(key=lambda x: x._data)
2801 else:
2801 else:
2802 markers = obsolete.getmarkers(repo)
2802 markers = obsolete.getmarkers(repo)
2803
2803
2804 markerstoiter = markers
2804 markerstoiter = markers
2805 isrelevant = lambda m: True
2805 isrelevant = lambda m: True
2806 if opts.get('rev') and opts.get('index'):
2806 if opts.get('rev') and opts.get('index'):
2807 markerstoiter = obsolete.getmarkers(repo)
2807 markerstoiter = obsolete.getmarkers(repo)
2808 markerset = set(markers)
2808 markerset = set(markers)
2809 isrelevant = lambda m: m in markerset
2809 isrelevant = lambda m: m in markerset
2810
2810
2811 fm = ui.formatter('debugobsolete', opts)
2811 fm = ui.formatter('debugobsolete', opts)
2812 for i, m in enumerate(markerstoiter):
2812 for i, m in enumerate(markerstoiter):
2813 if not isrelevant(m):
2813 if not isrelevant(m):
2814 # marker can be irrelevant when we're iterating over a set
2814 # marker can be irrelevant when we're iterating over a set
2815 # of markers (markerstoiter) which is bigger than the set
2815 # of markers (markerstoiter) which is bigger than the set
2816 # of markers we want to display (markers)
2816 # of markers we want to display (markers)
2817 # this can happen if both --index and --rev options are
2817 # this can happen if both --index and --rev options are
2818 # provided and thus we need to iterate over all of the markers
2818 # provided and thus we need to iterate over all of the markers
2819 # to get the correct indices, but only display the ones that
2819 # to get the correct indices, but only display the ones that
2820 # are relevant to --rev value
2820 # are relevant to --rev value
2821 continue
2821 continue
2822 fm.startitem()
2822 fm.startitem()
2823 ind = i if opts.get('index') else None
2823 ind = i if opts.get('index') else None
2824 cmdutil.showmarker(fm, m, index=ind)
2824 cmdutil.showmarker(fm, m, index=ind)
2825 fm.end()
2825 fm.end()
2826
2826
2827 @command('debugpathcomplete',
2827 @command('debugpathcomplete',
2828 [('f', 'full', None, _('complete an entire path')),
2828 [('f', 'full', None, _('complete an entire path')),
2829 ('n', 'normal', None, _('show only normal files')),
2829 ('n', 'normal', None, _('show only normal files')),
2830 ('a', 'added', None, _('show only added files')),
2830 ('a', 'added', None, _('show only added files')),
2831 ('r', 'removed', None, _('show only removed files'))],
2831 ('r', 'removed', None, _('show only removed files'))],
2832 _('FILESPEC...'))
2832 _('FILESPEC...'))
2833 def debugpathcomplete(ui, repo, *specs, **opts):
2833 def debugpathcomplete(ui, repo, *specs, **opts):
2834 '''complete part or all of a tracked path
2834 '''complete part or all of a tracked path
2835
2835
2836 This command supports shells that offer path name completion. It
2836 This command supports shells that offer path name completion. It
2837 currently completes only files already known to the dirstate.
2837 currently completes only files already known to the dirstate.
2838
2838
2839 Completion extends only to the next path segment unless
2839 Completion extends only to the next path segment unless
2840 --full is specified, in which case entire paths are used.'''
2840 --full is specified, in which case entire paths are used.'''
2841
2841
2842 def complete(path, acceptable):
2842 def complete(path, acceptable):
2843 dirstate = repo.dirstate
2843 dirstate = repo.dirstate
2844 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2844 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2845 rootdir = repo.root + os.sep
2845 rootdir = repo.root + os.sep
2846 if spec != repo.root and not spec.startswith(rootdir):
2846 if spec != repo.root and not spec.startswith(rootdir):
2847 return [], []
2847 return [], []
2848 if os.path.isdir(spec):
2848 if os.path.isdir(spec):
2849 spec += '/'
2849 spec += '/'
2850 spec = spec[len(rootdir):]
2850 spec = spec[len(rootdir):]
2851 fixpaths = pycompat.ossep != '/'
2851 fixpaths = pycompat.ossep != '/'
2852 if fixpaths:
2852 if fixpaths:
2853 spec = spec.replace(os.sep, '/')
2853 spec = spec.replace(os.sep, '/')
2854 speclen = len(spec)
2854 speclen = len(spec)
2855 fullpaths = opts['full']
2855 fullpaths = opts['full']
2856 files, dirs = set(), set()
2856 files, dirs = set(), set()
2857 adddir, addfile = dirs.add, files.add
2857 adddir, addfile = dirs.add, files.add
2858 for f, st in dirstate.iteritems():
2858 for f, st in dirstate.iteritems():
2859 if f.startswith(spec) and st[0] in acceptable:
2859 if f.startswith(spec) and st[0] in acceptable:
2860 if fixpaths:
2860 if fixpaths:
2861 f = f.replace('/', os.sep)
2861 f = f.replace('/', os.sep)
2862 if fullpaths:
2862 if fullpaths:
2863 addfile(f)
2863 addfile(f)
2864 continue
2864 continue
2865 s = f.find(os.sep, speclen)
2865 s = f.find(os.sep, speclen)
2866 if s >= 0:
2866 if s >= 0:
2867 adddir(f[:s])
2867 adddir(f[:s])
2868 else:
2868 else:
2869 addfile(f)
2869 addfile(f)
2870 return files, dirs
2870 return files, dirs
2871
2871
2872 acceptable = ''
2872 acceptable = ''
2873 if opts['normal']:
2873 if opts['normal']:
2874 acceptable += 'nm'
2874 acceptable += 'nm'
2875 if opts['added']:
2875 if opts['added']:
2876 acceptable += 'a'
2876 acceptable += 'a'
2877 if opts['removed']:
2877 if opts['removed']:
2878 acceptable += 'r'
2878 acceptable += 'r'
2879 cwd = repo.getcwd()
2879 cwd = repo.getcwd()
2880 if not specs:
2880 if not specs:
2881 specs = ['.']
2881 specs = ['.']
2882
2882
2883 files, dirs = set(), set()
2883 files, dirs = set(), set()
2884 for spec in specs:
2884 for spec in specs:
2885 f, d = complete(spec, acceptable or 'nmar')
2885 f, d = complete(spec, acceptable or 'nmar')
2886 files.update(f)
2886 files.update(f)
2887 dirs.update(d)
2887 dirs.update(d)
2888 files.update(dirs)
2888 files.update(dirs)
2889 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2889 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2890 ui.write('\n')
2890 ui.write('\n')
2891
2891
2892 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2892 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2893 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2893 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2894 '''access the pushkey key/value protocol
2894 '''access the pushkey key/value protocol
2895
2895
2896 With two args, list the keys in the given namespace.
2896 With two args, list the keys in the given namespace.
2897
2897
2898 With five args, set a key to new if it currently is set to old.
2898 With five args, set a key to new if it currently is set to old.
2899 Reports success or failure.
2899 Reports success or failure.
2900 '''
2900 '''
2901
2901
2902 target = hg.peer(ui, {}, repopath)
2902 target = hg.peer(ui, {}, repopath)
2903 if keyinfo:
2903 if keyinfo:
2904 key, old, new = keyinfo
2904 key, old, new = keyinfo
2905 r = target.pushkey(namespace, key, old, new)
2905 r = target.pushkey(namespace, key, old, new)
2906 ui.status(str(r) + '\n')
2906 ui.status(str(r) + '\n')
2907 return not r
2907 return not r
2908 else:
2908 else:
2909 for k, v in sorted(target.listkeys(namespace).iteritems()):
2909 for k, v in sorted(target.listkeys(namespace).iteritems()):
2910 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2910 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2911 v.encode('string-escape')))
2911 v.encode('string-escape')))
2912
2912
2913 @command('debugpvec', [], _('A B'))
2913 @command('debugpvec', [], _('A B'))
2914 def debugpvec(ui, repo, a, b=None):
2914 def debugpvec(ui, repo, a, b=None):
2915 ca = scmutil.revsingle(repo, a)
2915 ca = scmutil.revsingle(repo, a)
2916 cb = scmutil.revsingle(repo, b)
2916 cb = scmutil.revsingle(repo, b)
2917 pa = pvec.ctxpvec(ca)
2917 pa = pvec.ctxpvec(ca)
2918 pb = pvec.ctxpvec(cb)
2918 pb = pvec.ctxpvec(cb)
2919 if pa == pb:
2919 if pa == pb:
2920 rel = "="
2920 rel = "="
2921 elif pa > pb:
2921 elif pa > pb:
2922 rel = ">"
2922 rel = ">"
2923 elif pa < pb:
2923 elif pa < pb:
2924 rel = "<"
2924 rel = "<"
2925 elif pa | pb:
2925 elif pa | pb:
2926 rel = "|"
2926 rel = "|"
2927 ui.write(_("a: %s\n") % pa)
2927 ui.write(_("a: %s\n") % pa)
2928 ui.write(_("b: %s\n") % pb)
2928 ui.write(_("b: %s\n") % pb)
2929 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2929 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2930 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2930 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2931 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2931 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2932 pa.distance(pb), rel))
2932 pa.distance(pb), rel))
2933
2933
2934 @command('debugrebuilddirstate|debugrebuildstate',
2934 @command('debugrebuilddirstate|debugrebuildstate',
2935 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2935 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2936 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2936 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2937 'the working copy parent')),
2937 'the working copy parent')),
2938 ],
2938 ],
2939 _('[-r REV]'))
2939 _('[-r REV]'))
2940 def debugrebuilddirstate(ui, repo, rev, **opts):
2940 def debugrebuilddirstate(ui, repo, rev, **opts):
2941 """rebuild the dirstate as it would look like for the given revision
2941 """rebuild the dirstate as it would look like for the given revision
2942
2942
2943 If no revision is specified the first current parent will be used.
2943 If no revision is specified the first current parent will be used.
2944
2944
2945 The dirstate will be set to the files of the given revision.
2945 The dirstate will be set to the files of the given revision.
2946 The actual working directory content or existing dirstate
2946 The actual working directory content or existing dirstate
2947 information such as adds or removes is not considered.
2947 information such as adds or removes is not considered.
2948
2948
2949 ``minimal`` will only rebuild the dirstate status for files that claim to be
2949 ``minimal`` will only rebuild the dirstate status for files that claim to be
2950 tracked but are not in the parent manifest, or that exist in the parent
2950 tracked but are not in the parent manifest, or that exist in the parent
2951 manifest but are not in the dirstate. It will not change adds, removes, or
2951 manifest but are not in the dirstate. It will not change adds, removes, or
2952 modified files that are in the working copy parent.
2952 modified files that are in the working copy parent.
2953
2953
2954 One use of this command is to make the next :hg:`status` invocation
2954 One use of this command is to make the next :hg:`status` invocation
2955 check the actual file content.
2955 check the actual file content.
2956 """
2956 """
2957 ctx = scmutil.revsingle(repo, rev)
2957 ctx = scmutil.revsingle(repo, rev)
2958 with repo.wlock():
2958 with repo.wlock():
2959 dirstate = repo.dirstate
2959 dirstate = repo.dirstate
2960 changedfiles = None
2960 changedfiles = None
2961 # See command doc for what minimal does.
2961 # See command doc for what minimal does.
2962 if opts.get('minimal'):
2962 if opts.get('minimal'):
2963 manifestfiles = set(ctx.manifest().keys())
2963 manifestfiles = set(ctx.manifest().keys())
2964 dirstatefiles = set(dirstate)
2964 dirstatefiles = set(dirstate)
2965 manifestonly = manifestfiles - dirstatefiles
2965 manifestonly = manifestfiles - dirstatefiles
2966 dsonly = dirstatefiles - manifestfiles
2966 dsonly = dirstatefiles - manifestfiles
2967 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
2967 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
2968 changedfiles = manifestonly | dsnotadded
2968 changedfiles = manifestonly | dsnotadded
2969
2969
2970 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2970 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2971
2971
2972 @command('debugrebuildfncache', [], '')
2972 @command('debugrebuildfncache', [], '')
2973 def debugrebuildfncache(ui, repo):
2973 def debugrebuildfncache(ui, repo):
2974 """rebuild the fncache file"""
2974 """rebuild the fncache file"""
2975 repair.rebuildfncache(ui, repo)
2975 repair.rebuildfncache(ui, repo)
2976
2976
2977 @command('debugrename',
2977 @command('debugrename',
2978 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2978 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2979 _('[-r REV] FILE'))
2979 _('[-r REV] FILE'))
2980 def debugrename(ui, repo, file1, *pats, **opts):
2980 def debugrename(ui, repo, file1, *pats, **opts):
2981 """dump rename information"""
2981 """dump rename information"""
2982
2982
2983 ctx = scmutil.revsingle(repo, opts.get('rev'))
2983 ctx = scmutil.revsingle(repo, opts.get('rev'))
2984 m = scmutil.match(ctx, (file1,) + pats, opts)
2984 m = scmutil.match(ctx, (file1,) + pats, opts)
2985 for abs in ctx.walk(m):
2985 for abs in ctx.walk(m):
2986 fctx = ctx[abs]
2986 fctx = ctx[abs]
2987 o = fctx.filelog().renamed(fctx.filenode())
2987 o = fctx.filelog().renamed(fctx.filenode())
2988 rel = m.rel(abs)
2988 rel = m.rel(abs)
2989 if o:
2989 if o:
2990 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2990 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2991 else:
2991 else:
2992 ui.write(_("%s not renamed\n") % rel)
2992 ui.write(_("%s not renamed\n") % rel)
2993
2993
2994 @command('debugrevlog', debugrevlogopts +
2994 @command('debugrevlog', debugrevlogopts +
2995 [('d', 'dump', False, _('dump index data'))],
2995 [('d', 'dump', False, _('dump index data'))],
2996 _('-c|-m|FILE'),
2996 _('-c|-m|FILE'),
2997 optionalrepo=True)
2997 optionalrepo=True)
2998 def debugrevlog(ui, repo, file_=None, **opts):
2998 def debugrevlog(ui, repo, file_=None, **opts):
2999 """show data and statistics about a revlog"""
2999 """show data and statistics about a revlog"""
3000 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3000 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3001
3001
3002 if opts.get("dump"):
3002 if opts.get("dump"):
3003 numrevs = len(r)
3003 numrevs = len(r)
3004 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3004 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3005 " rawsize totalsize compression heads chainlen\n"))
3005 " rawsize totalsize compression heads chainlen\n"))
3006 ts = 0
3006 ts = 0
3007 heads = set()
3007 heads = set()
3008
3008
3009 for rev in xrange(numrevs):
3009 for rev in xrange(numrevs):
3010 dbase = r.deltaparent(rev)
3010 dbase = r.deltaparent(rev)
3011 if dbase == -1:
3011 if dbase == -1:
3012 dbase = rev
3012 dbase = rev
3013 cbase = r.chainbase(rev)
3013 cbase = r.chainbase(rev)
3014 clen = r.chainlen(rev)
3014 clen = r.chainlen(rev)
3015 p1, p2 = r.parentrevs(rev)
3015 p1, p2 = r.parentrevs(rev)
3016 rs = r.rawsize(rev)
3016 rs = r.rawsize(rev)
3017 ts = ts + rs
3017 ts = ts + rs
3018 heads -= set(r.parentrevs(rev))
3018 heads -= set(r.parentrevs(rev))
3019 heads.add(rev)
3019 heads.add(rev)
3020 try:
3020 try:
3021 compression = ts / r.end(rev)
3021 compression = ts / r.end(rev)
3022 except ZeroDivisionError:
3022 except ZeroDivisionError:
3023 compression = 0
3023 compression = 0
3024 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3024 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3025 "%11d %5d %8d\n" %
3025 "%11d %5d %8d\n" %
3026 (rev, p1, p2, r.start(rev), r.end(rev),
3026 (rev, p1, p2, r.start(rev), r.end(rev),
3027 r.start(dbase), r.start(cbase),
3027 r.start(dbase), r.start(cbase),
3028 r.start(p1), r.start(p2),
3028 r.start(p1), r.start(p2),
3029 rs, ts, compression, len(heads), clen))
3029 rs, ts, compression, len(heads), clen))
3030 return 0
3030 return 0
3031
3031
3032 v = r.version
3032 v = r.version
3033 format = v & 0xFFFF
3033 format = v & 0xFFFF
3034 flags = []
3034 flags = []
3035 gdelta = False
3035 gdelta = False
3036 if v & revlog.REVLOGNGINLINEDATA:
3036 if v & revlog.REVLOGNGINLINEDATA:
3037 flags.append('inline')
3037 flags.append('inline')
3038 if v & revlog.REVLOGGENERALDELTA:
3038 if v & revlog.REVLOGGENERALDELTA:
3039 gdelta = True
3039 gdelta = True
3040 flags.append('generaldelta')
3040 flags.append('generaldelta')
3041 if not flags:
3041 if not flags:
3042 flags = ['(none)']
3042 flags = ['(none)']
3043
3043
3044 nummerges = 0
3044 nummerges = 0
3045 numfull = 0
3045 numfull = 0
3046 numprev = 0
3046 numprev = 0
3047 nump1 = 0
3047 nump1 = 0
3048 nump2 = 0
3048 nump2 = 0
3049 numother = 0
3049 numother = 0
3050 nump1prev = 0
3050 nump1prev = 0
3051 nump2prev = 0
3051 nump2prev = 0
3052 chainlengths = []
3052 chainlengths = []
3053
3053
3054 datasize = [None, 0, 0]
3054 datasize = [None, 0, 0]
3055 fullsize = [None, 0, 0]
3055 fullsize = [None, 0, 0]
3056 deltasize = [None, 0, 0]
3056 deltasize = [None, 0, 0]
3057 chunktypecounts = {}
3057 chunktypecounts = {}
3058 chunktypesizes = {}
3058 chunktypesizes = {}
3059
3059
3060 def addsize(size, l):
3060 def addsize(size, l):
3061 if l[0] is None or size < l[0]:
3061 if l[0] is None or size < l[0]:
3062 l[0] = size
3062 l[0] = size
3063 if size > l[1]:
3063 if size > l[1]:
3064 l[1] = size
3064 l[1] = size
3065 l[2] += size
3065 l[2] += size
3066
3066
3067 numrevs = len(r)
3067 numrevs = len(r)
3068 for rev in xrange(numrevs):
3068 for rev in xrange(numrevs):
3069 p1, p2 = r.parentrevs(rev)
3069 p1, p2 = r.parentrevs(rev)
3070 delta = r.deltaparent(rev)
3070 delta = r.deltaparent(rev)
3071 if format > 0:
3071 if format > 0:
3072 addsize(r.rawsize(rev), datasize)
3072 addsize(r.rawsize(rev), datasize)
3073 if p2 != nullrev:
3073 if p2 != nullrev:
3074 nummerges += 1
3074 nummerges += 1
3075 size = r.length(rev)
3075 size = r.length(rev)
3076 if delta == nullrev:
3076 if delta == nullrev:
3077 chainlengths.append(0)
3077 chainlengths.append(0)
3078 numfull += 1
3078 numfull += 1
3079 addsize(size, fullsize)
3079 addsize(size, fullsize)
3080 else:
3080 else:
3081 chainlengths.append(chainlengths[delta] + 1)
3081 chainlengths.append(chainlengths[delta] + 1)
3082 addsize(size, deltasize)
3082 addsize(size, deltasize)
3083 if delta == rev - 1:
3083 if delta == rev - 1:
3084 numprev += 1
3084 numprev += 1
3085 if delta == p1:
3085 if delta == p1:
3086 nump1prev += 1
3086 nump1prev += 1
3087 elif delta == p2:
3087 elif delta == p2:
3088 nump2prev += 1
3088 nump2prev += 1
3089 elif delta == p1:
3089 elif delta == p1:
3090 nump1 += 1
3090 nump1 += 1
3091 elif delta == p2:
3091 elif delta == p2:
3092 nump2 += 1
3092 nump2 += 1
3093 elif delta != nullrev:
3093 elif delta != nullrev:
3094 numother += 1
3094 numother += 1
3095
3095
3096 # Obtain data on the raw chunks in the revlog.
3096 # Obtain data on the raw chunks in the revlog.
3097 chunk = r._chunkraw(rev, rev)[1]
3097 chunk = r._chunkraw(rev, rev)[1]
3098 if chunk:
3098 if chunk:
3099 chunktype = chunk[0]
3099 chunktype = chunk[0]
3100 else:
3100 else:
3101 chunktype = 'empty'
3101 chunktype = 'empty'
3102
3102
3103 if chunktype not in chunktypecounts:
3103 if chunktype not in chunktypecounts:
3104 chunktypecounts[chunktype] = 0
3104 chunktypecounts[chunktype] = 0
3105 chunktypesizes[chunktype] = 0
3105 chunktypesizes[chunktype] = 0
3106
3106
3107 chunktypecounts[chunktype] += 1
3107 chunktypecounts[chunktype] += 1
3108 chunktypesizes[chunktype] += size
3108 chunktypesizes[chunktype] += size
3109
3109
3110 # Adjust size min value for empty cases
3110 # Adjust size min value for empty cases
3111 for size in (datasize, fullsize, deltasize):
3111 for size in (datasize, fullsize, deltasize):
3112 if size[0] is None:
3112 if size[0] is None:
3113 size[0] = 0
3113 size[0] = 0
3114
3114
3115 numdeltas = numrevs - numfull
3115 numdeltas = numrevs - numfull
3116 numoprev = numprev - nump1prev - nump2prev
3116 numoprev = numprev - nump1prev - nump2prev
3117 totalrawsize = datasize[2]
3117 totalrawsize = datasize[2]
3118 datasize[2] /= numrevs
3118 datasize[2] /= numrevs
3119 fulltotal = fullsize[2]
3119 fulltotal = fullsize[2]
3120 fullsize[2] /= numfull
3120 fullsize[2] /= numfull
3121 deltatotal = deltasize[2]
3121 deltatotal = deltasize[2]
3122 if numrevs - numfull > 0:
3122 if numrevs - numfull > 0:
3123 deltasize[2] /= numrevs - numfull
3123 deltasize[2] /= numrevs - numfull
3124 totalsize = fulltotal + deltatotal
3124 totalsize = fulltotal + deltatotal
3125 avgchainlen = sum(chainlengths) / numrevs
3125 avgchainlen = sum(chainlengths) / numrevs
3126 maxchainlen = max(chainlengths)
3126 maxchainlen = max(chainlengths)
3127 compratio = 1
3127 compratio = 1
3128 if totalsize:
3128 if totalsize:
3129 compratio = totalrawsize / totalsize
3129 compratio = totalrawsize / totalsize
3130
3130
3131 basedfmtstr = '%%%dd\n'
3131 basedfmtstr = '%%%dd\n'
3132 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3132 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3133
3133
3134 def dfmtstr(max):
3134 def dfmtstr(max):
3135 return basedfmtstr % len(str(max))
3135 return basedfmtstr % len(str(max))
3136 def pcfmtstr(max, padding=0):
3136 def pcfmtstr(max, padding=0):
3137 return basepcfmtstr % (len(str(max)), ' ' * padding)
3137 return basepcfmtstr % (len(str(max)), ' ' * padding)
3138
3138
3139 def pcfmt(value, total):
3139 def pcfmt(value, total):
3140 if total:
3140 if total:
3141 return (value, 100 * float(value) / total)
3141 return (value, 100 * float(value) / total)
3142 else:
3142 else:
3143 return value, 100.0
3143 return value, 100.0
3144
3144
3145 ui.write(('format : %d\n') % format)
3145 ui.write(('format : %d\n') % format)
3146 ui.write(('flags : %s\n') % ', '.join(flags))
3146 ui.write(('flags : %s\n') % ', '.join(flags))
3147
3147
3148 ui.write('\n')
3148 ui.write('\n')
3149 fmt = pcfmtstr(totalsize)
3149 fmt = pcfmtstr(totalsize)
3150 fmt2 = dfmtstr(totalsize)
3150 fmt2 = dfmtstr(totalsize)
3151 ui.write(('revisions : ') + fmt2 % numrevs)
3151 ui.write(('revisions : ') + fmt2 % numrevs)
3152 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3152 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3153 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3153 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3154 ui.write(('revisions : ') + fmt2 % numrevs)
3154 ui.write(('revisions : ') + fmt2 % numrevs)
3155 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3155 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3156 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3156 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3157 ui.write(('revision size : ') + fmt2 % totalsize)
3157 ui.write(('revision size : ') + fmt2 % totalsize)
3158 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3158 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3159 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3159 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3160
3160
3161 def fmtchunktype(chunktype):
3161 def fmtchunktype(chunktype):
3162 if chunktype == 'empty':
3162 if chunktype == 'empty':
3163 return ' %s : ' % chunktype
3163 return ' %s : ' % chunktype
3164 elif chunktype in string.ascii_letters:
3164 elif chunktype in string.ascii_letters:
3165 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
3165 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
3166 else:
3166 else:
3167 return ' 0x%s : ' % hex(chunktype)
3167 return ' 0x%s : ' % hex(chunktype)
3168
3168
3169 ui.write('\n')
3169 ui.write('\n')
3170 ui.write(('chunks : ') + fmt2 % numrevs)
3170 ui.write(('chunks : ') + fmt2 % numrevs)
3171 for chunktype in sorted(chunktypecounts):
3171 for chunktype in sorted(chunktypecounts):
3172 ui.write(fmtchunktype(chunktype))
3172 ui.write(fmtchunktype(chunktype))
3173 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
3173 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
3174 ui.write(('chunks size : ') + fmt2 % totalsize)
3174 ui.write(('chunks size : ') + fmt2 % totalsize)
3175 for chunktype in sorted(chunktypecounts):
3175 for chunktype in sorted(chunktypecounts):
3176 ui.write(fmtchunktype(chunktype))
3176 ui.write(fmtchunktype(chunktype))
3177 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
3177 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
3178
3178
3179 ui.write('\n')
3179 ui.write('\n')
3180 fmt = dfmtstr(max(avgchainlen, compratio))
3180 fmt = dfmtstr(max(avgchainlen, compratio))
3181 ui.write(('avg chain length : ') + fmt % avgchainlen)
3181 ui.write(('avg chain length : ') + fmt % avgchainlen)
3182 ui.write(('max chain length : ') + fmt % maxchainlen)
3182 ui.write(('max chain length : ') + fmt % maxchainlen)
3183 ui.write(('compression ratio : ') + fmt % compratio)
3183 ui.write(('compression ratio : ') + fmt % compratio)
3184
3184
3185 if format > 0:
3185 if format > 0:
3186 ui.write('\n')
3186 ui.write('\n')
3187 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3187 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3188 % tuple(datasize))
3188 % tuple(datasize))
3189 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3189 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3190 % tuple(fullsize))
3190 % tuple(fullsize))
3191 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3191 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3192 % tuple(deltasize))
3192 % tuple(deltasize))
3193
3193
3194 if numdeltas > 0:
3194 if numdeltas > 0:
3195 ui.write('\n')
3195 ui.write('\n')
3196 fmt = pcfmtstr(numdeltas)
3196 fmt = pcfmtstr(numdeltas)
3197 fmt2 = pcfmtstr(numdeltas, 4)
3197 fmt2 = pcfmtstr(numdeltas, 4)
3198 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3198 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3199 if numprev > 0:
3199 if numprev > 0:
3200 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3200 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3201 numprev))
3201 numprev))
3202 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3202 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3203 numprev))
3203 numprev))
3204 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3204 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3205 numprev))
3205 numprev))
3206 if gdelta:
3206 if gdelta:
3207 ui.write(('deltas against p1 : ')
3207 ui.write(('deltas against p1 : ')
3208 + fmt % pcfmt(nump1, numdeltas))
3208 + fmt % pcfmt(nump1, numdeltas))
3209 ui.write(('deltas against p2 : ')
3209 ui.write(('deltas against p2 : ')
3210 + fmt % pcfmt(nump2, numdeltas))
3210 + fmt % pcfmt(nump2, numdeltas))
3211 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3211 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3212 numdeltas))
3212 numdeltas))
3213
3213
3214 @command('debugrevspec',
3214 @command('debugrevspec',
3215 [('', 'optimize', None,
3215 [('', 'optimize', None,
3216 _('print parsed tree after optimizing (DEPRECATED)')),
3216 _('print parsed tree after optimizing (DEPRECATED)')),
3217 ('p', 'show-stage', [],
3217 ('p', 'show-stage', [],
3218 _('print parsed tree at the given stage'), _('NAME')),
3218 _('print parsed tree at the given stage'), _('NAME')),
3219 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3219 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3220 ('', 'verify-optimized', False, _('verify optimized result')),
3220 ('', 'verify-optimized', False, _('verify optimized result')),
3221 ],
3221 ],
3222 ('REVSPEC'))
3222 ('REVSPEC'))
3223 def debugrevspec(ui, repo, expr, **opts):
3223 def debugrevspec(ui, repo, expr, **opts):
3224 """parse and apply a revision specification
3224 """parse and apply a revision specification
3225
3225
3226 Use -p/--show-stage option to print the parsed tree at the given stages.
3226 Use -p/--show-stage option to print the parsed tree at the given stages.
3227 Use -p all to print tree at every stage.
3227 Use -p all to print tree at every stage.
3228
3228
3229 Use --verify-optimized to compare the optimized result with the unoptimized
3229 Use --verify-optimized to compare the optimized result with the unoptimized
3230 one. Returns 1 if the optimized result differs.
3230 one. Returns 1 if the optimized result differs.
3231 """
3231 """
3232 stages = [
3232 stages = [
3233 ('parsed', lambda tree: tree),
3233 ('parsed', lambda tree: tree),
3234 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3234 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3235 ('concatenated', revset.foldconcat),
3235 ('concatenated', revset.foldconcat),
3236 ('analyzed', revset.analyze),
3236 ('analyzed', revset.analyze),
3237 ('optimized', revset.optimize),
3237 ('optimized', revset.optimize),
3238 ]
3238 ]
3239 if opts['no_optimized']:
3239 if opts['no_optimized']:
3240 stages = stages[:-1]
3240 stages = stages[:-1]
3241 if opts['verify_optimized'] and opts['no_optimized']:
3241 if opts['verify_optimized'] and opts['no_optimized']:
3242 raise error.Abort(_('cannot use --verify-optimized with '
3242 raise error.Abort(_('cannot use --verify-optimized with '
3243 '--no-optimized'))
3243 '--no-optimized'))
3244 stagenames = set(n for n, f in stages)
3244 stagenames = set(n for n, f in stages)
3245
3245
3246 showalways = set()
3246 showalways = set()
3247 showchanged = set()
3247 showchanged = set()
3248 if ui.verbose and not opts['show_stage']:
3248 if ui.verbose and not opts['show_stage']:
3249 # show parsed tree by --verbose (deprecated)
3249 # show parsed tree by --verbose (deprecated)
3250 showalways.add('parsed')
3250 showalways.add('parsed')
3251 showchanged.update(['expanded', 'concatenated'])
3251 showchanged.update(['expanded', 'concatenated'])
3252 if opts['optimize']:
3252 if opts['optimize']:
3253 showalways.add('optimized')
3253 showalways.add('optimized')
3254 if opts['show_stage'] and opts['optimize']:
3254 if opts['show_stage'] and opts['optimize']:
3255 raise error.Abort(_('cannot use --optimize with --show-stage'))
3255 raise error.Abort(_('cannot use --optimize with --show-stage'))
3256 if opts['show_stage'] == ['all']:
3256 if opts['show_stage'] == ['all']:
3257 showalways.update(stagenames)
3257 showalways.update(stagenames)
3258 else:
3258 else:
3259 for n in opts['show_stage']:
3259 for n in opts['show_stage']:
3260 if n not in stagenames:
3260 if n not in stagenames:
3261 raise error.Abort(_('invalid stage name: %s') % n)
3261 raise error.Abort(_('invalid stage name: %s') % n)
3262 showalways.update(opts['show_stage'])
3262 showalways.update(opts['show_stage'])
3263
3263
3264 treebystage = {}
3264 treebystage = {}
3265 printedtree = None
3265 printedtree = None
3266 tree = revset.parse(expr, lookup=repo.__contains__)
3266 tree = revset.parse(expr, lookup=repo.__contains__)
3267 for n, f in stages:
3267 for n, f in stages:
3268 treebystage[n] = tree = f(tree)
3268 treebystage[n] = tree = f(tree)
3269 if n in showalways or (n in showchanged and tree != printedtree):
3269 if n in showalways or (n in showchanged and tree != printedtree):
3270 if opts['show_stage'] or n != 'parsed':
3270 if opts['show_stage'] or n != 'parsed':
3271 ui.write(("* %s:\n") % n)
3271 ui.write(("* %s:\n") % n)
3272 ui.write(revset.prettyformat(tree), "\n")
3272 ui.write(revset.prettyformat(tree), "\n")
3273 printedtree = tree
3273 printedtree = tree
3274
3274
3275 if opts['verify_optimized']:
3275 if opts['verify_optimized']:
3276 arevs = revset.makematcher(treebystage['analyzed'])(repo)
3276 arevs = revset.makematcher(treebystage['analyzed'])(repo)
3277 brevs = revset.makematcher(treebystage['optimized'])(repo)
3277 brevs = revset.makematcher(treebystage['optimized'])(repo)
3278 if ui.verbose:
3278 if ui.verbose:
3279 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
3279 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
3280 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
3280 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
3281 arevs = list(arevs)
3281 arevs = list(arevs)
3282 brevs = list(brevs)
3282 brevs = list(brevs)
3283 if arevs == brevs:
3283 if arevs == brevs:
3284 return 0
3284 return 0
3285 ui.write(('--- analyzed\n'), label='diff.file_a')
3285 ui.write(('--- analyzed\n'), label='diff.file_a')
3286 ui.write(('+++ optimized\n'), label='diff.file_b')
3286 ui.write(('+++ optimized\n'), label='diff.file_b')
3287 sm = difflib.SequenceMatcher(None, arevs, brevs)
3287 sm = difflib.SequenceMatcher(None, arevs, brevs)
3288 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3288 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3289 if tag in ('delete', 'replace'):
3289 if tag in ('delete', 'replace'):
3290 for c in arevs[alo:ahi]:
3290 for c in arevs[alo:ahi]:
3291 ui.write('-%s\n' % c, label='diff.deleted')
3291 ui.write('-%s\n' % c, label='diff.deleted')
3292 if tag in ('insert', 'replace'):
3292 if tag in ('insert', 'replace'):
3293 for c in brevs[blo:bhi]:
3293 for c in brevs[blo:bhi]:
3294 ui.write('+%s\n' % c, label='diff.inserted')
3294 ui.write('+%s\n' % c, label='diff.inserted')
3295 if tag == 'equal':
3295 if tag == 'equal':
3296 for c in arevs[alo:ahi]:
3296 for c in arevs[alo:ahi]:
3297 ui.write(' %s\n' % c)
3297 ui.write(' %s\n' % c)
3298 return 1
3298 return 1
3299
3299
3300 func = revset.makematcher(tree)
3300 func = revset.makematcher(tree)
3301 revs = func(repo)
3301 revs = func(repo)
3302 if ui.verbose:
3302 if ui.verbose:
3303 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3303 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3304 for c in revs:
3304 for c in revs:
3305 ui.write("%s\n" % c)
3305 ui.write("%s\n" % c)
3306
3306
3307 @command('debugsetparents', [], _('REV1 [REV2]'))
3307 @command('debugsetparents', [], _('REV1 [REV2]'))
3308 def debugsetparents(ui, repo, rev1, rev2=None):
3308 def debugsetparents(ui, repo, rev1, rev2=None):
3309 """manually set the parents of the current working directory
3309 """manually set the parents of the current working directory
3310
3310
3311 This is useful for writing repository conversion tools, but should
3311 This is useful for writing repository conversion tools, but should
3312 be used with care. For example, neither the working directory nor the
3312 be used with care. For example, neither the working directory nor the
3313 dirstate is updated, so file status may be incorrect after running this
3313 dirstate is updated, so file status may be incorrect after running this
3314 command.
3314 command.
3315
3315
3316 Returns 0 on success.
3316 Returns 0 on success.
3317 """
3317 """
3318
3318
3319 r1 = scmutil.revsingle(repo, rev1).node()
3319 r1 = scmutil.revsingle(repo, rev1).node()
3320 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3320 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3321
3321
3322 with repo.wlock():
3322 with repo.wlock():
3323 repo.setparents(r1, r2)
3323 repo.setparents(r1, r2)
3324
3324
3325 @command('debugdirstate|debugstate',
3325 @command('debugdirstate|debugstate',
3326 [('', 'nodates', None, _('do not display the saved mtime')),
3326 [('', 'nodates', None, _('do not display the saved mtime')),
3327 ('', 'datesort', None, _('sort by saved mtime'))],
3327 ('', 'datesort', None, _('sort by saved mtime'))],
3328 _('[OPTION]...'))
3328 _('[OPTION]...'))
3329 def debugstate(ui, repo, **opts):
3329 def debugstate(ui, repo, **opts):
3330 """show the contents of the current dirstate"""
3330 """show the contents of the current dirstate"""
3331
3331
3332 nodates = opts.get('nodates')
3332 nodates = opts.get('nodates')
3333 datesort = opts.get('datesort')
3333 datesort = opts.get('datesort')
3334
3334
3335 timestr = ""
3335 timestr = ""
3336 if datesort:
3336 if datesort:
3337 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3337 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3338 else:
3338 else:
3339 keyfunc = None # sort by filename
3339 keyfunc = None # sort by filename
3340 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3340 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3341 if ent[3] == -1:
3341 if ent[3] == -1:
3342 timestr = 'unset '
3342 timestr = 'unset '
3343 elif nodates:
3343 elif nodates:
3344 timestr = 'set '
3344 timestr = 'set '
3345 else:
3345 else:
3346 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3346 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3347 time.localtime(ent[3]))
3347 time.localtime(ent[3]))
3348 if ent[1] & 0o20000:
3348 if ent[1] & 0o20000:
3349 mode = 'lnk'
3349 mode = 'lnk'
3350 else:
3350 else:
3351 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3351 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3352 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3352 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3353 for f in repo.dirstate.copies():
3353 for f in repo.dirstate.copies():
3354 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3354 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3355
3355
3356 @command('debugsub',
3356 @command('debugsub',
3357 [('r', 'rev', '',
3357 [('r', 'rev', '',
3358 _('revision to check'), _('REV'))],
3358 _('revision to check'), _('REV'))],
3359 _('[-r REV] [REV]'))
3359 _('[-r REV] [REV]'))
3360 def debugsub(ui, repo, rev=None):
3360 def debugsub(ui, repo, rev=None):
3361 ctx = scmutil.revsingle(repo, rev, None)
3361 ctx = scmutil.revsingle(repo, rev, None)
3362 for k, v in sorted(ctx.substate.items()):
3362 for k, v in sorted(ctx.substate.items()):
3363 ui.write(('path %s\n') % k)
3363 ui.write(('path %s\n') % k)
3364 ui.write((' source %s\n') % v[0])
3364 ui.write((' source %s\n') % v[0])
3365 ui.write((' revision %s\n') % v[1])
3365 ui.write((' revision %s\n') % v[1])
3366
3366
3367 @command('debugsuccessorssets',
3367 @command('debugsuccessorssets',
3368 [],
3368 [],
3369 _('[REV]'))
3369 _('[REV]'))
3370 def debugsuccessorssets(ui, repo, *revs):
3370 def debugsuccessorssets(ui, repo, *revs):
3371 """show set of successors for revision
3371 """show set of successors for revision
3372
3372
3373 A successors set of changeset A is a consistent group of revisions that
3373 A successors set of changeset A is a consistent group of revisions that
3374 succeed A. It contains non-obsolete changesets only.
3374 succeed A. It contains non-obsolete changesets only.
3375
3375
3376 In most cases a changeset A has a single successors set containing a single
3376 In most cases a changeset A has a single successors set containing a single
3377 successor (changeset A replaced by A').
3377 successor (changeset A replaced by A').
3378
3378
3379 A changeset that is made obsolete with no successors are called "pruned".
3379 A changeset that is made obsolete with no successors are called "pruned".
3380 Such changesets have no successors sets at all.
3380 Such changesets have no successors sets at all.
3381
3381
3382 A changeset that has been "split" will have a successors set containing
3382 A changeset that has been "split" will have a successors set containing
3383 more than one successor.
3383 more than one successor.
3384
3384
3385 A changeset that has been rewritten in multiple different ways is called
3385 A changeset that has been rewritten in multiple different ways is called
3386 "divergent". Such changesets have multiple successor sets (each of which
3386 "divergent". Such changesets have multiple successor sets (each of which
3387 may also be split, i.e. have multiple successors).
3387 may also be split, i.e. have multiple successors).
3388
3388
3389 Results are displayed as follows::
3389 Results are displayed as follows::
3390
3390
3391 <rev1>
3391 <rev1>
3392 <successors-1A>
3392 <successors-1A>
3393 <rev2>
3393 <rev2>
3394 <successors-2A>
3394 <successors-2A>
3395 <successors-2B1> <successors-2B2> <successors-2B3>
3395 <successors-2B1> <successors-2B2> <successors-2B3>
3396
3396
3397 Here rev2 has two possible (i.e. divergent) successors sets. The first
3397 Here rev2 has two possible (i.e. divergent) successors sets. The first
3398 holds one element, whereas the second holds three (i.e. the changeset has
3398 holds one element, whereas the second holds three (i.e. the changeset has
3399 been split).
3399 been split).
3400 """
3400 """
3401 # passed to successorssets caching computation from one call to another
3401 # passed to successorssets caching computation from one call to another
3402 cache = {}
3402 cache = {}
3403 ctx2str = str
3403 ctx2str = str
3404 node2str = short
3404 node2str = short
3405 if ui.debug():
3405 if ui.debug():
3406 def ctx2str(ctx):
3406 def ctx2str(ctx):
3407 return ctx.hex()
3407 return ctx.hex()
3408 node2str = hex
3408 node2str = hex
3409 for rev in scmutil.revrange(repo, revs):
3409 for rev in scmutil.revrange(repo, revs):
3410 ctx = repo[rev]
3410 ctx = repo[rev]
3411 ui.write('%s\n'% ctx2str(ctx))
3411 ui.write('%s\n'% ctx2str(ctx))
3412 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3412 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3413 if succsset:
3413 if succsset:
3414 ui.write(' ')
3414 ui.write(' ')
3415 ui.write(node2str(succsset[0]))
3415 ui.write(node2str(succsset[0]))
3416 for node in succsset[1:]:
3416 for node in succsset[1:]:
3417 ui.write(' ')
3417 ui.write(' ')
3418 ui.write(node2str(node))
3418 ui.write(node2str(node))
3419 ui.write('\n')
3419 ui.write('\n')
3420
3420
3421 @command('debugtemplate',
3421 @command('debugtemplate',
3422 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3422 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3423 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3423 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3424 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3424 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3425 optionalrepo=True)
3425 optionalrepo=True)
3426 def debugtemplate(ui, repo, tmpl, **opts):
3426 def debugtemplate(ui, repo, tmpl, **opts):
3427 """parse and apply a template
3427 """parse and apply a template
3428
3428
3429 If -r/--rev is given, the template is processed as a log template and
3429 If -r/--rev is given, the template is processed as a log template and
3430 applied to the given changesets. Otherwise, it is processed as a generic
3430 applied to the given changesets. Otherwise, it is processed as a generic
3431 template.
3431 template.
3432
3432
3433 Use --verbose to print the parsed tree.
3433 Use --verbose to print the parsed tree.
3434 """
3434 """
3435 revs = None
3435 revs = None
3436 if opts['rev']:
3436 if opts['rev']:
3437 if repo is None:
3437 if repo is None:
3438 raise error.RepoError(_('there is no Mercurial repository here '
3438 raise error.RepoError(_('there is no Mercurial repository here '
3439 '(.hg not found)'))
3439 '(.hg not found)'))
3440 revs = scmutil.revrange(repo, opts['rev'])
3440 revs = scmutil.revrange(repo, opts['rev'])
3441
3441
3442 props = {}
3442 props = {}
3443 for d in opts['define']:
3443 for d in opts['define']:
3444 try:
3444 try:
3445 k, v = (e.strip() for e in d.split('=', 1))
3445 k, v = (e.strip() for e in d.split('=', 1))
3446 if not k:
3446 if not k:
3447 raise ValueError
3447 raise ValueError
3448 props[k] = v
3448 props[k] = v
3449 except ValueError:
3449 except ValueError:
3450 raise error.Abort(_('malformed keyword definition: %s') % d)
3450 raise error.Abort(_('malformed keyword definition: %s') % d)
3451
3451
3452 if ui.verbose:
3452 if ui.verbose:
3453 aliases = ui.configitems('templatealias')
3453 aliases = ui.configitems('templatealias')
3454 tree = templater.parse(tmpl)
3454 tree = templater.parse(tmpl)
3455 ui.note(templater.prettyformat(tree), '\n')
3455 ui.note(templater.prettyformat(tree), '\n')
3456 newtree = templater.expandaliases(tree, aliases)
3456 newtree = templater.expandaliases(tree, aliases)
3457 if newtree != tree:
3457 if newtree != tree:
3458 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3458 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3459
3459
3460 mapfile = None
3460 mapfile = None
3461 if revs is None:
3461 if revs is None:
3462 k = 'debugtemplate'
3462 k = 'debugtemplate'
3463 t = formatter.maketemplater(ui, k, tmpl)
3463 t = formatter.maketemplater(ui, k, tmpl)
3464 ui.write(templater.stringify(t(k, **props)))
3464 ui.write(templater.stringify(t(k, **props)))
3465 else:
3465 else:
3466 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3466 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3467 mapfile, buffered=False)
3467 mapfile, buffered=False)
3468 for r in revs:
3468 for r in revs:
3469 displayer.show(repo[r], **props)
3469 displayer.show(repo[r], **props)
3470 displayer.close()
3470 displayer.close()
3471
3471
3472 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3472 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3473 def debugwalk(ui, repo, *pats, **opts):
3473 def debugwalk(ui, repo, *pats, **opts):
3474 """show how files match on given patterns"""
3474 """show how files match on given patterns"""
3475 m = scmutil.match(repo[None], pats, opts)
3475 m = scmutil.match(repo[None], pats, opts)
3476 items = list(repo.walk(m))
3476 items = list(repo.walk(m))
3477 if not items:
3477 if not items:
3478 return
3478 return
3479 f = lambda fn: fn
3479 f = lambda fn: fn
3480 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
3480 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
3481 f = lambda fn: util.normpath(fn)
3481 f = lambda fn: util.normpath(fn)
3482 fmt = 'f %%-%ds %%-%ds %%s' % (
3482 fmt = 'f %%-%ds %%-%ds %%s' % (
3483 max([len(abs) for abs in items]),
3483 max([len(abs) for abs in items]),
3484 max([len(m.rel(abs)) for abs in items]))
3484 max([len(m.rel(abs)) for abs in items]))
3485 for abs in items:
3485 for abs in items:
3486 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3486 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3487 ui.write("%s\n" % line.rstrip())
3487 ui.write("%s\n" % line.rstrip())
3488
3488
3489 @command('debugwireargs',
3489 @command('debugwireargs',
3490 [('', 'three', '', 'three'),
3490 [('', 'three', '', 'three'),
3491 ('', 'four', '', 'four'),
3491 ('', 'four', '', 'four'),
3492 ('', 'five', '', 'five'),
3492 ('', 'five', '', 'five'),
3493 ] + remoteopts,
3493 ] + remoteopts,
3494 _('REPO [OPTIONS]... [ONE [TWO]]'),
3494 _('REPO [OPTIONS]... [ONE [TWO]]'),
3495 norepo=True)
3495 norepo=True)
3496 def debugwireargs(ui, repopath, *vals, **opts):
3496 def debugwireargs(ui, repopath, *vals, **opts):
3497 repo = hg.peer(ui, opts, repopath)
3497 repo = hg.peer(ui, opts, repopath)
3498 for opt in remoteopts:
3498 for opt in remoteopts:
3499 del opts[opt[1]]
3499 del opts[opt[1]]
3500 args = {}
3500 args = {}
3501 for k, v in opts.iteritems():
3501 for k, v in opts.iteritems():
3502 if v:
3502 if v:
3503 args[k] = v
3503 args[k] = v
3504 # run twice to check that we don't mess up the stream for the next command
3504 # run twice to check that we don't mess up the stream for the next command
3505 res1 = repo.debugwireargs(*vals, **args)
3505 res1 = repo.debugwireargs(*vals, **args)
3506 res2 = repo.debugwireargs(*vals, **args)
3506 res2 = repo.debugwireargs(*vals, **args)
3507 ui.write("%s\n" % res1)
3507 ui.write("%s\n" % res1)
3508 if res1 != res2:
3508 if res1 != res2:
3509 ui.warn("%s\n" % res2)
3509 ui.warn("%s\n" % res2)
3510
3510
3511 @command('^diff',
3511 @command('^diff',
3512 [('r', 'rev', [], _('revision'), _('REV')),
3512 [('r', 'rev', [], _('revision'), _('REV')),
3513 ('c', 'change', '', _('change made by revision'), _('REV'))
3513 ('c', 'change', '', _('change made by revision'), _('REV'))
3514 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3514 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3515 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3515 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3516 inferrepo=True)
3516 inferrepo=True)
3517 def diff(ui, repo, *pats, **opts):
3517 def diff(ui, repo, *pats, **opts):
3518 """diff repository (or selected files)
3518 """diff repository (or selected files)
3519
3519
3520 Show differences between revisions for the specified files.
3520 Show differences between revisions for the specified files.
3521
3521
3522 Differences between files are shown using the unified diff format.
3522 Differences between files are shown using the unified diff format.
3523
3523
3524 .. note::
3524 .. note::
3525
3525
3526 :hg:`diff` may generate unexpected results for merges, as it will
3526 :hg:`diff` may generate unexpected results for merges, as it will
3527 default to comparing against the working directory's first
3527 default to comparing against the working directory's first
3528 parent changeset if no revisions are specified.
3528 parent changeset if no revisions are specified.
3529
3529
3530 When two revision arguments are given, then changes are shown
3530 When two revision arguments are given, then changes are shown
3531 between those revisions. If only one revision is specified then
3531 between those revisions. If only one revision is specified then
3532 that revision is compared to the working directory, and, when no
3532 that revision is compared to the working directory, and, when no
3533 revisions are specified, the working directory files are compared
3533 revisions are specified, the working directory files are compared
3534 to its first parent.
3534 to its first parent.
3535
3535
3536 Alternatively you can specify -c/--change with a revision to see
3536 Alternatively you can specify -c/--change with a revision to see
3537 the changes in that changeset relative to its first parent.
3537 the changes in that changeset relative to its first parent.
3538
3538
3539 Without the -a/--text option, diff will avoid generating diffs of
3539 Without the -a/--text option, diff will avoid generating diffs of
3540 files it detects as binary. With -a, diff will generate a diff
3540 files it detects as binary. With -a, diff will generate a diff
3541 anyway, probably with undesirable results.
3541 anyway, probably with undesirable results.
3542
3542
3543 Use the -g/--git option to generate diffs in the git extended diff
3543 Use the -g/--git option to generate diffs in the git extended diff
3544 format. For more information, read :hg:`help diffs`.
3544 format. For more information, read :hg:`help diffs`.
3545
3545
3546 .. container:: verbose
3546 .. container:: verbose
3547
3547
3548 Examples:
3548 Examples:
3549
3549
3550 - compare a file in the current working directory to its parent::
3550 - compare a file in the current working directory to its parent::
3551
3551
3552 hg diff foo.c
3552 hg diff foo.c
3553
3553
3554 - compare two historical versions of a directory, with rename info::
3554 - compare two historical versions of a directory, with rename info::
3555
3555
3556 hg diff --git -r 1.0:1.2 lib/
3556 hg diff --git -r 1.0:1.2 lib/
3557
3557
3558 - get change stats relative to the last change on some date::
3558 - get change stats relative to the last change on some date::
3559
3559
3560 hg diff --stat -r "date('may 2')"
3560 hg diff --stat -r "date('may 2')"
3561
3561
3562 - diff all newly-added files that contain a keyword::
3562 - diff all newly-added files that contain a keyword::
3563
3563
3564 hg diff "set:added() and grep(GNU)"
3564 hg diff "set:added() and grep(GNU)"
3565
3565
3566 - compare a revision and its parents::
3566 - compare a revision and its parents::
3567
3567
3568 hg diff -c 9353 # compare against first parent
3568 hg diff -c 9353 # compare against first parent
3569 hg diff -r 9353^:9353 # same using revset syntax
3569 hg diff -r 9353^:9353 # same using revset syntax
3570 hg diff -r 9353^2:9353 # compare against the second parent
3570 hg diff -r 9353^2:9353 # compare against the second parent
3571
3571
3572 Returns 0 on success.
3572 Returns 0 on success.
3573 """
3573 """
3574
3574
3575 revs = opts.get('rev')
3575 revs = opts.get('rev')
3576 change = opts.get('change')
3576 change = opts.get('change')
3577 stat = opts.get('stat')
3577 stat = opts.get('stat')
3578 reverse = opts.get('reverse')
3578 reverse = opts.get('reverse')
3579
3579
3580 if revs and change:
3580 if revs and change:
3581 msg = _('cannot specify --rev and --change at the same time')
3581 msg = _('cannot specify --rev and --change at the same time')
3582 raise error.Abort(msg)
3582 raise error.Abort(msg)
3583 elif change:
3583 elif change:
3584 node2 = scmutil.revsingle(repo, change, None).node()
3584 node2 = scmutil.revsingle(repo, change, None).node()
3585 node1 = repo[node2].p1().node()
3585 node1 = repo[node2].p1().node()
3586 else:
3586 else:
3587 node1, node2 = scmutil.revpair(repo, revs)
3587 node1, node2 = scmutil.revpair(repo, revs)
3588
3588
3589 if reverse:
3589 if reverse:
3590 node1, node2 = node2, node1
3590 node1, node2 = node2, node1
3591
3591
3592 diffopts = patch.diffallopts(ui, opts)
3592 diffopts = patch.diffallopts(ui, opts)
3593 m = scmutil.match(repo[node2], pats, opts)
3593 m = scmutil.match(repo[node2], pats, opts)
3594 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3594 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3595 listsubrepos=opts.get('subrepos'),
3595 listsubrepos=opts.get('subrepos'),
3596 root=opts.get('root'))
3596 root=opts.get('root'))
3597
3597
3598 @command('^export',
3598 @command('^export',
3599 [('o', 'output', '',
3599 [('o', 'output', '',
3600 _('print output to file with formatted name'), _('FORMAT')),
3600 _('print output to file with formatted name'), _('FORMAT')),
3601 ('', 'switch-parent', None, _('diff against the second parent')),
3601 ('', 'switch-parent', None, _('diff against the second parent')),
3602 ('r', 'rev', [], _('revisions to export'), _('REV')),
3602 ('r', 'rev', [], _('revisions to export'), _('REV')),
3603 ] + diffopts,
3603 ] + diffopts,
3604 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3604 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3605 def export(ui, repo, *changesets, **opts):
3605 def export(ui, repo, *changesets, **opts):
3606 """dump the header and diffs for one or more changesets
3606 """dump the header and diffs for one or more changesets
3607
3607
3608 Print the changeset header and diffs for one or more revisions.
3608 Print the changeset header and diffs for one or more revisions.
3609 If no revision is given, the parent of the working directory is used.
3609 If no revision is given, the parent of the working directory is used.
3610
3610
3611 The information shown in the changeset header is: author, date,
3611 The information shown in the changeset header is: author, date,
3612 branch name (if non-default), changeset hash, parent(s) and commit
3612 branch name (if non-default), changeset hash, parent(s) and commit
3613 comment.
3613 comment.
3614
3614
3615 .. note::
3615 .. note::
3616
3616
3617 :hg:`export` may generate unexpected diff output for merge
3617 :hg:`export` may generate unexpected diff output for merge
3618 changesets, as it will compare the merge changeset against its
3618 changesets, as it will compare the merge changeset against its
3619 first parent only.
3619 first parent only.
3620
3620
3621 Output may be to a file, in which case the name of the file is
3621 Output may be to a file, in which case the name of the file is
3622 given using a format string. The formatting rules are as follows:
3622 given using a format string. The formatting rules are as follows:
3623
3623
3624 :``%%``: literal "%" character
3624 :``%%``: literal "%" character
3625 :``%H``: changeset hash (40 hexadecimal digits)
3625 :``%H``: changeset hash (40 hexadecimal digits)
3626 :``%N``: number of patches being generated
3626 :``%N``: number of patches being generated
3627 :``%R``: changeset revision number
3627 :``%R``: changeset revision number
3628 :``%b``: basename of the exporting repository
3628 :``%b``: basename of the exporting repository
3629 :``%h``: short-form changeset hash (12 hexadecimal digits)
3629 :``%h``: short-form changeset hash (12 hexadecimal digits)
3630 :``%m``: first line of the commit message (only alphanumeric characters)
3630 :``%m``: first line of the commit message (only alphanumeric characters)
3631 :``%n``: zero-padded sequence number, starting at 1
3631 :``%n``: zero-padded sequence number, starting at 1
3632 :``%r``: zero-padded changeset revision number
3632 :``%r``: zero-padded changeset revision number
3633
3633
3634 Without the -a/--text option, export will avoid generating diffs
3634 Without the -a/--text option, export will avoid generating diffs
3635 of files it detects as binary. With -a, export will generate a
3635 of files it detects as binary. With -a, export will generate a
3636 diff anyway, probably with undesirable results.
3636 diff anyway, probably with undesirable results.
3637
3637
3638 Use the -g/--git option to generate diffs in the git extended diff
3638 Use the -g/--git option to generate diffs in the git extended diff
3639 format. See :hg:`help diffs` for more information.
3639 format. See :hg:`help diffs` for more information.
3640
3640
3641 With the --switch-parent option, the diff will be against the
3641 With the --switch-parent option, the diff will be against the
3642 second parent. It can be useful to review a merge.
3642 second parent. It can be useful to review a merge.
3643
3643
3644 .. container:: verbose
3644 .. container:: verbose
3645
3645
3646 Examples:
3646 Examples:
3647
3647
3648 - use export and import to transplant a bugfix to the current
3648 - use export and import to transplant a bugfix to the current
3649 branch::
3649 branch::
3650
3650
3651 hg export -r 9353 | hg import -
3651 hg export -r 9353 | hg import -
3652
3652
3653 - export all the changesets between two revisions to a file with
3653 - export all the changesets between two revisions to a file with
3654 rename information::
3654 rename information::
3655
3655
3656 hg export --git -r 123:150 > changes.txt
3656 hg export --git -r 123:150 > changes.txt
3657
3657
3658 - split outgoing changes into a series of patches with
3658 - split outgoing changes into a series of patches with
3659 descriptive names::
3659 descriptive names::
3660
3660
3661 hg export -r "outgoing()" -o "%n-%m.patch"
3661 hg export -r "outgoing()" -o "%n-%m.patch"
3662
3662
3663 Returns 0 on success.
3663 Returns 0 on success.
3664 """
3664 """
3665 changesets += tuple(opts.get('rev', []))
3665 changesets += tuple(opts.get('rev', []))
3666 if not changesets:
3666 if not changesets:
3667 changesets = ['.']
3667 changesets = ['.']
3668 revs = scmutil.revrange(repo, changesets)
3668 revs = scmutil.revrange(repo, changesets)
3669 if not revs:
3669 if not revs:
3670 raise error.Abort(_("export requires at least one changeset"))
3670 raise error.Abort(_("export requires at least one changeset"))
3671 if len(revs) > 1:
3671 if len(revs) > 1:
3672 ui.note(_('exporting patches:\n'))
3672 ui.note(_('exporting patches:\n'))
3673 else:
3673 else:
3674 ui.note(_('exporting patch:\n'))
3674 ui.note(_('exporting patch:\n'))
3675 cmdutil.export(repo, revs, template=opts.get('output'),
3675 cmdutil.export(repo, revs, template=opts.get('output'),
3676 switch_parent=opts.get('switch_parent'),
3676 switch_parent=opts.get('switch_parent'),
3677 opts=patch.diffallopts(ui, opts))
3677 opts=patch.diffallopts(ui, opts))
3678
3678
3679 @command('files',
3679 @command('files',
3680 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3680 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3681 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3681 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3682 ] + walkopts + formatteropts + subrepoopts,
3682 ] + walkopts + formatteropts + subrepoopts,
3683 _('[OPTION]... [FILE]...'))
3683 _('[OPTION]... [FILE]...'))
3684 def files(ui, repo, *pats, **opts):
3684 def files(ui, repo, *pats, **opts):
3685 """list tracked files
3685 """list tracked files
3686
3686
3687 Print files under Mercurial control in the working directory or
3687 Print files under Mercurial control in the working directory or
3688 specified revision for given files (excluding removed files).
3688 specified revision for given files (excluding removed files).
3689 Files can be specified as filenames or filesets.
3689 Files can be specified as filenames or filesets.
3690
3690
3691 If no files are given to match, this command prints the names
3691 If no files are given to match, this command prints the names
3692 of all files under Mercurial control.
3692 of all files under Mercurial control.
3693
3693
3694 .. container:: verbose
3694 .. container:: verbose
3695
3695
3696 Examples:
3696 Examples:
3697
3697
3698 - list all files under the current directory::
3698 - list all files under the current directory::
3699
3699
3700 hg files .
3700 hg files .
3701
3701
3702 - shows sizes and flags for current revision::
3702 - shows sizes and flags for current revision::
3703
3703
3704 hg files -vr .
3704 hg files -vr .
3705
3705
3706 - list all files named README::
3706 - list all files named README::
3707
3707
3708 hg files -I "**/README"
3708 hg files -I "**/README"
3709
3709
3710 - list all binary files::
3710 - list all binary files::
3711
3711
3712 hg files "set:binary()"
3712 hg files "set:binary()"
3713
3713
3714 - find files containing a regular expression::
3714 - find files containing a regular expression::
3715
3715
3716 hg files "set:grep('bob')"
3716 hg files "set:grep('bob')"
3717
3717
3718 - search tracked file contents with xargs and grep::
3718 - search tracked file contents with xargs and grep::
3719
3719
3720 hg files -0 | xargs -0 grep foo
3720 hg files -0 | xargs -0 grep foo
3721
3721
3722 See :hg:`help patterns` and :hg:`help filesets` for more information
3722 See :hg:`help patterns` and :hg:`help filesets` for more information
3723 on specifying file patterns.
3723 on specifying file patterns.
3724
3724
3725 Returns 0 if a match is found, 1 otherwise.
3725 Returns 0 if a match is found, 1 otherwise.
3726
3726
3727 """
3727 """
3728 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3728 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3729
3729
3730 end = '\n'
3730 end = '\n'
3731 if opts.get('print0'):
3731 if opts.get('print0'):
3732 end = '\0'
3732 end = '\0'
3733 fmt = '%s' + end
3733 fmt = '%s' + end
3734
3734
3735 m = scmutil.match(ctx, pats, opts)
3735 m = scmutil.match(ctx, pats, opts)
3736 with ui.formatter('files', opts) as fm:
3736 with ui.formatter('files', opts) as fm:
3737 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3737 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3738
3738
3739 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3739 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3740 def forget(ui, repo, *pats, **opts):
3740 def forget(ui, repo, *pats, **opts):
3741 """forget the specified files on the next commit
3741 """forget the specified files on the next commit
3742
3742
3743 Mark the specified files so they will no longer be tracked
3743 Mark the specified files so they will no longer be tracked
3744 after the next commit.
3744 after the next commit.
3745
3745
3746 This only removes files from the current branch, not from the
3746 This only removes files from the current branch, not from the
3747 entire project history, and it does not delete them from the
3747 entire project history, and it does not delete them from the
3748 working directory.
3748 working directory.
3749
3749
3750 To delete the file from the working directory, see :hg:`remove`.
3750 To delete the file from the working directory, see :hg:`remove`.
3751
3751
3752 To undo a forget before the next commit, see :hg:`add`.
3752 To undo a forget before the next commit, see :hg:`add`.
3753
3753
3754 .. container:: verbose
3754 .. container:: verbose
3755
3755
3756 Examples:
3756 Examples:
3757
3757
3758 - forget newly-added binary files::
3758 - forget newly-added binary files::
3759
3759
3760 hg forget "set:added() and binary()"
3760 hg forget "set:added() and binary()"
3761
3761
3762 - forget files that would be excluded by .hgignore::
3762 - forget files that would be excluded by .hgignore::
3763
3763
3764 hg forget "set:hgignore()"
3764 hg forget "set:hgignore()"
3765
3765
3766 Returns 0 on success.
3766 Returns 0 on success.
3767 """
3767 """
3768
3768
3769 if not pats:
3769 if not pats:
3770 raise error.Abort(_('no files specified'))
3770 raise error.Abort(_('no files specified'))
3771
3771
3772 m = scmutil.match(repo[None], pats, opts)
3772 m = scmutil.match(repo[None], pats, opts)
3773 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3773 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3774 return rejected and 1 or 0
3774 return rejected and 1 or 0
3775
3775
3776 @command(
3776 @command(
3777 'graft',
3777 'graft',
3778 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3778 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3779 ('c', 'continue', False, _('resume interrupted graft')),
3779 ('c', 'continue', False, _('resume interrupted graft')),
3780 ('e', 'edit', False, _('invoke editor on commit messages')),
3780 ('e', 'edit', False, _('invoke editor on commit messages')),
3781 ('', 'log', None, _('append graft info to log message')),
3781 ('', 'log', None, _('append graft info to log message')),
3782 ('f', 'force', False, _('force graft')),
3782 ('f', 'force', False, _('force graft')),
3783 ('D', 'currentdate', False,
3783 ('D', 'currentdate', False,
3784 _('record the current date as commit date')),
3784 _('record the current date as commit date')),
3785 ('U', 'currentuser', False,
3785 ('U', 'currentuser', False,
3786 _('record the current user as committer'), _('DATE'))]
3786 _('record the current user as committer'), _('DATE'))]
3787 + commitopts2 + mergetoolopts + dryrunopts,
3787 + commitopts2 + mergetoolopts + dryrunopts,
3788 _('[OPTION]... [-r REV]... REV...'))
3788 _('[OPTION]... [-r REV]... REV...'))
3789 def graft(ui, repo, *revs, **opts):
3789 def graft(ui, repo, *revs, **opts):
3790 '''copy changes from other branches onto the current branch
3790 '''copy changes from other branches onto the current branch
3791
3791
3792 This command uses Mercurial's merge logic to copy individual
3792 This command uses Mercurial's merge logic to copy individual
3793 changes from other branches without merging branches in the
3793 changes from other branches without merging branches in the
3794 history graph. This is sometimes known as 'backporting' or
3794 history graph. This is sometimes known as 'backporting' or
3795 'cherry-picking'. By default, graft will copy user, date, and
3795 'cherry-picking'. By default, graft will copy user, date, and
3796 description from the source changesets.
3796 description from the source changesets.
3797
3797
3798 Changesets that are ancestors of the current revision, that have
3798 Changesets that are ancestors of the current revision, that have
3799 already been grafted, or that are merges will be skipped.
3799 already been grafted, or that are merges will be skipped.
3800
3800
3801 If --log is specified, log messages will have a comment appended
3801 If --log is specified, log messages will have a comment appended
3802 of the form::
3802 of the form::
3803
3803
3804 (grafted from CHANGESETHASH)
3804 (grafted from CHANGESETHASH)
3805
3805
3806 If --force is specified, revisions will be grafted even if they
3806 If --force is specified, revisions will be grafted even if they
3807 are already ancestors of or have been grafted to the destination.
3807 are already ancestors of or have been grafted to the destination.
3808 This is useful when the revisions have since been backed out.
3808 This is useful when the revisions have since been backed out.
3809
3809
3810 If a graft merge results in conflicts, the graft process is
3810 If a graft merge results in conflicts, the graft process is
3811 interrupted so that the current merge can be manually resolved.
3811 interrupted so that the current merge can be manually resolved.
3812 Once all conflicts are addressed, the graft process can be
3812 Once all conflicts are addressed, the graft process can be
3813 continued with the -c/--continue option.
3813 continued with the -c/--continue option.
3814
3814
3815 .. note::
3815 .. note::
3816
3816
3817 The -c/--continue option does not reapply earlier options, except
3817 The -c/--continue option does not reapply earlier options, except
3818 for --force.
3818 for --force.
3819
3819
3820 .. container:: verbose
3820 .. container:: verbose
3821
3821
3822 Examples:
3822 Examples:
3823
3823
3824 - copy a single change to the stable branch and edit its description::
3824 - copy a single change to the stable branch and edit its description::
3825
3825
3826 hg update stable
3826 hg update stable
3827 hg graft --edit 9393
3827 hg graft --edit 9393
3828
3828
3829 - graft a range of changesets with one exception, updating dates::
3829 - graft a range of changesets with one exception, updating dates::
3830
3830
3831 hg graft -D "2085::2093 and not 2091"
3831 hg graft -D "2085::2093 and not 2091"
3832
3832
3833 - continue a graft after resolving conflicts::
3833 - continue a graft after resolving conflicts::
3834
3834
3835 hg graft -c
3835 hg graft -c
3836
3836
3837 - show the source of a grafted changeset::
3837 - show the source of a grafted changeset::
3838
3838
3839 hg log --debug -r .
3839 hg log --debug -r .
3840
3840
3841 - show revisions sorted by date::
3841 - show revisions sorted by date::
3842
3842
3843 hg log -r "sort(all(), date)"
3843 hg log -r "sort(all(), date)"
3844
3844
3845 See :hg:`help revisions` and :hg:`help revsets` for more about
3845 See :hg:`help revisions` and :hg:`help revsets` for more about
3846 specifying revisions.
3846 specifying revisions.
3847
3847
3848 Returns 0 on successful completion.
3848 Returns 0 on successful completion.
3849 '''
3849 '''
3850 with repo.wlock():
3850 with repo.wlock():
3851 return _dograft(ui, repo, *revs, **opts)
3851 return _dograft(ui, repo, *revs, **opts)
3852
3852
3853 def _dograft(ui, repo, *revs, **opts):
3853 def _dograft(ui, repo, *revs, **opts):
3854 if revs and opts.get('rev'):
3854 if revs and opts.get('rev'):
3855 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3855 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3856 'revision ordering!\n'))
3856 'revision ordering!\n'))
3857
3857
3858 revs = list(revs)
3858 revs = list(revs)
3859 revs.extend(opts.get('rev'))
3859 revs.extend(opts.get('rev'))
3860
3860
3861 if not opts.get('user') and opts.get('currentuser'):
3861 if not opts.get('user') and opts.get('currentuser'):
3862 opts['user'] = ui.username()
3862 opts['user'] = ui.username()
3863 if not opts.get('date') and opts.get('currentdate'):
3863 if not opts.get('date') and opts.get('currentdate'):
3864 opts['date'] = "%d %d" % util.makedate()
3864 opts['date'] = "%d %d" % util.makedate()
3865
3865
3866 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3866 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3867
3867
3868 cont = False
3868 cont = False
3869 if opts.get('continue'):
3869 if opts.get('continue'):
3870 cont = True
3870 cont = True
3871 if revs:
3871 if revs:
3872 raise error.Abort(_("can't specify --continue and revisions"))
3872 raise error.Abort(_("can't specify --continue and revisions"))
3873 # read in unfinished revisions
3873 # read in unfinished revisions
3874 try:
3874 try:
3875 nodes = repo.vfs.read('graftstate').splitlines()
3875 nodes = repo.vfs.read('graftstate').splitlines()
3876 revs = [repo[node].rev() for node in nodes]
3876 revs = [repo[node].rev() for node in nodes]
3877 except IOError as inst:
3877 except IOError as inst:
3878 if inst.errno != errno.ENOENT:
3878 if inst.errno != errno.ENOENT:
3879 raise
3879 raise
3880 cmdutil.wrongtooltocontinue(repo, _('graft'))
3880 cmdutil.wrongtooltocontinue(repo, _('graft'))
3881 else:
3881 else:
3882 cmdutil.checkunfinished(repo)
3882 cmdutil.checkunfinished(repo)
3883 cmdutil.bailifchanged(repo)
3883 cmdutil.bailifchanged(repo)
3884 if not revs:
3884 if not revs:
3885 raise error.Abort(_('no revisions specified'))
3885 raise error.Abort(_('no revisions specified'))
3886 revs = scmutil.revrange(repo, revs)
3886 revs = scmutil.revrange(repo, revs)
3887
3887
3888 skipped = set()
3888 skipped = set()
3889 # check for merges
3889 # check for merges
3890 for rev in repo.revs('%ld and merge()', revs):
3890 for rev in repo.revs('%ld and merge()', revs):
3891 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3891 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3892 skipped.add(rev)
3892 skipped.add(rev)
3893 revs = [r for r in revs if r not in skipped]
3893 revs = [r for r in revs if r not in skipped]
3894 if not revs:
3894 if not revs:
3895 return -1
3895 return -1
3896
3896
3897 # Don't check in the --continue case, in effect retaining --force across
3897 # Don't check in the --continue case, in effect retaining --force across
3898 # --continues. That's because without --force, any revisions we decided to
3898 # --continues. That's because without --force, any revisions we decided to
3899 # skip would have been filtered out here, so they wouldn't have made their
3899 # skip would have been filtered out here, so they wouldn't have made their
3900 # way to the graftstate. With --force, any revisions we would have otherwise
3900 # way to the graftstate. With --force, any revisions we would have otherwise
3901 # skipped would not have been filtered out, and if they hadn't been applied
3901 # skipped would not have been filtered out, and if they hadn't been applied
3902 # already, they'd have been in the graftstate.
3902 # already, they'd have been in the graftstate.
3903 if not (cont or opts.get('force')):
3903 if not (cont or opts.get('force')):
3904 # check for ancestors of dest branch
3904 # check for ancestors of dest branch
3905 crev = repo['.'].rev()
3905 crev = repo['.'].rev()
3906 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3906 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3907 # XXX make this lazy in the future
3907 # XXX make this lazy in the future
3908 # don't mutate while iterating, create a copy
3908 # don't mutate while iterating, create a copy
3909 for rev in list(revs):
3909 for rev in list(revs):
3910 if rev in ancestors:
3910 if rev in ancestors:
3911 ui.warn(_('skipping ancestor revision %d:%s\n') %
3911 ui.warn(_('skipping ancestor revision %d:%s\n') %
3912 (rev, repo[rev]))
3912 (rev, repo[rev]))
3913 # XXX remove on list is slow
3913 # XXX remove on list is slow
3914 revs.remove(rev)
3914 revs.remove(rev)
3915 if not revs:
3915 if not revs:
3916 return -1
3916 return -1
3917
3917
3918 # analyze revs for earlier grafts
3918 # analyze revs for earlier grafts
3919 ids = {}
3919 ids = {}
3920 for ctx in repo.set("%ld", revs):
3920 for ctx in repo.set("%ld", revs):
3921 ids[ctx.hex()] = ctx.rev()
3921 ids[ctx.hex()] = ctx.rev()
3922 n = ctx.extra().get('source')
3922 n = ctx.extra().get('source')
3923 if n:
3923 if n:
3924 ids[n] = ctx.rev()
3924 ids[n] = ctx.rev()
3925
3925
3926 # check ancestors for earlier grafts
3926 # check ancestors for earlier grafts
3927 ui.debug('scanning for duplicate grafts\n')
3927 ui.debug('scanning for duplicate grafts\n')
3928
3928
3929 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3929 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3930 ctx = repo[rev]
3930 ctx = repo[rev]
3931 n = ctx.extra().get('source')
3931 n = ctx.extra().get('source')
3932 if n in ids:
3932 if n in ids:
3933 try:
3933 try:
3934 r = repo[n].rev()
3934 r = repo[n].rev()
3935 except error.RepoLookupError:
3935 except error.RepoLookupError:
3936 r = None
3936 r = None
3937 if r in revs:
3937 if r in revs:
3938 ui.warn(_('skipping revision %d:%s '
3938 ui.warn(_('skipping revision %d:%s '
3939 '(already grafted to %d:%s)\n')
3939 '(already grafted to %d:%s)\n')
3940 % (r, repo[r], rev, ctx))
3940 % (r, repo[r], rev, ctx))
3941 revs.remove(r)
3941 revs.remove(r)
3942 elif ids[n] in revs:
3942 elif ids[n] in revs:
3943 if r is None:
3943 if r is None:
3944 ui.warn(_('skipping already grafted revision %d:%s '
3944 ui.warn(_('skipping already grafted revision %d:%s '
3945 '(%d:%s also has unknown origin %s)\n')
3945 '(%d:%s also has unknown origin %s)\n')
3946 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3946 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3947 else:
3947 else:
3948 ui.warn(_('skipping already grafted revision %d:%s '
3948 ui.warn(_('skipping already grafted revision %d:%s '
3949 '(%d:%s also has origin %d:%s)\n')
3949 '(%d:%s also has origin %d:%s)\n')
3950 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3950 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3951 revs.remove(ids[n])
3951 revs.remove(ids[n])
3952 elif ctx.hex() in ids:
3952 elif ctx.hex() in ids:
3953 r = ids[ctx.hex()]
3953 r = ids[ctx.hex()]
3954 ui.warn(_('skipping already grafted revision %d:%s '
3954 ui.warn(_('skipping already grafted revision %d:%s '
3955 '(was grafted from %d:%s)\n') %
3955 '(was grafted from %d:%s)\n') %
3956 (r, repo[r], rev, ctx))
3956 (r, repo[r], rev, ctx))
3957 revs.remove(r)
3957 revs.remove(r)
3958 if not revs:
3958 if not revs:
3959 return -1
3959 return -1
3960
3960
3961 for pos, ctx in enumerate(repo.set("%ld", revs)):
3961 for pos, ctx in enumerate(repo.set("%ld", revs)):
3962 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3962 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3963 ctx.description().split('\n', 1)[0])
3963 ctx.description().split('\n', 1)[0])
3964 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3964 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3965 if names:
3965 if names:
3966 desc += ' (%s)' % ' '.join(names)
3966 desc += ' (%s)' % ' '.join(names)
3967 ui.status(_('grafting %s\n') % desc)
3967 ui.status(_('grafting %s\n') % desc)
3968 if opts.get('dry_run'):
3968 if opts.get('dry_run'):
3969 continue
3969 continue
3970
3970
3971 source = ctx.extra().get('source')
3971 source = ctx.extra().get('source')
3972 extra = {}
3972 extra = {}
3973 if source:
3973 if source:
3974 extra['source'] = source
3974 extra['source'] = source
3975 extra['intermediate-source'] = ctx.hex()
3975 extra['intermediate-source'] = ctx.hex()
3976 else:
3976 else:
3977 extra['source'] = ctx.hex()
3977 extra['source'] = ctx.hex()
3978 user = ctx.user()
3978 user = ctx.user()
3979 if opts.get('user'):
3979 if opts.get('user'):
3980 user = opts['user']
3980 user = opts['user']
3981 date = ctx.date()
3981 date = ctx.date()
3982 if opts.get('date'):
3982 if opts.get('date'):
3983 date = opts['date']
3983 date = opts['date']
3984 message = ctx.description()
3984 message = ctx.description()
3985 if opts.get('log'):
3985 if opts.get('log'):
3986 message += '\n(grafted from %s)' % ctx.hex()
3986 message += '\n(grafted from %s)' % ctx.hex()
3987
3987
3988 # we don't merge the first commit when continuing
3988 # we don't merge the first commit when continuing
3989 if not cont:
3989 if not cont:
3990 # perform the graft merge with p1(rev) as 'ancestor'
3990 # perform the graft merge with p1(rev) as 'ancestor'
3991 try:
3991 try:
3992 # ui.forcemerge is an internal variable, do not document
3992 # ui.forcemerge is an internal variable, do not document
3993 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3993 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3994 'graft')
3994 'graft')
3995 stats = mergemod.graft(repo, ctx, ctx.p1(),
3995 stats = mergemod.graft(repo, ctx, ctx.p1(),
3996 ['local', 'graft'])
3996 ['local', 'graft'])
3997 finally:
3997 finally:
3998 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3998 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3999 # report any conflicts
3999 # report any conflicts
4000 if stats and stats[3] > 0:
4000 if stats and stats[3] > 0:
4001 # write out state for --continue
4001 # write out state for --continue
4002 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4002 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4003 repo.vfs.write('graftstate', ''.join(nodelines))
4003 repo.vfs.write('graftstate', ''.join(nodelines))
4004 extra = ''
4004 extra = ''
4005 if opts.get('user'):
4005 if opts.get('user'):
4006 extra += ' --user %s' % util.shellquote(opts['user'])
4006 extra += ' --user %s' % util.shellquote(opts['user'])
4007 if opts.get('date'):
4007 if opts.get('date'):
4008 extra += ' --date %s' % util.shellquote(opts['date'])
4008 extra += ' --date %s' % util.shellquote(opts['date'])
4009 if opts.get('log'):
4009 if opts.get('log'):
4010 extra += ' --log'
4010 extra += ' --log'
4011 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4011 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4012 raise error.Abort(
4012 raise error.Abort(
4013 _("unresolved conflicts, can't continue"),
4013 _("unresolved conflicts, can't continue"),
4014 hint=hint)
4014 hint=hint)
4015 else:
4015 else:
4016 cont = False
4016 cont = False
4017
4017
4018 # commit
4018 # commit
4019 node = repo.commit(text=message, user=user,
4019 node = repo.commit(text=message, user=user,
4020 date=date, extra=extra, editor=editor)
4020 date=date, extra=extra, editor=editor)
4021 if node is None:
4021 if node is None:
4022 ui.warn(
4022 ui.warn(
4023 _('note: graft of %d:%s created no changes to commit\n') %
4023 _('note: graft of %d:%s created no changes to commit\n') %
4024 (ctx.rev(), ctx))
4024 (ctx.rev(), ctx))
4025
4025
4026 # remove state when we complete successfully
4026 # remove state when we complete successfully
4027 if not opts.get('dry_run'):
4027 if not opts.get('dry_run'):
4028 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4028 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4029
4029
4030 return 0
4030 return 0
4031
4031
4032 @command('grep',
4032 @command('grep',
4033 [('0', 'print0', None, _('end fields with NUL')),
4033 [('0', 'print0', None, _('end fields with NUL')),
4034 ('', 'all', None, _('print all revisions that match')),
4034 ('', 'all', None, _('print all revisions that match')),
4035 ('a', 'text', None, _('treat all files as text')),
4035 ('a', 'text', None, _('treat all files as text')),
4036 ('f', 'follow', None,
4036 ('f', 'follow', None,
4037 _('follow changeset history,'
4037 _('follow changeset history,'
4038 ' or file history across copies and renames')),
4038 ' or file history across copies and renames')),
4039 ('i', 'ignore-case', None, _('ignore case when matching')),
4039 ('i', 'ignore-case', None, _('ignore case when matching')),
4040 ('l', 'files-with-matches', None,
4040 ('l', 'files-with-matches', None,
4041 _('print only filenames and revisions that match')),
4041 _('print only filenames and revisions that match')),
4042 ('n', 'line-number', None, _('print matching line numbers')),
4042 ('n', 'line-number', None, _('print matching line numbers')),
4043 ('r', 'rev', [],
4043 ('r', 'rev', [],
4044 _('only search files changed within revision range'), _('REV')),
4044 _('only search files changed within revision range'), _('REV')),
4045 ('u', 'user', None, _('list the author (long with -v)')),
4045 ('u', 'user', None, _('list the author (long with -v)')),
4046 ('d', 'date', None, _('list the date (short with -q)')),
4046 ('d', 'date', None, _('list the date (short with -q)')),
4047 ] + formatteropts + walkopts,
4047 ] + formatteropts + walkopts,
4048 _('[OPTION]... PATTERN [FILE]...'),
4048 _('[OPTION]... PATTERN [FILE]...'),
4049 inferrepo=True)
4049 inferrepo=True)
4050 def grep(ui, repo, pattern, *pats, **opts):
4050 def grep(ui, repo, pattern, *pats, **opts):
4051 """search revision history for a pattern in specified files
4051 """search revision history for a pattern in specified files
4052
4052
4053 Search revision history for a regular expression in the specified
4053 Search revision history for a regular expression in the specified
4054 files or the entire project.
4054 files or the entire project.
4055
4055
4056 By default, grep prints the most recent revision number for each
4056 By default, grep prints the most recent revision number for each
4057 file in which it finds a match. To get it to print every revision
4057 file in which it finds a match. To get it to print every revision
4058 that contains a change in match status ("-" for a match that becomes
4058 that contains a change in match status ("-" for a match that becomes
4059 a non-match, or "+" for a non-match that becomes a match), use the
4059 a non-match, or "+" for a non-match that becomes a match), use the
4060 --all flag.
4060 --all flag.
4061
4061
4062 PATTERN can be any Python (roughly Perl-compatible) regular
4062 PATTERN can be any Python (roughly Perl-compatible) regular
4063 expression.
4063 expression.
4064
4064
4065 If no FILEs are specified (and -f/--follow isn't set), all files in
4065 If no FILEs are specified (and -f/--follow isn't set), all files in
4066 the repository are searched, including those that don't exist in the
4066 the repository are searched, including those that don't exist in the
4067 current branch or have been deleted in a prior changeset.
4067 current branch or have been deleted in a prior changeset.
4068
4068
4069 Returns 0 if a match is found, 1 otherwise.
4069 Returns 0 if a match is found, 1 otherwise.
4070 """
4070 """
4071 reflags = re.M
4071 reflags = re.M
4072 if opts.get('ignore_case'):
4072 if opts.get('ignore_case'):
4073 reflags |= re.I
4073 reflags |= re.I
4074 try:
4074 try:
4075 regexp = util.re.compile(pattern, reflags)
4075 regexp = util.re.compile(pattern, reflags)
4076 except re.error as inst:
4076 except re.error as inst:
4077 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4077 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4078 return 1
4078 return 1
4079 sep, eol = ':', '\n'
4079 sep, eol = ':', '\n'
4080 if opts.get('print0'):
4080 if opts.get('print0'):
4081 sep = eol = '\0'
4081 sep = eol = '\0'
4082
4082
4083 getfile = util.lrucachefunc(repo.file)
4083 getfile = util.lrucachefunc(repo.file)
4084
4084
4085 def matchlines(body):
4085 def matchlines(body):
4086 begin = 0
4086 begin = 0
4087 linenum = 0
4087 linenum = 0
4088 while begin < len(body):
4088 while begin < len(body):
4089 match = regexp.search(body, begin)
4089 match = regexp.search(body, begin)
4090 if not match:
4090 if not match:
4091 break
4091 break
4092 mstart, mend = match.span()
4092 mstart, mend = match.span()
4093 linenum += body.count('\n', begin, mstart) + 1
4093 linenum += body.count('\n', begin, mstart) + 1
4094 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4094 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4095 begin = body.find('\n', mend) + 1 or len(body) + 1
4095 begin = body.find('\n', mend) + 1 or len(body) + 1
4096 lend = begin - 1
4096 lend = begin - 1
4097 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4097 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4098
4098
4099 class linestate(object):
4099 class linestate(object):
4100 def __init__(self, line, linenum, colstart, colend):
4100 def __init__(self, line, linenum, colstart, colend):
4101 self.line = line
4101 self.line = line
4102 self.linenum = linenum
4102 self.linenum = linenum
4103 self.colstart = colstart
4103 self.colstart = colstart
4104 self.colend = colend
4104 self.colend = colend
4105
4105
4106 def __hash__(self):
4106 def __hash__(self):
4107 return hash((self.linenum, self.line))
4107 return hash((self.linenum, self.line))
4108
4108
4109 def __eq__(self, other):
4109 def __eq__(self, other):
4110 return self.line == other.line
4110 return self.line == other.line
4111
4111
4112 def findpos(self):
4112 def findpos(self):
4113 """Iterate all (start, end) indices of matches"""
4113 """Iterate all (start, end) indices of matches"""
4114 yield self.colstart, self.colend
4114 yield self.colstart, self.colend
4115 p = self.colend
4115 p = self.colend
4116 while p < len(self.line):
4116 while p < len(self.line):
4117 m = regexp.search(self.line, p)
4117 m = regexp.search(self.line, p)
4118 if not m:
4118 if not m:
4119 break
4119 break
4120 yield m.span()
4120 yield m.span()
4121 p = m.end()
4121 p = m.end()
4122
4122
4123 matches = {}
4123 matches = {}
4124 copies = {}
4124 copies = {}
4125 def grepbody(fn, rev, body):
4125 def grepbody(fn, rev, body):
4126 matches[rev].setdefault(fn, [])
4126 matches[rev].setdefault(fn, [])
4127 m = matches[rev][fn]
4127 m = matches[rev][fn]
4128 for lnum, cstart, cend, line in matchlines(body):
4128 for lnum, cstart, cend, line in matchlines(body):
4129 s = linestate(line, lnum, cstart, cend)
4129 s = linestate(line, lnum, cstart, cend)
4130 m.append(s)
4130 m.append(s)
4131
4131
4132 def difflinestates(a, b):
4132 def difflinestates(a, b):
4133 sm = difflib.SequenceMatcher(None, a, b)
4133 sm = difflib.SequenceMatcher(None, a, b)
4134 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4134 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4135 if tag == 'insert':
4135 if tag == 'insert':
4136 for i in xrange(blo, bhi):
4136 for i in xrange(blo, bhi):
4137 yield ('+', b[i])
4137 yield ('+', b[i])
4138 elif tag == 'delete':
4138 elif tag == 'delete':
4139 for i in xrange(alo, ahi):
4139 for i in xrange(alo, ahi):
4140 yield ('-', a[i])
4140 yield ('-', a[i])
4141 elif tag == 'replace':
4141 elif tag == 'replace':
4142 for i in xrange(alo, ahi):
4142 for i in xrange(alo, ahi):
4143 yield ('-', a[i])
4143 yield ('-', a[i])
4144 for i in xrange(blo, bhi):
4144 for i in xrange(blo, bhi):
4145 yield ('+', b[i])
4145 yield ('+', b[i])
4146
4146
4147 def display(fm, fn, ctx, pstates, states):
4147 def display(fm, fn, ctx, pstates, states):
4148 rev = ctx.rev()
4148 rev = ctx.rev()
4149 if fm.isplain():
4149 if fm.isplain():
4150 formatuser = ui.shortuser
4150 formatuser = ui.shortuser
4151 else:
4151 else:
4152 formatuser = str
4152 formatuser = str
4153 if ui.quiet:
4153 if ui.quiet:
4154 datefmt = '%Y-%m-%d'
4154 datefmt = '%Y-%m-%d'
4155 else:
4155 else:
4156 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4156 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4157 found = False
4157 found = False
4158 @util.cachefunc
4158 @util.cachefunc
4159 def binary():
4159 def binary():
4160 flog = getfile(fn)
4160 flog = getfile(fn)
4161 return util.binary(flog.read(ctx.filenode(fn)))
4161 return util.binary(flog.read(ctx.filenode(fn)))
4162
4162
4163 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4163 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4164 if opts.get('all'):
4164 if opts.get('all'):
4165 iter = difflinestates(pstates, states)
4165 iter = difflinestates(pstates, states)
4166 else:
4166 else:
4167 iter = [('', l) for l in states]
4167 iter = [('', l) for l in states]
4168 for change, l in iter:
4168 for change, l in iter:
4169 fm.startitem()
4169 fm.startitem()
4170 fm.data(node=fm.hexfunc(ctx.node()))
4170 fm.data(node=fm.hexfunc(ctx.node()))
4171 cols = [
4171 cols = [
4172 ('filename', fn, True),
4172 ('filename', fn, True),
4173 ('rev', rev, True),
4173 ('rev', rev, True),
4174 ('linenumber', l.linenum, opts.get('line_number')),
4174 ('linenumber', l.linenum, opts.get('line_number')),
4175 ]
4175 ]
4176 if opts.get('all'):
4176 if opts.get('all'):
4177 cols.append(('change', change, True))
4177 cols.append(('change', change, True))
4178 cols.extend([
4178 cols.extend([
4179 ('user', formatuser(ctx.user()), opts.get('user')),
4179 ('user', formatuser(ctx.user()), opts.get('user')),
4180 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4180 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4181 ])
4181 ])
4182 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4182 lastcol = next(name for name, data, cond in reversed(cols) if cond)
4183 for name, data, cond in cols:
4183 for name, data, cond in cols:
4184 field = fieldnamemap.get(name, name)
4184 field = fieldnamemap.get(name, name)
4185 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4185 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4186 if cond and name != lastcol:
4186 if cond and name != lastcol:
4187 fm.plain(sep, label='grep.sep')
4187 fm.plain(sep, label='grep.sep')
4188 if not opts.get('files_with_matches'):
4188 if not opts.get('files_with_matches'):
4189 fm.plain(sep, label='grep.sep')
4189 fm.plain(sep, label='grep.sep')
4190 if not opts.get('text') and binary():
4190 if not opts.get('text') and binary():
4191 fm.plain(_(" Binary file matches"))
4191 fm.plain(_(" Binary file matches"))
4192 else:
4192 else:
4193 displaymatches(fm.nested('texts'), l)
4193 displaymatches(fm.nested('texts'), l)
4194 fm.plain(eol)
4194 fm.plain(eol)
4195 found = True
4195 found = True
4196 if opts.get('files_with_matches'):
4196 if opts.get('files_with_matches'):
4197 break
4197 break
4198 return found
4198 return found
4199
4199
4200 def displaymatches(fm, l):
4200 def displaymatches(fm, l):
4201 p = 0
4201 p = 0
4202 for s, e in l.findpos():
4202 for s, e in l.findpos():
4203 if p < s:
4203 if p < s:
4204 fm.startitem()
4204 fm.startitem()
4205 fm.write('text', '%s', l.line[p:s])
4205 fm.write('text', '%s', l.line[p:s])
4206 fm.data(matched=False)
4206 fm.data(matched=False)
4207 fm.startitem()
4207 fm.startitem()
4208 fm.write('text', '%s', l.line[s:e], label='grep.match')
4208 fm.write('text', '%s', l.line[s:e], label='grep.match')
4209 fm.data(matched=True)
4209 fm.data(matched=True)
4210 p = e
4210 p = e
4211 if p < len(l.line):
4211 if p < len(l.line):
4212 fm.startitem()
4212 fm.startitem()
4213 fm.write('text', '%s', l.line[p:])
4213 fm.write('text', '%s', l.line[p:])
4214 fm.data(matched=False)
4214 fm.data(matched=False)
4215 fm.end()
4215 fm.end()
4216
4216
4217 skip = {}
4217 skip = {}
4218 revfiles = {}
4218 revfiles = {}
4219 matchfn = scmutil.match(repo[None], pats, opts)
4219 matchfn = scmutil.match(repo[None], pats, opts)
4220 found = False
4220 found = False
4221 follow = opts.get('follow')
4221 follow = opts.get('follow')
4222
4222
4223 def prep(ctx, fns):
4223 def prep(ctx, fns):
4224 rev = ctx.rev()
4224 rev = ctx.rev()
4225 pctx = ctx.p1()
4225 pctx = ctx.p1()
4226 parent = pctx.rev()
4226 parent = pctx.rev()
4227 matches.setdefault(rev, {})
4227 matches.setdefault(rev, {})
4228 matches.setdefault(parent, {})
4228 matches.setdefault(parent, {})
4229 files = revfiles.setdefault(rev, [])
4229 files = revfiles.setdefault(rev, [])
4230 for fn in fns:
4230 for fn in fns:
4231 flog = getfile(fn)
4231 flog = getfile(fn)
4232 try:
4232 try:
4233 fnode = ctx.filenode(fn)
4233 fnode = ctx.filenode(fn)
4234 except error.LookupError:
4234 except error.LookupError:
4235 continue
4235 continue
4236
4236
4237 copied = flog.renamed(fnode)
4237 copied = flog.renamed(fnode)
4238 copy = follow and copied and copied[0]
4238 copy = follow and copied and copied[0]
4239 if copy:
4239 if copy:
4240 copies.setdefault(rev, {})[fn] = copy
4240 copies.setdefault(rev, {})[fn] = copy
4241 if fn in skip:
4241 if fn in skip:
4242 if copy:
4242 if copy:
4243 skip[copy] = True
4243 skip[copy] = True
4244 continue
4244 continue
4245 files.append(fn)
4245 files.append(fn)
4246
4246
4247 if fn not in matches[rev]:
4247 if fn not in matches[rev]:
4248 grepbody(fn, rev, flog.read(fnode))
4248 grepbody(fn, rev, flog.read(fnode))
4249
4249
4250 pfn = copy or fn
4250 pfn = copy or fn
4251 if pfn not in matches[parent]:
4251 if pfn not in matches[parent]:
4252 try:
4252 try:
4253 fnode = pctx.filenode(pfn)
4253 fnode = pctx.filenode(pfn)
4254 grepbody(pfn, parent, flog.read(fnode))
4254 grepbody(pfn, parent, flog.read(fnode))
4255 except error.LookupError:
4255 except error.LookupError:
4256 pass
4256 pass
4257
4257
4258 fm = ui.formatter('grep', opts)
4258 fm = ui.formatter('grep', opts)
4259 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4259 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4260 rev = ctx.rev()
4260 rev = ctx.rev()
4261 parent = ctx.p1().rev()
4261 parent = ctx.p1().rev()
4262 for fn in sorted(revfiles.get(rev, [])):
4262 for fn in sorted(revfiles.get(rev, [])):
4263 states = matches[rev][fn]
4263 states = matches[rev][fn]
4264 copy = copies.get(rev, {}).get(fn)
4264 copy = copies.get(rev, {}).get(fn)
4265 if fn in skip:
4265 if fn in skip:
4266 if copy:
4266 if copy:
4267 skip[copy] = True
4267 skip[copy] = True
4268 continue
4268 continue
4269 pstates = matches.get(parent, {}).get(copy or fn, [])
4269 pstates = matches.get(parent, {}).get(copy or fn, [])
4270 if pstates or states:
4270 if pstates or states:
4271 r = display(fm, fn, ctx, pstates, states)
4271 r = display(fm, fn, ctx, pstates, states)
4272 found = found or r
4272 found = found or r
4273 if r and not opts.get('all'):
4273 if r and not opts.get('all'):
4274 skip[fn] = True
4274 skip[fn] = True
4275 if copy:
4275 if copy:
4276 skip[copy] = True
4276 skip[copy] = True
4277 del matches[rev]
4277 del matches[rev]
4278 del revfiles[rev]
4278 del revfiles[rev]
4279 fm.end()
4279 fm.end()
4280
4280
4281 return not found
4281 return not found
4282
4282
4283 @command('heads',
4283 @command('heads',
4284 [('r', 'rev', '',
4284 [('r', 'rev', '',
4285 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4285 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4286 ('t', 'topo', False, _('show topological heads only')),
4286 ('t', 'topo', False, _('show topological heads only')),
4287 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4287 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4288 ('c', 'closed', False, _('show normal and closed branch heads')),
4288 ('c', 'closed', False, _('show normal and closed branch heads')),
4289 ] + templateopts,
4289 ] + templateopts,
4290 _('[-ct] [-r STARTREV] [REV]...'))
4290 _('[-ct] [-r STARTREV] [REV]...'))
4291 def heads(ui, repo, *branchrevs, **opts):
4291 def heads(ui, repo, *branchrevs, **opts):
4292 """show branch heads
4292 """show branch heads
4293
4293
4294 With no arguments, show all open branch heads in the repository.
4294 With no arguments, show all open branch heads in the repository.
4295 Branch heads are changesets that have no descendants on the
4295 Branch heads are changesets that have no descendants on the
4296 same branch. They are where development generally takes place and
4296 same branch. They are where development generally takes place and
4297 are the usual targets for update and merge operations.
4297 are the usual targets for update and merge operations.
4298
4298
4299 If one or more REVs are given, only open branch heads on the
4299 If one or more REVs are given, only open branch heads on the
4300 branches associated with the specified changesets are shown. This
4300 branches associated with the specified changesets are shown. This
4301 means that you can use :hg:`heads .` to see the heads on the
4301 means that you can use :hg:`heads .` to see the heads on the
4302 currently checked-out branch.
4302 currently checked-out branch.
4303
4303
4304 If -c/--closed is specified, also show branch heads marked closed
4304 If -c/--closed is specified, also show branch heads marked closed
4305 (see :hg:`commit --close-branch`).
4305 (see :hg:`commit --close-branch`).
4306
4306
4307 If STARTREV is specified, only those heads that are descendants of
4307 If STARTREV is specified, only those heads that are descendants of
4308 STARTREV will be displayed.
4308 STARTREV will be displayed.
4309
4309
4310 If -t/--topo is specified, named branch mechanics will be ignored and only
4310 If -t/--topo is specified, named branch mechanics will be ignored and only
4311 topological heads (changesets with no children) will be shown.
4311 topological heads (changesets with no children) will be shown.
4312
4312
4313 Returns 0 if matching heads are found, 1 if not.
4313 Returns 0 if matching heads are found, 1 if not.
4314 """
4314 """
4315
4315
4316 start = None
4316 start = None
4317 if 'rev' in opts:
4317 if 'rev' in opts:
4318 start = scmutil.revsingle(repo, opts['rev'], None).node()
4318 start = scmutil.revsingle(repo, opts['rev'], None).node()
4319
4319
4320 if opts.get('topo'):
4320 if opts.get('topo'):
4321 heads = [repo[h] for h in repo.heads(start)]
4321 heads = [repo[h] for h in repo.heads(start)]
4322 else:
4322 else:
4323 heads = []
4323 heads = []
4324 for branch in repo.branchmap():
4324 for branch in repo.branchmap():
4325 heads += repo.branchheads(branch, start, opts.get('closed'))
4325 heads += repo.branchheads(branch, start, opts.get('closed'))
4326 heads = [repo[h] for h in heads]
4326 heads = [repo[h] for h in heads]
4327
4327
4328 if branchrevs:
4328 if branchrevs:
4329 branches = set(repo[br].branch() for br in branchrevs)
4329 branches = set(repo[br].branch() for br in branchrevs)
4330 heads = [h for h in heads if h.branch() in branches]
4330 heads = [h for h in heads if h.branch() in branches]
4331
4331
4332 if opts.get('active') and branchrevs:
4332 if opts.get('active') and branchrevs:
4333 dagheads = repo.heads(start)
4333 dagheads = repo.heads(start)
4334 heads = [h for h in heads if h.node() in dagheads]
4334 heads = [h for h in heads if h.node() in dagheads]
4335
4335
4336 if branchrevs:
4336 if branchrevs:
4337 haveheads = set(h.branch() for h in heads)
4337 haveheads = set(h.branch() for h in heads)
4338 if branches - haveheads:
4338 if branches - haveheads:
4339 headless = ', '.join(b for b in branches - haveheads)
4339 headless = ', '.join(b for b in branches - haveheads)
4340 msg = _('no open branch heads found on branches %s')
4340 msg = _('no open branch heads found on branches %s')
4341 if opts.get('rev'):
4341 if opts.get('rev'):
4342 msg += _(' (started at %s)') % opts['rev']
4342 msg += _(' (started at %s)') % opts['rev']
4343 ui.warn((msg + '\n') % headless)
4343 ui.warn((msg + '\n') % headless)
4344
4344
4345 if not heads:
4345 if not heads:
4346 return 1
4346 return 1
4347
4347
4348 heads = sorted(heads, key=lambda x: -x.rev())
4348 heads = sorted(heads, key=lambda x: -x.rev())
4349 displayer = cmdutil.show_changeset(ui, repo, opts)
4349 displayer = cmdutil.show_changeset(ui, repo, opts)
4350 for ctx in heads:
4350 for ctx in heads:
4351 displayer.show(ctx)
4351 displayer.show(ctx)
4352 displayer.close()
4352 displayer.close()
4353
4353
4354 @command('help',
4354 @command('help',
4355 [('e', 'extension', None, _('show only help for extensions')),
4355 [('e', 'extension', None, _('show only help for extensions')),
4356 ('c', 'command', None, _('show only help for commands')),
4356 ('c', 'command', None, _('show only help for commands')),
4357 ('k', 'keyword', None, _('show topics matching keyword')),
4357 ('k', 'keyword', None, _('show topics matching keyword')),
4358 ('s', 'system', [], _('show help for specific platform(s)')),
4358 ('s', 'system', [], _('show help for specific platform(s)')),
4359 ],
4359 ],
4360 _('[-ecks] [TOPIC]'),
4360 _('[-ecks] [TOPIC]'),
4361 norepo=True)
4361 norepo=True)
4362 def help_(ui, name=None, **opts):
4362 def help_(ui, name=None, **opts):
4363 """show help for a given topic or a help overview
4363 """show help for a given topic or a help overview
4364
4364
4365 With no arguments, print a list of commands with short help messages.
4365 With no arguments, print a list of commands with short help messages.
4366
4366
4367 Given a topic, extension, or command name, print help for that
4367 Given a topic, extension, or command name, print help for that
4368 topic.
4368 topic.
4369
4369
4370 Returns 0 if successful.
4370 Returns 0 if successful.
4371 """
4371 """
4372
4372
4373 textwidth = ui.configint('ui', 'textwidth', 78)
4373 textwidth = ui.configint('ui', 'textwidth', 78)
4374 termwidth = ui.termwidth() - 2
4374 termwidth = ui.termwidth() - 2
4375 if textwidth <= 0 or termwidth < textwidth:
4375 if textwidth <= 0 or termwidth < textwidth:
4376 textwidth = termwidth
4376 textwidth = termwidth
4377
4377
4378 keep = opts.get('system') or []
4378 keep = opts.get('system') or []
4379 if len(keep) == 0:
4379 if len(keep) == 0:
4380 if sys.platform.startswith('win'):
4380 if sys.platform.startswith('win'):
4381 keep.append('windows')
4381 keep.append('windows')
4382 elif sys.platform == 'OpenVMS':
4382 elif sys.platform == 'OpenVMS':
4383 keep.append('vms')
4383 keep.append('vms')
4384 elif sys.platform == 'plan9':
4384 elif sys.platform == 'plan9':
4385 keep.append('plan9')
4385 keep.append('plan9')
4386 else:
4386 else:
4387 keep.append('unix')
4387 keep.append('unix')
4388 keep.append(sys.platform.lower())
4388 keep.append(sys.platform.lower())
4389 if ui.verbose:
4389 if ui.verbose:
4390 keep.append('verbose')
4390 keep.append('verbose')
4391
4391
4392 section = None
4392 section = None
4393 subtopic = None
4393 subtopic = None
4394 if name and '.' in name:
4394 if name and '.' in name:
4395 name, remaining = name.split('.', 1)
4395 name, remaining = name.split('.', 1)
4396 remaining = encoding.lower(remaining)
4396 remaining = encoding.lower(remaining)
4397 if '.' in remaining:
4397 if '.' in remaining:
4398 subtopic, section = remaining.split('.', 1)
4398 subtopic, section = remaining.split('.', 1)
4399 else:
4399 else:
4400 if name in help.subtopics:
4400 if name in help.subtopics:
4401 subtopic = remaining
4401 subtopic = remaining
4402 else:
4402 else:
4403 section = remaining
4403 section = remaining
4404
4404
4405 text = help.help_(ui, name, subtopic=subtopic, **opts)
4405 text = help.help_(ui, name, subtopic=subtopic, **opts)
4406
4406
4407 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4407 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4408 section=section)
4408 section=section)
4409
4409
4410 # We could have been given a weird ".foo" section without a name
4410 # We could have been given a weird ".foo" section without a name
4411 # to look for, or we could have simply failed to found "foo.bar"
4411 # to look for, or we could have simply failed to found "foo.bar"
4412 # because bar isn't a section of foo
4412 # because bar isn't a section of foo
4413 if section and not (formatted and name):
4413 if section and not (formatted and name):
4414 raise error.Abort(_("help section not found"))
4414 raise error.Abort(_("help section not found"))
4415
4415
4416 if 'verbose' in pruned:
4416 if 'verbose' in pruned:
4417 keep.append('omitted')
4417 keep.append('omitted')
4418 else:
4418 else:
4419 keep.append('notomitted')
4419 keep.append('notomitted')
4420 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4420 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4421 section=section)
4421 section=section)
4422 ui.write(formatted)
4422 ui.write(formatted)
4423
4423
4424
4424
4425 @command('identify|id',
4425 @command('identify|id',
4426 [('r', 'rev', '',
4426 [('r', 'rev', '',
4427 _('identify the specified revision'), _('REV')),
4427 _('identify the specified revision'), _('REV')),
4428 ('n', 'num', None, _('show local revision number')),
4428 ('n', 'num', None, _('show local revision number')),
4429 ('i', 'id', None, _('show global revision id')),
4429 ('i', 'id', None, _('show global revision id')),
4430 ('b', 'branch', None, _('show branch')),
4430 ('b', 'branch', None, _('show branch')),
4431 ('t', 'tags', None, _('show tags')),
4431 ('t', 'tags', None, _('show tags')),
4432 ('B', 'bookmarks', None, _('show bookmarks')),
4432 ('B', 'bookmarks', None, _('show bookmarks')),
4433 ] + remoteopts,
4433 ] + remoteopts,
4434 _('[-nibtB] [-r REV] [SOURCE]'),
4434 _('[-nibtB] [-r REV] [SOURCE]'),
4435 optionalrepo=True)
4435 optionalrepo=True)
4436 def identify(ui, repo, source=None, rev=None,
4436 def identify(ui, repo, source=None, rev=None,
4437 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4437 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4438 """identify the working directory or specified revision
4438 """identify the working directory or specified revision
4439
4439
4440 Print a summary identifying the repository state at REV using one or
4440 Print a summary identifying the repository state at REV using one or
4441 two parent hash identifiers, followed by a "+" if the working
4441 two parent hash identifiers, followed by a "+" if the working
4442 directory has uncommitted changes, the branch name (if not default),
4442 directory has uncommitted changes, the branch name (if not default),
4443 a list of tags, and a list of bookmarks.
4443 a list of tags, and a list of bookmarks.
4444
4444
4445 When REV is not given, print a summary of the current state of the
4445 When REV is not given, print a summary of the current state of the
4446 repository.
4446 repository.
4447
4447
4448 Specifying a path to a repository root or Mercurial bundle will
4448 Specifying a path to a repository root or Mercurial bundle will
4449 cause lookup to operate on that repository/bundle.
4449 cause lookup to operate on that repository/bundle.
4450
4450
4451 .. container:: verbose
4451 .. container:: verbose
4452
4452
4453 Examples:
4453 Examples:
4454
4454
4455 - generate a build identifier for the working directory::
4455 - generate a build identifier for the working directory::
4456
4456
4457 hg id --id > build-id.dat
4457 hg id --id > build-id.dat
4458
4458
4459 - find the revision corresponding to a tag::
4459 - find the revision corresponding to a tag::
4460
4460
4461 hg id -n -r 1.3
4461 hg id -n -r 1.3
4462
4462
4463 - check the most recent revision of a remote repository::
4463 - check the most recent revision of a remote repository::
4464
4464
4465 hg id -r tip https://www.mercurial-scm.org/repo/hg/
4465 hg id -r tip https://www.mercurial-scm.org/repo/hg/
4466
4466
4467 See :hg:`log` for generating more information about specific revisions,
4467 See :hg:`log` for generating more information about specific revisions,
4468 including full hash identifiers.
4468 including full hash identifiers.
4469
4469
4470 Returns 0 if successful.
4470 Returns 0 if successful.
4471 """
4471 """
4472
4472
4473 if not repo and not source:
4473 if not repo and not source:
4474 raise error.Abort(_("there is no Mercurial repository here "
4474 raise error.Abort(_("there is no Mercurial repository here "
4475 "(.hg not found)"))
4475 "(.hg not found)"))
4476
4476
4477 if ui.debugflag:
4477 if ui.debugflag:
4478 hexfunc = hex
4478 hexfunc = hex
4479 else:
4479 else:
4480 hexfunc = short
4480 hexfunc = short
4481 default = not (num or id or branch or tags or bookmarks)
4481 default = not (num or id or branch or tags or bookmarks)
4482 output = []
4482 output = []
4483 revs = []
4483 revs = []
4484
4484
4485 if source:
4485 if source:
4486 source, branches = hg.parseurl(ui.expandpath(source))
4486 source, branches = hg.parseurl(ui.expandpath(source))
4487 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4487 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4488 repo = peer.local()
4488 repo = peer.local()
4489 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4489 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4490
4490
4491 if not repo:
4491 if not repo:
4492 if num or branch or tags:
4492 if num or branch or tags:
4493 raise error.Abort(
4493 raise error.Abort(
4494 _("can't query remote revision number, branch, or tags"))
4494 _("can't query remote revision number, branch, or tags"))
4495 if not rev and revs:
4495 if not rev and revs:
4496 rev = revs[0]
4496 rev = revs[0]
4497 if not rev:
4497 if not rev:
4498 rev = "tip"
4498 rev = "tip"
4499
4499
4500 remoterev = peer.lookup(rev)
4500 remoterev = peer.lookup(rev)
4501 if default or id:
4501 if default or id:
4502 output = [hexfunc(remoterev)]
4502 output = [hexfunc(remoterev)]
4503
4503
4504 def getbms():
4504 def getbms():
4505 bms = []
4505 bms = []
4506
4506
4507 if 'bookmarks' in peer.listkeys('namespaces'):
4507 if 'bookmarks' in peer.listkeys('namespaces'):
4508 hexremoterev = hex(remoterev)
4508 hexremoterev = hex(remoterev)
4509 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4509 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4510 if bmr == hexremoterev]
4510 if bmr == hexremoterev]
4511
4511
4512 return sorted(bms)
4512 return sorted(bms)
4513
4513
4514 if bookmarks:
4514 if bookmarks:
4515 output.extend(getbms())
4515 output.extend(getbms())
4516 elif default and not ui.quiet:
4516 elif default and not ui.quiet:
4517 # multiple bookmarks for a single parent separated by '/'
4517 # multiple bookmarks for a single parent separated by '/'
4518 bm = '/'.join(getbms())
4518 bm = '/'.join(getbms())
4519 if bm:
4519 if bm:
4520 output.append(bm)
4520 output.append(bm)
4521 else:
4521 else:
4522 ctx = scmutil.revsingle(repo, rev, None)
4522 ctx = scmutil.revsingle(repo, rev, None)
4523
4523
4524 if ctx.rev() is None:
4524 if ctx.rev() is None:
4525 ctx = repo[None]
4525 ctx = repo[None]
4526 parents = ctx.parents()
4526 parents = ctx.parents()
4527 taglist = []
4527 taglist = []
4528 for p in parents:
4528 for p in parents:
4529 taglist.extend(p.tags())
4529 taglist.extend(p.tags())
4530
4530
4531 changed = ""
4531 changed = ""
4532 if default or id or num:
4532 if default or id or num:
4533 if (any(repo.status())
4533 if (any(repo.status())
4534 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4534 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4535 changed = '+'
4535 changed = '+'
4536 if default or id:
4536 if default or id:
4537 output = ["%s%s" %
4537 output = ["%s%s" %
4538 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4538 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4539 if num:
4539 if num:
4540 output.append("%s%s" %
4540 output.append("%s%s" %
4541 ('+'.join([str(p.rev()) for p in parents]), changed))
4541 ('+'.join([str(p.rev()) for p in parents]), changed))
4542 else:
4542 else:
4543 if default or id:
4543 if default or id:
4544 output = [hexfunc(ctx.node())]
4544 output = [hexfunc(ctx.node())]
4545 if num:
4545 if num:
4546 output.append(str(ctx.rev()))
4546 output.append(str(ctx.rev()))
4547 taglist = ctx.tags()
4547 taglist = ctx.tags()
4548
4548
4549 if default and not ui.quiet:
4549 if default and not ui.quiet:
4550 b = ctx.branch()
4550 b = ctx.branch()
4551 if b != 'default':
4551 if b != 'default':
4552 output.append("(%s)" % b)
4552 output.append("(%s)" % b)
4553
4553
4554 # multiple tags for a single parent separated by '/'
4554 # multiple tags for a single parent separated by '/'
4555 t = '/'.join(taglist)
4555 t = '/'.join(taglist)
4556 if t:
4556 if t:
4557 output.append(t)
4557 output.append(t)
4558
4558
4559 # multiple bookmarks for a single parent separated by '/'
4559 # multiple bookmarks for a single parent separated by '/'
4560 bm = '/'.join(ctx.bookmarks())
4560 bm = '/'.join(ctx.bookmarks())
4561 if bm:
4561 if bm:
4562 output.append(bm)
4562 output.append(bm)
4563 else:
4563 else:
4564 if branch:
4564 if branch:
4565 output.append(ctx.branch())
4565 output.append(ctx.branch())
4566
4566
4567 if tags:
4567 if tags:
4568 output.extend(taglist)
4568 output.extend(taglist)
4569
4569
4570 if bookmarks:
4570 if bookmarks:
4571 output.extend(ctx.bookmarks())
4571 output.extend(ctx.bookmarks())
4572
4572
4573 ui.write("%s\n" % ' '.join(output))
4573 ui.write("%s\n" % ' '.join(output))
4574
4574
4575 @command('import|patch',
4575 @command('import|patch',
4576 [('p', 'strip', 1,
4576 [('p', 'strip', 1,
4577 _('directory strip option for patch. This has the same '
4577 _('directory strip option for patch. This has the same '
4578 'meaning as the corresponding patch option'), _('NUM')),
4578 'meaning as the corresponding patch option'), _('NUM')),
4579 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4579 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4580 ('e', 'edit', False, _('invoke editor on commit messages')),
4580 ('e', 'edit', False, _('invoke editor on commit messages')),
4581 ('f', 'force', None,
4581 ('f', 'force', None,
4582 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4582 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4583 ('', 'no-commit', None,
4583 ('', 'no-commit', None,
4584 _("don't commit, just update the working directory")),
4584 _("don't commit, just update the working directory")),
4585 ('', 'bypass', None,
4585 ('', 'bypass', None,
4586 _("apply patch without touching the working directory")),
4586 _("apply patch without touching the working directory")),
4587 ('', 'partial', None,
4587 ('', 'partial', None,
4588 _('commit even if some hunks fail')),
4588 _('commit even if some hunks fail')),
4589 ('', 'exact', None,
4589 ('', 'exact', None,
4590 _('abort if patch would apply lossily')),
4590 _('abort if patch would apply lossily')),
4591 ('', 'prefix', '',
4591 ('', 'prefix', '',
4592 _('apply patch to subdirectory'), _('DIR')),
4592 _('apply patch to subdirectory'), _('DIR')),
4593 ('', 'import-branch', None,
4593 ('', 'import-branch', None,
4594 _('use any branch information in patch (implied by --exact)'))] +
4594 _('use any branch information in patch (implied by --exact)'))] +
4595 commitopts + commitopts2 + similarityopts,
4595 commitopts + commitopts2 + similarityopts,
4596 _('[OPTION]... PATCH...'))
4596 _('[OPTION]... PATCH...'))
4597 def import_(ui, repo, patch1=None, *patches, **opts):
4597 def import_(ui, repo, patch1=None, *patches, **opts):
4598 """import an ordered set of patches
4598 """import an ordered set of patches
4599
4599
4600 Import a list of patches and commit them individually (unless
4600 Import a list of patches and commit them individually (unless
4601 --no-commit is specified).
4601 --no-commit is specified).
4602
4602
4603 To read a patch from standard input, use "-" as the patch name. If
4603 To read a patch from standard input, use "-" as the patch name. If
4604 a URL is specified, the patch will be downloaded from there.
4604 a URL is specified, the patch will be downloaded from there.
4605
4605
4606 Import first applies changes to the working directory (unless
4606 Import first applies changes to the working directory (unless
4607 --bypass is specified), import will abort if there are outstanding
4607 --bypass is specified), import will abort if there are outstanding
4608 changes.
4608 changes.
4609
4609
4610 Use --bypass to apply and commit patches directly to the
4610 Use --bypass to apply and commit patches directly to the
4611 repository, without affecting the working directory. Without
4611 repository, without affecting the working directory. Without
4612 --exact, patches will be applied on top of the working directory
4612 --exact, patches will be applied on top of the working directory
4613 parent revision.
4613 parent revision.
4614
4614
4615 You can import a patch straight from a mail message. Even patches
4615 You can import a patch straight from a mail message. Even patches
4616 as attachments work (to use the body part, it must have type
4616 as attachments work (to use the body part, it must have type
4617 text/plain or text/x-patch). From and Subject headers of email
4617 text/plain or text/x-patch). From and Subject headers of email
4618 message are used as default committer and commit message. All
4618 message are used as default committer and commit message. All
4619 text/plain body parts before first diff are added to the commit
4619 text/plain body parts before first diff are added to the commit
4620 message.
4620 message.
4621
4621
4622 If the imported patch was generated by :hg:`export`, user and
4622 If the imported patch was generated by :hg:`export`, user and
4623 description from patch override values from message headers and
4623 description from patch override values from message headers and
4624 body. Values given on command line with -m/--message and -u/--user
4624 body. Values given on command line with -m/--message and -u/--user
4625 override these.
4625 override these.
4626
4626
4627 If --exact is specified, import will set the working directory to
4627 If --exact is specified, import will set the working directory to
4628 the parent of each patch before applying it, and will abort if the
4628 the parent of each patch before applying it, and will abort if the
4629 resulting changeset has a different ID than the one recorded in
4629 resulting changeset has a different ID than the one recorded in
4630 the patch. This will guard against various ways that portable
4630 the patch. This will guard against various ways that portable
4631 patch formats and mail systems might fail to transfer Mercurial
4631 patch formats and mail systems might fail to transfer Mercurial
4632 data or metadata. See :hg:`bundle` for lossless transmission.
4632 data or metadata. See :hg:`bundle` for lossless transmission.
4633
4633
4634 Use --partial to ensure a changeset will be created from the patch
4634 Use --partial to ensure a changeset will be created from the patch
4635 even if some hunks fail to apply. Hunks that fail to apply will be
4635 even if some hunks fail to apply. Hunks that fail to apply will be
4636 written to a <target-file>.rej file. Conflicts can then be resolved
4636 written to a <target-file>.rej file. Conflicts can then be resolved
4637 by hand before :hg:`commit --amend` is run to update the created
4637 by hand before :hg:`commit --amend` is run to update the created
4638 changeset. This flag exists to let people import patches that
4638 changeset. This flag exists to let people import patches that
4639 partially apply without losing the associated metadata (author,
4639 partially apply without losing the associated metadata (author,
4640 date, description, ...).
4640 date, description, ...).
4641
4641
4642 .. note::
4642 .. note::
4643
4643
4644 When no hunks apply cleanly, :hg:`import --partial` will create
4644 When no hunks apply cleanly, :hg:`import --partial` will create
4645 an empty changeset, importing only the patch metadata.
4645 an empty changeset, importing only the patch metadata.
4646
4646
4647 With -s/--similarity, hg will attempt to discover renames and
4647 With -s/--similarity, hg will attempt to discover renames and
4648 copies in the patch in the same way as :hg:`addremove`.
4648 copies in the patch in the same way as :hg:`addremove`.
4649
4649
4650 It is possible to use external patch programs to perform the patch
4650 It is possible to use external patch programs to perform the patch
4651 by setting the ``ui.patch`` configuration option. For the default
4651 by setting the ``ui.patch`` configuration option. For the default
4652 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4652 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4653 See :hg:`help config` for more information about configuration
4653 See :hg:`help config` for more information about configuration
4654 files and how to use these options.
4654 files and how to use these options.
4655
4655
4656 See :hg:`help dates` for a list of formats valid for -d/--date.
4656 See :hg:`help dates` for a list of formats valid for -d/--date.
4657
4657
4658 .. container:: verbose
4658 .. container:: verbose
4659
4659
4660 Examples:
4660 Examples:
4661
4661
4662 - import a traditional patch from a website and detect renames::
4662 - import a traditional patch from a website and detect renames::
4663
4663
4664 hg import -s 80 http://example.com/bugfix.patch
4664 hg import -s 80 http://example.com/bugfix.patch
4665
4665
4666 - import a changeset from an hgweb server::
4666 - import a changeset from an hgweb server::
4667
4667
4668 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4668 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4669
4669
4670 - import all the patches in an Unix-style mbox::
4670 - import all the patches in an Unix-style mbox::
4671
4671
4672 hg import incoming-patches.mbox
4672 hg import incoming-patches.mbox
4673
4673
4674 - attempt to exactly restore an exported changeset (not always
4674 - attempt to exactly restore an exported changeset (not always
4675 possible)::
4675 possible)::
4676
4676
4677 hg import --exact proposed-fix.patch
4677 hg import --exact proposed-fix.patch
4678
4678
4679 - use an external tool to apply a patch which is too fuzzy for
4679 - use an external tool to apply a patch which is too fuzzy for
4680 the default internal tool.
4680 the default internal tool.
4681
4681
4682 hg import --config ui.patch="patch --merge" fuzzy.patch
4682 hg import --config ui.patch="patch --merge" fuzzy.patch
4683
4683
4684 - change the default fuzzing from 2 to a less strict 7
4684 - change the default fuzzing from 2 to a less strict 7
4685
4685
4686 hg import --config ui.fuzz=7 fuzz.patch
4686 hg import --config ui.fuzz=7 fuzz.patch
4687
4687
4688 Returns 0 on success, 1 on partial success (see --partial).
4688 Returns 0 on success, 1 on partial success (see --partial).
4689 """
4689 """
4690
4690
4691 if not patch1:
4691 if not patch1:
4692 raise error.Abort(_('need at least one patch to import'))
4692 raise error.Abort(_('need at least one patch to import'))
4693
4693
4694 patches = (patch1,) + patches
4694 patches = (patch1,) + patches
4695
4695
4696 date = opts.get('date')
4696 date = opts.get('date')
4697 if date:
4697 if date:
4698 opts['date'] = util.parsedate(date)
4698 opts['date'] = util.parsedate(date)
4699
4699
4700 exact = opts.get('exact')
4700 exact = opts.get('exact')
4701 update = not opts.get('bypass')
4701 update = not opts.get('bypass')
4702 if not update and opts.get('no_commit'):
4702 if not update and opts.get('no_commit'):
4703 raise error.Abort(_('cannot use --no-commit with --bypass'))
4703 raise error.Abort(_('cannot use --no-commit with --bypass'))
4704 try:
4704 try:
4705 sim = float(opts.get('similarity') or 0)
4705 sim = float(opts.get('similarity') or 0)
4706 except ValueError:
4706 except ValueError:
4707 raise error.Abort(_('similarity must be a number'))
4707 raise error.Abort(_('similarity must be a number'))
4708 if sim < 0 or sim > 100:
4708 if sim < 0 or sim > 100:
4709 raise error.Abort(_('similarity must be between 0 and 100'))
4709 raise error.Abort(_('similarity must be between 0 and 100'))
4710 if sim and not update:
4710 if sim and not update:
4711 raise error.Abort(_('cannot use --similarity with --bypass'))
4711 raise error.Abort(_('cannot use --similarity with --bypass'))
4712 if exact:
4712 if exact:
4713 if opts.get('edit'):
4713 if opts.get('edit'):
4714 raise error.Abort(_('cannot use --exact with --edit'))
4714 raise error.Abort(_('cannot use --exact with --edit'))
4715 if opts.get('prefix'):
4715 if opts.get('prefix'):
4716 raise error.Abort(_('cannot use --exact with --prefix'))
4716 raise error.Abort(_('cannot use --exact with --prefix'))
4717
4717
4718 base = opts["base"]
4718 base = opts["base"]
4719 wlock = dsguard = lock = tr = None
4719 wlock = dsguard = lock = tr = None
4720 msgs = []
4720 msgs = []
4721 ret = 0
4721 ret = 0
4722
4722
4723
4723
4724 try:
4724 try:
4725 wlock = repo.wlock()
4725 wlock = repo.wlock()
4726
4726
4727 if update:
4727 if update:
4728 cmdutil.checkunfinished(repo)
4728 cmdutil.checkunfinished(repo)
4729 if (exact or not opts.get('force')):
4729 if (exact or not opts.get('force')):
4730 cmdutil.bailifchanged(repo)
4730 cmdutil.bailifchanged(repo)
4731
4731
4732 if not opts.get('no_commit'):
4732 if not opts.get('no_commit'):
4733 lock = repo.lock()
4733 lock = repo.lock()
4734 tr = repo.transaction('import')
4734 tr = repo.transaction('import')
4735 else:
4735 else:
4736 dsguard = dirstateguard.dirstateguard(repo, 'import')
4736 dsguard = dirstateguard.dirstateguard(repo, 'import')
4737 parents = repo[None].parents()
4737 parents = repo[None].parents()
4738 for patchurl in patches:
4738 for patchurl in patches:
4739 if patchurl == '-':
4739 if patchurl == '-':
4740 ui.status(_('applying patch from stdin\n'))
4740 ui.status(_('applying patch from stdin\n'))
4741 patchfile = ui.fin
4741 patchfile = ui.fin
4742 patchurl = 'stdin' # for error message
4742 patchurl = 'stdin' # for error message
4743 else:
4743 else:
4744 patchurl = os.path.join(base, patchurl)
4744 patchurl = os.path.join(base, patchurl)
4745 ui.status(_('applying %s\n') % patchurl)
4745 ui.status(_('applying %s\n') % patchurl)
4746 patchfile = hg.openpath(ui, patchurl)
4746 patchfile = hg.openpath(ui, patchurl)
4747
4747
4748 haspatch = False
4748 haspatch = False
4749 for hunk in patch.split(patchfile):
4749 for hunk in patch.split(patchfile):
4750 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4750 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4751 parents, opts,
4751 parents, opts,
4752 msgs, hg.clean)
4752 msgs, hg.clean)
4753 if msg:
4753 if msg:
4754 haspatch = True
4754 haspatch = True
4755 ui.note(msg + '\n')
4755 ui.note(msg + '\n')
4756 if update or exact:
4756 if update or exact:
4757 parents = repo[None].parents()
4757 parents = repo[None].parents()
4758 else:
4758 else:
4759 parents = [repo[node]]
4759 parents = [repo[node]]
4760 if rej:
4760 if rej:
4761 ui.write_err(_("patch applied partially\n"))
4761 ui.write_err(_("patch applied partially\n"))
4762 ui.write_err(_("(fix the .rej files and run "
4762 ui.write_err(_("(fix the .rej files and run "
4763 "`hg commit --amend`)\n"))
4763 "`hg commit --amend`)\n"))
4764 ret = 1
4764 ret = 1
4765 break
4765 break
4766
4766
4767 if not haspatch:
4767 if not haspatch:
4768 raise error.Abort(_('%s: no diffs found') % patchurl)
4768 raise error.Abort(_('%s: no diffs found') % patchurl)
4769
4769
4770 if tr:
4770 if tr:
4771 tr.close()
4771 tr.close()
4772 if msgs:
4772 if msgs:
4773 repo.savecommitmessage('\n* * *\n'.join(msgs))
4773 repo.savecommitmessage('\n* * *\n'.join(msgs))
4774 if dsguard:
4774 if dsguard:
4775 dsguard.close()
4775 dsguard.close()
4776 return ret
4776 return ret
4777 finally:
4777 finally:
4778 if tr:
4778 if tr:
4779 tr.release()
4779 tr.release()
4780 release(lock, dsguard, wlock)
4780 release(lock, dsguard, wlock)
4781
4781
4782 @command('incoming|in',
4782 @command('incoming|in',
4783 [('f', 'force', None,
4783 [('f', 'force', None,
4784 _('run even if remote repository is unrelated')),
4784 _('run even if remote repository is unrelated')),
4785 ('n', 'newest-first', None, _('show newest record first')),
4785 ('n', 'newest-first', None, _('show newest record first')),
4786 ('', 'bundle', '',
4786 ('', 'bundle', '',
4787 _('file to store the bundles into'), _('FILE')),
4787 _('file to store the bundles into'), _('FILE')),
4788 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4788 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4789 ('B', 'bookmarks', False, _("compare bookmarks")),
4789 ('B', 'bookmarks', False, _("compare bookmarks")),
4790 ('b', 'branch', [],
4790 ('b', 'branch', [],
4791 _('a specific branch you would like to pull'), _('BRANCH')),
4791 _('a specific branch you would like to pull'), _('BRANCH')),
4792 ] + logopts + remoteopts + subrepoopts,
4792 ] + logopts + remoteopts + subrepoopts,
4793 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4793 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4794 def incoming(ui, repo, source="default", **opts):
4794 def incoming(ui, repo, source="default", **opts):
4795 """show new changesets found in source
4795 """show new changesets found in source
4796
4796
4797 Show new changesets found in the specified path/URL or the default
4797 Show new changesets found in the specified path/URL or the default
4798 pull location. These are the changesets that would have been pulled
4798 pull location. These are the changesets that would have been pulled
4799 if a pull at the time you issued this command.
4799 if a pull at the time you issued this command.
4800
4800
4801 See pull for valid source format details.
4801 See pull for valid source format details.
4802
4802
4803 .. container:: verbose
4803 .. container:: verbose
4804
4804
4805 With -B/--bookmarks, the result of bookmark comparison between
4805 With -B/--bookmarks, the result of bookmark comparison between
4806 local and remote repositories is displayed. With -v/--verbose,
4806 local and remote repositories is displayed. With -v/--verbose,
4807 status is also displayed for each bookmark like below::
4807 status is also displayed for each bookmark like below::
4808
4808
4809 BM1 01234567890a added
4809 BM1 01234567890a added
4810 BM2 1234567890ab advanced
4810 BM2 1234567890ab advanced
4811 BM3 234567890abc diverged
4811 BM3 234567890abc diverged
4812 BM4 34567890abcd changed
4812 BM4 34567890abcd changed
4813
4813
4814 The action taken locally when pulling depends on the
4814 The action taken locally when pulling depends on the
4815 status of each bookmark:
4815 status of each bookmark:
4816
4816
4817 :``added``: pull will create it
4817 :``added``: pull will create it
4818 :``advanced``: pull will update it
4818 :``advanced``: pull will update it
4819 :``diverged``: pull will create a divergent bookmark
4819 :``diverged``: pull will create a divergent bookmark
4820 :``changed``: result depends on remote changesets
4820 :``changed``: result depends on remote changesets
4821
4821
4822 From the point of view of pulling behavior, bookmark
4822 From the point of view of pulling behavior, bookmark
4823 existing only in the remote repository are treated as ``added``,
4823 existing only in the remote repository are treated as ``added``,
4824 even if it is in fact locally deleted.
4824 even if it is in fact locally deleted.
4825
4825
4826 .. container:: verbose
4826 .. container:: verbose
4827
4827
4828 For remote repository, using --bundle avoids downloading the
4828 For remote repository, using --bundle avoids downloading the
4829 changesets twice if the incoming is followed by a pull.
4829 changesets twice if the incoming is followed by a pull.
4830
4830
4831 Examples:
4831 Examples:
4832
4832
4833 - show incoming changes with patches and full description::
4833 - show incoming changes with patches and full description::
4834
4834
4835 hg incoming -vp
4835 hg incoming -vp
4836
4836
4837 - show incoming changes excluding merges, store a bundle::
4837 - show incoming changes excluding merges, store a bundle::
4838
4838
4839 hg in -vpM --bundle incoming.hg
4839 hg in -vpM --bundle incoming.hg
4840 hg pull incoming.hg
4840 hg pull incoming.hg
4841
4841
4842 - briefly list changes inside a bundle::
4842 - briefly list changes inside a bundle::
4843
4843
4844 hg in changes.hg -T "{desc|firstline}\\n"
4844 hg in changes.hg -T "{desc|firstline}\\n"
4845
4845
4846 Returns 0 if there are incoming changes, 1 otherwise.
4846 Returns 0 if there are incoming changes, 1 otherwise.
4847 """
4847 """
4848 if opts.get('graph'):
4848 if opts.get('graph'):
4849 cmdutil.checkunsupportedgraphflags([], opts)
4849 cmdutil.checkunsupportedgraphflags([], opts)
4850 def display(other, chlist, displayer):
4850 def display(other, chlist, displayer):
4851 revdag = cmdutil.graphrevs(other, chlist, opts)
4851 revdag = cmdutil.graphrevs(other, chlist, opts)
4852 cmdutil.displaygraph(ui, repo, revdag, displayer,
4852 cmdutil.displaygraph(ui, repo, revdag, displayer,
4853 graphmod.asciiedges)
4853 graphmod.asciiedges)
4854
4854
4855 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4855 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4856 return 0
4856 return 0
4857
4857
4858 if opts.get('bundle') and opts.get('subrepos'):
4858 if opts.get('bundle') and opts.get('subrepos'):
4859 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4859 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4860
4860
4861 if opts.get('bookmarks'):
4861 if opts.get('bookmarks'):
4862 source, branches = hg.parseurl(ui.expandpath(source),
4862 source, branches = hg.parseurl(ui.expandpath(source),
4863 opts.get('branch'))
4863 opts.get('branch'))
4864 other = hg.peer(repo, opts, source)
4864 other = hg.peer(repo, opts, source)
4865 if 'bookmarks' not in other.listkeys('namespaces'):
4865 if 'bookmarks' not in other.listkeys('namespaces'):
4866 ui.warn(_("remote doesn't support bookmarks\n"))
4866 ui.warn(_("remote doesn't support bookmarks\n"))
4867 return 0
4867 return 0
4868 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4868 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4869 return bookmarks.incoming(ui, repo, other)
4869 return bookmarks.incoming(ui, repo, other)
4870
4870
4871 repo._subtoppath = ui.expandpath(source)
4871 repo._subtoppath = ui.expandpath(source)
4872 try:
4872 try:
4873 return hg.incoming(ui, repo, source, opts)
4873 return hg.incoming(ui, repo, source, opts)
4874 finally:
4874 finally:
4875 del repo._subtoppath
4875 del repo._subtoppath
4876
4876
4877
4877
4878 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4878 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4879 norepo=True)
4879 norepo=True)
4880 def init(ui, dest=".", **opts):
4880 def init(ui, dest=".", **opts):
4881 """create a new repository in the given directory
4881 """create a new repository in the given directory
4882
4882
4883 Initialize a new repository in the given directory. If the given
4883 Initialize a new repository in the given directory. If the given
4884 directory does not exist, it will be created.
4884 directory does not exist, it will be created.
4885
4885
4886 If no directory is given, the current directory is used.
4886 If no directory is given, the current directory is used.
4887
4887
4888 It is possible to specify an ``ssh://`` URL as the destination.
4888 It is possible to specify an ``ssh://`` URL as the destination.
4889 See :hg:`help urls` for more information.
4889 See :hg:`help urls` for more information.
4890
4890
4891 Returns 0 on success.
4891 Returns 0 on success.
4892 """
4892 """
4893 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4893 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4894
4894
4895 @command('locate',
4895 @command('locate',
4896 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4896 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4897 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4897 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4898 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4898 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4899 ] + walkopts,
4899 ] + walkopts,
4900 _('[OPTION]... [PATTERN]...'))
4900 _('[OPTION]... [PATTERN]...'))
4901 def locate(ui, repo, *pats, **opts):
4901 def locate(ui, repo, *pats, **opts):
4902 """locate files matching specific patterns (DEPRECATED)
4902 """locate files matching specific patterns (DEPRECATED)
4903
4903
4904 Print files under Mercurial control in the working directory whose
4904 Print files under Mercurial control in the working directory whose
4905 names match the given patterns.
4905 names match the given patterns.
4906
4906
4907 By default, this command searches all directories in the working
4907 By default, this command searches all directories in the working
4908 directory. To search just the current directory and its
4908 directory. To search just the current directory and its
4909 subdirectories, use "--include .".
4909 subdirectories, use "--include .".
4910
4910
4911 If no patterns are given to match, this command prints the names
4911 If no patterns are given to match, this command prints the names
4912 of all files under Mercurial control in the working directory.
4912 of all files under Mercurial control in the working directory.
4913
4913
4914 If you want to feed the output of this command into the "xargs"
4914 If you want to feed the output of this command into the "xargs"
4915 command, use the -0 option to both this command and "xargs". This
4915 command, use the -0 option to both this command and "xargs". This
4916 will avoid the problem of "xargs" treating single filenames that
4916 will avoid the problem of "xargs" treating single filenames that
4917 contain whitespace as multiple filenames.
4917 contain whitespace as multiple filenames.
4918
4918
4919 See :hg:`help files` for a more versatile command.
4919 See :hg:`help files` for a more versatile command.
4920
4920
4921 Returns 0 if a match is found, 1 otherwise.
4921 Returns 0 if a match is found, 1 otherwise.
4922 """
4922 """
4923 if opts.get('print0'):
4923 if opts.get('print0'):
4924 end = '\0'
4924 end = '\0'
4925 else:
4925 else:
4926 end = '\n'
4926 end = '\n'
4927 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4927 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4928
4928
4929 ret = 1
4929 ret = 1
4930 ctx = repo[rev]
4930 ctx = repo[rev]
4931 m = scmutil.match(ctx, pats, opts, default='relglob',
4931 m = scmutil.match(ctx, pats, opts, default='relglob',
4932 badfn=lambda x, y: False)
4932 badfn=lambda x, y: False)
4933
4933
4934 for abs in ctx.matches(m):
4934 for abs in ctx.matches(m):
4935 if opts.get('fullpath'):
4935 if opts.get('fullpath'):
4936 ui.write(repo.wjoin(abs), end)
4936 ui.write(repo.wjoin(abs), end)
4937 else:
4937 else:
4938 ui.write(((pats and m.rel(abs)) or abs), end)
4938 ui.write(((pats and m.rel(abs)) or abs), end)
4939 ret = 0
4939 ret = 0
4940
4940
4941 return ret
4941 return ret
4942
4942
4943 @command('^log|history',
4943 @command('^log|history',
4944 [('f', 'follow', None,
4944 [('f', 'follow', None,
4945 _('follow changeset history, or file history across copies and renames')),
4945 _('follow changeset history, or file history across copies and renames')),
4946 ('', 'follow-first', None,
4946 ('', 'follow-first', None,
4947 _('only follow the first parent of merge changesets (DEPRECATED)')),
4947 _('only follow the first parent of merge changesets (DEPRECATED)')),
4948 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4948 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4949 ('C', 'copies', None, _('show copied files')),
4949 ('C', 'copies', None, _('show copied files')),
4950 ('k', 'keyword', [],
4950 ('k', 'keyword', [],
4951 _('do case-insensitive search for a given text'), _('TEXT')),
4951 _('do case-insensitive search for a given text'), _('TEXT')),
4952 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4952 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4953 ('', 'removed', None, _('include revisions where files were removed')),
4953 ('', 'removed', None, _('include revisions where files were removed')),
4954 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4954 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4955 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4955 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4956 ('', 'only-branch', [],
4956 ('', 'only-branch', [],
4957 _('show only changesets within the given named branch (DEPRECATED)'),
4957 _('show only changesets within the given named branch (DEPRECATED)'),
4958 _('BRANCH')),
4958 _('BRANCH')),
4959 ('b', 'branch', [],
4959 ('b', 'branch', [],
4960 _('show changesets within the given named branch'), _('BRANCH')),
4960 _('show changesets within the given named branch'), _('BRANCH')),
4961 ('P', 'prune', [],
4961 ('P', 'prune', [],
4962 _('do not display revision or any of its ancestors'), _('REV')),
4962 _('do not display revision or any of its ancestors'), _('REV')),
4963 ] + logopts + walkopts,
4963 ] + logopts + walkopts,
4964 _('[OPTION]... [FILE]'),
4964 _('[OPTION]... [FILE]'),
4965 inferrepo=True)
4965 inferrepo=True)
4966 def log(ui, repo, *pats, **opts):
4966 def log(ui, repo, *pats, **opts):
4967 """show revision history of entire repository or files
4967 """show revision history of entire repository or files
4968
4968
4969 Print the revision history of the specified files or the entire
4969 Print the revision history of the specified files or the entire
4970 project.
4970 project.
4971
4971
4972 If no revision range is specified, the default is ``tip:0`` unless
4972 If no revision range is specified, the default is ``tip:0`` unless
4973 --follow is set, in which case the working directory parent is
4973 --follow is set, in which case the working directory parent is
4974 used as the starting revision.
4974 used as the starting revision.
4975
4975
4976 File history is shown without following rename or copy history of
4976 File history is shown without following rename or copy history of
4977 files. Use -f/--follow with a filename to follow history across
4977 files. Use -f/--follow with a filename to follow history across
4978 renames and copies. --follow without a filename will only show
4978 renames and copies. --follow without a filename will only show
4979 ancestors or descendants of the starting revision.
4979 ancestors or descendants of the starting revision.
4980
4980
4981 By default this command prints revision number and changeset id,
4981 By default this command prints revision number and changeset id,
4982 tags, non-trivial parents, user, date and time, and a summary for
4982 tags, non-trivial parents, user, date and time, and a summary for
4983 each commit. When the -v/--verbose switch is used, the list of
4983 each commit. When the -v/--verbose switch is used, the list of
4984 changed files and full commit message are shown.
4984 changed files and full commit message are shown.
4985
4985
4986 With --graph the revisions are shown as an ASCII art DAG with the most
4986 With --graph the revisions are shown as an ASCII art DAG with the most
4987 recent changeset at the top.
4987 recent changeset at the top.
4988 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4988 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4989 and '+' represents a fork where the changeset from the lines below is a
4989 and '+' represents a fork where the changeset from the lines below is a
4990 parent of the 'o' merge on the same line.
4990 parent of the 'o' merge on the same line.
4991
4991
4992 .. note::
4992 .. note::
4993
4993
4994 :hg:`log --patch` may generate unexpected diff output for merge
4994 :hg:`log --patch` may generate unexpected diff output for merge
4995 changesets, as it will only compare the merge changeset against
4995 changesets, as it will only compare the merge changeset against
4996 its first parent. Also, only files different from BOTH parents
4996 its first parent. Also, only files different from BOTH parents
4997 will appear in files:.
4997 will appear in files:.
4998
4998
4999 .. note::
4999 .. note::
5000
5000
5001 For performance reasons, :hg:`log FILE` may omit duplicate changes
5001 For performance reasons, :hg:`log FILE` may omit duplicate changes
5002 made on branches and will not show removals or mode changes. To
5002 made on branches and will not show removals or mode changes. To
5003 see all such changes, use the --removed switch.
5003 see all such changes, use the --removed switch.
5004
5004
5005 .. container:: verbose
5005 .. container:: verbose
5006
5006
5007 Some examples:
5007 Some examples:
5008
5008
5009 - changesets with full descriptions and file lists::
5009 - changesets with full descriptions and file lists::
5010
5010
5011 hg log -v
5011 hg log -v
5012
5012
5013 - changesets ancestral to the working directory::
5013 - changesets ancestral to the working directory::
5014
5014
5015 hg log -f
5015 hg log -f
5016
5016
5017 - last 10 commits on the current branch::
5017 - last 10 commits on the current branch::
5018
5018
5019 hg log -l 10 -b .
5019 hg log -l 10 -b .
5020
5020
5021 - changesets showing all modifications of a file, including removals::
5021 - changesets showing all modifications of a file, including removals::
5022
5022
5023 hg log --removed file.c
5023 hg log --removed file.c
5024
5024
5025 - all changesets that touch a directory, with diffs, excluding merges::
5025 - all changesets that touch a directory, with diffs, excluding merges::
5026
5026
5027 hg log -Mp lib/
5027 hg log -Mp lib/
5028
5028
5029 - all revision numbers that match a keyword::
5029 - all revision numbers that match a keyword::
5030
5030
5031 hg log -k bug --template "{rev}\\n"
5031 hg log -k bug --template "{rev}\\n"
5032
5032
5033 - the full hash identifier of the working directory parent::
5033 - the full hash identifier of the working directory parent::
5034
5034
5035 hg log -r . --template "{node}\\n"
5035 hg log -r . --template "{node}\\n"
5036
5036
5037 - list available log templates::
5037 - list available log templates::
5038
5038
5039 hg log -T list
5039 hg log -T list
5040
5040
5041 - check if a given changeset is included in a tagged release::
5041 - check if a given changeset is included in a tagged release::
5042
5042
5043 hg log -r "a21ccf and ancestor(1.9)"
5043 hg log -r "a21ccf and ancestor(1.9)"
5044
5044
5045 - find all changesets by some user in a date range::
5045 - find all changesets by some user in a date range::
5046
5046
5047 hg log -k alice -d "may 2008 to jul 2008"
5047 hg log -k alice -d "may 2008 to jul 2008"
5048
5048
5049 - summary of all changesets after the last tag::
5049 - summary of all changesets after the last tag::
5050
5050
5051 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5051 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5052
5052
5053 See :hg:`help dates` for a list of formats valid for -d/--date.
5053 See :hg:`help dates` for a list of formats valid for -d/--date.
5054
5054
5055 See :hg:`help revisions` and :hg:`help revsets` for more about
5055 See :hg:`help revisions` and :hg:`help revsets` for more about
5056 specifying and ordering revisions.
5056 specifying and ordering revisions.
5057
5057
5058 See :hg:`help templates` for more about pre-packaged styles and
5058 See :hg:`help templates` for more about pre-packaged styles and
5059 specifying custom templates.
5059 specifying custom templates.
5060
5060
5061 Returns 0 on success.
5061 Returns 0 on success.
5062
5062
5063 """
5063 """
5064 if opts.get('follow') and opts.get('rev'):
5064 if opts.get('follow') and opts.get('rev'):
5065 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5065 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5066 del opts['follow']
5066 del opts['follow']
5067
5067
5068 if opts.get('graph'):
5068 if opts.get('graph'):
5069 return cmdutil.graphlog(ui, repo, *pats, **opts)
5069 return cmdutil.graphlog(ui, repo, *pats, **opts)
5070
5070
5071 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5071 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5072 limit = cmdutil.loglimit(opts)
5072 limit = cmdutil.loglimit(opts)
5073 count = 0
5073 count = 0
5074
5074
5075 getrenamed = None
5075 getrenamed = None
5076 if opts.get('copies'):
5076 if opts.get('copies'):
5077 endrev = None
5077 endrev = None
5078 if opts.get('rev'):
5078 if opts.get('rev'):
5079 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5079 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5080 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5080 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5081
5081
5082 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5082 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5083 for rev in revs:
5083 for rev in revs:
5084 if count == limit:
5084 if count == limit:
5085 break
5085 break
5086 ctx = repo[rev]
5086 ctx = repo[rev]
5087 copies = None
5087 copies = None
5088 if getrenamed is not None and rev:
5088 if getrenamed is not None and rev:
5089 copies = []
5089 copies = []
5090 for fn in ctx.files():
5090 for fn in ctx.files():
5091 rename = getrenamed(fn, rev)
5091 rename = getrenamed(fn, rev)
5092 if rename:
5092 if rename:
5093 copies.append((fn, rename[0]))
5093 copies.append((fn, rename[0]))
5094 if filematcher:
5094 if filematcher:
5095 revmatchfn = filematcher(ctx.rev())
5095 revmatchfn = filematcher(ctx.rev())
5096 else:
5096 else:
5097 revmatchfn = None
5097 revmatchfn = None
5098 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5098 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5099 if displayer.flush(ctx):
5099 if displayer.flush(ctx):
5100 count += 1
5100 count += 1
5101
5101
5102 displayer.close()
5102 displayer.close()
5103
5103
5104 @command('manifest',
5104 @command('manifest',
5105 [('r', 'rev', '', _('revision to display'), _('REV')),
5105 [('r', 'rev', '', _('revision to display'), _('REV')),
5106 ('', 'all', False, _("list files from all revisions"))]
5106 ('', 'all', False, _("list files from all revisions"))]
5107 + formatteropts,
5107 + formatteropts,
5108 _('[-r REV]'))
5108 _('[-r REV]'))
5109 def manifest(ui, repo, node=None, rev=None, **opts):
5109 def manifest(ui, repo, node=None, rev=None, **opts):
5110 """output the current or given revision of the project manifest
5110 """output the current or given revision of the project manifest
5111
5111
5112 Print a list of version controlled files for the given revision.
5112 Print a list of version controlled files for the given revision.
5113 If no revision is given, the first parent of the working directory
5113 If no revision is given, the first parent of the working directory
5114 is used, or the null revision if no revision is checked out.
5114 is used, or the null revision if no revision is checked out.
5115
5115
5116 With -v, print file permissions, symlink and executable bits.
5116 With -v, print file permissions, symlink and executable bits.
5117 With --debug, print file revision hashes.
5117 With --debug, print file revision hashes.
5118
5118
5119 If option --all is specified, the list of all files from all revisions
5119 If option --all is specified, the list of all files from all revisions
5120 is printed. This includes deleted and renamed files.
5120 is printed. This includes deleted and renamed files.
5121
5121
5122 Returns 0 on success.
5122 Returns 0 on success.
5123 """
5123 """
5124
5124
5125 fm = ui.formatter('manifest', opts)
5125 fm = ui.formatter('manifest', opts)
5126
5126
5127 if opts.get('all'):
5127 if opts.get('all'):
5128 if rev or node:
5128 if rev or node:
5129 raise error.Abort(_("can't specify a revision with --all"))
5129 raise error.Abort(_("can't specify a revision with --all"))
5130
5130
5131 res = []
5131 res = []
5132 prefix = "data/"
5132 prefix = "data/"
5133 suffix = ".i"
5133 suffix = ".i"
5134 plen = len(prefix)
5134 plen = len(prefix)
5135 slen = len(suffix)
5135 slen = len(suffix)
5136 with repo.lock():
5136 with repo.lock():
5137 for fn, b, size in repo.store.datafiles():
5137 for fn, b, size in repo.store.datafiles():
5138 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5138 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5139 res.append(fn[plen:-slen])
5139 res.append(fn[plen:-slen])
5140 for f in res:
5140 for f in res:
5141 fm.startitem()
5141 fm.startitem()
5142 fm.write("path", '%s\n', f)
5142 fm.write("path", '%s\n', f)
5143 fm.end()
5143 fm.end()
5144 return
5144 return
5145
5145
5146 if rev and node:
5146 if rev and node:
5147 raise error.Abort(_("please specify just one revision"))
5147 raise error.Abort(_("please specify just one revision"))
5148
5148
5149 if not node:
5149 if not node:
5150 node = rev
5150 node = rev
5151
5151
5152 char = {'l': '@', 'x': '*', '': ''}
5152 char = {'l': '@', 'x': '*', '': ''}
5153 mode = {'l': '644', 'x': '755', '': '644'}
5153 mode = {'l': '644', 'x': '755', '': '644'}
5154 ctx = scmutil.revsingle(repo, node)
5154 ctx = scmutil.revsingle(repo, node)
5155 mf = ctx.manifest()
5155 mf = ctx.manifest()
5156 for f in ctx:
5156 for f in ctx:
5157 fm.startitem()
5157 fm.startitem()
5158 fl = ctx[f].flags()
5158 fl = ctx[f].flags()
5159 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5159 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5160 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5160 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5161 fm.write('path', '%s\n', f)
5161 fm.write('path', '%s\n', f)
5162 fm.end()
5162 fm.end()
5163
5163
5164 @command('^merge',
5164 @command('^merge',
5165 [('f', 'force', None,
5165 [('f', 'force', None,
5166 _('force a merge including outstanding changes (DEPRECATED)')),
5166 _('force a merge including outstanding changes (DEPRECATED)')),
5167 ('r', 'rev', '', _('revision to merge'), _('REV')),
5167 ('r', 'rev', '', _('revision to merge'), _('REV')),
5168 ('P', 'preview', None,
5168 ('P', 'preview', None,
5169 _('review revisions to merge (no merge is performed)'))
5169 _('review revisions to merge (no merge is performed)'))
5170 ] + mergetoolopts,
5170 ] + mergetoolopts,
5171 _('[-P] [[-r] REV]'))
5171 _('[-P] [[-r] REV]'))
5172 def merge(ui, repo, node=None, **opts):
5172 def merge(ui, repo, node=None, **opts):
5173 """merge another revision into working directory
5173 """merge another revision into working directory
5174
5174
5175 The current working directory is updated with all changes made in
5175 The current working directory is updated with all changes made in
5176 the requested revision since the last common predecessor revision.
5176 the requested revision since the last common predecessor revision.
5177
5177
5178 Files that changed between either parent are marked as changed for
5178 Files that changed between either parent are marked as changed for
5179 the next commit and a commit must be performed before any further
5179 the next commit and a commit must be performed before any further
5180 updates to the repository are allowed. The next commit will have
5180 updates to the repository are allowed. The next commit will have
5181 two parents.
5181 two parents.
5182
5182
5183 ``--tool`` can be used to specify the merge tool used for file
5183 ``--tool`` can be used to specify the merge tool used for file
5184 merges. It overrides the HGMERGE environment variable and your
5184 merges. It overrides the HGMERGE environment variable and your
5185 configuration files. See :hg:`help merge-tools` for options.
5185 configuration files. See :hg:`help merge-tools` for options.
5186
5186
5187 If no revision is specified, the working directory's parent is a
5187 If no revision is specified, the working directory's parent is a
5188 head revision, and the current branch contains exactly one other
5188 head revision, and the current branch contains exactly one other
5189 head, the other head is merged with by default. Otherwise, an
5189 head, the other head is merged with by default. Otherwise, an
5190 explicit revision with which to merge with must be provided.
5190 explicit revision with which to merge with must be provided.
5191
5191
5192 See :hg:`help resolve` for information on handling file conflicts.
5192 See :hg:`help resolve` for information on handling file conflicts.
5193
5193
5194 To undo an uncommitted merge, use :hg:`update --clean .` which
5194 To undo an uncommitted merge, use :hg:`update --clean .` which
5195 will check out a clean copy of the original merge parent, losing
5195 will check out a clean copy of the original merge parent, losing
5196 all changes.
5196 all changes.
5197
5197
5198 Returns 0 on success, 1 if there are unresolved files.
5198 Returns 0 on success, 1 if there are unresolved files.
5199 """
5199 """
5200
5200
5201 if opts.get('rev') and node:
5201 if opts.get('rev') and node:
5202 raise error.Abort(_("please specify just one revision"))
5202 raise error.Abort(_("please specify just one revision"))
5203 if not node:
5203 if not node:
5204 node = opts.get('rev')
5204 node = opts.get('rev')
5205
5205
5206 if node:
5206 if node:
5207 node = scmutil.revsingle(repo, node).node()
5207 node = scmutil.revsingle(repo, node).node()
5208
5208
5209 if not node:
5209 if not node:
5210 node = repo[destutil.destmerge(repo)].node()
5210 node = repo[destutil.destmerge(repo)].node()
5211
5211
5212 if opts.get('preview'):
5212 if opts.get('preview'):
5213 # find nodes that are ancestors of p2 but not of p1
5213 # find nodes that are ancestors of p2 but not of p1
5214 p1 = repo.lookup('.')
5214 p1 = repo.lookup('.')
5215 p2 = repo.lookup(node)
5215 p2 = repo.lookup(node)
5216 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5216 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5217
5217
5218 displayer = cmdutil.show_changeset(ui, repo, opts)
5218 displayer = cmdutil.show_changeset(ui, repo, opts)
5219 for node in nodes:
5219 for node in nodes:
5220 displayer.show(repo[node])
5220 displayer.show(repo[node])
5221 displayer.close()
5221 displayer.close()
5222 return 0
5222 return 0
5223
5223
5224 try:
5224 try:
5225 # ui.forcemerge is an internal variable, do not document
5225 # ui.forcemerge is an internal variable, do not document
5226 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5226 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5227 force = opts.get('force')
5227 force = opts.get('force')
5228 labels = ['working copy', 'merge rev']
5228 labels = ['working copy', 'merge rev']
5229 return hg.merge(repo, node, force=force, mergeforce=force,
5229 return hg.merge(repo, node, force=force, mergeforce=force,
5230 labels=labels)
5230 labels=labels)
5231 finally:
5231 finally:
5232 ui.setconfig('ui', 'forcemerge', '', 'merge')
5232 ui.setconfig('ui', 'forcemerge', '', 'merge')
5233
5233
5234 @command('outgoing|out',
5234 @command('outgoing|out',
5235 [('f', 'force', None, _('run even when the destination is unrelated')),
5235 [('f', 'force', None, _('run even when the destination is unrelated')),
5236 ('r', 'rev', [],
5236 ('r', 'rev', [],
5237 _('a changeset intended to be included in the destination'), _('REV')),
5237 _('a changeset intended to be included in the destination'), _('REV')),
5238 ('n', 'newest-first', None, _('show newest record first')),
5238 ('n', 'newest-first', None, _('show newest record first')),
5239 ('B', 'bookmarks', False, _('compare bookmarks')),
5239 ('B', 'bookmarks', False, _('compare bookmarks')),
5240 ('b', 'branch', [], _('a specific branch you would like to push'),
5240 ('b', 'branch', [], _('a specific branch you would like to push'),
5241 _('BRANCH')),
5241 _('BRANCH')),
5242 ] + logopts + remoteopts + subrepoopts,
5242 ] + logopts + remoteopts + subrepoopts,
5243 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5243 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5244 def outgoing(ui, repo, dest=None, **opts):
5244 def outgoing(ui, repo, dest=None, **opts):
5245 """show changesets not found in the destination
5245 """show changesets not found in the destination
5246
5246
5247 Show changesets not found in the specified destination repository
5247 Show changesets not found in the specified destination repository
5248 or the default push location. These are the changesets that would
5248 or the default push location. These are the changesets that would
5249 be pushed if a push was requested.
5249 be pushed if a push was requested.
5250
5250
5251 See pull for details of valid destination formats.
5251 See pull for details of valid destination formats.
5252
5252
5253 .. container:: verbose
5253 .. container:: verbose
5254
5254
5255 With -B/--bookmarks, the result of bookmark comparison between
5255 With -B/--bookmarks, the result of bookmark comparison between
5256 local and remote repositories is displayed. With -v/--verbose,
5256 local and remote repositories is displayed. With -v/--verbose,
5257 status is also displayed for each bookmark like below::
5257 status is also displayed for each bookmark like below::
5258
5258
5259 BM1 01234567890a added
5259 BM1 01234567890a added
5260 BM2 deleted
5260 BM2 deleted
5261 BM3 234567890abc advanced
5261 BM3 234567890abc advanced
5262 BM4 34567890abcd diverged
5262 BM4 34567890abcd diverged
5263 BM5 4567890abcde changed
5263 BM5 4567890abcde changed
5264
5264
5265 The action taken when pushing depends on the
5265 The action taken when pushing depends on the
5266 status of each bookmark:
5266 status of each bookmark:
5267
5267
5268 :``added``: push with ``-B`` will create it
5268 :``added``: push with ``-B`` will create it
5269 :``deleted``: push with ``-B`` will delete it
5269 :``deleted``: push with ``-B`` will delete it
5270 :``advanced``: push will update it
5270 :``advanced``: push will update it
5271 :``diverged``: push with ``-B`` will update it
5271 :``diverged``: push with ``-B`` will update it
5272 :``changed``: push with ``-B`` will update it
5272 :``changed``: push with ``-B`` will update it
5273
5273
5274 From the point of view of pushing behavior, bookmarks
5274 From the point of view of pushing behavior, bookmarks
5275 existing only in the remote repository are treated as
5275 existing only in the remote repository are treated as
5276 ``deleted``, even if it is in fact added remotely.
5276 ``deleted``, even if it is in fact added remotely.
5277
5277
5278 Returns 0 if there are outgoing changes, 1 otherwise.
5278 Returns 0 if there are outgoing changes, 1 otherwise.
5279 """
5279 """
5280 if opts.get('graph'):
5280 if opts.get('graph'):
5281 cmdutil.checkunsupportedgraphflags([], opts)
5281 cmdutil.checkunsupportedgraphflags([], opts)
5282 o, other = hg._outgoing(ui, repo, dest, opts)
5282 o, other = hg._outgoing(ui, repo, dest, opts)
5283 if not o:
5283 if not o:
5284 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5284 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5285 return
5285 return
5286
5286
5287 revdag = cmdutil.graphrevs(repo, o, opts)
5287 revdag = cmdutil.graphrevs(repo, o, opts)
5288 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5288 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5289 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5289 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5290 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5290 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5291 return 0
5291 return 0
5292
5292
5293 if opts.get('bookmarks'):
5293 if opts.get('bookmarks'):
5294 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5294 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5295 dest, branches = hg.parseurl(dest, opts.get('branch'))
5295 dest, branches = hg.parseurl(dest, opts.get('branch'))
5296 other = hg.peer(repo, opts, dest)
5296 other = hg.peer(repo, opts, dest)
5297 if 'bookmarks' not in other.listkeys('namespaces'):
5297 if 'bookmarks' not in other.listkeys('namespaces'):
5298 ui.warn(_("remote doesn't support bookmarks\n"))
5298 ui.warn(_("remote doesn't support bookmarks\n"))
5299 return 0
5299 return 0
5300 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5300 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5301 return bookmarks.outgoing(ui, repo, other)
5301 return bookmarks.outgoing(ui, repo, other)
5302
5302
5303 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5303 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5304 try:
5304 try:
5305 return hg.outgoing(ui, repo, dest, opts)
5305 return hg.outgoing(ui, repo, dest, opts)
5306 finally:
5306 finally:
5307 del repo._subtoppath
5307 del repo._subtoppath
5308
5308
5309 @command('parents',
5309 @command('parents',
5310 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5310 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5311 ] + templateopts,
5311 ] + templateopts,
5312 _('[-r REV] [FILE]'),
5312 _('[-r REV] [FILE]'),
5313 inferrepo=True)
5313 inferrepo=True)
5314 def parents(ui, repo, file_=None, **opts):
5314 def parents(ui, repo, file_=None, **opts):
5315 """show the parents of the working directory or revision (DEPRECATED)
5315 """show the parents of the working directory or revision (DEPRECATED)
5316
5316
5317 Print the working directory's parent revisions. If a revision is
5317 Print the working directory's parent revisions. If a revision is
5318 given via -r/--rev, the parent of that revision will be printed.
5318 given via -r/--rev, the parent of that revision will be printed.
5319 If a file argument is given, the revision in which the file was
5319 If a file argument is given, the revision in which the file was
5320 last changed (before the working directory revision or the
5320 last changed (before the working directory revision or the
5321 argument to --rev if given) is printed.
5321 argument to --rev if given) is printed.
5322
5322
5323 This command is equivalent to::
5323 This command is equivalent to::
5324
5324
5325 hg log -r "p1()+p2()" or
5325 hg log -r "p1()+p2()" or
5326 hg log -r "p1(REV)+p2(REV)" or
5326 hg log -r "p1(REV)+p2(REV)" or
5327 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5327 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5328 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5328 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5329
5329
5330 See :hg:`summary` and :hg:`help revsets` for related information.
5330 See :hg:`summary` and :hg:`help revsets` for related information.
5331
5331
5332 Returns 0 on success.
5332 Returns 0 on success.
5333 """
5333 """
5334
5334
5335 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5335 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5336
5336
5337 if file_:
5337 if file_:
5338 m = scmutil.match(ctx, (file_,), opts)
5338 m = scmutil.match(ctx, (file_,), opts)
5339 if m.anypats() or len(m.files()) != 1:
5339 if m.anypats() or len(m.files()) != 1:
5340 raise error.Abort(_('can only specify an explicit filename'))
5340 raise error.Abort(_('can only specify an explicit filename'))
5341 file_ = m.files()[0]
5341 file_ = m.files()[0]
5342 filenodes = []
5342 filenodes = []
5343 for cp in ctx.parents():
5343 for cp in ctx.parents():
5344 if not cp:
5344 if not cp:
5345 continue
5345 continue
5346 try:
5346 try:
5347 filenodes.append(cp.filenode(file_))
5347 filenodes.append(cp.filenode(file_))
5348 except error.LookupError:
5348 except error.LookupError:
5349 pass
5349 pass
5350 if not filenodes:
5350 if not filenodes:
5351 raise error.Abort(_("'%s' not found in manifest!") % file_)
5351 raise error.Abort(_("'%s' not found in manifest!") % file_)
5352 p = []
5352 p = []
5353 for fn in filenodes:
5353 for fn in filenodes:
5354 fctx = repo.filectx(file_, fileid=fn)
5354 fctx = repo.filectx(file_, fileid=fn)
5355 p.append(fctx.node())
5355 p.append(fctx.node())
5356 else:
5356 else:
5357 p = [cp.node() for cp in ctx.parents()]
5357 p = [cp.node() for cp in ctx.parents()]
5358
5358
5359 displayer = cmdutil.show_changeset(ui, repo, opts)
5359 displayer = cmdutil.show_changeset(ui, repo, opts)
5360 for n in p:
5360 for n in p:
5361 if n != nullid:
5361 if n != nullid:
5362 displayer.show(repo[n])
5362 displayer.show(repo[n])
5363 displayer.close()
5363 displayer.close()
5364
5364
5365 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5365 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5366 def paths(ui, repo, search=None, **opts):
5366 def paths(ui, repo, search=None, **opts):
5367 """show aliases for remote repositories
5367 """show aliases for remote repositories
5368
5368
5369 Show definition of symbolic path name NAME. If no name is given,
5369 Show definition of symbolic path name NAME. If no name is given,
5370 show definition of all available names.
5370 show definition of all available names.
5371
5371
5372 Option -q/--quiet suppresses all output when searching for NAME
5372 Option -q/--quiet suppresses all output when searching for NAME
5373 and shows only the path names when listing all definitions.
5373 and shows only the path names when listing all definitions.
5374
5374
5375 Path names are defined in the [paths] section of your
5375 Path names are defined in the [paths] section of your
5376 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5376 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5377 repository, ``.hg/hgrc`` is used, too.
5377 repository, ``.hg/hgrc`` is used, too.
5378
5378
5379 The path names ``default`` and ``default-push`` have a special
5379 The path names ``default`` and ``default-push`` have a special
5380 meaning. When performing a push or pull operation, they are used
5380 meaning. When performing a push or pull operation, they are used
5381 as fallbacks if no location is specified on the command-line.
5381 as fallbacks if no location is specified on the command-line.
5382 When ``default-push`` is set, it will be used for push and
5382 When ``default-push`` is set, it will be used for push and
5383 ``default`` will be used for pull; otherwise ``default`` is used
5383 ``default`` will be used for pull; otherwise ``default`` is used
5384 as the fallback for both. When cloning a repository, the clone
5384 as the fallback for both. When cloning a repository, the clone
5385 source is written as ``default`` in ``.hg/hgrc``.
5385 source is written as ``default`` in ``.hg/hgrc``.
5386
5386
5387 .. note::
5387 .. note::
5388
5388
5389 ``default`` and ``default-push`` apply to all inbound (e.g.
5389 ``default`` and ``default-push`` apply to all inbound (e.g.
5390 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5390 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5391 and :hg:`bundle`) operations.
5391 and :hg:`bundle`) operations.
5392
5392
5393 See :hg:`help urls` for more information.
5393 See :hg:`help urls` for more information.
5394
5394
5395 Returns 0 on success.
5395 Returns 0 on success.
5396 """
5396 """
5397 if search:
5397 if search:
5398 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5398 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5399 if name == search]
5399 if name == search]
5400 else:
5400 else:
5401 pathitems = sorted(ui.paths.iteritems())
5401 pathitems = sorted(ui.paths.iteritems())
5402
5402
5403 fm = ui.formatter('paths', opts)
5403 fm = ui.formatter('paths', opts)
5404 if fm.isplain():
5404 if fm.isplain():
5405 hidepassword = util.hidepassword
5405 hidepassword = util.hidepassword
5406 else:
5406 else:
5407 hidepassword = str
5407 hidepassword = str
5408 if ui.quiet:
5408 if ui.quiet:
5409 namefmt = '%s\n'
5409 namefmt = '%s\n'
5410 else:
5410 else:
5411 namefmt = '%s = '
5411 namefmt = '%s = '
5412 showsubopts = not search and not ui.quiet
5412 showsubopts = not search and not ui.quiet
5413
5413
5414 for name, path in pathitems:
5414 for name, path in pathitems:
5415 fm.startitem()
5415 fm.startitem()
5416 fm.condwrite(not search, 'name', namefmt, name)
5416 fm.condwrite(not search, 'name', namefmt, name)
5417 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5417 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5418 for subopt, value in sorted(path.suboptions.items()):
5418 for subopt, value in sorted(path.suboptions.items()):
5419 assert subopt not in ('name', 'url')
5419 assert subopt not in ('name', 'url')
5420 if showsubopts:
5420 if showsubopts:
5421 fm.plain('%s:%s = ' % (name, subopt))
5421 fm.plain('%s:%s = ' % (name, subopt))
5422 fm.condwrite(showsubopts, subopt, '%s\n', value)
5422 fm.condwrite(showsubopts, subopt, '%s\n', value)
5423
5423
5424 fm.end()
5424 fm.end()
5425
5425
5426 if search and not pathitems:
5426 if search and not pathitems:
5427 if not ui.quiet:
5427 if not ui.quiet:
5428 ui.warn(_("not found!\n"))
5428 ui.warn(_("not found!\n"))
5429 return 1
5429 return 1
5430 else:
5430 else:
5431 return 0
5431 return 0
5432
5432
5433 @command('phase',
5433 @command('phase',
5434 [('p', 'public', False, _('set changeset phase to public')),
5434 [('p', 'public', False, _('set changeset phase to public')),
5435 ('d', 'draft', False, _('set changeset phase to draft')),
5435 ('d', 'draft', False, _('set changeset phase to draft')),
5436 ('s', 'secret', False, _('set changeset phase to secret')),
5436 ('s', 'secret', False, _('set changeset phase to secret')),
5437 ('f', 'force', False, _('allow to move boundary backward')),
5437 ('f', 'force', False, _('allow to move boundary backward')),
5438 ('r', 'rev', [], _('target revision'), _('REV')),
5438 ('r', 'rev', [], _('target revision'), _('REV')),
5439 ],
5439 ],
5440 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5440 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5441 def phase(ui, repo, *revs, **opts):
5441 def phase(ui, repo, *revs, **opts):
5442 """set or show the current phase name
5442 """set or show the current phase name
5443
5443
5444 With no argument, show the phase name of the current revision(s).
5444 With no argument, show the phase name of the current revision(s).
5445
5445
5446 With one of -p/--public, -d/--draft or -s/--secret, change the
5446 With one of -p/--public, -d/--draft or -s/--secret, change the
5447 phase value of the specified revisions.
5447 phase value of the specified revisions.
5448
5448
5449 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5449 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5450 lower phase to an higher phase. Phases are ordered as follows::
5450 lower phase to an higher phase. Phases are ordered as follows::
5451
5451
5452 public < draft < secret
5452 public < draft < secret
5453
5453
5454 Returns 0 on success, 1 if some phases could not be changed.
5454 Returns 0 on success, 1 if some phases could not be changed.
5455
5455
5456 (For more information about the phases concept, see :hg:`help phases`.)
5456 (For more information about the phases concept, see :hg:`help phases`.)
5457 """
5457 """
5458 # search for a unique phase argument
5458 # search for a unique phase argument
5459 targetphase = None
5459 targetphase = None
5460 for idx, name in enumerate(phases.phasenames):
5460 for idx, name in enumerate(phases.phasenames):
5461 if opts[name]:
5461 if opts[name]:
5462 if targetphase is not None:
5462 if targetphase is not None:
5463 raise error.Abort(_('only one phase can be specified'))
5463 raise error.Abort(_('only one phase can be specified'))
5464 targetphase = idx
5464 targetphase = idx
5465
5465
5466 # look for specified revision
5466 # look for specified revision
5467 revs = list(revs)
5467 revs = list(revs)
5468 revs.extend(opts['rev'])
5468 revs.extend(opts['rev'])
5469 if not revs:
5469 if not revs:
5470 # display both parents as the second parent phase can influence
5470 # display both parents as the second parent phase can influence
5471 # the phase of a merge commit
5471 # the phase of a merge commit
5472 revs = [c.rev() for c in repo[None].parents()]
5472 revs = [c.rev() for c in repo[None].parents()]
5473
5473
5474 revs = scmutil.revrange(repo, revs)
5474 revs = scmutil.revrange(repo, revs)
5475
5475
5476 lock = None
5476 lock = None
5477 ret = 0
5477 ret = 0
5478 if targetphase is None:
5478 if targetphase is None:
5479 # display
5479 # display
5480 for r in revs:
5480 for r in revs:
5481 ctx = repo[r]
5481 ctx = repo[r]
5482 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5482 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5483 else:
5483 else:
5484 tr = None
5484 tr = None
5485 lock = repo.lock()
5485 lock = repo.lock()
5486 try:
5486 try:
5487 tr = repo.transaction("phase")
5487 tr = repo.transaction("phase")
5488 # set phase
5488 # set phase
5489 if not revs:
5489 if not revs:
5490 raise error.Abort(_('empty revision set'))
5490 raise error.Abort(_('empty revision set'))
5491 nodes = [repo[r].node() for r in revs]
5491 nodes = [repo[r].node() for r in revs]
5492 # moving revision from public to draft may hide them
5492 # moving revision from public to draft may hide them
5493 # We have to check result on an unfiltered repository
5493 # We have to check result on an unfiltered repository
5494 unfi = repo.unfiltered()
5494 unfi = repo.unfiltered()
5495 getphase = unfi._phasecache.phase
5495 getphase = unfi._phasecache.phase
5496 olddata = [getphase(unfi, r) for r in unfi]
5496 olddata = [getphase(unfi, r) for r in unfi]
5497 phases.advanceboundary(repo, tr, targetphase, nodes)
5497 phases.advanceboundary(repo, tr, targetphase, nodes)
5498 if opts['force']:
5498 if opts['force']:
5499 phases.retractboundary(repo, tr, targetphase, nodes)
5499 phases.retractboundary(repo, tr, targetphase, nodes)
5500 tr.close()
5500 tr.close()
5501 finally:
5501 finally:
5502 if tr is not None:
5502 if tr is not None:
5503 tr.release()
5503 tr.release()
5504 lock.release()
5504 lock.release()
5505 getphase = unfi._phasecache.phase
5505 getphase = unfi._phasecache.phase
5506 newdata = [getphase(unfi, r) for r in unfi]
5506 newdata = [getphase(unfi, r) for r in unfi]
5507 changes = sum(newdata[r] != olddata[r] for r in unfi)
5507 changes = sum(newdata[r] != olddata[r] for r in unfi)
5508 cl = unfi.changelog
5508 cl = unfi.changelog
5509 rejected = [n for n in nodes
5509 rejected = [n for n in nodes
5510 if newdata[cl.rev(n)] < targetphase]
5510 if newdata[cl.rev(n)] < targetphase]
5511 if rejected:
5511 if rejected:
5512 ui.warn(_('cannot move %i changesets to a higher '
5512 ui.warn(_('cannot move %i changesets to a higher '
5513 'phase, use --force\n') % len(rejected))
5513 'phase, use --force\n') % len(rejected))
5514 ret = 1
5514 ret = 1
5515 if changes:
5515 if changes:
5516 msg = _('phase changed for %i changesets\n') % changes
5516 msg = _('phase changed for %i changesets\n') % changes
5517 if ret:
5517 if ret:
5518 ui.status(msg)
5518 ui.status(msg)
5519 else:
5519 else:
5520 ui.note(msg)
5520 ui.note(msg)
5521 else:
5521 else:
5522 ui.warn(_('no phases changed\n'))
5522 ui.warn(_('no phases changed\n'))
5523 return ret
5523 return ret
5524
5524
5525 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5525 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5526 """Run after a changegroup has been added via pull/unbundle
5526 """Run after a changegroup has been added via pull/unbundle
5527
5527
5528 This takes arguments below:
5528 This takes arguments below:
5529
5529
5530 :modheads: change of heads by pull/unbundle
5530 :modheads: change of heads by pull/unbundle
5531 :optupdate: updating working directory is needed or not
5531 :optupdate: updating working directory is needed or not
5532 :checkout: update destination revision (or None to default destination)
5532 :checkout: update destination revision (or None to default destination)
5533 :brev: a name, which might be a bookmark to be activated after updating
5533 :brev: a name, which might be a bookmark to be activated after updating
5534 """
5534 """
5535 if modheads == 0:
5535 if modheads == 0:
5536 return
5536 return
5537 if optupdate:
5537 if optupdate:
5538 try:
5538 try:
5539 return hg.updatetotally(ui, repo, checkout, brev)
5539 return hg.updatetotally(ui, repo, checkout, brev)
5540 except error.UpdateAbort as inst:
5540 except error.UpdateAbort as inst:
5541 msg = _("not updating: %s") % str(inst)
5541 msg = _("not updating: %s") % str(inst)
5542 hint = inst.hint
5542 hint = inst.hint
5543 raise error.UpdateAbort(msg, hint=hint)
5543 raise error.UpdateAbort(msg, hint=hint)
5544 if modheads > 1:
5544 if modheads > 1:
5545 currentbranchheads = len(repo.branchheads())
5545 currentbranchheads = len(repo.branchheads())
5546 if currentbranchheads == modheads:
5546 if currentbranchheads == modheads:
5547 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5547 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5548 elif currentbranchheads > 1:
5548 elif currentbranchheads > 1:
5549 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5549 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5550 "merge)\n"))
5550 "merge)\n"))
5551 else:
5551 else:
5552 ui.status(_("(run 'hg heads' to see heads)\n"))
5552 ui.status(_("(run 'hg heads' to see heads)\n"))
5553 else:
5553 else:
5554 ui.status(_("(run 'hg update' to get a working copy)\n"))
5554 ui.status(_("(run 'hg update' to get a working copy)\n"))
5555
5555
5556 @command('^pull',
5556 @command('^pull',
5557 [('u', 'update', None,
5557 [('u', 'update', None,
5558 _('update to new branch head if changesets were pulled')),
5558 _('update to new branch head if changesets were pulled')),
5559 ('f', 'force', None, _('run even when remote repository is unrelated')),
5559 ('f', 'force', None, _('run even when remote repository is unrelated')),
5560 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5560 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5561 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5561 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5562 ('b', 'branch', [], _('a specific branch you would like to pull'),
5562 ('b', 'branch', [], _('a specific branch you would like to pull'),
5563 _('BRANCH')),
5563 _('BRANCH')),
5564 ] + remoteopts,
5564 ] + remoteopts,
5565 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5565 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5566 def pull(ui, repo, source="default", **opts):
5566 def pull(ui, repo, source="default", **opts):
5567 """pull changes from the specified source
5567 """pull changes from the specified source
5568
5568
5569 Pull changes from a remote repository to a local one.
5569 Pull changes from a remote repository to a local one.
5570
5570
5571 This finds all changes from the repository at the specified path
5571 This finds all changes from the repository at the specified path
5572 or URL and adds them to a local repository (the current one unless
5572 or URL and adds them to a local repository (the current one unless
5573 -R is specified). By default, this does not update the copy of the
5573 -R is specified). By default, this does not update the copy of the
5574 project in the working directory.
5574 project in the working directory.
5575
5575
5576 Use :hg:`incoming` if you want to see what would have been added
5576 Use :hg:`incoming` if you want to see what would have been added
5577 by a pull at the time you issued this command. If you then decide
5577 by a pull at the time you issued this command. If you then decide
5578 to add those changes to the repository, you should use :hg:`pull
5578 to add those changes to the repository, you should use :hg:`pull
5579 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5579 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5580
5580
5581 If SOURCE is omitted, the 'default' path will be used.
5581 If SOURCE is omitted, the 'default' path will be used.
5582 See :hg:`help urls` for more information.
5582 See :hg:`help urls` for more information.
5583
5583
5584 Specifying bookmark as ``.`` is equivalent to specifying the active
5584 Specifying bookmark as ``.`` is equivalent to specifying the active
5585 bookmark's name.
5585 bookmark's name.
5586
5586
5587 Returns 0 on success, 1 if an update had unresolved files.
5587 Returns 0 on success, 1 if an update had unresolved files.
5588 """
5588 """
5589 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5589 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5590 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5590 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5591 other = hg.peer(repo, opts, source)
5591 other = hg.peer(repo, opts, source)
5592 try:
5592 try:
5593 revs, checkout = hg.addbranchrevs(repo, other, branches,
5593 revs, checkout = hg.addbranchrevs(repo, other, branches,
5594 opts.get('rev'))
5594 opts.get('rev'))
5595
5595
5596
5596
5597 pullopargs = {}
5597 pullopargs = {}
5598 if opts.get('bookmark'):
5598 if opts.get('bookmark'):
5599 if not revs:
5599 if not revs:
5600 revs = []
5600 revs = []
5601 # The list of bookmark used here is not the one used to actually
5601 # The list of bookmark used here is not the one used to actually
5602 # update the bookmark name. This can result in the revision pulled
5602 # update the bookmark name. This can result in the revision pulled
5603 # not ending up with the name of the bookmark because of a race
5603 # not ending up with the name of the bookmark because of a race
5604 # condition on the server. (See issue 4689 for details)
5604 # condition on the server. (See issue 4689 for details)
5605 remotebookmarks = other.listkeys('bookmarks')
5605 remotebookmarks = other.listkeys('bookmarks')
5606 pullopargs['remotebookmarks'] = remotebookmarks
5606 pullopargs['remotebookmarks'] = remotebookmarks
5607 for b in opts['bookmark']:
5607 for b in opts['bookmark']:
5608 b = repo._bookmarks.expandname(b)
5608 b = repo._bookmarks.expandname(b)
5609 if b not in remotebookmarks:
5609 if b not in remotebookmarks:
5610 raise error.Abort(_('remote bookmark %s not found!') % b)
5610 raise error.Abort(_('remote bookmark %s not found!') % b)
5611 revs.append(remotebookmarks[b])
5611 revs.append(remotebookmarks[b])
5612
5612
5613 if revs:
5613 if revs:
5614 try:
5614 try:
5615 # When 'rev' is a bookmark name, we cannot guarantee that it
5615 # When 'rev' is a bookmark name, we cannot guarantee that it
5616 # will be updated with that name because of a race condition
5616 # will be updated with that name because of a race condition
5617 # server side. (See issue 4689 for details)
5617 # server side. (See issue 4689 for details)
5618 oldrevs = revs
5618 oldrevs = revs
5619 revs = [] # actually, nodes
5619 revs = [] # actually, nodes
5620 for r in oldrevs:
5620 for r in oldrevs:
5621 node = other.lookup(r)
5621 node = other.lookup(r)
5622 revs.append(node)
5622 revs.append(node)
5623 if r == checkout:
5623 if r == checkout:
5624 checkout = node
5624 checkout = node
5625 except error.CapabilityError:
5625 except error.CapabilityError:
5626 err = _("other repository doesn't support revision lookup, "
5626 err = _("other repository doesn't support revision lookup, "
5627 "so a rev cannot be specified.")
5627 "so a rev cannot be specified.")
5628 raise error.Abort(err)
5628 raise error.Abort(err)
5629
5629
5630 pullopargs.update(opts.get('opargs', {}))
5630 pullopargs.update(opts.get('opargs', {}))
5631 modheads = exchange.pull(repo, other, heads=revs,
5631 modheads = exchange.pull(repo, other, heads=revs,
5632 force=opts.get('force'),
5632 force=opts.get('force'),
5633 bookmarks=opts.get('bookmark', ()),
5633 bookmarks=opts.get('bookmark', ()),
5634 opargs=pullopargs).cgresult
5634 opargs=pullopargs).cgresult
5635
5635
5636 # brev is a name, which might be a bookmark to be activated at
5636 # brev is a name, which might be a bookmark to be activated at
5637 # the end of the update. In other words, it is an explicit
5637 # the end of the update. In other words, it is an explicit
5638 # destination of the update
5638 # destination of the update
5639 brev = None
5639 brev = None
5640
5640
5641 if checkout:
5641 if checkout:
5642 checkout = str(repo.changelog.rev(checkout))
5642 checkout = str(repo.changelog.rev(checkout))
5643
5643
5644 # order below depends on implementation of
5644 # order below depends on implementation of
5645 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5645 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5646 # because 'checkout' is determined without it.
5646 # because 'checkout' is determined without it.
5647 if opts.get('rev'):
5647 if opts.get('rev'):
5648 brev = opts['rev'][0]
5648 brev = opts['rev'][0]
5649 elif opts.get('branch'):
5649 elif opts.get('branch'):
5650 brev = opts['branch'][0]
5650 brev = opts['branch'][0]
5651 else:
5651 else:
5652 brev = branches[0]
5652 brev = branches[0]
5653 repo._subtoppath = source
5653 repo._subtoppath = source
5654 try:
5654 try:
5655 ret = postincoming(ui, repo, modheads, opts.get('update'),
5655 ret = postincoming(ui, repo, modheads, opts.get('update'),
5656 checkout, brev)
5656 checkout, brev)
5657
5657
5658 finally:
5658 finally:
5659 del repo._subtoppath
5659 del repo._subtoppath
5660
5660
5661 finally:
5661 finally:
5662 other.close()
5662 other.close()
5663 return ret
5663 return ret
5664
5664
5665 @command('^push',
5665 @command('^push',
5666 [('f', 'force', None, _('force push')),
5666 [('f', 'force', None, _('force push')),
5667 ('r', 'rev', [],
5667 ('r', 'rev', [],
5668 _('a changeset intended to be included in the destination'),
5668 _('a changeset intended to be included in the destination'),
5669 _('REV')),
5669 _('REV')),
5670 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5670 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5671 ('b', 'branch', [],
5671 ('b', 'branch', [],
5672 _('a specific branch you would like to push'), _('BRANCH')),
5672 _('a specific branch you would like to push'), _('BRANCH')),
5673 ('', 'new-branch', False, _('allow pushing a new branch')),
5673 ('', 'new-branch', False, _('allow pushing a new branch')),
5674 ] + remoteopts,
5674 ] + remoteopts,
5675 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5675 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5676 def push(ui, repo, dest=None, **opts):
5676 def push(ui, repo, dest=None, **opts):
5677 """push changes to the specified destination
5677 """push changes to the specified destination
5678
5678
5679 Push changesets from the local repository to the specified
5679 Push changesets from the local repository to the specified
5680 destination.
5680 destination.
5681
5681
5682 This operation is symmetrical to pull: it is identical to a pull
5682 This operation is symmetrical to pull: it is identical to a pull
5683 in the destination repository from the current one.
5683 in the destination repository from the current one.
5684
5684
5685 By default, push will not allow creation of new heads at the
5685 By default, push will not allow creation of new heads at the
5686 destination, since multiple heads would make it unclear which head
5686 destination, since multiple heads would make it unclear which head
5687 to use. In this situation, it is recommended to pull and merge
5687 to use. In this situation, it is recommended to pull and merge
5688 before pushing.
5688 before pushing.
5689
5689
5690 Use --new-branch if you want to allow push to create a new named
5690 Use --new-branch if you want to allow push to create a new named
5691 branch that is not present at the destination. This allows you to
5691 branch that is not present at the destination. This allows you to
5692 only create a new branch without forcing other changes.
5692 only create a new branch without forcing other changes.
5693
5693
5694 .. note::
5694 .. note::
5695
5695
5696 Extra care should be taken with the -f/--force option,
5696 Extra care should be taken with the -f/--force option,
5697 which will push all new heads on all branches, an action which will
5697 which will push all new heads on all branches, an action which will
5698 almost always cause confusion for collaborators.
5698 almost always cause confusion for collaborators.
5699
5699
5700 If -r/--rev is used, the specified revision and all its ancestors
5700 If -r/--rev is used, the specified revision and all its ancestors
5701 will be pushed to the remote repository.
5701 will be pushed to the remote repository.
5702
5702
5703 If -B/--bookmark is used, the specified bookmarked revision, its
5703 If -B/--bookmark is used, the specified bookmarked revision, its
5704 ancestors, and the bookmark will be pushed to the remote
5704 ancestors, and the bookmark will be pushed to the remote
5705 repository. Specifying ``.`` is equivalent to specifying the active
5705 repository. Specifying ``.`` is equivalent to specifying the active
5706 bookmark's name.
5706 bookmark's name.
5707
5707
5708 Please see :hg:`help urls` for important details about ``ssh://``
5708 Please see :hg:`help urls` for important details about ``ssh://``
5709 URLs. If DESTINATION is omitted, a default path will be used.
5709 URLs. If DESTINATION is omitted, a default path will be used.
5710
5710
5711 Returns 0 if push was successful, 1 if nothing to push.
5711 Returns 0 if push was successful, 1 if nothing to push.
5712 """
5712 """
5713
5713
5714 if opts.get('bookmark'):
5714 if opts.get('bookmark'):
5715 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5715 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5716 for b in opts['bookmark']:
5716 for b in opts['bookmark']:
5717 # translate -B options to -r so changesets get pushed
5717 # translate -B options to -r so changesets get pushed
5718 b = repo._bookmarks.expandname(b)
5718 b = repo._bookmarks.expandname(b)
5719 if b in repo._bookmarks:
5719 if b in repo._bookmarks:
5720 opts.setdefault('rev', []).append(b)
5720 opts.setdefault('rev', []).append(b)
5721 else:
5721 else:
5722 # if we try to push a deleted bookmark, translate it to null
5722 # if we try to push a deleted bookmark, translate it to null
5723 # this lets simultaneous -r, -b options continue working
5723 # this lets simultaneous -r, -b options continue working
5724 opts.setdefault('rev', []).append("null")
5724 opts.setdefault('rev', []).append("null")
5725
5725
5726 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5726 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5727 if not path:
5727 if not path:
5728 raise error.Abort(_('default repository not configured!'),
5728 raise error.Abort(_('default repository not configured!'),
5729 hint=_("see 'hg help config.paths'"))
5729 hint=_("see 'hg help config.paths'"))
5730 dest = path.pushloc or path.loc
5730 dest = path.pushloc or path.loc
5731 branches = (path.branch, opts.get('branch') or [])
5731 branches = (path.branch, opts.get('branch') or [])
5732 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5732 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5733 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5733 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5734 other = hg.peer(repo, opts, dest)
5734 other = hg.peer(repo, opts, dest)
5735
5735
5736 if revs:
5736 if revs:
5737 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5737 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5738 if not revs:
5738 if not revs:
5739 raise error.Abort(_("specified revisions evaluate to an empty set"),
5739 raise error.Abort(_("specified revisions evaluate to an empty set"),
5740 hint=_("use different revision arguments"))
5740 hint=_("use different revision arguments"))
5741 elif path.pushrev:
5741 elif path.pushrev:
5742 # It doesn't make any sense to specify ancestor revisions. So limit
5742 # It doesn't make any sense to specify ancestor revisions. So limit
5743 # to DAG heads to make discovery simpler.
5743 # to DAG heads to make discovery simpler.
5744 expr = revset.formatspec('heads(%r)', path.pushrev)
5744 expr = revset.formatspec('heads(%r)', path.pushrev)
5745 revs = scmutil.revrange(repo, [expr])
5745 revs = scmutil.revrange(repo, [expr])
5746 revs = [repo[rev].node() for rev in revs]
5746 revs = [repo[rev].node() for rev in revs]
5747 if not revs:
5747 if not revs:
5748 raise error.Abort(_('default push revset for path evaluates to an '
5748 raise error.Abort(_('default push revset for path evaluates to an '
5749 'empty set'))
5749 'empty set'))
5750
5750
5751 repo._subtoppath = dest
5751 repo._subtoppath = dest
5752 try:
5752 try:
5753 # push subrepos depth-first for coherent ordering
5753 # push subrepos depth-first for coherent ordering
5754 c = repo['']
5754 c = repo['']
5755 subs = c.substate # only repos that are committed
5755 subs = c.substate # only repos that are committed
5756 for s in sorted(subs):
5756 for s in sorted(subs):
5757 result = c.sub(s).push(opts)
5757 result = c.sub(s).push(opts)
5758 if result == 0:
5758 if result == 0:
5759 return not result
5759 return not result
5760 finally:
5760 finally:
5761 del repo._subtoppath
5761 del repo._subtoppath
5762 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5762 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5763 newbranch=opts.get('new_branch'),
5763 newbranch=opts.get('new_branch'),
5764 bookmarks=opts.get('bookmark', ()),
5764 bookmarks=opts.get('bookmark', ()),
5765 opargs=opts.get('opargs'))
5765 opargs=opts.get('opargs'))
5766
5766
5767 result = not pushop.cgresult
5767 result = not pushop.cgresult
5768
5768
5769 if pushop.bkresult is not None:
5769 if pushop.bkresult is not None:
5770 if pushop.bkresult == 2:
5770 if pushop.bkresult == 2:
5771 result = 2
5771 result = 2
5772 elif not result and pushop.bkresult:
5772 elif not result and pushop.bkresult:
5773 result = 2
5773 result = 2
5774
5774
5775 return result
5775 return result
5776
5776
5777 @command('recover', [])
5777 @command('recover', [])
5778 def recover(ui, repo):
5778 def recover(ui, repo):
5779 """roll back an interrupted transaction
5779 """roll back an interrupted transaction
5780
5780
5781 Recover from an interrupted commit or pull.
5781 Recover from an interrupted commit or pull.
5782
5782
5783 This command tries to fix the repository status after an
5783 This command tries to fix the repository status after an
5784 interrupted operation. It should only be necessary when Mercurial
5784 interrupted operation. It should only be necessary when Mercurial
5785 suggests it.
5785 suggests it.
5786
5786
5787 Returns 0 if successful, 1 if nothing to recover or verify fails.
5787 Returns 0 if successful, 1 if nothing to recover or verify fails.
5788 """
5788 """
5789 if repo.recover():
5789 if repo.recover():
5790 return hg.verify(repo)
5790 return hg.verify(repo)
5791 return 1
5791 return 1
5792
5792
5793 @command('^remove|rm',
5793 @command('^remove|rm',
5794 [('A', 'after', None, _('record delete for missing files')),
5794 [('A', 'after', None, _('record delete for missing files')),
5795 ('f', 'force', None,
5795 ('f', 'force', None,
5796 _('forget added files, delete modified files')),
5796 _('forget added files, delete modified files')),
5797 ] + subrepoopts + walkopts,
5797 ] + subrepoopts + walkopts,
5798 _('[OPTION]... FILE...'),
5798 _('[OPTION]... FILE...'),
5799 inferrepo=True)
5799 inferrepo=True)
5800 def remove(ui, repo, *pats, **opts):
5800 def remove(ui, repo, *pats, **opts):
5801 """remove the specified files on the next commit
5801 """remove the specified files on the next commit
5802
5802
5803 Schedule the indicated files for removal from the current branch.
5803 Schedule the indicated files for removal from the current branch.
5804
5804
5805 This command schedules the files to be removed at the next commit.
5805 This command schedules the files to be removed at the next commit.
5806 To undo a remove before that, see :hg:`revert`. To undo added
5806 To undo a remove before that, see :hg:`revert`. To undo added
5807 files, see :hg:`forget`.
5807 files, see :hg:`forget`.
5808
5808
5809 .. container:: verbose
5809 .. container:: verbose
5810
5810
5811 -A/--after can be used to remove only files that have already
5811 -A/--after can be used to remove only files that have already
5812 been deleted, -f/--force can be used to force deletion, and -Af
5812 been deleted, -f/--force can be used to force deletion, and -Af
5813 can be used to remove files from the next revision without
5813 can be used to remove files from the next revision without
5814 deleting them from the working directory.
5814 deleting them from the working directory.
5815
5815
5816 The following table details the behavior of remove for different
5816 The following table details the behavior of remove for different
5817 file states (columns) and option combinations (rows). The file
5817 file states (columns) and option combinations (rows). The file
5818 states are Added [A], Clean [C], Modified [M] and Missing [!]
5818 states are Added [A], Clean [C], Modified [M] and Missing [!]
5819 (as reported by :hg:`status`). The actions are Warn, Remove
5819 (as reported by :hg:`status`). The actions are Warn, Remove
5820 (from branch) and Delete (from disk):
5820 (from branch) and Delete (from disk):
5821
5821
5822 ========= == == == ==
5822 ========= == == == ==
5823 opt/state A C M !
5823 opt/state A C M !
5824 ========= == == == ==
5824 ========= == == == ==
5825 none W RD W R
5825 none W RD W R
5826 -f R RD RD R
5826 -f R RD RD R
5827 -A W W W R
5827 -A W W W R
5828 -Af R R R R
5828 -Af R R R R
5829 ========= == == == ==
5829 ========= == == == ==
5830
5830
5831 .. note::
5831 .. note::
5832
5832
5833 :hg:`remove` never deletes files in Added [A] state from the
5833 :hg:`remove` never deletes files in Added [A] state from the
5834 working directory, not even if ``--force`` is specified.
5834 working directory, not even if ``--force`` is specified.
5835
5835
5836 Returns 0 on success, 1 if any warnings encountered.
5836 Returns 0 on success, 1 if any warnings encountered.
5837 """
5837 """
5838
5838
5839 after, force = opts.get('after'), opts.get('force')
5839 after, force = opts.get('after'), opts.get('force')
5840 if not pats and not after:
5840 if not pats and not after:
5841 raise error.Abort(_('no files specified'))
5841 raise error.Abort(_('no files specified'))
5842
5842
5843 m = scmutil.match(repo[None], pats, opts)
5843 m = scmutil.match(repo[None], pats, opts)
5844 subrepos = opts.get('subrepos')
5844 subrepos = opts.get('subrepos')
5845 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5845 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5846
5846
5847 @command('rename|move|mv',
5847 @command('rename|move|mv',
5848 [('A', 'after', None, _('record a rename that has already occurred')),
5848 [('A', 'after', None, _('record a rename that has already occurred')),
5849 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5849 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5850 ] + walkopts + dryrunopts,
5850 ] + walkopts + dryrunopts,
5851 _('[OPTION]... SOURCE... DEST'))
5851 _('[OPTION]... SOURCE... DEST'))
5852 def rename(ui, repo, *pats, **opts):
5852 def rename(ui, repo, *pats, **opts):
5853 """rename files; equivalent of copy + remove
5853 """rename files; equivalent of copy + remove
5854
5854
5855 Mark dest as copies of sources; mark sources for deletion. If dest
5855 Mark dest as copies of sources; mark sources for deletion. If dest
5856 is a directory, copies are put in that directory. If dest is a
5856 is a directory, copies are put in that directory. If dest is a
5857 file, there can only be one source.
5857 file, there can only be one source.
5858
5858
5859 By default, this command copies the contents of files as they
5859 By default, this command copies the contents of files as they
5860 exist in the working directory. If invoked with -A/--after, the
5860 exist in the working directory. If invoked with -A/--after, the
5861 operation is recorded, but no copying is performed.
5861 operation is recorded, but no copying is performed.
5862
5862
5863 This command takes effect at the next commit. To undo a rename
5863 This command takes effect at the next commit. To undo a rename
5864 before that, see :hg:`revert`.
5864 before that, see :hg:`revert`.
5865
5865
5866 Returns 0 on success, 1 if errors are encountered.
5866 Returns 0 on success, 1 if errors are encountered.
5867 """
5867 """
5868 with repo.wlock(False):
5868 with repo.wlock(False):
5869 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5869 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5870
5870
5871 @command('resolve',
5871 @command('resolve',
5872 [('a', 'all', None, _('select all unresolved files')),
5872 [('a', 'all', None, _('select all unresolved files')),
5873 ('l', 'list', None, _('list state of files needing merge')),
5873 ('l', 'list', None, _('list state of files needing merge')),
5874 ('m', 'mark', None, _('mark files as resolved')),
5874 ('m', 'mark', None, _('mark files as resolved')),
5875 ('u', 'unmark', None, _('mark files as unresolved')),
5875 ('u', 'unmark', None, _('mark files as unresolved')),
5876 ('n', 'no-status', None, _('hide status prefix'))]
5876 ('n', 'no-status', None, _('hide status prefix'))]
5877 + mergetoolopts + walkopts + formatteropts,
5877 + mergetoolopts + walkopts + formatteropts,
5878 _('[OPTION]... [FILE]...'),
5878 _('[OPTION]... [FILE]...'),
5879 inferrepo=True)
5879 inferrepo=True)
5880 def resolve(ui, repo, *pats, **opts):
5880 def resolve(ui, repo, *pats, **opts):
5881 """redo merges or set/view the merge status of files
5881 """redo merges or set/view the merge status of files
5882
5882
5883 Merges with unresolved conflicts are often the result of
5883 Merges with unresolved conflicts are often the result of
5884 non-interactive merging using the ``internal:merge`` configuration
5884 non-interactive merging using the ``internal:merge`` configuration
5885 setting, or a command-line merge tool like ``diff3``. The resolve
5885 setting, or a command-line merge tool like ``diff3``. The resolve
5886 command is used to manage the files involved in a merge, after
5886 command is used to manage the files involved in a merge, after
5887 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5887 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5888 working directory must have two parents). See :hg:`help
5888 working directory must have two parents). See :hg:`help
5889 merge-tools` for information on configuring merge tools.
5889 merge-tools` for information on configuring merge tools.
5890
5890
5891 The resolve command can be used in the following ways:
5891 The resolve command can be used in the following ways:
5892
5892
5893 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5893 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5894 files, discarding any previous merge attempts. Re-merging is not
5894 files, discarding any previous merge attempts. Re-merging is not
5895 performed for files already marked as resolved. Use ``--all/-a``
5895 performed for files already marked as resolved. Use ``--all/-a``
5896 to select all unresolved files. ``--tool`` can be used to specify
5896 to select all unresolved files. ``--tool`` can be used to specify
5897 the merge tool used for the given files. It overrides the HGMERGE
5897 the merge tool used for the given files. It overrides the HGMERGE
5898 environment variable and your configuration files. Previous file
5898 environment variable and your configuration files. Previous file
5899 contents are saved with a ``.orig`` suffix.
5899 contents are saved with a ``.orig`` suffix.
5900
5900
5901 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5901 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5902 (e.g. after having manually fixed-up the files). The default is
5902 (e.g. after having manually fixed-up the files). The default is
5903 to mark all unresolved files.
5903 to mark all unresolved files.
5904
5904
5905 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5905 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5906 default is to mark all resolved files.
5906 default is to mark all resolved files.
5907
5907
5908 - :hg:`resolve -l`: list files which had or still have conflicts.
5908 - :hg:`resolve -l`: list files which had or still have conflicts.
5909 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5909 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5910
5910
5911 .. note::
5911 .. note::
5912
5912
5913 Mercurial will not let you commit files with unresolved merge
5913 Mercurial will not let you commit files with unresolved merge
5914 conflicts. You must use :hg:`resolve -m ...` before you can
5914 conflicts. You must use :hg:`resolve -m ...` before you can
5915 commit after a conflicting merge.
5915 commit after a conflicting merge.
5916
5916
5917 Returns 0 on success, 1 if any files fail a resolve attempt.
5917 Returns 0 on success, 1 if any files fail a resolve attempt.
5918 """
5918 """
5919
5919
5920 flaglist = 'all mark unmark list no_status'.split()
5920 flaglist = 'all mark unmark list no_status'.split()
5921 all, mark, unmark, show, nostatus = \
5921 all, mark, unmark, show, nostatus = \
5922 [opts.get(o) for o in flaglist]
5922 [opts.get(o) for o in flaglist]
5923
5923
5924 if (show and (mark or unmark)) or (mark and unmark):
5924 if (show and (mark or unmark)) or (mark and unmark):
5925 raise error.Abort(_("too many options specified"))
5925 raise error.Abort(_("too many options specified"))
5926 if pats and all:
5926 if pats and all:
5927 raise error.Abort(_("can't specify --all and patterns"))
5927 raise error.Abort(_("can't specify --all and patterns"))
5928 if not (all or pats or show or mark or unmark):
5928 if not (all or pats or show or mark or unmark):
5929 raise error.Abort(_('no files or directories specified'),
5929 raise error.Abort(_('no files or directories specified'),
5930 hint=('use --all to re-merge all unresolved files'))
5930 hint=('use --all to re-merge all unresolved files'))
5931
5931
5932 if show:
5932 if show:
5933 fm = ui.formatter('resolve', opts)
5933 fm = ui.formatter('resolve', opts)
5934 ms = mergemod.mergestate.read(repo)
5934 ms = mergemod.mergestate.read(repo)
5935 m = scmutil.match(repo[None], pats, opts)
5935 m = scmutil.match(repo[None], pats, opts)
5936 for f in ms:
5936 for f in ms:
5937 if not m(f):
5937 if not m(f):
5938 continue
5938 continue
5939 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5939 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5940 'd': 'driverresolved'}[ms[f]]
5940 'd': 'driverresolved'}[ms[f]]
5941 fm.startitem()
5941 fm.startitem()
5942 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5942 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5943 fm.write('path', '%s\n', f, label=l)
5943 fm.write('path', '%s\n', f, label=l)
5944 fm.end()
5944 fm.end()
5945 return 0
5945 return 0
5946
5946
5947 with repo.wlock():
5947 with repo.wlock():
5948 ms = mergemod.mergestate.read(repo)
5948 ms = mergemod.mergestate.read(repo)
5949
5949
5950 if not (ms.active() or repo.dirstate.p2() != nullid):
5950 if not (ms.active() or repo.dirstate.p2() != nullid):
5951 raise error.Abort(
5951 raise error.Abort(
5952 _('resolve command not applicable when not merging'))
5952 _('resolve command not applicable when not merging'))
5953
5953
5954 wctx = repo[None]
5954 wctx = repo[None]
5955
5955
5956 if ms.mergedriver and ms.mdstate() == 'u':
5956 if ms.mergedriver and ms.mdstate() == 'u':
5957 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5957 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5958 ms.commit()
5958 ms.commit()
5959 # allow mark and unmark to go through
5959 # allow mark and unmark to go through
5960 if not mark and not unmark and not proceed:
5960 if not mark and not unmark and not proceed:
5961 return 1
5961 return 1
5962
5962
5963 m = scmutil.match(wctx, pats, opts)
5963 m = scmutil.match(wctx, pats, opts)
5964 ret = 0
5964 ret = 0
5965 didwork = False
5965 didwork = False
5966 runconclude = False
5966 runconclude = False
5967
5967
5968 tocomplete = []
5968 tocomplete = []
5969 for f in ms:
5969 for f in ms:
5970 if not m(f):
5970 if not m(f):
5971 continue
5971 continue
5972
5972
5973 didwork = True
5973 didwork = True
5974
5974
5975 # don't let driver-resolved files be marked, and run the conclude
5975 # don't let driver-resolved files be marked, and run the conclude
5976 # step if asked to resolve
5976 # step if asked to resolve
5977 if ms[f] == "d":
5977 if ms[f] == "d":
5978 exact = m.exact(f)
5978 exact = m.exact(f)
5979 if mark:
5979 if mark:
5980 if exact:
5980 if exact:
5981 ui.warn(_('not marking %s as it is driver-resolved\n')
5981 ui.warn(_('not marking %s as it is driver-resolved\n')
5982 % f)
5982 % f)
5983 elif unmark:
5983 elif unmark:
5984 if exact:
5984 if exact:
5985 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5985 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5986 % f)
5986 % f)
5987 else:
5987 else:
5988 runconclude = True
5988 runconclude = True
5989 continue
5989 continue
5990
5990
5991 if mark:
5991 if mark:
5992 ms.mark(f, "r")
5992 ms.mark(f, "r")
5993 elif unmark:
5993 elif unmark:
5994 ms.mark(f, "u")
5994 ms.mark(f, "u")
5995 else:
5995 else:
5996 # backup pre-resolve (merge uses .orig for its own purposes)
5996 # backup pre-resolve (merge uses .orig for its own purposes)
5997 a = repo.wjoin(f)
5997 a = repo.wjoin(f)
5998 try:
5998 try:
5999 util.copyfile(a, a + ".resolve")
5999 util.copyfile(a, a + ".resolve")
6000 except (IOError, OSError) as inst:
6000 except (IOError, OSError) as inst:
6001 if inst.errno != errno.ENOENT:
6001 if inst.errno != errno.ENOENT:
6002 raise
6002 raise
6003
6003
6004 try:
6004 try:
6005 # preresolve file
6005 # preresolve file
6006 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6006 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6007 'resolve')
6007 'resolve')
6008 complete, r = ms.preresolve(f, wctx)
6008 complete, r = ms.preresolve(f, wctx)
6009 if not complete:
6009 if not complete:
6010 tocomplete.append(f)
6010 tocomplete.append(f)
6011 elif r:
6011 elif r:
6012 ret = 1
6012 ret = 1
6013 finally:
6013 finally:
6014 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6014 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6015 ms.commit()
6015 ms.commit()
6016
6016
6017 # replace filemerge's .orig file with our resolve file, but only
6017 # replace filemerge's .orig file with our resolve file, but only
6018 # for merges that are complete
6018 # for merges that are complete
6019 if complete:
6019 if complete:
6020 try:
6020 try:
6021 util.rename(a + ".resolve",
6021 util.rename(a + ".resolve",
6022 scmutil.origpath(ui, repo, a))
6022 scmutil.origpath(ui, repo, a))
6023 except OSError as inst:
6023 except OSError as inst:
6024 if inst.errno != errno.ENOENT:
6024 if inst.errno != errno.ENOENT:
6025 raise
6025 raise
6026
6026
6027 for f in tocomplete:
6027 for f in tocomplete:
6028 try:
6028 try:
6029 # resolve file
6029 # resolve file
6030 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6030 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6031 'resolve')
6031 'resolve')
6032 r = ms.resolve(f, wctx)
6032 r = ms.resolve(f, wctx)
6033 if r:
6033 if r:
6034 ret = 1
6034 ret = 1
6035 finally:
6035 finally:
6036 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6036 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6037 ms.commit()
6037 ms.commit()
6038
6038
6039 # replace filemerge's .orig file with our resolve file
6039 # replace filemerge's .orig file with our resolve file
6040 a = repo.wjoin(f)
6040 a = repo.wjoin(f)
6041 try:
6041 try:
6042 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6042 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6043 except OSError as inst:
6043 except OSError as inst:
6044 if inst.errno != errno.ENOENT:
6044 if inst.errno != errno.ENOENT:
6045 raise
6045 raise
6046
6046
6047 ms.commit()
6047 ms.commit()
6048 ms.recordactions()
6048 ms.recordactions()
6049
6049
6050 if not didwork and pats:
6050 if not didwork and pats:
6051 hint = None
6051 hint = None
6052 if not any([p for p in pats if p.find(':') >= 0]):
6052 if not any([p for p in pats if p.find(':') >= 0]):
6053 pats = ['path:%s' % p for p in pats]
6053 pats = ['path:%s' % p for p in pats]
6054 m = scmutil.match(wctx, pats, opts)
6054 m = scmutil.match(wctx, pats, opts)
6055 for f in ms:
6055 for f in ms:
6056 if not m(f):
6056 if not m(f):
6057 continue
6057 continue
6058 flags = ''.join(['-%s ' % o[0] for o in flaglist
6058 flags = ''.join(['-%s ' % o[0] for o in flaglist
6059 if opts.get(o)])
6059 if opts.get(o)])
6060 hint = _("(try: hg resolve %s%s)\n") % (
6060 hint = _("(try: hg resolve %s%s)\n") % (
6061 flags,
6061 flags,
6062 ' '.join(pats))
6062 ' '.join(pats))
6063 break
6063 break
6064 ui.warn(_("arguments do not match paths that need resolving\n"))
6064 ui.warn(_("arguments do not match paths that need resolving\n"))
6065 if hint:
6065 if hint:
6066 ui.warn(hint)
6066 ui.warn(hint)
6067 elif ms.mergedriver and ms.mdstate() != 's':
6067 elif ms.mergedriver and ms.mdstate() != 's':
6068 # run conclude step when either a driver-resolved file is requested
6068 # run conclude step when either a driver-resolved file is requested
6069 # or there are no driver-resolved files
6069 # or there are no driver-resolved files
6070 # we can't use 'ret' to determine whether any files are unresolved
6070 # we can't use 'ret' to determine whether any files are unresolved
6071 # because we might not have tried to resolve some
6071 # because we might not have tried to resolve some
6072 if ((runconclude or not list(ms.driverresolved()))
6072 if ((runconclude or not list(ms.driverresolved()))
6073 and not list(ms.unresolved())):
6073 and not list(ms.unresolved())):
6074 proceed = mergemod.driverconclude(repo, ms, wctx)
6074 proceed = mergemod.driverconclude(repo, ms, wctx)
6075 ms.commit()
6075 ms.commit()
6076 if not proceed:
6076 if not proceed:
6077 return 1
6077 return 1
6078
6078
6079 # Nudge users into finishing an unfinished operation
6079 # Nudge users into finishing an unfinished operation
6080 unresolvedf = list(ms.unresolved())
6080 unresolvedf = list(ms.unresolved())
6081 driverresolvedf = list(ms.driverresolved())
6081 driverresolvedf = list(ms.driverresolved())
6082 if not unresolvedf and not driverresolvedf:
6082 if not unresolvedf and not driverresolvedf:
6083 ui.status(_('(no more unresolved files)\n'))
6083 ui.status(_('(no more unresolved files)\n'))
6084 cmdutil.checkafterresolved(repo)
6084 cmdutil.checkafterresolved(repo)
6085 elif not unresolvedf:
6085 elif not unresolvedf:
6086 ui.status(_('(no more unresolved files -- '
6086 ui.status(_('(no more unresolved files -- '
6087 'run "hg resolve --all" to conclude)\n'))
6087 'run "hg resolve --all" to conclude)\n'))
6088
6088
6089 return ret
6089 return ret
6090
6090
6091 @command('revert',
6091 @command('revert',
6092 [('a', 'all', None, _('revert all changes when no arguments given')),
6092 [('a', 'all', None, _('revert all changes when no arguments given')),
6093 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6093 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6094 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6094 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6095 ('C', 'no-backup', None, _('do not save backup copies of files')),
6095 ('C', 'no-backup', None, _('do not save backup copies of files')),
6096 ('i', 'interactive', None,
6096 ('i', 'interactive', None,
6097 _('interactively select the changes (EXPERIMENTAL)')),
6097 _('interactively select the changes (EXPERIMENTAL)')),
6098 ] + walkopts + dryrunopts,
6098 ] + walkopts + dryrunopts,
6099 _('[OPTION]... [-r REV] [NAME]...'))
6099 _('[OPTION]... [-r REV] [NAME]...'))
6100 def revert(ui, repo, *pats, **opts):
6100 def revert(ui, repo, *pats, **opts):
6101 """restore files to their checkout state
6101 """restore files to their checkout state
6102
6102
6103 .. note::
6103 .. note::
6104
6104
6105 To check out earlier revisions, you should use :hg:`update REV`.
6105 To check out earlier revisions, you should use :hg:`update REV`.
6106 To cancel an uncommitted merge (and lose your changes),
6106 To cancel an uncommitted merge (and lose your changes),
6107 use :hg:`update --clean .`.
6107 use :hg:`update --clean .`.
6108
6108
6109 With no revision specified, revert the specified files or directories
6109 With no revision specified, revert the specified files or directories
6110 to the contents they had in the parent of the working directory.
6110 to the contents they had in the parent of the working directory.
6111 This restores the contents of files to an unmodified
6111 This restores the contents of files to an unmodified
6112 state and unschedules adds, removes, copies, and renames. If the
6112 state and unschedules adds, removes, copies, and renames. If the
6113 working directory has two parents, you must explicitly specify a
6113 working directory has two parents, you must explicitly specify a
6114 revision.
6114 revision.
6115
6115
6116 Using the -r/--rev or -d/--date options, revert the given files or
6116 Using the -r/--rev or -d/--date options, revert the given files or
6117 directories to their states as of a specific revision. Because
6117 directories to their states as of a specific revision. Because
6118 revert does not change the working directory parents, this will
6118 revert does not change the working directory parents, this will
6119 cause these files to appear modified. This can be helpful to "back
6119 cause these files to appear modified. This can be helpful to "back
6120 out" some or all of an earlier change. See :hg:`backout` for a
6120 out" some or all of an earlier change. See :hg:`backout` for a
6121 related method.
6121 related method.
6122
6122
6123 Modified files are saved with a .orig suffix before reverting.
6123 Modified files are saved with a .orig suffix before reverting.
6124 To disable these backups, use --no-backup. It is possible to store
6124 To disable these backups, use --no-backup. It is possible to store
6125 the backup files in a custom directory relative to the root of the
6125 the backup files in a custom directory relative to the root of the
6126 repository by setting the ``ui.origbackuppath`` configuration
6126 repository by setting the ``ui.origbackuppath`` configuration
6127 option.
6127 option.
6128
6128
6129 See :hg:`help dates` for a list of formats valid for -d/--date.
6129 See :hg:`help dates` for a list of formats valid for -d/--date.
6130
6130
6131 See :hg:`help backout` for a way to reverse the effect of an
6131 See :hg:`help backout` for a way to reverse the effect of an
6132 earlier changeset.
6132 earlier changeset.
6133
6133
6134 Returns 0 on success.
6134 Returns 0 on success.
6135 """
6135 """
6136
6136
6137 if opts.get("date"):
6137 if opts.get("date"):
6138 if opts.get("rev"):
6138 if opts.get("rev"):
6139 raise error.Abort(_("you can't specify a revision and a date"))
6139 raise error.Abort(_("you can't specify a revision and a date"))
6140 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6140 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6141
6141
6142 parent, p2 = repo.dirstate.parents()
6142 parent, p2 = repo.dirstate.parents()
6143 if not opts.get('rev') and p2 != nullid:
6143 if not opts.get('rev') and p2 != nullid:
6144 # revert after merge is a trap for new users (issue2915)
6144 # revert after merge is a trap for new users (issue2915)
6145 raise error.Abort(_('uncommitted merge with no revision specified'),
6145 raise error.Abort(_('uncommitted merge with no revision specified'),
6146 hint=_("use 'hg update' or see 'hg help revert'"))
6146 hint=_("use 'hg update' or see 'hg help revert'"))
6147
6147
6148 ctx = scmutil.revsingle(repo, opts.get('rev'))
6148 ctx = scmutil.revsingle(repo, opts.get('rev'))
6149
6149
6150 if (not (pats or opts.get('include') or opts.get('exclude') or
6150 if (not (pats or opts.get('include') or opts.get('exclude') or
6151 opts.get('all') or opts.get('interactive'))):
6151 opts.get('all') or opts.get('interactive'))):
6152 msg = _("no files or directories specified")
6152 msg = _("no files or directories specified")
6153 if p2 != nullid:
6153 if p2 != nullid:
6154 hint = _("uncommitted merge, use --all to discard all changes,"
6154 hint = _("uncommitted merge, use --all to discard all changes,"
6155 " or 'hg update -C .' to abort the merge")
6155 " or 'hg update -C .' to abort the merge")
6156 raise error.Abort(msg, hint=hint)
6156 raise error.Abort(msg, hint=hint)
6157 dirty = any(repo.status())
6157 dirty = any(repo.status())
6158 node = ctx.node()
6158 node = ctx.node()
6159 if node != parent:
6159 if node != parent:
6160 if dirty:
6160 if dirty:
6161 hint = _("uncommitted changes, use --all to discard all"
6161 hint = _("uncommitted changes, use --all to discard all"
6162 " changes, or 'hg update %s' to update") % ctx.rev()
6162 " changes, or 'hg update %s' to update") % ctx.rev()
6163 else:
6163 else:
6164 hint = _("use --all to revert all files,"
6164 hint = _("use --all to revert all files,"
6165 " or 'hg update %s' to update") % ctx.rev()
6165 " or 'hg update %s' to update") % ctx.rev()
6166 elif dirty:
6166 elif dirty:
6167 hint = _("uncommitted changes, use --all to discard all changes")
6167 hint = _("uncommitted changes, use --all to discard all changes")
6168 else:
6168 else:
6169 hint = _("use --all to revert all files")
6169 hint = _("use --all to revert all files")
6170 raise error.Abort(msg, hint=hint)
6170 raise error.Abort(msg, hint=hint)
6171
6171
6172 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6172 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6173
6173
6174 @command('rollback', dryrunopts +
6174 @command('rollback', dryrunopts +
6175 [('f', 'force', False, _('ignore safety measures'))])
6175 [('f', 'force', False, _('ignore safety measures'))])
6176 def rollback(ui, repo, **opts):
6176 def rollback(ui, repo, **opts):
6177 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6177 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6178
6178
6179 Please use :hg:`commit --amend` instead of rollback to correct
6179 Please use :hg:`commit --amend` instead of rollback to correct
6180 mistakes in the last commit.
6180 mistakes in the last commit.
6181
6181
6182 This command should be used with care. There is only one level of
6182 This command should be used with care. There is only one level of
6183 rollback, and there is no way to undo a rollback. It will also
6183 rollback, and there is no way to undo a rollback. It will also
6184 restore the dirstate at the time of the last transaction, losing
6184 restore the dirstate at the time of the last transaction, losing
6185 any dirstate changes since that time. This command does not alter
6185 any dirstate changes since that time. This command does not alter
6186 the working directory.
6186 the working directory.
6187
6187
6188 Transactions are used to encapsulate the effects of all commands
6188 Transactions are used to encapsulate the effects of all commands
6189 that create new changesets or propagate existing changesets into a
6189 that create new changesets or propagate existing changesets into a
6190 repository.
6190 repository.
6191
6191
6192 .. container:: verbose
6192 .. container:: verbose
6193
6193
6194 For example, the following commands are transactional, and their
6194 For example, the following commands are transactional, and their
6195 effects can be rolled back:
6195 effects can be rolled back:
6196
6196
6197 - commit
6197 - commit
6198 - import
6198 - import
6199 - pull
6199 - pull
6200 - push (with this repository as the destination)
6200 - push (with this repository as the destination)
6201 - unbundle
6201 - unbundle
6202
6202
6203 To avoid permanent data loss, rollback will refuse to rollback a
6203 To avoid permanent data loss, rollback will refuse to rollback a
6204 commit transaction if it isn't checked out. Use --force to
6204 commit transaction if it isn't checked out. Use --force to
6205 override this protection.
6205 override this protection.
6206
6206
6207 The rollback command can be entirely disabled by setting the
6207 The rollback command can be entirely disabled by setting the
6208 ``ui.rollback`` configuration setting to false. If you're here
6208 ``ui.rollback`` configuration setting to false. If you're here
6209 because you want to use rollback and it's disabled, you can
6209 because you want to use rollback and it's disabled, you can
6210 re-enable the command by setting ``ui.rollback`` to true.
6210 re-enable the command by setting ``ui.rollback`` to true.
6211
6211
6212 This command is not intended for use on public repositories. Once
6212 This command is not intended for use on public repositories. Once
6213 changes are visible for pull by other users, rolling a transaction
6213 changes are visible for pull by other users, rolling a transaction
6214 back locally is ineffective (someone else may already have pulled
6214 back locally is ineffective (someone else may already have pulled
6215 the changes). Furthermore, a race is possible with readers of the
6215 the changes). Furthermore, a race is possible with readers of the
6216 repository; for example an in-progress pull from the repository
6216 repository; for example an in-progress pull from the repository
6217 may fail if a rollback is performed.
6217 may fail if a rollback is performed.
6218
6218
6219 Returns 0 on success, 1 if no rollback data is available.
6219 Returns 0 on success, 1 if no rollback data is available.
6220 """
6220 """
6221 if not ui.configbool('ui', 'rollback', True):
6221 if not ui.configbool('ui', 'rollback', True):
6222 raise error.Abort(_('rollback is disabled because it is unsafe'),
6222 raise error.Abort(_('rollback is disabled because it is unsafe'),
6223 hint=('see `hg help -v rollback` for information'))
6223 hint=('see `hg help -v rollback` for information'))
6224 return repo.rollback(dryrun=opts.get('dry_run'),
6224 return repo.rollback(dryrun=opts.get('dry_run'),
6225 force=opts.get('force'))
6225 force=opts.get('force'))
6226
6226
6227 @command('root', [])
6227 @command('root', [])
6228 def root(ui, repo):
6228 def root(ui, repo):
6229 """print the root (top) of the current working directory
6229 """print the root (top) of the current working directory
6230
6230
6231 Print the root directory of the current repository.
6231 Print the root directory of the current repository.
6232
6232
6233 Returns 0 on success.
6233 Returns 0 on success.
6234 """
6234 """
6235 ui.write(repo.root + "\n")
6235 ui.write(repo.root + "\n")
6236
6236
6237 @command('^serve',
6237 @command('^serve',
6238 [('A', 'accesslog', '', _('name of access log file to write to'),
6238 [('A', 'accesslog', '', _('name of access log file to write to'),
6239 _('FILE')),
6239 _('FILE')),
6240 ('d', 'daemon', None, _('run server in background')),
6240 ('d', 'daemon', None, _('run server in background')),
6241 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6241 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6242 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6242 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6243 # use string type, then we can check if something was passed
6243 # use string type, then we can check if something was passed
6244 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6244 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6245 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6245 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6246 _('ADDR')),
6246 _('ADDR')),
6247 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6247 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6248 _('PREFIX')),
6248 _('PREFIX')),
6249 ('n', 'name', '',
6249 ('n', 'name', '',
6250 _('name to show in web pages (default: working directory)'), _('NAME')),
6250 _('name to show in web pages (default: working directory)'), _('NAME')),
6251 ('', 'web-conf', '',
6251 ('', 'web-conf', '',
6252 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
6252 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
6253 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6253 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6254 _('FILE')),
6254 _('FILE')),
6255 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6255 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6256 ('', 'stdio', None, _('for remote clients')),
6256 ('', 'stdio', None, _('for remote clients')),
6257 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6257 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6258 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6258 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6259 ('', 'style', '', _('template style to use'), _('STYLE')),
6259 ('', 'style', '', _('template style to use'), _('STYLE')),
6260 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6260 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6261 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6261 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6262 _('[OPTION]...'),
6262 _('[OPTION]...'),
6263 optionalrepo=True)
6263 optionalrepo=True)
6264 def serve(ui, repo, **opts):
6264 def serve(ui, repo, **opts):
6265 """start stand-alone webserver
6265 """start stand-alone webserver
6266
6266
6267 Start a local HTTP repository browser and pull server. You can use
6267 Start a local HTTP repository browser and pull server. You can use
6268 this for ad-hoc sharing and browsing of repositories. It is
6268 this for ad-hoc sharing and browsing of repositories. It is
6269 recommended to use a real web server to serve a repository for
6269 recommended to use a real web server to serve a repository for
6270 longer periods of time.
6270 longer periods of time.
6271
6271
6272 Please note that the server does not implement access control.
6272 Please note that the server does not implement access control.
6273 This means that, by default, anybody can read from the server and
6273 This means that, by default, anybody can read from the server and
6274 nobody can write to it by default. Set the ``web.allow_push``
6274 nobody can write to it by default. Set the ``web.allow_push``
6275 option to ``*`` to allow everybody to push to the server. You
6275 option to ``*`` to allow everybody to push to the server. You
6276 should use a real web server if you need to authenticate users.
6276 should use a real web server if you need to authenticate users.
6277
6277
6278 By default, the server logs accesses to stdout and errors to
6278 By default, the server logs accesses to stdout and errors to
6279 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6279 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6280 files.
6280 files.
6281
6281
6282 To have the server choose a free port number to listen on, specify
6282 To have the server choose a free port number to listen on, specify
6283 a port number of 0; in this case, the server will print the port
6283 a port number of 0; in this case, the server will print the port
6284 number it uses.
6284 number it uses.
6285
6285
6286 Returns 0 on success.
6286 Returns 0 on success.
6287 """
6287 """
6288
6288
6289 if opts["stdio"] and opts["cmdserver"]:
6289 if opts["stdio"] and opts["cmdserver"]:
6290 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6290 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6291
6291
6292 if opts["stdio"]:
6292 if opts["stdio"]:
6293 if repo is None:
6293 if repo is None:
6294 raise error.RepoError(_("there is no Mercurial repository here"
6294 raise error.RepoError(_("there is no Mercurial repository here"
6295 " (.hg not found)"))
6295 " (.hg not found)"))
6296 s = sshserver.sshserver(ui, repo)
6296 s = sshserver.sshserver(ui, repo)
6297 s.serve_forever()
6297 s.serve_forever()
6298
6298
6299 if opts["cmdserver"]:
6299 service = server.createservice(ui, repo, opts)
6300 service = server.createcmdservice(ui, repo, opts)
6301 else:
6302 service = server.createhgwebservice(ui, repo, opts)
6303 return server.runservice(opts, initfn=service.init, runfn=service.run)
6300 return server.runservice(opts, initfn=service.init, runfn=service.run)
6304
6301
6305 @command('^status|st',
6302 @command('^status|st',
6306 [('A', 'all', None, _('show status of all files')),
6303 [('A', 'all', None, _('show status of all files')),
6307 ('m', 'modified', None, _('show only modified files')),
6304 ('m', 'modified', None, _('show only modified files')),
6308 ('a', 'added', None, _('show only added files')),
6305 ('a', 'added', None, _('show only added files')),
6309 ('r', 'removed', None, _('show only removed files')),
6306 ('r', 'removed', None, _('show only removed files')),
6310 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6307 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6311 ('c', 'clean', None, _('show only files without changes')),
6308 ('c', 'clean', None, _('show only files without changes')),
6312 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6309 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6313 ('i', 'ignored', None, _('show only ignored files')),
6310 ('i', 'ignored', None, _('show only ignored files')),
6314 ('n', 'no-status', None, _('hide status prefix')),
6311 ('n', 'no-status', None, _('hide status prefix')),
6315 ('C', 'copies', None, _('show source of copied files')),
6312 ('C', 'copies', None, _('show source of copied files')),
6316 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6313 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6317 ('', 'rev', [], _('show difference from revision'), _('REV')),
6314 ('', 'rev', [], _('show difference from revision'), _('REV')),
6318 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6315 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6319 ] + walkopts + subrepoopts + formatteropts,
6316 ] + walkopts + subrepoopts + formatteropts,
6320 _('[OPTION]... [FILE]...'),
6317 _('[OPTION]... [FILE]...'),
6321 inferrepo=True)
6318 inferrepo=True)
6322 def status(ui, repo, *pats, **opts):
6319 def status(ui, repo, *pats, **opts):
6323 """show changed files in the working directory
6320 """show changed files in the working directory
6324
6321
6325 Show status of files in the repository. If names are given, only
6322 Show status of files in the repository. If names are given, only
6326 files that match are shown. Files that are clean or ignored or
6323 files that match are shown. Files that are clean or ignored or
6327 the source of a copy/move operation, are not listed unless
6324 the source of a copy/move operation, are not listed unless
6328 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6325 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6329 Unless options described with "show only ..." are given, the
6326 Unless options described with "show only ..." are given, the
6330 options -mardu are used.
6327 options -mardu are used.
6331
6328
6332 Option -q/--quiet hides untracked (unknown and ignored) files
6329 Option -q/--quiet hides untracked (unknown and ignored) files
6333 unless explicitly requested with -u/--unknown or -i/--ignored.
6330 unless explicitly requested with -u/--unknown or -i/--ignored.
6334
6331
6335 .. note::
6332 .. note::
6336
6333
6337 :hg:`status` may appear to disagree with diff if permissions have
6334 :hg:`status` may appear to disagree with diff if permissions have
6338 changed or a merge has occurred. The standard diff format does
6335 changed or a merge has occurred. The standard diff format does
6339 not report permission changes and diff only reports changes
6336 not report permission changes and diff only reports changes
6340 relative to one merge parent.
6337 relative to one merge parent.
6341
6338
6342 If one revision is given, it is used as the base revision.
6339 If one revision is given, it is used as the base revision.
6343 If two revisions are given, the differences between them are
6340 If two revisions are given, the differences between them are
6344 shown. The --change option can also be used as a shortcut to list
6341 shown. The --change option can also be used as a shortcut to list
6345 the changed files of a revision from its first parent.
6342 the changed files of a revision from its first parent.
6346
6343
6347 The codes used to show the status of files are::
6344 The codes used to show the status of files are::
6348
6345
6349 M = modified
6346 M = modified
6350 A = added
6347 A = added
6351 R = removed
6348 R = removed
6352 C = clean
6349 C = clean
6353 ! = missing (deleted by non-hg command, but still tracked)
6350 ! = missing (deleted by non-hg command, but still tracked)
6354 ? = not tracked
6351 ? = not tracked
6355 I = ignored
6352 I = ignored
6356 = origin of the previous file (with --copies)
6353 = origin of the previous file (with --copies)
6357
6354
6358 .. container:: verbose
6355 .. container:: verbose
6359
6356
6360 Examples:
6357 Examples:
6361
6358
6362 - show changes in the working directory relative to a
6359 - show changes in the working directory relative to a
6363 changeset::
6360 changeset::
6364
6361
6365 hg status --rev 9353
6362 hg status --rev 9353
6366
6363
6367 - show changes in the working directory relative to the
6364 - show changes in the working directory relative to the
6368 current directory (see :hg:`help patterns` for more information)::
6365 current directory (see :hg:`help patterns` for more information)::
6369
6366
6370 hg status re:
6367 hg status re:
6371
6368
6372 - show all changes including copies in an existing changeset::
6369 - show all changes including copies in an existing changeset::
6373
6370
6374 hg status --copies --change 9353
6371 hg status --copies --change 9353
6375
6372
6376 - get a NUL separated list of added files, suitable for xargs::
6373 - get a NUL separated list of added files, suitable for xargs::
6377
6374
6378 hg status -an0
6375 hg status -an0
6379
6376
6380 Returns 0 on success.
6377 Returns 0 on success.
6381 """
6378 """
6382
6379
6383 revs = opts.get('rev')
6380 revs = opts.get('rev')
6384 change = opts.get('change')
6381 change = opts.get('change')
6385
6382
6386 if revs and change:
6383 if revs and change:
6387 msg = _('cannot specify --rev and --change at the same time')
6384 msg = _('cannot specify --rev and --change at the same time')
6388 raise error.Abort(msg)
6385 raise error.Abort(msg)
6389 elif change:
6386 elif change:
6390 node2 = scmutil.revsingle(repo, change, None).node()
6387 node2 = scmutil.revsingle(repo, change, None).node()
6391 node1 = repo[node2].p1().node()
6388 node1 = repo[node2].p1().node()
6392 else:
6389 else:
6393 node1, node2 = scmutil.revpair(repo, revs)
6390 node1, node2 = scmutil.revpair(repo, revs)
6394
6391
6395 if pats:
6392 if pats:
6396 cwd = repo.getcwd()
6393 cwd = repo.getcwd()
6397 else:
6394 else:
6398 cwd = ''
6395 cwd = ''
6399
6396
6400 if opts.get('print0'):
6397 if opts.get('print0'):
6401 end = '\0'
6398 end = '\0'
6402 else:
6399 else:
6403 end = '\n'
6400 end = '\n'
6404 copy = {}
6401 copy = {}
6405 states = 'modified added removed deleted unknown ignored clean'.split()
6402 states = 'modified added removed deleted unknown ignored clean'.split()
6406 show = [k for k in states if opts.get(k)]
6403 show = [k for k in states if opts.get(k)]
6407 if opts.get('all'):
6404 if opts.get('all'):
6408 show += ui.quiet and (states[:4] + ['clean']) or states
6405 show += ui.quiet and (states[:4] + ['clean']) or states
6409 if not show:
6406 if not show:
6410 if ui.quiet:
6407 if ui.quiet:
6411 show = states[:4]
6408 show = states[:4]
6412 else:
6409 else:
6413 show = states[:5]
6410 show = states[:5]
6414
6411
6415 m = scmutil.match(repo[node2], pats, opts)
6412 m = scmutil.match(repo[node2], pats, opts)
6416 stat = repo.status(node1, node2, m,
6413 stat = repo.status(node1, node2, m,
6417 'ignored' in show, 'clean' in show, 'unknown' in show,
6414 'ignored' in show, 'clean' in show, 'unknown' in show,
6418 opts.get('subrepos'))
6415 opts.get('subrepos'))
6419 changestates = zip(states, 'MAR!?IC', stat)
6416 changestates = zip(states, 'MAR!?IC', stat)
6420
6417
6421 if (opts.get('all') or opts.get('copies')
6418 if (opts.get('all') or opts.get('copies')
6422 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6419 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6423 copy = copies.pathcopies(repo[node1], repo[node2], m)
6420 copy = copies.pathcopies(repo[node1], repo[node2], m)
6424
6421
6425 fm = ui.formatter('status', opts)
6422 fm = ui.formatter('status', opts)
6426 fmt = '%s' + end
6423 fmt = '%s' + end
6427 showchar = not opts.get('no_status')
6424 showchar = not opts.get('no_status')
6428
6425
6429 for state, char, files in changestates:
6426 for state, char, files in changestates:
6430 if state in show:
6427 if state in show:
6431 label = 'status.' + state
6428 label = 'status.' + state
6432 for f in files:
6429 for f in files:
6433 fm.startitem()
6430 fm.startitem()
6434 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6431 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6435 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6432 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6436 if f in copy:
6433 if f in copy:
6437 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6434 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6438 label='status.copied')
6435 label='status.copied')
6439 fm.end()
6436 fm.end()
6440
6437
6441 @command('^summary|sum',
6438 @command('^summary|sum',
6442 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6439 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6443 def summary(ui, repo, **opts):
6440 def summary(ui, repo, **opts):
6444 """summarize working directory state
6441 """summarize working directory state
6445
6442
6446 This generates a brief summary of the working directory state,
6443 This generates a brief summary of the working directory state,
6447 including parents, branch, commit status, phase and available updates.
6444 including parents, branch, commit status, phase and available updates.
6448
6445
6449 With the --remote option, this will check the default paths for
6446 With the --remote option, this will check the default paths for
6450 incoming and outgoing changes. This can be time-consuming.
6447 incoming and outgoing changes. This can be time-consuming.
6451
6448
6452 Returns 0 on success.
6449 Returns 0 on success.
6453 """
6450 """
6454
6451
6455 ctx = repo[None]
6452 ctx = repo[None]
6456 parents = ctx.parents()
6453 parents = ctx.parents()
6457 pnode = parents[0].node()
6454 pnode = parents[0].node()
6458 marks = []
6455 marks = []
6459
6456
6460 ms = None
6457 ms = None
6461 try:
6458 try:
6462 ms = mergemod.mergestate.read(repo)
6459 ms = mergemod.mergestate.read(repo)
6463 except error.UnsupportedMergeRecords as e:
6460 except error.UnsupportedMergeRecords as e:
6464 s = ' '.join(e.recordtypes)
6461 s = ' '.join(e.recordtypes)
6465 ui.warn(
6462 ui.warn(
6466 _('warning: merge state has unsupported record types: %s\n') % s)
6463 _('warning: merge state has unsupported record types: %s\n') % s)
6467 unresolved = 0
6464 unresolved = 0
6468 else:
6465 else:
6469 unresolved = [f for f in ms if ms[f] == 'u']
6466 unresolved = [f for f in ms if ms[f] == 'u']
6470
6467
6471 for p in parents:
6468 for p in parents:
6472 # label with log.changeset (instead of log.parent) since this
6469 # label with log.changeset (instead of log.parent) since this
6473 # shows a working directory parent *changeset*:
6470 # shows a working directory parent *changeset*:
6474 # i18n: column positioning for "hg summary"
6471 # i18n: column positioning for "hg summary"
6475 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6472 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6476 label='log.changeset changeset.%s' % p.phasestr())
6473 label='log.changeset changeset.%s' % p.phasestr())
6477 ui.write(' '.join(p.tags()), label='log.tag')
6474 ui.write(' '.join(p.tags()), label='log.tag')
6478 if p.bookmarks():
6475 if p.bookmarks():
6479 marks.extend(p.bookmarks())
6476 marks.extend(p.bookmarks())
6480 if p.rev() == -1:
6477 if p.rev() == -1:
6481 if not len(repo):
6478 if not len(repo):
6482 ui.write(_(' (empty repository)'))
6479 ui.write(_(' (empty repository)'))
6483 else:
6480 else:
6484 ui.write(_(' (no revision checked out)'))
6481 ui.write(_(' (no revision checked out)'))
6485 ui.write('\n')
6482 ui.write('\n')
6486 if p.description():
6483 if p.description():
6487 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6484 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6488 label='log.summary')
6485 label='log.summary')
6489
6486
6490 branch = ctx.branch()
6487 branch = ctx.branch()
6491 bheads = repo.branchheads(branch)
6488 bheads = repo.branchheads(branch)
6492 # i18n: column positioning for "hg summary"
6489 # i18n: column positioning for "hg summary"
6493 m = _('branch: %s\n') % branch
6490 m = _('branch: %s\n') % branch
6494 if branch != 'default':
6491 if branch != 'default':
6495 ui.write(m, label='log.branch')
6492 ui.write(m, label='log.branch')
6496 else:
6493 else:
6497 ui.status(m, label='log.branch')
6494 ui.status(m, label='log.branch')
6498
6495
6499 if marks:
6496 if marks:
6500 active = repo._activebookmark
6497 active = repo._activebookmark
6501 # i18n: column positioning for "hg summary"
6498 # i18n: column positioning for "hg summary"
6502 ui.write(_('bookmarks:'), label='log.bookmark')
6499 ui.write(_('bookmarks:'), label='log.bookmark')
6503 if active is not None:
6500 if active is not None:
6504 if active in marks:
6501 if active in marks:
6505 ui.write(' *' + active, label=activebookmarklabel)
6502 ui.write(' *' + active, label=activebookmarklabel)
6506 marks.remove(active)
6503 marks.remove(active)
6507 else:
6504 else:
6508 ui.write(' [%s]' % active, label=activebookmarklabel)
6505 ui.write(' [%s]' % active, label=activebookmarklabel)
6509 for m in marks:
6506 for m in marks:
6510 ui.write(' ' + m, label='log.bookmark')
6507 ui.write(' ' + m, label='log.bookmark')
6511 ui.write('\n', label='log.bookmark')
6508 ui.write('\n', label='log.bookmark')
6512
6509
6513 status = repo.status(unknown=True)
6510 status = repo.status(unknown=True)
6514
6511
6515 c = repo.dirstate.copies()
6512 c = repo.dirstate.copies()
6516 copied, renamed = [], []
6513 copied, renamed = [], []
6517 for d, s in c.iteritems():
6514 for d, s in c.iteritems():
6518 if s in status.removed:
6515 if s in status.removed:
6519 status.removed.remove(s)
6516 status.removed.remove(s)
6520 renamed.append(d)
6517 renamed.append(d)
6521 else:
6518 else:
6522 copied.append(d)
6519 copied.append(d)
6523 if d in status.added:
6520 if d in status.added:
6524 status.added.remove(d)
6521 status.added.remove(d)
6525
6522
6526 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6523 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6527
6524
6528 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6525 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6529 (ui.label(_('%d added'), 'status.added'), status.added),
6526 (ui.label(_('%d added'), 'status.added'), status.added),
6530 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6527 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6531 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6528 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6532 (ui.label(_('%d copied'), 'status.copied'), copied),
6529 (ui.label(_('%d copied'), 'status.copied'), copied),
6533 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6530 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6534 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6531 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6535 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6532 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6536 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6533 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6537 t = []
6534 t = []
6538 for l, s in labels:
6535 for l, s in labels:
6539 if s:
6536 if s:
6540 t.append(l % len(s))
6537 t.append(l % len(s))
6541
6538
6542 t = ', '.join(t)
6539 t = ', '.join(t)
6543 cleanworkdir = False
6540 cleanworkdir = False
6544
6541
6545 if repo.vfs.exists('graftstate'):
6542 if repo.vfs.exists('graftstate'):
6546 t += _(' (graft in progress)')
6543 t += _(' (graft in progress)')
6547 if repo.vfs.exists('updatestate'):
6544 if repo.vfs.exists('updatestate'):
6548 t += _(' (interrupted update)')
6545 t += _(' (interrupted update)')
6549 elif len(parents) > 1:
6546 elif len(parents) > 1:
6550 t += _(' (merge)')
6547 t += _(' (merge)')
6551 elif branch != parents[0].branch():
6548 elif branch != parents[0].branch():
6552 t += _(' (new branch)')
6549 t += _(' (new branch)')
6553 elif (parents[0].closesbranch() and
6550 elif (parents[0].closesbranch() and
6554 pnode in repo.branchheads(branch, closed=True)):
6551 pnode in repo.branchheads(branch, closed=True)):
6555 t += _(' (head closed)')
6552 t += _(' (head closed)')
6556 elif not (status.modified or status.added or status.removed or renamed or
6553 elif not (status.modified or status.added or status.removed or renamed or
6557 copied or subs):
6554 copied or subs):
6558 t += _(' (clean)')
6555 t += _(' (clean)')
6559 cleanworkdir = True
6556 cleanworkdir = True
6560 elif pnode not in bheads:
6557 elif pnode not in bheads:
6561 t += _(' (new branch head)')
6558 t += _(' (new branch head)')
6562
6559
6563 if parents:
6560 if parents:
6564 pendingphase = max(p.phase() for p in parents)
6561 pendingphase = max(p.phase() for p in parents)
6565 else:
6562 else:
6566 pendingphase = phases.public
6563 pendingphase = phases.public
6567
6564
6568 if pendingphase > phases.newcommitphase(ui):
6565 if pendingphase > phases.newcommitphase(ui):
6569 t += ' (%s)' % phases.phasenames[pendingphase]
6566 t += ' (%s)' % phases.phasenames[pendingphase]
6570
6567
6571 if cleanworkdir:
6568 if cleanworkdir:
6572 # i18n: column positioning for "hg summary"
6569 # i18n: column positioning for "hg summary"
6573 ui.status(_('commit: %s\n') % t.strip())
6570 ui.status(_('commit: %s\n') % t.strip())
6574 else:
6571 else:
6575 # i18n: column positioning for "hg summary"
6572 # i18n: column positioning for "hg summary"
6576 ui.write(_('commit: %s\n') % t.strip())
6573 ui.write(_('commit: %s\n') % t.strip())
6577
6574
6578 # all ancestors of branch heads - all ancestors of parent = new csets
6575 # all ancestors of branch heads - all ancestors of parent = new csets
6579 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6576 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6580 bheads))
6577 bheads))
6581
6578
6582 if new == 0:
6579 if new == 0:
6583 # i18n: column positioning for "hg summary"
6580 # i18n: column positioning for "hg summary"
6584 ui.status(_('update: (current)\n'))
6581 ui.status(_('update: (current)\n'))
6585 elif pnode not in bheads:
6582 elif pnode not in bheads:
6586 # i18n: column positioning for "hg summary"
6583 # i18n: column positioning for "hg summary"
6587 ui.write(_('update: %d new changesets (update)\n') % new)
6584 ui.write(_('update: %d new changesets (update)\n') % new)
6588 else:
6585 else:
6589 # i18n: column positioning for "hg summary"
6586 # i18n: column positioning for "hg summary"
6590 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6587 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6591 (new, len(bheads)))
6588 (new, len(bheads)))
6592
6589
6593 t = []
6590 t = []
6594 draft = len(repo.revs('draft()'))
6591 draft = len(repo.revs('draft()'))
6595 if draft:
6592 if draft:
6596 t.append(_('%d draft') % draft)
6593 t.append(_('%d draft') % draft)
6597 secret = len(repo.revs('secret()'))
6594 secret = len(repo.revs('secret()'))
6598 if secret:
6595 if secret:
6599 t.append(_('%d secret') % secret)
6596 t.append(_('%d secret') % secret)
6600
6597
6601 if draft or secret:
6598 if draft or secret:
6602 ui.status(_('phases: %s\n') % ', '.join(t))
6599 ui.status(_('phases: %s\n') % ', '.join(t))
6603
6600
6604 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6601 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6605 for trouble in ("unstable", "divergent", "bumped"):
6602 for trouble in ("unstable", "divergent", "bumped"):
6606 numtrouble = len(repo.revs(trouble + "()"))
6603 numtrouble = len(repo.revs(trouble + "()"))
6607 # We write all the possibilities to ease translation
6604 # We write all the possibilities to ease translation
6608 troublemsg = {
6605 troublemsg = {
6609 "unstable": _("unstable: %d changesets"),
6606 "unstable": _("unstable: %d changesets"),
6610 "divergent": _("divergent: %d changesets"),
6607 "divergent": _("divergent: %d changesets"),
6611 "bumped": _("bumped: %d changesets"),
6608 "bumped": _("bumped: %d changesets"),
6612 }
6609 }
6613 if numtrouble > 0:
6610 if numtrouble > 0:
6614 ui.status(troublemsg[trouble] % numtrouble + "\n")
6611 ui.status(troublemsg[trouble] % numtrouble + "\n")
6615
6612
6616 cmdutil.summaryhooks(ui, repo)
6613 cmdutil.summaryhooks(ui, repo)
6617
6614
6618 if opts.get('remote'):
6615 if opts.get('remote'):
6619 needsincoming, needsoutgoing = True, True
6616 needsincoming, needsoutgoing = True, True
6620 else:
6617 else:
6621 needsincoming, needsoutgoing = False, False
6618 needsincoming, needsoutgoing = False, False
6622 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6619 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6623 if i:
6620 if i:
6624 needsincoming = True
6621 needsincoming = True
6625 if o:
6622 if o:
6626 needsoutgoing = True
6623 needsoutgoing = True
6627 if not needsincoming and not needsoutgoing:
6624 if not needsincoming and not needsoutgoing:
6628 return
6625 return
6629
6626
6630 def getincoming():
6627 def getincoming():
6631 source, branches = hg.parseurl(ui.expandpath('default'))
6628 source, branches = hg.parseurl(ui.expandpath('default'))
6632 sbranch = branches[0]
6629 sbranch = branches[0]
6633 try:
6630 try:
6634 other = hg.peer(repo, {}, source)
6631 other = hg.peer(repo, {}, source)
6635 except error.RepoError:
6632 except error.RepoError:
6636 if opts.get('remote'):
6633 if opts.get('remote'):
6637 raise
6634 raise
6638 return source, sbranch, None, None, None
6635 return source, sbranch, None, None, None
6639 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6636 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6640 if revs:
6637 if revs:
6641 revs = [other.lookup(rev) for rev in revs]
6638 revs = [other.lookup(rev) for rev in revs]
6642 ui.debug('comparing with %s\n' % util.hidepassword(source))
6639 ui.debug('comparing with %s\n' % util.hidepassword(source))
6643 repo.ui.pushbuffer()
6640 repo.ui.pushbuffer()
6644 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6641 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6645 repo.ui.popbuffer()
6642 repo.ui.popbuffer()
6646 return source, sbranch, other, commoninc, commoninc[1]
6643 return source, sbranch, other, commoninc, commoninc[1]
6647
6644
6648 if needsincoming:
6645 if needsincoming:
6649 source, sbranch, sother, commoninc, incoming = getincoming()
6646 source, sbranch, sother, commoninc, incoming = getincoming()
6650 else:
6647 else:
6651 source = sbranch = sother = commoninc = incoming = None
6648 source = sbranch = sother = commoninc = incoming = None
6652
6649
6653 def getoutgoing():
6650 def getoutgoing():
6654 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6651 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6655 dbranch = branches[0]
6652 dbranch = branches[0]
6656 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6653 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6657 if source != dest:
6654 if source != dest:
6658 try:
6655 try:
6659 dother = hg.peer(repo, {}, dest)
6656 dother = hg.peer(repo, {}, dest)
6660 except error.RepoError:
6657 except error.RepoError:
6661 if opts.get('remote'):
6658 if opts.get('remote'):
6662 raise
6659 raise
6663 return dest, dbranch, None, None
6660 return dest, dbranch, None, None
6664 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6661 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6665 elif sother is None:
6662 elif sother is None:
6666 # there is no explicit destination peer, but source one is invalid
6663 # there is no explicit destination peer, but source one is invalid
6667 return dest, dbranch, None, None
6664 return dest, dbranch, None, None
6668 else:
6665 else:
6669 dother = sother
6666 dother = sother
6670 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6667 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6671 common = None
6668 common = None
6672 else:
6669 else:
6673 common = commoninc
6670 common = commoninc
6674 if revs:
6671 if revs:
6675 revs = [repo.lookup(rev) for rev in revs]
6672 revs = [repo.lookup(rev) for rev in revs]
6676 repo.ui.pushbuffer()
6673 repo.ui.pushbuffer()
6677 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6674 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6678 commoninc=common)
6675 commoninc=common)
6679 repo.ui.popbuffer()
6676 repo.ui.popbuffer()
6680 return dest, dbranch, dother, outgoing
6677 return dest, dbranch, dother, outgoing
6681
6678
6682 if needsoutgoing:
6679 if needsoutgoing:
6683 dest, dbranch, dother, outgoing = getoutgoing()
6680 dest, dbranch, dother, outgoing = getoutgoing()
6684 else:
6681 else:
6685 dest = dbranch = dother = outgoing = None
6682 dest = dbranch = dother = outgoing = None
6686
6683
6687 if opts.get('remote'):
6684 if opts.get('remote'):
6688 t = []
6685 t = []
6689 if incoming:
6686 if incoming:
6690 t.append(_('1 or more incoming'))
6687 t.append(_('1 or more incoming'))
6691 o = outgoing.missing
6688 o = outgoing.missing
6692 if o:
6689 if o:
6693 t.append(_('%d outgoing') % len(o))
6690 t.append(_('%d outgoing') % len(o))
6694 other = dother or sother
6691 other = dother or sother
6695 if 'bookmarks' in other.listkeys('namespaces'):
6692 if 'bookmarks' in other.listkeys('namespaces'):
6696 counts = bookmarks.summary(repo, other)
6693 counts = bookmarks.summary(repo, other)
6697 if counts[0] > 0:
6694 if counts[0] > 0:
6698 t.append(_('%d incoming bookmarks') % counts[0])
6695 t.append(_('%d incoming bookmarks') % counts[0])
6699 if counts[1] > 0:
6696 if counts[1] > 0:
6700 t.append(_('%d outgoing bookmarks') % counts[1])
6697 t.append(_('%d outgoing bookmarks') % counts[1])
6701
6698
6702 if t:
6699 if t:
6703 # i18n: column positioning for "hg summary"
6700 # i18n: column positioning for "hg summary"
6704 ui.write(_('remote: %s\n') % (', '.join(t)))
6701 ui.write(_('remote: %s\n') % (', '.join(t)))
6705 else:
6702 else:
6706 # i18n: column positioning for "hg summary"
6703 # i18n: column positioning for "hg summary"
6707 ui.status(_('remote: (synced)\n'))
6704 ui.status(_('remote: (synced)\n'))
6708
6705
6709 cmdutil.summaryremotehooks(ui, repo, opts,
6706 cmdutil.summaryremotehooks(ui, repo, opts,
6710 ((source, sbranch, sother, commoninc),
6707 ((source, sbranch, sother, commoninc),
6711 (dest, dbranch, dother, outgoing)))
6708 (dest, dbranch, dother, outgoing)))
6712
6709
6713 @command('tag',
6710 @command('tag',
6714 [('f', 'force', None, _('force tag')),
6711 [('f', 'force', None, _('force tag')),
6715 ('l', 'local', None, _('make the tag local')),
6712 ('l', 'local', None, _('make the tag local')),
6716 ('r', 'rev', '', _('revision to tag'), _('REV')),
6713 ('r', 'rev', '', _('revision to tag'), _('REV')),
6717 ('', 'remove', None, _('remove a tag')),
6714 ('', 'remove', None, _('remove a tag')),
6718 # -l/--local is already there, commitopts cannot be used
6715 # -l/--local is already there, commitopts cannot be used
6719 ('e', 'edit', None, _('invoke editor on commit messages')),
6716 ('e', 'edit', None, _('invoke editor on commit messages')),
6720 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6717 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6721 ] + commitopts2,
6718 ] + commitopts2,
6722 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6719 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6723 def tag(ui, repo, name1, *names, **opts):
6720 def tag(ui, repo, name1, *names, **opts):
6724 """add one or more tags for the current or given revision
6721 """add one or more tags for the current or given revision
6725
6722
6726 Name a particular revision using <name>.
6723 Name a particular revision using <name>.
6727
6724
6728 Tags are used to name particular revisions of the repository and are
6725 Tags are used to name particular revisions of the repository and are
6729 very useful to compare different revisions, to go back to significant
6726 very useful to compare different revisions, to go back to significant
6730 earlier versions or to mark branch points as releases, etc. Changing
6727 earlier versions or to mark branch points as releases, etc. Changing
6731 an existing tag is normally disallowed; use -f/--force to override.
6728 an existing tag is normally disallowed; use -f/--force to override.
6732
6729
6733 If no revision is given, the parent of the working directory is
6730 If no revision is given, the parent of the working directory is
6734 used.
6731 used.
6735
6732
6736 To facilitate version control, distribution, and merging of tags,
6733 To facilitate version control, distribution, and merging of tags,
6737 they are stored as a file named ".hgtags" which is managed similarly
6734 they are stored as a file named ".hgtags" which is managed similarly
6738 to other project files and can be hand-edited if necessary. This
6735 to other project files and can be hand-edited if necessary. This
6739 also means that tagging creates a new commit. The file
6736 also means that tagging creates a new commit. The file
6740 ".hg/localtags" is used for local tags (not shared among
6737 ".hg/localtags" is used for local tags (not shared among
6741 repositories).
6738 repositories).
6742
6739
6743 Tag commits are usually made at the head of a branch. If the parent
6740 Tag commits are usually made at the head of a branch. If the parent
6744 of the working directory is not a branch head, :hg:`tag` aborts; use
6741 of the working directory is not a branch head, :hg:`tag` aborts; use
6745 -f/--force to force the tag commit to be based on a non-head
6742 -f/--force to force the tag commit to be based on a non-head
6746 changeset.
6743 changeset.
6747
6744
6748 See :hg:`help dates` for a list of formats valid for -d/--date.
6745 See :hg:`help dates` for a list of formats valid for -d/--date.
6749
6746
6750 Since tag names have priority over branch names during revision
6747 Since tag names have priority over branch names during revision
6751 lookup, using an existing branch name as a tag name is discouraged.
6748 lookup, using an existing branch name as a tag name is discouraged.
6752
6749
6753 Returns 0 on success.
6750 Returns 0 on success.
6754 """
6751 """
6755 wlock = lock = None
6752 wlock = lock = None
6756 try:
6753 try:
6757 wlock = repo.wlock()
6754 wlock = repo.wlock()
6758 lock = repo.lock()
6755 lock = repo.lock()
6759 rev_ = "."
6756 rev_ = "."
6760 names = [t.strip() for t in (name1,) + names]
6757 names = [t.strip() for t in (name1,) + names]
6761 if len(names) != len(set(names)):
6758 if len(names) != len(set(names)):
6762 raise error.Abort(_('tag names must be unique'))
6759 raise error.Abort(_('tag names must be unique'))
6763 for n in names:
6760 for n in names:
6764 scmutil.checknewlabel(repo, n, 'tag')
6761 scmutil.checknewlabel(repo, n, 'tag')
6765 if not n:
6762 if not n:
6766 raise error.Abort(_('tag names cannot consist entirely of '
6763 raise error.Abort(_('tag names cannot consist entirely of '
6767 'whitespace'))
6764 'whitespace'))
6768 if opts.get('rev') and opts.get('remove'):
6765 if opts.get('rev') and opts.get('remove'):
6769 raise error.Abort(_("--rev and --remove are incompatible"))
6766 raise error.Abort(_("--rev and --remove are incompatible"))
6770 if opts.get('rev'):
6767 if opts.get('rev'):
6771 rev_ = opts['rev']
6768 rev_ = opts['rev']
6772 message = opts.get('message')
6769 message = opts.get('message')
6773 if opts.get('remove'):
6770 if opts.get('remove'):
6774 if opts.get('local'):
6771 if opts.get('local'):
6775 expectedtype = 'local'
6772 expectedtype = 'local'
6776 else:
6773 else:
6777 expectedtype = 'global'
6774 expectedtype = 'global'
6778
6775
6779 for n in names:
6776 for n in names:
6780 if not repo.tagtype(n):
6777 if not repo.tagtype(n):
6781 raise error.Abort(_("tag '%s' does not exist") % n)
6778 raise error.Abort(_("tag '%s' does not exist") % n)
6782 if repo.tagtype(n) != expectedtype:
6779 if repo.tagtype(n) != expectedtype:
6783 if expectedtype == 'global':
6780 if expectedtype == 'global':
6784 raise error.Abort(_("tag '%s' is not a global tag") % n)
6781 raise error.Abort(_("tag '%s' is not a global tag") % n)
6785 else:
6782 else:
6786 raise error.Abort(_("tag '%s' is not a local tag") % n)
6783 raise error.Abort(_("tag '%s' is not a local tag") % n)
6787 rev_ = 'null'
6784 rev_ = 'null'
6788 if not message:
6785 if not message:
6789 # we don't translate commit messages
6786 # we don't translate commit messages
6790 message = 'Removed tag %s' % ', '.join(names)
6787 message = 'Removed tag %s' % ', '.join(names)
6791 elif not opts.get('force'):
6788 elif not opts.get('force'):
6792 for n in names:
6789 for n in names:
6793 if n in repo.tags():
6790 if n in repo.tags():
6794 raise error.Abort(_("tag '%s' already exists "
6791 raise error.Abort(_("tag '%s' already exists "
6795 "(use -f to force)") % n)
6792 "(use -f to force)") % n)
6796 if not opts.get('local'):
6793 if not opts.get('local'):
6797 p1, p2 = repo.dirstate.parents()
6794 p1, p2 = repo.dirstate.parents()
6798 if p2 != nullid:
6795 if p2 != nullid:
6799 raise error.Abort(_('uncommitted merge'))
6796 raise error.Abort(_('uncommitted merge'))
6800 bheads = repo.branchheads()
6797 bheads = repo.branchheads()
6801 if not opts.get('force') and bheads and p1 not in bheads:
6798 if not opts.get('force') and bheads and p1 not in bheads:
6802 raise error.Abort(_('working directory is not at a branch head '
6799 raise error.Abort(_('working directory is not at a branch head '
6803 '(use -f to force)'))
6800 '(use -f to force)'))
6804 r = scmutil.revsingle(repo, rev_).node()
6801 r = scmutil.revsingle(repo, rev_).node()
6805
6802
6806 if not message:
6803 if not message:
6807 # we don't translate commit messages
6804 # we don't translate commit messages
6808 message = ('Added tag %s for changeset %s' %
6805 message = ('Added tag %s for changeset %s' %
6809 (', '.join(names), short(r)))
6806 (', '.join(names), short(r)))
6810
6807
6811 date = opts.get('date')
6808 date = opts.get('date')
6812 if date:
6809 if date:
6813 date = util.parsedate(date)
6810 date = util.parsedate(date)
6814
6811
6815 if opts.get('remove'):
6812 if opts.get('remove'):
6816 editform = 'tag.remove'
6813 editform = 'tag.remove'
6817 else:
6814 else:
6818 editform = 'tag.add'
6815 editform = 'tag.add'
6819 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6816 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6820
6817
6821 # don't allow tagging the null rev
6818 # don't allow tagging the null rev
6822 if (not opts.get('remove') and
6819 if (not opts.get('remove') and
6823 scmutil.revsingle(repo, rev_).rev() == nullrev):
6820 scmutil.revsingle(repo, rev_).rev() == nullrev):
6824 raise error.Abort(_("cannot tag null revision"))
6821 raise error.Abort(_("cannot tag null revision"))
6825
6822
6826 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6823 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6827 editor=editor)
6824 editor=editor)
6828 finally:
6825 finally:
6829 release(lock, wlock)
6826 release(lock, wlock)
6830
6827
6831 @command('tags', formatteropts, '')
6828 @command('tags', formatteropts, '')
6832 def tags(ui, repo, **opts):
6829 def tags(ui, repo, **opts):
6833 """list repository tags
6830 """list repository tags
6834
6831
6835 This lists both regular and local tags. When the -v/--verbose
6832 This lists both regular and local tags. When the -v/--verbose
6836 switch is used, a third column "local" is printed for local tags.
6833 switch is used, a third column "local" is printed for local tags.
6837 When the -q/--quiet switch is used, only the tag name is printed.
6834 When the -q/--quiet switch is used, only the tag name is printed.
6838
6835
6839 Returns 0 on success.
6836 Returns 0 on success.
6840 """
6837 """
6841
6838
6842 fm = ui.formatter('tags', opts)
6839 fm = ui.formatter('tags', opts)
6843 hexfunc = fm.hexfunc
6840 hexfunc = fm.hexfunc
6844 tagtype = ""
6841 tagtype = ""
6845
6842
6846 for t, n in reversed(repo.tagslist()):
6843 for t, n in reversed(repo.tagslist()):
6847 hn = hexfunc(n)
6844 hn = hexfunc(n)
6848 label = 'tags.normal'
6845 label = 'tags.normal'
6849 tagtype = ''
6846 tagtype = ''
6850 if repo.tagtype(t) == 'local':
6847 if repo.tagtype(t) == 'local':
6851 label = 'tags.local'
6848 label = 'tags.local'
6852 tagtype = 'local'
6849 tagtype = 'local'
6853
6850
6854 fm.startitem()
6851 fm.startitem()
6855 fm.write('tag', '%s', t, label=label)
6852 fm.write('tag', '%s', t, label=label)
6856 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6853 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6857 fm.condwrite(not ui.quiet, 'rev node', fmt,
6854 fm.condwrite(not ui.quiet, 'rev node', fmt,
6858 repo.changelog.rev(n), hn, label=label)
6855 repo.changelog.rev(n), hn, label=label)
6859 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6856 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6860 tagtype, label=label)
6857 tagtype, label=label)
6861 fm.plain('\n')
6858 fm.plain('\n')
6862 fm.end()
6859 fm.end()
6863
6860
6864 @command('tip',
6861 @command('tip',
6865 [('p', 'patch', None, _('show patch')),
6862 [('p', 'patch', None, _('show patch')),
6866 ('g', 'git', None, _('use git extended diff format')),
6863 ('g', 'git', None, _('use git extended diff format')),
6867 ] + templateopts,
6864 ] + templateopts,
6868 _('[-p] [-g]'))
6865 _('[-p] [-g]'))
6869 def tip(ui, repo, **opts):
6866 def tip(ui, repo, **opts):
6870 """show the tip revision (DEPRECATED)
6867 """show the tip revision (DEPRECATED)
6871
6868
6872 The tip revision (usually just called the tip) is the changeset
6869 The tip revision (usually just called the tip) is the changeset
6873 most recently added to the repository (and therefore the most
6870 most recently added to the repository (and therefore the most
6874 recently changed head).
6871 recently changed head).
6875
6872
6876 If you have just made a commit, that commit will be the tip. If
6873 If you have just made a commit, that commit will be the tip. If
6877 you have just pulled changes from another repository, the tip of
6874 you have just pulled changes from another repository, the tip of
6878 that repository becomes the current tip. The "tip" tag is special
6875 that repository becomes the current tip. The "tip" tag is special
6879 and cannot be renamed or assigned to a different changeset.
6876 and cannot be renamed or assigned to a different changeset.
6880
6877
6881 This command is deprecated, please use :hg:`heads` instead.
6878 This command is deprecated, please use :hg:`heads` instead.
6882
6879
6883 Returns 0 on success.
6880 Returns 0 on success.
6884 """
6881 """
6885 displayer = cmdutil.show_changeset(ui, repo, opts)
6882 displayer = cmdutil.show_changeset(ui, repo, opts)
6886 displayer.show(repo['tip'])
6883 displayer.show(repo['tip'])
6887 displayer.close()
6884 displayer.close()
6888
6885
6889 @command('unbundle',
6886 @command('unbundle',
6890 [('u', 'update', None,
6887 [('u', 'update', None,
6891 _('update to new branch head if changesets were unbundled'))],
6888 _('update to new branch head if changesets were unbundled'))],
6892 _('[-u] FILE...'))
6889 _('[-u] FILE...'))
6893 def unbundle(ui, repo, fname1, *fnames, **opts):
6890 def unbundle(ui, repo, fname1, *fnames, **opts):
6894 """apply one or more changegroup files
6891 """apply one or more changegroup files
6895
6892
6896 Apply one or more compressed changegroup files generated by the
6893 Apply one or more compressed changegroup files generated by the
6897 bundle command.
6894 bundle command.
6898
6895
6899 Returns 0 on success, 1 if an update has unresolved files.
6896 Returns 0 on success, 1 if an update has unresolved files.
6900 """
6897 """
6901 fnames = (fname1,) + fnames
6898 fnames = (fname1,) + fnames
6902
6899
6903 with repo.lock():
6900 with repo.lock():
6904 for fname in fnames:
6901 for fname in fnames:
6905 f = hg.openpath(ui, fname)
6902 f = hg.openpath(ui, fname)
6906 gen = exchange.readbundle(ui, f, fname)
6903 gen = exchange.readbundle(ui, f, fname)
6907 if isinstance(gen, bundle2.unbundle20):
6904 if isinstance(gen, bundle2.unbundle20):
6908 tr = repo.transaction('unbundle')
6905 tr = repo.transaction('unbundle')
6909 try:
6906 try:
6910 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6907 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6911 url='bundle:' + fname)
6908 url='bundle:' + fname)
6912 tr.close()
6909 tr.close()
6913 except error.BundleUnknownFeatureError as exc:
6910 except error.BundleUnknownFeatureError as exc:
6914 raise error.Abort(_('%s: unknown bundle feature, %s')
6911 raise error.Abort(_('%s: unknown bundle feature, %s')
6915 % (fname, exc),
6912 % (fname, exc),
6916 hint=_("see https://mercurial-scm.org/"
6913 hint=_("see https://mercurial-scm.org/"
6917 "wiki/BundleFeature for more "
6914 "wiki/BundleFeature for more "
6918 "information"))
6915 "information"))
6919 finally:
6916 finally:
6920 if tr:
6917 if tr:
6921 tr.release()
6918 tr.release()
6922 changes = [r.get('return', 0)
6919 changes = [r.get('return', 0)
6923 for r in op.records['changegroup']]
6920 for r in op.records['changegroup']]
6924 modheads = changegroup.combineresults(changes)
6921 modheads = changegroup.combineresults(changes)
6925 elif isinstance(gen, streamclone.streamcloneapplier):
6922 elif isinstance(gen, streamclone.streamcloneapplier):
6926 raise error.Abort(
6923 raise error.Abort(
6927 _('packed bundles cannot be applied with '
6924 _('packed bundles cannot be applied with '
6928 '"hg unbundle"'),
6925 '"hg unbundle"'),
6929 hint=_('use "hg debugapplystreamclonebundle"'))
6926 hint=_('use "hg debugapplystreamclonebundle"'))
6930 else:
6927 else:
6931 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6928 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6932
6929
6933 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
6930 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
6934
6931
6935 @command('^update|up|checkout|co',
6932 @command('^update|up|checkout|co',
6936 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6933 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6937 ('c', 'check', None, _('require clean working directory')),
6934 ('c', 'check', None, _('require clean working directory')),
6938 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6935 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6939 ('r', 'rev', '', _('revision'), _('REV'))
6936 ('r', 'rev', '', _('revision'), _('REV'))
6940 ] + mergetoolopts,
6937 ] + mergetoolopts,
6941 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6938 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6942 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6939 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6943 tool=None):
6940 tool=None):
6944 """update working directory (or switch revisions)
6941 """update working directory (or switch revisions)
6945
6942
6946 Update the repository's working directory to the specified
6943 Update the repository's working directory to the specified
6947 changeset. If no changeset is specified, update to the tip of the
6944 changeset. If no changeset is specified, update to the tip of the
6948 current named branch and move the active bookmark (see :hg:`help
6945 current named branch and move the active bookmark (see :hg:`help
6949 bookmarks`).
6946 bookmarks`).
6950
6947
6951 Update sets the working directory's parent revision to the specified
6948 Update sets the working directory's parent revision to the specified
6952 changeset (see :hg:`help parents`).
6949 changeset (see :hg:`help parents`).
6953
6950
6954 If the changeset is not a descendant or ancestor of the working
6951 If the changeset is not a descendant or ancestor of the working
6955 directory's parent, the update is aborted. With the -c/--check
6952 directory's parent, the update is aborted. With the -c/--check
6956 option, the working directory is checked for uncommitted changes; if
6953 option, the working directory is checked for uncommitted changes; if
6957 none are found, the working directory is updated to the specified
6954 none are found, the working directory is updated to the specified
6958 changeset.
6955 changeset.
6959
6956
6960 .. container:: verbose
6957 .. container:: verbose
6961
6958
6962 The following rules apply when the working directory contains
6959 The following rules apply when the working directory contains
6963 uncommitted changes:
6960 uncommitted changes:
6964
6961
6965 1. If neither -c/--check nor -C/--clean is specified, and if
6962 1. If neither -c/--check nor -C/--clean is specified, and if
6966 the requested changeset is an ancestor or descendant of
6963 the requested changeset is an ancestor or descendant of
6967 the working directory's parent, the uncommitted changes
6964 the working directory's parent, the uncommitted changes
6968 are merged into the requested changeset and the merged
6965 are merged into the requested changeset and the merged
6969 result is left uncommitted. If the requested changeset is
6966 result is left uncommitted. If the requested changeset is
6970 not an ancestor or descendant (that is, it is on another
6967 not an ancestor or descendant (that is, it is on another
6971 branch), the update is aborted and the uncommitted changes
6968 branch), the update is aborted and the uncommitted changes
6972 are preserved.
6969 are preserved.
6973
6970
6974 2. With the -c/--check option, the update is aborted and the
6971 2. With the -c/--check option, the update is aborted and the
6975 uncommitted changes are preserved.
6972 uncommitted changes are preserved.
6976
6973
6977 3. With the -C/--clean option, uncommitted changes are discarded and
6974 3. With the -C/--clean option, uncommitted changes are discarded and
6978 the working directory is updated to the requested changeset.
6975 the working directory is updated to the requested changeset.
6979
6976
6980 To cancel an uncommitted merge (and lose your changes), use
6977 To cancel an uncommitted merge (and lose your changes), use
6981 :hg:`update --clean .`.
6978 :hg:`update --clean .`.
6982
6979
6983 Use null as the changeset to remove the working directory (like
6980 Use null as the changeset to remove the working directory (like
6984 :hg:`clone -U`).
6981 :hg:`clone -U`).
6985
6982
6986 If you want to revert just one file to an older revision, use
6983 If you want to revert just one file to an older revision, use
6987 :hg:`revert [-r REV] NAME`.
6984 :hg:`revert [-r REV] NAME`.
6988
6985
6989 See :hg:`help dates` for a list of formats valid for -d/--date.
6986 See :hg:`help dates` for a list of formats valid for -d/--date.
6990
6987
6991 Returns 0 on success, 1 if there are unresolved files.
6988 Returns 0 on success, 1 if there are unresolved files.
6992 """
6989 """
6993 if rev and node:
6990 if rev and node:
6994 raise error.Abort(_("please specify just one revision"))
6991 raise error.Abort(_("please specify just one revision"))
6995
6992
6996 if rev is None or rev == '':
6993 if rev is None or rev == '':
6997 rev = node
6994 rev = node
6998
6995
6999 if date and rev is not None:
6996 if date and rev is not None:
7000 raise error.Abort(_("you can't specify a revision and a date"))
6997 raise error.Abort(_("you can't specify a revision and a date"))
7001
6998
7002 if check and clean:
6999 if check and clean:
7003 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7000 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7004
7001
7005 with repo.wlock():
7002 with repo.wlock():
7006 cmdutil.clearunfinished(repo)
7003 cmdutil.clearunfinished(repo)
7007
7004
7008 if date:
7005 if date:
7009 rev = cmdutil.finddate(ui, repo, date)
7006 rev = cmdutil.finddate(ui, repo, date)
7010
7007
7011 # if we defined a bookmark, we have to remember the original name
7008 # if we defined a bookmark, we have to remember the original name
7012 brev = rev
7009 brev = rev
7013 rev = scmutil.revsingle(repo, rev, rev).rev()
7010 rev = scmutil.revsingle(repo, rev, rev).rev()
7014
7011
7015 if check:
7012 if check:
7016 cmdutil.bailifchanged(repo, merge=False)
7013 cmdutil.bailifchanged(repo, merge=False)
7017
7014
7018 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7015 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7019
7016
7020 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7017 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7021
7018
7022 @command('verify', [])
7019 @command('verify', [])
7023 def verify(ui, repo):
7020 def verify(ui, repo):
7024 """verify the integrity of the repository
7021 """verify the integrity of the repository
7025
7022
7026 Verify the integrity of the current repository.
7023 Verify the integrity of the current repository.
7027
7024
7028 This will perform an extensive check of the repository's
7025 This will perform an extensive check of the repository's
7029 integrity, validating the hashes and checksums of each entry in
7026 integrity, validating the hashes and checksums of each entry in
7030 the changelog, manifest, and tracked files, as well as the
7027 the changelog, manifest, and tracked files, as well as the
7031 integrity of their crosslinks and indices.
7028 integrity of their crosslinks and indices.
7032
7029
7033 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7030 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7034 for more information about recovery from corruption of the
7031 for more information about recovery from corruption of the
7035 repository.
7032 repository.
7036
7033
7037 Returns 0 on success, 1 if errors are encountered.
7034 Returns 0 on success, 1 if errors are encountered.
7038 """
7035 """
7039 return hg.verify(repo)
7036 return hg.verify(repo)
7040
7037
7041 @command('version', [] + formatteropts, norepo=True)
7038 @command('version', [] + formatteropts, norepo=True)
7042 def version_(ui, **opts):
7039 def version_(ui, **opts):
7043 """output version and copyright information"""
7040 """output version and copyright information"""
7044 fm = ui.formatter("version", opts)
7041 fm = ui.formatter("version", opts)
7045 fm.startitem()
7042 fm.startitem()
7046 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7043 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7047 util.version())
7044 util.version())
7048 license = _(
7045 license = _(
7049 "(see https://mercurial-scm.org for more information)\n"
7046 "(see https://mercurial-scm.org for more information)\n"
7050 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7047 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7051 "This is free software; see the source for copying conditions. "
7048 "This is free software; see the source for copying conditions. "
7052 "There is NO\nwarranty; "
7049 "There is NO\nwarranty; "
7053 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7050 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7054 )
7051 )
7055 if not ui.quiet:
7052 if not ui.quiet:
7056 fm.plain(license)
7053 fm.plain(license)
7057
7054
7058 if ui.verbose:
7055 if ui.verbose:
7059 fm.plain(_("\nEnabled extensions:\n\n"))
7056 fm.plain(_("\nEnabled extensions:\n\n"))
7060 # format names and versions into columns
7057 # format names and versions into columns
7061 names = []
7058 names = []
7062 vers = []
7059 vers = []
7063 isinternals = []
7060 isinternals = []
7064 for name, module in extensions.extensions():
7061 for name, module in extensions.extensions():
7065 names.append(name)
7062 names.append(name)
7066 vers.append(extensions.moduleversion(module) or None)
7063 vers.append(extensions.moduleversion(module) or None)
7067 isinternals.append(extensions.ismoduleinternal(module))
7064 isinternals.append(extensions.ismoduleinternal(module))
7068 fn = fm.nested("extensions")
7065 fn = fm.nested("extensions")
7069 if names:
7066 if names:
7070 namefmt = " %%-%ds " % max(len(n) for n in names)
7067 namefmt = " %%-%ds " % max(len(n) for n in names)
7071 places = [_("external"), _("internal")]
7068 places = [_("external"), _("internal")]
7072 for n, v, p in zip(names, vers, isinternals):
7069 for n, v, p in zip(names, vers, isinternals):
7073 fn.startitem()
7070 fn.startitem()
7074 fn.condwrite(ui.verbose, "name", namefmt, n)
7071 fn.condwrite(ui.verbose, "name", namefmt, n)
7075 if ui.verbose:
7072 if ui.verbose:
7076 fn.plain("%s " % places[p])
7073 fn.plain("%s " % places[p])
7077 fn.data(bundled=p)
7074 fn.data(bundled=p)
7078 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7075 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7079 if ui.verbose:
7076 if ui.verbose:
7080 fn.plain("\n")
7077 fn.plain("\n")
7081 fn.end()
7078 fn.end()
7082 fm.end()
7079 fm.end()
7083
7080
7084 def loadcmdtable(ui, name, cmdtable):
7081 def loadcmdtable(ui, name, cmdtable):
7085 """Load command functions from specified cmdtable
7082 """Load command functions from specified cmdtable
7086 """
7083 """
7087 overrides = [cmd for cmd in cmdtable if cmd in table]
7084 overrides = [cmd for cmd in cmdtable if cmd in table]
7088 if overrides:
7085 if overrides:
7089 ui.warn(_("extension '%s' overrides commands: %s\n")
7086 ui.warn(_("extension '%s' overrides commands: %s\n")
7090 % (name, " ".join(overrides)))
7087 % (name, " ".join(overrides)))
7091 table.update(cmdtable)
7088 table.update(cmdtable)
@@ -1,154 +1,160 b''
1 # server.py - utility and factory of server
1 # server.py - utility and factory of server
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 errno
10 import errno
11 import os
11 import os
12 import sys
12 import sys
13 import tempfile
13 import tempfile
14
14
15 from .i18n import _
15 from .i18n import _
16
16
17 from . import (
17 from . import (
18 commandserver,
18 commandserver,
19 error,
19 error,
20 hgweb,
20 hgweb,
21 util,
21 util,
22 )
22 )
23
23
24 def runservice(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
24 def runservice(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
25 runargs=None, appendpid=False):
25 runargs=None, appendpid=False):
26 '''Run a command as a service.'''
26 '''Run a command as a service.'''
27
27
28 def writepid(pid):
28 def writepid(pid):
29 if opts['pid_file']:
29 if opts['pid_file']:
30 if appendpid:
30 if appendpid:
31 mode = 'a'
31 mode = 'a'
32 else:
32 else:
33 mode = 'w'
33 mode = 'w'
34 fp = open(opts['pid_file'], mode)
34 fp = open(opts['pid_file'], mode)
35 fp.write(str(pid) + '\n')
35 fp.write(str(pid) + '\n')
36 fp.close()
36 fp.close()
37
37
38 if opts['daemon'] and not opts['daemon_postexec']:
38 if opts['daemon'] and not opts['daemon_postexec']:
39 # Signal child process startup with file removal
39 # Signal child process startup with file removal
40 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
40 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
41 os.close(lockfd)
41 os.close(lockfd)
42 try:
42 try:
43 if not runargs:
43 if not runargs:
44 runargs = util.hgcmd() + sys.argv[1:]
44 runargs = util.hgcmd() + sys.argv[1:]
45 runargs.append('--daemon-postexec=unlink:%s' % lockpath)
45 runargs.append('--daemon-postexec=unlink:%s' % lockpath)
46 # Don't pass --cwd to the child process, because we've already
46 # Don't pass --cwd to the child process, because we've already
47 # changed directory.
47 # changed directory.
48 for i in xrange(1, len(runargs)):
48 for i in xrange(1, len(runargs)):
49 if runargs[i].startswith('--cwd='):
49 if runargs[i].startswith('--cwd='):
50 del runargs[i]
50 del runargs[i]
51 break
51 break
52 elif runargs[i].startswith('--cwd'):
52 elif runargs[i].startswith('--cwd'):
53 del runargs[i:i + 2]
53 del runargs[i:i + 2]
54 break
54 break
55 def condfn():
55 def condfn():
56 return not os.path.exists(lockpath)
56 return not os.path.exists(lockpath)
57 pid = util.rundetached(runargs, condfn)
57 pid = util.rundetached(runargs, condfn)
58 if pid < 0:
58 if pid < 0:
59 raise error.Abort(_('child process failed to start'))
59 raise error.Abort(_('child process failed to start'))
60 writepid(pid)
60 writepid(pid)
61 finally:
61 finally:
62 try:
62 try:
63 os.unlink(lockpath)
63 os.unlink(lockpath)
64 except OSError as e:
64 except OSError as e:
65 if e.errno != errno.ENOENT:
65 if e.errno != errno.ENOENT:
66 raise
66 raise
67 if parentfn:
67 if parentfn:
68 return parentfn(pid)
68 return parentfn(pid)
69 else:
69 else:
70 return
70 return
71
71
72 if initfn:
72 if initfn:
73 initfn()
73 initfn()
74
74
75 if not opts['daemon']:
75 if not opts['daemon']:
76 writepid(util.getpid())
76 writepid(util.getpid())
77
77
78 if opts['daemon_postexec']:
78 if opts['daemon_postexec']:
79 try:
79 try:
80 os.setsid()
80 os.setsid()
81 except AttributeError:
81 except AttributeError:
82 pass
82 pass
83 for inst in opts['daemon_postexec']:
83 for inst in opts['daemon_postexec']:
84 if inst.startswith('unlink:'):
84 if inst.startswith('unlink:'):
85 lockpath = inst[7:]
85 lockpath = inst[7:]
86 os.unlink(lockpath)
86 os.unlink(lockpath)
87 elif inst.startswith('chdir:'):
87 elif inst.startswith('chdir:'):
88 os.chdir(inst[6:])
88 os.chdir(inst[6:])
89 elif inst != 'none':
89 elif inst != 'none':
90 raise error.Abort(_('invalid value for --daemon-postexec: %s')
90 raise error.Abort(_('invalid value for --daemon-postexec: %s')
91 % inst)
91 % inst)
92 util.hidewindow()
92 util.hidewindow()
93 util.stdout.flush()
93 util.stdout.flush()
94 util.stderr.flush()
94 util.stderr.flush()
95
95
96 nullfd = os.open(os.devnull, os.O_RDWR)
96 nullfd = os.open(os.devnull, os.O_RDWR)
97 logfilefd = nullfd
97 logfilefd = nullfd
98 if logfile:
98 if logfile:
99 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
99 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
100 os.dup2(nullfd, 0)
100 os.dup2(nullfd, 0)
101 os.dup2(logfilefd, 1)
101 os.dup2(logfilefd, 1)
102 os.dup2(logfilefd, 2)
102 os.dup2(logfilefd, 2)
103 if nullfd not in (0, 1, 2):
103 if nullfd not in (0, 1, 2):
104 os.close(nullfd)
104 os.close(nullfd)
105 if logfile and logfilefd not in (0, 1, 2):
105 if logfile and logfilefd not in (0, 1, 2):
106 os.close(logfilefd)
106 os.close(logfilefd)
107
107
108 if runfn:
108 if runfn:
109 return runfn()
109 return runfn()
110
110
111 _cmdservicemap = {
111 _cmdservicemap = {
112 'pipe': commandserver.pipeservice,
112 'pipe': commandserver.pipeservice,
113 'unix': commandserver.unixforkingservice,
113 'unix': commandserver.unixforkingservice,
114 }
114 }
115
115
116 def createcmdservice(ui, repo, opts):
116 def _createcmdservice(ui, repo, opts):
117 mode = opts['cmdserver']
117 mode = opts['cmdserver']
118 try:
118 try:
119 return _cmdservicemap[mode](ui, repo, opts)
119 return _cmdservicemap[mode](ui, repo, opts)
120 except KeyError:
120 except KeyError:
121 raise error.Abort(_('unknown mode %s') % mode)
121 raise error.Abort(_('unknown mode %s') % mode)
122
122
123 def createhgwebservice(ui, repo, opts):
123 def _createhgwebservice(ui, repo, opts):
124 # this way we can check if something was given in the command-line
124 # this way we can check if something was given in the command-line
125 if opts.get('port'):
125 if opts.get('port'):
126 opts['port'] = util.getport(opts.get('port'))
126 opts['port'] = util.getport(opts.get('port'))
127
127
128 alluis = set([ui])
128 alluis = set([ui])
129 if repo:
129 if repo:
130 baseui = repo.baseui
130 baseui = repo.baseui
131 alluis.update([repo.baseui, repo.ui])
131 alluis.update([repo.baseui, repo.ui])
132 else:
132 else:
133 baseui = ui
133 baseui = ui
134 webconf = opts.get('web_conf') or opts.get('webdir_conf')
134 webconf = opts.get('web_conf') or opts.get('webdir_conf')
135 if webconf:
135 if webconf:
136 # load server settings (e.g. web.port) to "copied" ui, which allows
136 # load server settings (e.g. web.port) to "copied" ui, which allows
137 # hgwebdir to reload webconf cleanly
137 # hgwebdir to reload webconf cleanly
138 servui = ui.copy()
138 servui = ui.copy()
139 servui.readconfig(webconf, sections=['web'])
139 servui.readconfig(webconf, sections=['web'])
140 alluis.add(servui)
140 alluis.add(servui)
141 else:
141 else:
142 servui = ui
142 servui = ui
143
143
144 optlist = ("name templates style address port prefix ipv6"
144 optlist = ("name templates style address port prefix ipv6"
145 " accesslog errorlog certificate encoding")
145 " accesslog errorlog certificate encoding")
146 for o in optlist.split():
146 for o in optlist.split():
147 val = opts.get(o, '')
147 val = opts.get(o, '')
148 if val in (None, ''): # should check against default options instead
148 if val in (None, ''): # should check against default options instead
149 continue
149 continue
150 for u in alluis:
150 for u in alluis:
151 u.setconfig("web", o, val, 'serve')
151 u.setconfig("web", o, val, 'serve')
152
152
153 app = hgweb.createapp(baseui, repo, webconf)
153 app = hgweb.createapp(baseui, repo, webconf)
154 return hgweb.httpservice(servui, app, opts)
154 return hgweb.httpservice(servui, app, opts)
155
156 def createservice(ui, repo, opts):
157 if opts["cmdserver"]:
158 return _createcmdservice(ui, repo, opts)
159 else:
160 return _createhgwebservice(ui, repo, opts)
General Comments 0
You need to be logged in to leave comments. Login now