##// END OF EJS Templates
server: move service factory from hgweb
Yuya Nishihara -
r30509:add7bcad default
parent child Browse files
Show More
@@ -1,7092 +1,7091 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 hgweb,
55 localrepo,
54 localrepo,
56 lock as lockmod,
55 lock as lockmod,
57 merge as mergemod,
56 merge as mergemod,
58 minirst,
57 minirst,
59 obsolete,
58 obsolete,
60 patch,
59 patch,
61 phases,
60 phases,
62 policy,
61 policy,
63 pvec,
62 pvec,
64 pycompat,
63 pycompat,
65 repair,
64 repair,
66 revlog,
65 revlog,
67 revset,
66 revset,
68 scmutil,
67 scmutil,
69 server,
68 server,
70 setdiscovery,
69 setdiscovery,
71 sshserver,
70 sshserver,
72 sslutil,
71 sslutil,
73 streamclone,
72 streamclone,
74 templatekw,
73 templatekw,
75 templater,
74 templater,
76 treediscovery,
75 treediscovery,
77 ui as uimod,
76 ui as uimod,
78 util,
77 util,
79 )
78 )
80
79
81 release = lockmod.release
80 release = lockmod.release
82
81
83 table = {}
82 table = {}
84
83
85 command = cmdutil.command(table)
84 command = cmdutil.command(table)
86
85
87 # label constants
86 # label constants
88 # until 3.5, bookmarks.current was the advertised name, not
87 # until 3.5, bookmarks.current was the advertised name, not
89 # bookmarks.active, so we must use both to avoid breaking old
88 # bookmarks.active, so we must use both to avoid breaking old
90 # custom styles
89 # custom styles
91 activebookmarklabel = 'bookmarks.active bookmarks.current'
90 activebookmarklabel = 'bookmarks.active bookmarks.current'
92
91
93 # common command options
92 # common command options
94
93
95 globalopts = [
94 globalopts = [
96 ('R', 'repository', '',
95 ('R', 'repository', '',
97 _('repository root directory or name of overlay bundle file'),
96 _('repository root directory or name of overlay bundle file'),
98 _('REPO')),
97 _('REPO')),
99 ('', 'cwd', '',
98 ('', 'cwd', '',
100 _('change working directory'), _('DIR')),
99 _('change working directory'), _('DIR')),
101 ('y', 'noninteractive', None,
100 ('y', 'noninteractive', None,
102 _('do not prompt, automatically pick the first choice for all prompts')),
101 _('do not prompt, automatically pick the first choice for all prompts')),
103 ('q', 'quiet', None, _('suppress output')),
102 ('q', 'quiet', None, _('suppress output')),
104 ('v', 'verbose', None, _('enable additional output')),
103 ('v', 'verbose', None, _('enable additional output')),
105 ('', 'config', [],
104 ('', 'config', [],
106 _('set/override config option (use \'section.name=value\')'),
105 _('set/override config option (use \'section.name=value\')'),
107 _('CONFIG')),
106 _('CONFIG')),
108 ('', 'debug', None, _('enable debugging output')),
107 ('', 'debug', None, _('enable debugging output')),
109 ('', 'debugger', None, _('start debugger')),
108 ('', 'debugger', None, _('start debugger')),
110 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
109 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
111 _('ENCODE')),
110 _('ENCODE')),
112 ('', 'encodingmode', encoding.encodingmode,
111 ('', 'encodingmode', encoding.encodingmode,
113 _('set the charset encoding mode'), _('MODE')),
112 _('set the charset encoding mode'), _('MODE')),
114 ('', 'traceback', None, _('always print a traceback on exception')),
113 ('', 'traceback', None, _('always print a traceback on exception')),
115 ('', 'time', None, _('time how long the command takes')),
114 ('', 'time', None, _('time how long the command takes')),
116 ('', 'profile', None, _('print command execution profile')),
115 ('', 'profile', None, _('print command execution profile')),
117 ('', 'version', None, _('output version information and exit')),
116 ('', 'version', None, _('output version information and exit')),
118 ('h', 'help', None, _('display help and exit')),
117 ('h', 'help', None, _('display help and exit')),
119 ('', 'hidden', False, _('consider hidden changesets')),
118 ('', 'hidden', False, _('consider hidden changesets')),
120 ]
119 ]
121
120
122 dryrunopts = [('n', 'dry-run', None,
121 dryrunopts = [('n', 'dry-run', None,
123 _('do not perform actions, just print output'))]
122 _('do not perform actions, just print output'))]
124
123
125 remoteopts = [
124 remoteopts = [
126 ('e', 'ssh', '',
125 ('e', 'ssh', '',
127 _('specify ssh command to use'), _('CMD')),
126 _('specify ssh command to use'), _('CMD')),
128 ('', 'remotecmd', '',
127 ('', 'remotecmd', '',
129 _('specify hg command to run on the remote side'), _('CMD')),
128 _('specify hg command to run on the remote side'), _('CMD')),
130 ('', 'insecure', None,
129 ('', 'insecure', None,
131 _('do not verify server certificate (ignoring web.cacerts config)')),
130 _('do not verify server certificate (ignoring web.cacerts config)')),
132 ]
131 ]
133
132
134 walkopts = [
133 walkopts = [
135 ('I', 'include', [],
134 ('I', 'include', [],
136 _('include names matching the given patterns'), _('PATTERN')),
135 _('include names matching the given patterns'), _('PATTERN')),
137 ('X', 'exclude', [],
136 ('X', 'exclude', [],
138 _('exclude names matching the given patterns'), _('PATTERN')),
137 _('exclude names matching the given patterns'), _('PATTERN')),
139 ]
138 ]
140
139
141 commitopts = [
140 commitopts = [
142 ('m', 'message', '',
141 ('m', 'message', '',
143 _('use text as commit message'), _('TEXT')),
142 _('use text as commit message'), _('TEXT')),
144 ('l', 'logfile', '',
143 ('l', 'logfile', '',
145 _('read commit message from file'), _('FILE')),
144 _('read commit message from file'), _('FILE')),
146 ]
145 ]
147
146
148 commitopts2 = [
147 commitopts2 = [
149 ('d', 'date', '',
148 ('d', 'date', '',
150 _('record the specified date as commit date'), _('DATE')),
149 _('record the specified date as commit date'), _('DATE')),
151 ('u', 'user', '',
150 ('u', 'user', '',
152 _('record the specified user as committer'), _('USER')),
151 _('record the specified user as committer'), _('USER')),
153 ]
152 ]
154
153
155 # hidden for now
154 # hidden for now
156 formatteropts = [
155 formatteropts = [
157 ('T', 'template', '',
156 ('T', 'template', '',
158 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
157 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
159 ]
158 ]
160
159
161 templateopts = [
160 templateopts = [
162 ('', 'style', '',
161 ('', 'style', '',
163 _('display using template map file (DEPRECATED)'), _('STYLE')),
162 _('display using template map file (DEPRECATED)'), _('STYLE')),
164 ('T', 'template', '',
163 ('T', 'template', '',
165 _('display with template'), _('TEMPLATE')),
164 _('display with template'), _('TEMPLATE')),
166 ]
165 ]
167
166
168 logopts = [
167 logopts = [
169 ('p', 'patch', None, _('show patch')),
168 ('p', 'patch', None, _('show patch')),
170 ('g', 'git', None, _('use git extended diff format')),
169 ('g', 'git', None, _('use git extended diff format')),
171 ('l', 'limit', '',
170 ('l', 'limit', '',
172 _('limit number of changes displayed'), _('NUM')),
171 _('limit number of changes displayed'), _('NUM')),
173 ('M', 'no-merges', None, _('do not show merges')),
172 ('M', 'no-merges', None, _('do not show merges')),
174 ('', 'stat', None, _('output diffstat-style summary of changes')),
173 ('', 'stat', None, _('output diffstat-style summary of changes')),
175 ('G', 'graph', None, _("show the revision DAG")),
174 ('G', 'graph', None, _("show the revision DAG")),
176 ] + templateopts
175 ] + templateopts
177
176
178 diffopts = [
177 diffopts = [
179 ('a', 'text', None, _('treat all files as text')),
178 ('a', 'text', None, _('treat all files as text')),
180 ('g', 'git', None, _('use git extended diff format')),
179 ('g', 'git', None, _('use git extended diff format')),
181 ('', 'nodates', None, _('omit dates from diff headers'))
180 ('', 'nodates', None, _('omit dates from diff headers'))
182 ]
181 ]
183
182
184 diffwsopts = [
183 diffwsopts = [
185 ('w', 'ignore-all-space', None,
184 ('w', 'ignore-all-space', None,
186 _('ignore white space when comparing lines')),
185 _('ignore white space when comparing lines')),
187 ('b', 'ignore-space-change', None,
186 ('b', 'ignore-space-change', None,
188 _('ignore changes in the amount of white space')),
187 _('ignore changes in the amount of white space')),
189 ('B', 'ignore-blank-lines', None,
188 ('B', 'ignore-blank-lines', None,
190 _('ignore changes whose lines are all blank')),
189 _('ignore changes whose lines are all blank')),
191 ]
190 ]
192
191
193 diffopts2 = [
192 diffopts2 = [
194 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
193 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
195 ('p', 'show-function', None, _('show which function each change is in')),
194 ('p', 'show-function', None, _('show which function each change is in')),
196 ('', 'reverse', None, _('produce a diff that undoes the changes')),
195 ('', 'reverse', None, _('produce a diff that undoes the changes')),
197 ] + diffwsopts + [
196 ] + diffwsopts + [
198 ('U', 'unified', '',
197 ('U', 'unified', '',
199 _('number of lines of context to show'), _('NUM')),
198 _('number of lines of context to show'), _('NUM')),
200 ('', 'stat', None, _('output diffstat-style summary of changes')),
199 ('', 'stat', None, _('output diffstat-style summary of changes')),
201 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
200 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
202 ]
201 ]
203
202
204 mergetoolopts = [
203 mergetoolopts = [
205 ('t', 'tool', '', _('specify merge tool')),
204 ('t', 'tool', '', _('specify merge tool')),
206 ]
205 ]
207
206
208 similarityopts = [
207 similarityopts = [
209 ('s', 'similarity', '',
208 ('s', 'similarity', '',
210 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
209 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
211 ]
210 ]
212
211
213 subrepoopts = [
212 subrepoopts = [
214 ('S', 'subrepos', None,
213 ('S', 'subrepos', None,
215 _('recurse into subrepositories'))
214 _('recurse into subrepositories'))
216 ]
215 ]
217
216
218 debugrevlogopts = [
217 debugrevlogopts = [
219 ('c', 'changelog', False, _('open changelog')),
218 ('c', 'changelog', False, _('open changelog')),
220 ('m', 'manifest', False, _('open manifest')),
219 ('m', 'manifest', False, _('open manifest')),
221 ('', 'dir', '', _('open directory manifest')),
220 ('', 'dir', '', _('open directory manifest')),
222 ]
221 ]
223
222
224 # Commands start here, listed alphabetically
223 # Commands start here, listed alphabetically
225
224
226 @command('^add',
225 @command('^add',
227 walkopts + subrepoopts + dryrunopts,
226 walkopts + subrepoopts + dryrunopts,
228 _('[OPTION]... [FILE]...'),
227 _('[OPTION]... [FILE]...'),
229 inferrepo=True)
228 inferrepo=True)
230 def add(ui, repo, *pats, **opts):
229 def add(ui, repo, *pats, **opts):
231 """add the specified files on the next commit
230 """add the specified files on the next commit
232
231
233 Schedule files to be version controlled and added to the
232 Schedule files to be version controlled and added to the
234 repository.
233 repository.
235
234
236 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
237 undo an add before that, see :hg:`forget`.
236 undo an add before that, see :hg:`forget`.
238
237
239 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
240 files matching ``.hgignore``).
239 files matching ``.hgignore``).
241
240
242 .. container:: verbose
241 .. container:: verbose
243
242
244 Examples:
243 Examples:
245
244
246 - New (unknown) files are added
245 - New (unknown) files are added
247 automatically by :hg:`add`::
246 automatically by :hg:`add`::
248
247
249 $ ls
248 $ ls
250 foo.c
249 foo.c
251 $ hg status
250 $ hg status
252 ? foo.c
251 ? foo.c
253 $ hg add
252 $ hg add
254 adding foo.c
253 adding foo.c
255 $ hg status
254 $ hg status
256 A foo.c
255 A foo.c
257
256
258 - Specific files to be added can be specified::
257 - Specific files to be added can be specified::
259
258
260 $ ls
259 $ ls
261 bar.c foo.c
260 bar.c foo.c
262 $ hg status
261 $ hg status
263 ? bar.c
262 ? bar.c
264 ? foo.c
263 ? foo.c
265 $ hg add bar.c
264 $ hg add bar.c
266 $ hg status
265 $ hg status
267 A bar.c
266 A bar.c
268 ? foo.c
267 ? foo.c
269
268
270 Returns 0 if all files are successfully added.
269 Returns 0 if all files are successfully added.
271 """
270 """
272
271
273 m = scmutil.match(repo[None], pats, opts)
272 m = scmutil.match(repo[None], pats, opts)
274 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
273 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
275 return rejected and 1 or 0
274 return rejected and 1 or 0
276
275
277 @command('addremove',
276 @command('addremove',
278 similarityopts + subrepoopts + walkopts + dryrunopts,
277 similarityopts + subrepoopts + walkopts + dryrunopts,
279 _('[OPTION]... [FILE]...'),
278 _('[OPTION]... [FILE]...'),
280 inferrepo=True)
279 inferrepo=True)
281 def addremove(ui, repo, *pats, **opts):
280 def addremove(ui, repo, *pats, **opts):
282 """add all new files, delete all missing files
281 """add all new files, delete all missing files
283
282
284 Add all new files and remove all missing files from the
283 Add all new files and remove all missing files from the
285 repository.
284 repository.
286
285
287 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
288 the patterns in ``.hgignore``. As with add, these changes take
287 the patterns in ``.hgignore``. As with add, these changes take
289 effect at the next commit.
288 effect at the next commit.
290
289
291 Use the -s/--similarity option to detect renamed files. This
290 Use the -s/--similarity option to detect renamed files. This
292 option takes a percentage between 0 (disabled) and 100 (files must
291 option takes a percentage between 0 (disabled) and 100 (files must
293 be identical) as its parameter. With a parameter greater than 0,
292 be identical) as its parameter. With a parameter greater than 0,
294 this compares every removed file with every added file and records
293 this compares every removed file with every added file and records
295 those similar enough as renames. Detecting renamed files this way
294 those similar enough as renames. Detecting renamed files this way
296 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
297 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
298 not specified, -s/--similarity defaults to 100 and only renames of
297 not specified, -s/--similarity defaults to 100 and only renames of
299 identical files are detected.
298 identical files are detected.
300
299
301 .. container:: verbose
300 .. container:: verbose
302
301
303 Examples:
302 Examples:
304
303
305 - A number of files (bar.c and foo.c) are new,
304 - A number of files (bar.c and foo.c) are new,
306 while foobar.c has been removed (without using :hg:`remove`)
305 while foobar.c has been removed (without using :hg:`remove`)
307 from the repository::
306 from the repository::
308
307
309 $ ls
308 $ ls
310 bar.c foo.c
309 bar.c foo.c
311 $ hg status
310 $ hg status
312 ! foobar.c
311 ! foobar.c
313 ? bar.c
312 ? bar.c
314 ? foo.c
313 ? foo.c
315 $ hg addremove
314 $ hg addremove
316 adding bar.c
315 adding bar.c
317 adding foo.c
316 adding foo.c
318 removing foobar.c
317 removing foobar.c
319 $ hg status
318 $ hg status
320 A bar.c
319 A bar.c
321 A foo.c
320 A foo.c
322 R foobar.c
321 R foobar.c
323
322
324 - 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`.
325 Afterwards, it was edited slightly::
324 Afterwards, it was edited slightly::
326
325
327 $ ls
326 $ ls
328 foo.c
327 foo.c
329 $ hg status
328 $ hg status
330 ! foobar.c
329 ! foobar.c
331 ? foo.c
330 ? foo.c
332 $ hg addremove --similarity 90
331 $ hg addremove --similarity 90
333 removing foobar.c
332 removing foobar.c
334 adding foo.c
333 adding foo.c
335 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)
336 $ hg status -C
335 $ hg status -C
337 A foo.c
336 A foo.c
338 foobar.c
337 foobar.c
339 R foobar.c
338 R foobar.c
340
339
341 Returns 0 if all files are successfully added.
340 Returns 0 if all files are successfully added.
342 """
341 """
343 try:
342 try:
344 sim = float(opts.get('similarity') or 100)
343 sim = float(opts.get('similarity') or 100)
345 except ValueError:
344 except ValueError:
346 raise error.Abort(_('similarity must be a number'))
345 raise error.Abort(_('similarity must be a number'))
347 if sim < 0 or sim > 100:
346 if sim < 0 or sim > 100:
348 raise error.Abort(_('similarity must be between 0 and 100'))
347 raise error.Abort(_('similarity must be between 0 and 100'))
349 matcher = scmutil.match(repo[None], pats, opts)
348 matcher = scmutil.match(repo[None], pats, opts)
350 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
349 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
351
350
352 @command('^annotate|blame',
351 @command('^annotate|blame',
353 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
352 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
354 ('', 'follow', None,
353 ('', 'follow', None,
355 _('follow copies/renames and list the filename (DEPRECATED)')),
354 _('follow copies/renames and list the filename (DEPRECATED)')),
356 ('', 'no-follow', None, _("don't follow copies and renames")),
355 ('', 'no-follow', None, _("don't follow copies and renames")),
357 ('a', 'text', None, _('treat all files as text')),
356 ('a', 'text', None, _('treat all files as text')),
358 ('u', 'user', None, _('list the author (long with -v)')),
357 ('u', 'user', None, _('list the author (long with -v)')),
359 ('f', 'file', None, _('list the filename')),
358 ('f', 'file', None, _('list the filename')),
360 ('d', 'date', None, _('list the date (short with -q)')),
359 ('d', 'date', None, _('list the date (short with -q)')),
361 ('n', 'number', None, _('list the revision number (default)')),
360 ('n', 'number', None, _('list the revision number (default)')),
362 ('c', 'changeset', None, _('list the changeset')),
361 ('c', 'changeset', None, _('list the changeset')),
363 ('l', 'line-number', None, _('show line number at the first appearance'))
362 ('l', 'line-number', None, _('show line number at the first appearance'))
364 ] + diffwsopts + walkopts + formatteropts,
363 ] + diffwsopts + walkopts + formatteropts,
365 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
364 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
366 inferrepo=True)
365 inferrepo=True)
367 def annotate(ui, repo, *pats, **opts):
366 def annotate(ui, repo, *pats, **opts):
368 """show changeset information by line for each file
367 """show changeset information by line for each file
369
368
370 List changes in files, showing the revision id responsible for
369 List changes in files, showing the revision id responsible for
371 each line.
370 each line.
372
371
373 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
374 by whom.
373 by whom.
375
374
376 If you include --file, --user, or --date, the revision number is
375 If you include --file, --user, or --date, the revision number is
377 suppressed unless you also include --number.
376 suppressed unless you also include --number.
378
377
379 Without the -a/--text option, annotate will avoid processing files
378 Without the -a/--text option, annotate will avoid processing files
380 it detects as binary. With -a, annotate will annotate the file
379 it detects as binary. With -a, annotate will annotate the file
381 anyway, although the results will probably be neither useful
380 anyway, although the results will probably be neither useful
382 nor desirable.
381 nor desirable.
383
382
384 Returns 0 on success.
383 Returns 0 on success.
385 """
384 """
386 if not pats:
385 if not pats:
387 raise error.Abort(_('at least one filename or pattern is required'))
386 raise error.Abort(_('at least one filename or pattern is required'))
388
387
389 if opts.get('follow'):
388 if opts.get('follow'):
390 # --follow is deprecated and now just an alias for -f/--file
389 # --follow is deprecated and now just an alias for -f/--file
391 # to mimic the behavior of Mercurial before version 1.5
390 # to mimic the behavior of Mercurial before version 1.5
392 opts['file'] = True
391 opts['file'] = True
393
392
394 ctx = scmutil.revsingle(repo, opts.get('rev'))
393 ctx = scmutil.revsingle(repo, opts.get('rev'))
395
394
396 fm = ui.formatter('annotate', opts)
395 fm = ui.formatter('annotate', opts)
397 if ui.quiet:
396 if ui.quiet:
398 datefunc = util.shortdate
397 datefunc = util.shortdate
399 else:
398 else:
400 datefunc = util.datestr
399 datefunc = util.datestr
401 if ctx.rev() is None:
400 if ctx.rev() is None:
402 def hexfn(node):
401 def hexfn(node):
403 if node is None:
402 if node is None:
404 return None
403 return None
405 else:
404 else:
406 return fm.hexfunc(node)
405 return fm.hexfunc(node)
407 if opts.get('changeset'):
406 if opts.get('changeset'):
408 # omit "+" suffix which is appended to node hex
407 # omit "+" suffix which is appended to node hex
409 def formatrev(rev):
408 def formatrev(rev):
410 if rev is None:
409 if rev is None:
411 return '%d' % ctx.p1().rev()
410 return '%d' % ctx.p1().rev()
412 else:
411 else:
413 return '%d' % rev
412 return '%d' % rev
414 else:
413 else:
415 def formatrev(rev):
414 def formatrev(rev):
416 if rev is None:
415 if rev is None:
417 return '%d+' % ctx.p1().rev()
416 return '%d+' % ctx.p1().rev()
418 else:
417 else:
419 return '%d ' % rev
418 return '%d ' % rev
420 def formathex(hex):
419 def formathex(hex):
421 if hex is None:
420 if hex is None:
422 return '%s+' % fm.hexfunc(ctx.p1().node())
421 return '%s+' % fm.hexfunc(ctx.p1().node())
423 else:
422 else:
424 return '%s ' % hex
423 return '%s ' % hex
425 else:
424 else:
426 hexfn = fm.hexfunc
425 hexfn = fm.hexfunc
427 formatrev = formathex = str
426 formatrev = formathex = str
428
427
429 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
428 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
430 ('number', ' ', lambda x: x[0].rev(), formatrev),
429 ('number', ' ', lambda x: x[0].rev(), formatrev),
431 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
430 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
432 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
431 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
433 ('file', ' ', lambda x: x[0].path(), str),
432 ('file', ' ', lambda x: x[0].path(), str),
434 ('line_number', ':', lambda x: x[1], str),
433 ('line_number', ':', lambda x: x[1], str),
435 ]
434 ]
436 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
435 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
437
436
438 if (not opts.get('user') and not opts.get('changeset')
437 if (not opts.get('user') and not opts.get('changeset')
439 and not opts.get('date') and not opts.get('file')):
438 and not opts.get('date') and not opts.get('file')):
440 opts['number'] = True
439 opts['number'] = True
441
440
442 linenumber = opts.get('line_number') is not None
441 linenumber = opts.get('line_number') is not None
443 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')):
444 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'))
445
444
446 if fm.isplain():
445 if fm.isplain():
447 def makefunc(get, fmt):
446 def makefunc(get, fmt):
448 return lambda x: fmt(get(x))
447 return lambda x: fmt(get(x))
449 else:
448 else:
450 def makefunc(get, fmt):
449 def makefunc(get, fmt):
451 return get
450 return get
452 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
453 if opts.get(op)]
452 if opts.get(op)]
454 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
455 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
456 if opts.get(op))
455 if opts.get(op))
457
456
458 def bad(x, y):
457 def bad(x, y):
459 raise error.Abort("%s: %s" % (x, y))
458 raise error.Abort("%s: %s" % (x, y))
460
459
461 m = scmutil.match(ctx, pats, opts, badfn=bad)
460 m = scmutil.match(ctx, pats, opts, badfn=bad)
462
461
463 follow = not opts.get('no_follow')
462 follow = not opts.get('no_follow')
464 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
463 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
465 whitespace=True)
464 whitespace=True)
466 for abs in ctx.walk(m):
465 for abs in ctx.walk(m):
467 fctx = ctx[abs]
466 fctx = ctx[abs]
468 if not opts.get('text') and util.binary(fctx.data()):
467 if not opts.get('text') and util.binary(fctx.data()):
469 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))
470 continue
469 continue
471
470
472 lines = fctx.annotate(follow=follow, linenumber=linenumber,
471 lines = fctx.annotate(follow=follow, linenumber=linenumber,
473 diffopts=diffopts)
472 diffopts=diffopts)
474 if not lines:
473 if not lines:
475 continue
474 continue
476 formats = []
475 formats = []
477 pieces = []
476 pieces = []
478
477
479 for f, sep in funcmap:
478 for f, sep in funcmap:
480 l = [f(n) for n, dummy in lines]
479 l = [f(n) for n, dummy in lines]
481 if fm.isplain():
480 if fm.isplain():
482 sizes = [encoding.colwidth(x) for x in l]
481 sizes = [encoding.colwidth(x) for x in l]
483 ml = max(sizes)
482 ml = max(sizes)
484 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
483 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
485 else:
484 else:
486 formats.append(['%s' for x in l])
485 formats.append(['%s' for x in l])
487 pieces.append(l)
486 pieces.append(l)
488
487
489 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
488 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
490 fm.startitem()
489 fm.startitem()
491 fm.write(fields, "".join(f), *p)
490 fm.write(fields, "".join(f), *p)
492 fm.write('line', ": %s", l[1])
491 fm.write('line', ": %s", l[1])
493
492
494 if not lines[-1][1].endswith('\n'):
493 if not lines[-1][1].endswith('\n'):
495 fm.plain('\n')
494 fm.plain('\n')
496
495
497 fm.end()
496 fm.end()
498
497
499 @command('archive',
498 @command('archive',
500 [('', 'no-decode', None, _('do not pass files through decoders')),
499 [('', 'no-decode', None, _('do not pass files through decoders')),
501 ('p', 'prefix', '', _('directory prefix for files in archive'),
500 ('p', 'prefix', '', _('directory prefix for files in archive'),
502 _('PREFIX')),
501 _('PREFIX')),
503 ('r', 'rev', '', _('revision to distribute'), _('REV')),
502 ('r', 'rev', '', _('revision to distribute'), _('REV')),
504 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
503 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
505 ] + subrepoopts + walkopts,
504 ] + subrepoopts + walkopts,
506 _('[OPTION]... DEST'))
505 _('[OPTION]... DEST'))
507 def archive(ui, repo, dest, **opts):
506 def archive(ui, repo, dest, **opts):
508 '''create an unversioned archive of a repository revision
507 '''create an unversioned archive of a repository revision
509
508
510 By default, the revision used is the parent of the working
509 By default, the revision used is the parent of the working
511 directory; use -r/--rev to specify a different revision.
510 directory; use -r/--rev to specify a different revision.
512
511
513 The archive type is automatically detected based on file
512 The archive type is automatically detected based on file
514 extension (to override, use -t/--type).
513 extension (to override, use -t/--type).
515
514
516 .. container:: verbose
515 .. container:: verbose
517
516
518 Examples:
517 Examples:
519
518
520 - create a zip file containing the 1.0 release::
519 - create a zip file containing the 1.0 release::
521
520
522 hg archive -r 1.0 project-1.0.zip
521 hg archive -r 1.0 project-1.0.zip
523
522
524 - create a tarball excluding .hg files::
523 - create a tarball excluding .hg files::
525
524
526 hg archive project.tar.gz -X ".hg*"
525 hg archive project.tar.gz -X ".hg*"
527
526
528 Valid types are:
527 Valid types are:
529
528
530 :``files``: a directory full of files (default)
529 :``files``: a directory full of files (default)
531 :``tar``: tar archive, uncompressed
530 :``tar``: tar archive, uncompressed
532 :``tbz2``: tar archive, compressed using bzip2
531 :``tbz2``: tar archive, compressed using bzip2
533 :``tgz``: tar archive, compressed using gzip
532 :``tgz``: tar archive, compressed using gzip
534 :``uzip``: zip archive, uncompressed
533 :``uzip``: zip archive, uncompressed
535 :``zip``: zip archive, compressed using deflate
534 :``zip``: zip archive, compressed using deflate
536
535
537 The exact name of the destination archive or directory is given
536 The exact name of the destination archive or directory is given
538 using a format string; see :hg:`help export` for details.
537 using a format string; see :hg:`help export` for details.
539
538
540 Each member added to an archive file has a directory prefix
539 Each member added to an archive file has a directory prefix
541 prepended. Use -p/--prefix to specify a format string for the
540 prepended. Use -p/--prefix to specify a format string for the
542 prefix. The default is the basename of the archive, with suffixes
541 prefix. The default is the basename of the archive, with suffixes
543 removed.
542 removed.
544
543
545 Returns 0 on success.
544 Returns 0 on success.
546 '''
545 '''
547
546
548 ctx = scmutil.revsingle(repo, opts.get('rev'))
547 ctx = scmutil.revsingle(repo, opts.get('rev'))
549 if not ctx:
548 if not ctx:
550 raise error.Abort(_('no working directory: please specify a revision'))
549 raise error.Abort(_('no working directory: please specify a revision'))
551 node = ctx.node()
550 node = ctx.node()
552 dest = cmdutil.makefilename(repo, dest, node)
551 dest = cmdutil.makefilename(repo, dest, node)
553 if os.path.realpath(dest) == repo.root:
552 if os.path.realpath(dest) == repo.root:
554 raise error.Abort(_('repository root cannot be destination'))
553 raise error.Abort(_('repository root cannot be destination'))
555
554
556 kind = opts.get('type') or archival.guesskind(dest) or 'files'
555 kind = opts.get('type') or archival.guesskind(dest) or 'files'
557 prefix = opts.get('prefix')
556 prefix = opts.get('prefix')
558
557
559 if dest == '-':
558 if dest == '-':
560 if kind == 'files':
559 if kind == 'files':
561 raise error.Abort(_('cannot archive plain files to stdout'))
560 raise error.Abort(_('cannot archive plain files to stdout'))
562 dest = cmdutil.makefileobj(repo, dest)
561 dest = cmdutil.makefileobj(repo, dest)
563 if not prefix:
562 if not prefix:
564 prefix = os.path.basename(repo.root) + '-%h'
563 prefix = os.path.basename(repo.root) + '-%h'
565
564
566 prefix = cmdutil.makefilename(repo, prefix, node)
565 prefix = cmdutil.makefilename(repo, prefix, node)
567 matchfn = scmutil.match(ctx, [], opts)
566 matchfn = scmutil.match(ctx, [], opts)
568 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
567 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
569 matchfn, prefix, subrepos=opts.get('subrepos'))
568 matchfn, prefix, subrepos=opts.get('subrepos'))
570
569
571 @command('backout',
570 @command('backout',
572 [('', 'merge', None, _('merge with old dirstate parent after backout')),
571 [('', 'merge', None, _('merge with old dirstate parent after backout')),
573 ('', 'commit', None,
572 ('', 'commit', None,
574 _('commit if no conflicts were encountered (DEPRECATED)')),
573 _('commit if no conflicts were encountered (DEPRECATED)')),
575 ('', 'no-commit', None, _('do not commit')),
574 ('', 'no-commit', None, _('do not commit')),
576 ('', 'parent', '',
575 ('', 'parent', '',
577 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
576 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
578 ('r', 'rev', '', _('revision to backout'), _('REV')),
577 ('r', 'rev', '', _('revision to backout'), _('REV')),
579 ('e', 'edit', False, _('invoke editor on commit messages')),
578 ('e', 'edit', False, _('invoke editor on commit messages')),
580 ] + mergetoolopts + walkopts + commitopts + commitopts2,
579 ] + mergetoolopts + walkopts + commitopts + commitopts2,
581 _('[OPTION]... [-r] REV'))
580 _('[OPTION]... [-r] REV'))
582 def backout(ui, repo, node=None, rev=None, **opts):
581 def backout(ui, repo, node=None, rev=None, **opts):
583 '''reverse effect of earlier changeset
582 '''reverse effect of earlier changeset
584
583
585 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
586 current working directory. If no conflicts were encountered,
585 current working directory. If no conflicts were encountered,
587 it will be committed immediately.
586 it will be committed immediately.
588
587
589 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
590 is committed automatically (unless --no-commit is specified).
589 is committed automatically (unless --no-commit is specified).
591
590
592 .. note::
591 .. note::
593
592
594 :hg:`backout` cannot be used to fix either an unwanted or
593 :hg:`backout` cannot be used to fix either an unwanted or
595 incorrect merge.
594 incorrect merge.
596
595
597 .. container:: verbose
596 .. container:: verbose
598
597
599 Examples:
598 Examples:
600
599
601 - Reverse the effect of the parent of the working directory.
600 - Reverse the effect of the parent of the working directory.
602 This backout will be committed immediately::
601 This backout will be committed immediately::
603
602
604 hg backout -r .
603 hg backout -r .
605
604
606 - Reverse the effect of previous bad revision 23::
605 - Reverse the effect of previous bad revision 23::
607
606
608 hg backout -r 23
607 hg backout -r 23
609
608
610 - Reverse the effect of previous bad revision 23 and
609 - Reverse the effect of previous bad revision 23 and
611 leave changes uncommitted::
610 leave changes uncommitted::
612
611
613 hg backout -r 23 --no-commit
612 hg backout -r 23 --no-commit
614 hg commit -m "Backout revision 23"
613 hg commit -m "Backout revision 23"
615
614
616 By default, the pending changeset will have one parent,
615 By default, the pending changeset will have one parent,
617 maintaining a linear history. With --merge, the pending
616 maintaining a linear history. With --merge, the pending
618 changeset will instead have two parents: the old parent of the
617 changeset will instead have two parents: the old parent of the
619 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.
620
619
621 Before version 1.7, the behavior without --merge was equivalent
620 Before version 1.7, the behavior without --merge was equivalent
622 to specifying --merge followed by :hg:`update --clean .` to
621 to specifying --merge followed by :hg:`update --clean .` to
623 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
624 merged separately.
623 merged separately.
625
624
626 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.
627
626
628 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
629 of another revision.
628 of another revision.
630
629
631 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
632 files.
631 files.
633 '''
632 '''
634 wlock = lock = None
633 wlock = lock = None
635 try:
634 try:
636 wlock = repo.wlock()
635 wlock = repo.wlock()
637 lock = repo.lock()
636 lock = repo.lock()
638 return _dobackout(ui, repo, node, rev, **opts)
637 return _dobackout(ui, repo, node, rev, **opts)
639 finally:
638 finally:
640 release(lock, wlock)
639 release(lock, wlock)
641
640
642 def _dobackout(ui, repo, node=None, rev=None, **opts):
641 def _dobackout(ui, repo, node=None, rev=None, **opts):
643 if opts.get('commit') and opts.get('no_commit'):
642 if opts.get('commit') and opts.get('no_commit'):
644 raise error.Abort(_("cannot use --commit with --no-commit"))
643 raise error.Abort(_("cannot use --commit with --no-commit"))
645 if opts.get('merge') and opts.get('no_commit'):
644 if opts.get('merge') and opts.get('no_commit'):
646 raise error.Abort(_("cannot use --merge with --no-commit"))
645 raise error.Abort(_("cannot use --merge with --no-commit"))
647
646
648 if rev and node:
647 if rev and node:
649 raise error.Abort(_("please specify just one revision"))
648 raise error.Abort(_("please specify just one revision"))
650
649
651 if not rev:
650 if not rev:
652 rev = node
651 rev = node
653
652
654 if not rev:
653 if not rev:
655 raise error.Abort(_("please specify a revision to backout"))
654 raise error.Abort(_("please specify a revision to backout"))
656
655
657 date = opts.get('date')
656 date = opts.get('date')
658 if date:
657 if date:
659 opts['date'] = util.parsedate(date)
658 opts['date'] = util.parsedate(date)
660
659
661 cmdutil.checkunfinished(repo)
660 cmdutil.checkunfinished(repo)
662 cmdutil.bailifchanged(repo)
661 cmdutil.bailifchanged(repo)
663 node = scmutil.revsingle(repo, rev).node()
662 node = scmutil.revsingle(repo, rev).node()
664
663
665 op1, op2 = repo.dirstate.parents()
664 op1, op2 = repo.dirstate.parents()
666 if not repo.changelog.isancestor(node, op1):
665 if not repo.changelog.isancestor(node, op1):
667 raise error.Abort(_('cannot backout change that is not an ancestor'))
666 raise error.Abort(_('cannot backout change that is not an ancestor'))
668
667
669 p1, p2 = repo.changelog.parents(node)
668 p1, p2 = repo.changelog.parents(node)
670 if p1 == nullid:
669 if p1 == nullid:
671 raise error.Abort(_('cannot backout a change with no parents'))
670 raise error.Abort(_('cannot backout a change with no parents'))
672 if p2 != nullid:
671 if p2 != nullid:
673 if not opts.get('parent'):
672 if not opts.get('parent'):
674 raise error.Abort(_('cannot backout a merge changeset'))
673 raise error.Abort(_('cannot backout a merge changeset'))
675 p = repo.lookup(opts['parent'])
674 p = repo.lookup(opts['parent'])
676 if p not in (p1, p2):
675 if p not in (p1, p2):
677 raise error.Abort(_('%s is not a parent of %s') %
676 raise error.Abort(_('%s is not a parent of %s') %
678 (short(p), short(node)))
677 (short(p), short(node)))
679 parent = p
678 parent = p
680 else:
679 else:
681 if opts.get('parent'):
680 if opts.get('parent'):
682 raise error.Abort(_('cannot use --parent on non-merge changeset'))
681 raise error.Abort(_('cannot use --parent on non-merge changeset'))
683 parent = p1
682 parent = p1
684
683
685 # the backout should appear on the same branch
684 # the backout should appear on the same branch
686 branch = repo.dirstate.branch()
685 branch = repo.dirstate.branch()
687 bheads = repo.branchheads(branch)
686 bheads = repo.branchheads(branch)
688 rctx = scmutil.revsingle(repo, hex(parent))
687 rctx = scmutil.revsingle(repo, hex(parent))
689 if not opts.get('merge') and op1 != node:
688 if not opts.get('merge') and op1 != node:
690 dsguard = dirstateguard.dirstateguard(repo, 'backout')
689 dsguard = dirstateguard.dirstateguard(repo, 'backout')
691 try:
690 try:
692 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
691 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
693 'backout')
692 'backout')
694 stats = mergemod.update(repo, parent, True, True, node, False)
693 stats = mergemod.update(repo, parent, True, True, node, False)
695 repo.setparents(op1, op2)
694 repo.setparents(op1, op2)
696 dsguard.close()
695 dsguard.close()
697 hg._showstats(repo, stats)
696 hg._showstats(repo, stats)
698 if stats[3]:
697 if stats[3]:
699 repo.ui.status(_("use 'hg resolve' to retry unresolved "
698 repo.ui.status(_("use 'hg resolve' to retry unresolved "
700 "file merges\n"))
699 "file merges\n"))
701 return 1
700 return 1
702 finally:
701 finally:
703 ui.setconfig('ui', 'forcemerge', '', '')
702 ui.setconfig('ui', 'forcemerge', '', '')
704 lockmod.release(dsguard)
703 lockmod.release(dsguard)
705 else:
704 else:
706 hg.clean(repo, node, show_stats=False)
705 hg.clean(repo, node, show_stats=False)
707 repo.dirstate.setbranch(branch)
706 repo.dirstate.setbranch(branch)
708 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
707 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
709
708
710 if opts.get('no_commit'):
709 if opts.get('no_commit'):
711 msg = _("changeset %s backed out, "
710 msg = _("changeset %s backed out, "
712 "don't forget to commit.\n")
711 "don't forget to commit.\n")
713 ui.status(msg % short(node))
712 ui.status(msg % short(node))
714 return 0
713 return 0
715
714
716 def commitfunc(ui, repo, message, match, opts):
715 def commitfunc(ui, repo, message, match, opts):
717 editform = 'backout'
716 editform = 'backout'
718 e = cmdutil.getcommiteditor(editform=editform, **opts)
717 e = cmdutil.getcommiteditor(editform=editform, **opts)
719 if not message:
718 if not message:
720 # we don't translate commit messages
719 # we don't translate commit messages
721 message = "Backed out changeset %s" % short(node)
720 message = "Backed out changeset %s" % short(node)
722 e = cmdutil.getcommiteditor(edit=True, editform=editform)
721 e = cmdutil.getcommiteditor(edit=True, editform=editform)
723 return repo.commit(message, opts.get('user'), opts.get('date'),
722 return repo.commit(message, opts.get('user'), opts.get('date'),
724 match, editor=e)
723 match, editor=e)
725 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
724 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
726 if not newnode:
725 if not newnode:
727 ui.status(_("nothing changed\n"))
726 ui.status(_("nothing changed\n"))
728 return 1
727 return 1
729 cmdutil.commitstatus(repo, newnode, branch, bheads)
728 cmdutil.commitstatus(repo, newnode, branch, bheads)
730
729
731 def nice(node):
730 def nice(node):
732 return '%d:%s' % (repo.changelog.rev(node), short(node))
731 return '%d:%s' % (repo.changelog.rev(node), short(node))
733 ui.status(_('changeset %s backs out changeset %s\n') %
732 ui.status(_('changeset %s backs out changeset %s\n') %
734 (nice(repo.changelog.tip()), nice(node)))
733 (nice(repo.changelog.tip()), nice(node)))
735 if opts.get('merge') and op1 != node:
734 if opts.get('merge') and op1 != node:
736 hg.clean(repo, op1, show_stats=False)
735 hg.clean(repo, op1, show_stats=False)
737 ui.status(_('merging with changeset %s\n')
736 ui.status(_('merging with changeset %s\n')
738 % nice(repo.changelog.tip()))
737 % nice(repo.changelog.tip()))
739 try:
738 try:
740 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
739 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
741 'backout')
740 'backout')
742 return hg.merge(repo, hex(repo.changelog.tip()))
741 return hg.merge(repo, hex(repo.changelog.tip()))
743 finally:
742 finally:
744 ui.setconfig('ui', 'forcemerge', '', '')
743 ui.setconfig('ui', 'forcemerge', '', '')
745 return 0
744 return 0
746
745
747 @command('bisect',
746 @command('bisect',
748 [('r', 'reset', False, _('reset bisect state')),
747 [('r', 'reset', False, _('reset bisect state')),
749 ('g', 'good', False, _('mark changeset good')),
748 ('g', 'good', False, _('mark changeset good')),
750 ('b', 'bad', False, _('mark changeset bad')),
749 ('b', 'bad', False, _('mark changeset bad')),
751 ('s', 'skip', False, _('skip testing changeset')),
750 ('s', 'skip', False, _('skip testing changeset')),
752 ('e', 'extend', False, _('extend the bisect range')),
751 ('e', 'extend', False, _('extend the bisect range')),
753 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
752 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
754 ('U', 'noupdate', False, _('do not update to target'))],
753 ('U', 'noupdate', False, _('do not update to target'))],
755 _("[-gbsr] [-U] [-c CMD] [REV]"))
754 _("[-gbsr] [-U] [-c CMD] [REV]"))
756 def bisect(ui, repo, rev=None, extra=None, command=None,
755 def bisect(ui, repo, rev=None, extra=None, command=None,
757 reset=None, good=None, bad=None, skip=None, extend=None,
756 reset=None, good=None, bad=None, skip=None, extend=None,
758 noupdate=None):
757 noupdate=None):
759 """subdivision search of changesets
758 """subdivision search of changesets
760
759
761 This command helps to find changesets which introduce problems. To
760 This command helps to find changesets which introduce problems. To
762 use, mark the earliest changeset you know exhibits the problem as
761 use, mark the earliest changeset you know exhibits the problem as
763 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
764 as good. Bisect will update your working directory to a revision
763 as good. Bisect will update your working directory to a revision
765 for testing (unless the -U/--noupdate option is specified). Once
764 for testing (unless the -U/--noupdate option is specified). Once
766 you have performed tests, mark the working directory as good or
765 you have performed tests, mark the working directory as good or
767 bad, and bisect will either update to another candidate changeset
766 bad, and bisect will either update to another candidate changeset
768 or announce that it has found the bad revision.
767 or announce that it has found the bad revision.
769
768
770 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
771 revision as good or bad without checking it out first.
770 revision as good or bad without checking it out first.
772
771
773 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.
774 The environment variable HG_NODE will contain the ID of the
773 The environment variable HG_NODE will contain the ID of the
775 changeset being tested. The exit status of the command will be
774 changeset being tested. The exit status of the command will be
776 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
777 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
778 bisection, and any other non-zero exit status means the revision
777 bisection, and any other non-zero exit status means the revision
779 is bad.
778 is bad.
780
779
781 .. container:: verbose
780 .. container:: verbose
782
781
783 Some examples:
782 Some examples:
784
783
785 - 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::
786
785
787 hg bisect --bad 34
786 hg bisect --bad 34
788 hg bisect --good 12
787 hg bisect --good 12
789
788
790 - advance the current bisection by marking current revision as good or
789 - advance the current bisection by marking current revision as good or
791 bad::
790 bad::
792
791
793 hg bisect --good
792 hg bisect --good
794 hg bisect --bad
793 hg bisect --bad
795
794
796 - 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
797 that revision is not usable because of another issue)::
796 that revision is not usable because of another issue)::
798
797
799 hg bisect --skip
798 hg bisect --skip
800 hg bisect --skip 23
799 hg bisect --skip 23
801
800
802 - skip all revisions that do not touch directories ``foo`` or ``bar``::
801 - skip all revisions that do not touch directories ``foo`` or ``bar``::
803
802
804 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
803 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
805
804
806 - forget the current bisection::
805 - forget the current bisection::
807
806
808 hg bisect --reset
807 hg bisect --reset
809
808
810 - use 'make && make tests' to automatically find the first broken
809 - use 'make && make tests' to automatically find the first broken
811 revision::
810 revision::
812
811
813 hg bisect --reset
812 hg bisect --reset
814 hg bisect --bad 34
813 hg bisect --bad 34
815 hg bisect --good 12
814 hg bisect --good 12
816 hg bisect --command "make && make tests"
815 hg bisect --command "make && make tests"
817
816
818 - see all changesets whose states are already known in the current
817 - see all changesets whose states are already known in the current
819 bisection::
818 bisection::
820
819
821 hg log -r "bisect(pruned)"
820 hg log -r "bisect(pruned)"
822
821
823 - see the changeset currently being bisected (especially useful
822 - see the changeset currently being bisected (especially useful
824 if running with -U/--noupdate)::
823 if running with -U/--noupdate)::
825
824
826 hg log -r "bisect(current)"
825 hg log -r "bisect(current)"
827
826
828 - see all changesets that took part in the current bisection::
827 - see all changesets that took part in the current bisection::
829
828
830 hg log -r "bisect(range)"
829 hg log -r "bisect(range)"
831
830
832 - you can even get a nice graph::
831 - you can even get a nice graph::
833
832
834 hg log --graph -r "bisect(range)"
833 hg log --graph -r "bisect(range)"
835
834
836 See :hg:`help revsets` for more about the `bisect()` keyword.
835 See :hg:`help revsets` for more about the `bisect()` keyword.
837
836
838 Returns 0 on success.
837 Returns 0 on success.
839 """
838 """
840 # backward compatibility
839 # backward compatibility
841 if rev in "good bad reset init".split():
840 if rev in "good bad reset init".split():
842 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
841 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
843 cmd, rev, extra = rev, extra, None
842 cmd, rev, extra = rev, extra, None
844 if cmd == "good":
843 if cmd == "good":
845 good = True
844 good = True
846 elif cmd == "bad":
845 elif cmd == "bad":
847 bad = True
846 bad = True
848 else:
847 else:
849 reset = True
848 reset = True
850 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
849 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
851 raise error.Abort(_('incompatible arguments'))
850 raise error.Abort(_('incompatible arguments'))
852
851
853 cmdutil.checkunfinished(repo)
852 cmdutil.checkunfinished(repo)
854
853
855 if reset:
854 if reset:
856 hbisect.resetstate(repo)
855 hbisect.resetstate(repo)
857 return
856 return
858
857
859 state = hbisect.load_state(repo)
858 state = hbisect.load_state(repo)
860
859
861 # update state
860 # update state
862 if good or bad or skip:
861 if good or bad or skip:
863 if rev:
862 if rev:
864 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
863 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
865 else:
864 else:
866 nodes = [repo.lookup('.')]
865 nodes = [repo.lookup('.')]
867 if good:
866 if good:
868 state['good'] += nodes
867 state['good'] += nodes
869 elif bad:
868 elif bad:
870 state['bad'] += nodes
869 state['bad'] += nodes
871 elif skip:
870 elif skip:
872 state['skip'] += nodes
871 state['skip'] += nodes
873 hbisect.save_state(repo, state)
872 hbisect.save_state(repo, state)
874 if not (state['good'] and state['bad']):
873 if not (state['good'] and state['bad']):
875 return
874 return
876
875
877 def mayupdate(repo, node, show_stats=True):
876 def mayupdate(repo, node, show_stats=True):
878 """common used update sequence"""
877 """common used update sequence"""
879 if noupdate:
878 if noupdate:
880 return
879 return
881 cmdutil.bailifchanged(repo)
880 cmdutil.bailifchanged(repo)
882 return hg.clean(repo, node, show_stats=show_stats)
881 return hg.clean(repo, node, show_stats=show_stats)
883
882
884 displayer = cmdutil.show_changeset(ui, repo, {})
883 displayer = cmdutil.show_changeset(ui, repo, {})
885
884
886 if command:
885 if command:
887 changesets = 1
886 changesets = 1
888 if noupdate:
887 if noupdate:
889 try:
888 try:
890 node = state['current'][0]
889 node = state['current'][0]
891 except LookupError:
890 except LookupError:
892 raise error.Abort(_('current bisect revision is unknown - '
891 raise error.Abort(_('current bisect revision is unknown - '
893 'start a new bisect to fix'))
892 'start a new bisect to fix'))
894 else:
893 else:
895 node, p2 = repo.dirstate.parents()
894 node, p2 = repo.dirstate.parents()
896 if p2 != nullid:
895 if p2 != nullid:
897 raise error.Abort(_('current bisect revision is a merge'))
896 raise error.Abort(_('current bisect revision is a merge'))
898 if rev:
897 if rev:
899 node = repo[scmutil.revsingle(repo, rev, node)].node()
898 node = repo[scmutil.revsingle(repo, rev, node)].node()
900 try:
899 try:
901 while changesets:
900 while changesets:
902 # update state
901 # update state
903 state['current'] = [node]
902 state['current'] = [node]
904 hbisect.save_state(repo, state)
903 hbisect.save_state(repo, state)
905 status = ui.system(command, environ={'HG_NODE': hex(node)})
904 status = ui.system(command, environ={'HG_NODE': hex(node)})
906 if status == 125:
905 if status == 125:
907 transition = "skip"
906 transition = "skip"
908 elif status == 0:
907 elif status == 0:
909 transition = "good"
908 transition = "good"
910 # status < 0 means process was killed
909 # status < 0 means process was killed
911 elif status == 127:
910 elif status == 127:
912 raise error.Abort(_("failed to execute %s") % command)
911 raise error.Abort(_("failed to execute %s") % command)
913 elif status < 0:
912 elif status < 0:
914 raise error.Abort(_("%s killed") % command)
913 raise error.Abort(_("%s killed") % command)
915 else:
914 else:
916 transition = "bad"
915 transition = "bad"
917 state[transition].append(node)
916 state[transition].append(node)
918 ctx = repo[node]
917 ctx = repo[node]
919 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
918 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
920 hbisect.checkstate(state)
919 hbisect.checkstate(state)
921 # bisect
920 # bisect
922 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
921 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
923 # update to next check
922 # update to next check
924 node = nodes[0]
923 node = nodes[0]
925 mayupdate(repo, node, show_stats=False)
924 mayupdate(repo, node, show_stats=False)
926 finally:
925 finally:
927 state['current'] = [node]
926 state['current'] = [node]
928 hbisect.save_state(repo, state)
927 hbisect.save_state(repo, state)
929 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
928 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
930 return
929 return
931
930
932 hbisect.checkstate(state)
931 hbisect.checkstate(state)
933
932
934 # actually bisect
933 # actually bisect
935 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
934 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
936 if extend:
935 if extend:
937 if not changesets:
936 if not changesets:
938 extendnode = hbisect.extendrange(repo, state, nodes, good)
937 extendnode = hbisect.extendrange(repo, state, nodes, good)
939 if extendnode is not None:
938 if extendnode is not None:
940 ui.write(_("Extending search to changeset %d:%s\n")
939 ui.write(_("Extending search to changeset %d:%s\n")
941 % (extendnode.rev(), extendnode))
940 % (extendnode.rev(), extendnode))
942 state['current'] = [extendnode.node()]
941 state['current'] = [extendnode.node()]
943 hbisect.save_state(repo, state)
942 hbisect.save_state(repo, state)
944 return mayupdate(repo, extendnode.node())
943 return mayupdate(repo, extendnode.node())
945 raise error.Abort(_("nothing to extend"))
944 raise error.Abort(_("nothing to extend"))
946
945
947 if changesets == 0:
946 if changesets == 0:
948 hbisect.printresult(ui, repo, state, displayer, nodes, good)
947 hbisect.printresult(ui, repo, state, displayer, nodes, good)
949 else:
948 else:
950 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
951 node = nodes[0]
950 node = nodes[0]
952 # compute the approximate number of remaining tests
951 # compute the approximate number of remaining tests
953 tests, size = 0, 2
952 tests, size = 0, 2
954 while size <= changesets:
953 while size <= changesets:
955 tests, size = tests + 1, size * 2
954 tests, size = tests + 1, size * 2
956 rev = repo.changelog.rev(node)
955 rev = repo.changelog.rev(node)
957 ui.write(_("Testing changeset %d:%s "
956 ui.write(_("Testing changeset %d:%s "
958 "(%d changesets remaining, ~%d tests)\n")
957 "(%d changesets remaining, ~%d tests)\n")
959 % (rev, short(node), changesets, tests))
958 % (rev, short(node), changesets, tests))
960 state['current'] = [node]
959 state['current'] = [node]
961 hbisect.save_state(repo, state)
960 hbisect.save_state(repo, state)
962 return mayupdate(repo, node)
961 return mayupdate(repo, node)
963
962
964 @command('bookmarks|bookmark',
963 @command('bookmarks|bookmark',
965 [('f', 'force', False, _('force')),
964 [('f', 'force', False, _('force')),
966 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
965 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
967 ('d', 'delete', False, _('delete a given bookmark')),
966 ('d', 'delete', False, _('delete a given bookmark')),
968 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
967 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
969 ('i', 'inactive', False, _('mark a bookmark inactive')),
968 ('i', 'inactive', False, _('mark a bookmark inactive')),
970 ] + formatteropts,
969 ] + formatteropts,
971 _('hg bookmarks [OPTIONS]... [NAME]...'))
970 _('hg bookmarks [OPTIONS]... [NAME]...'))
972 def bookmark(ui, repo, *names, **opts):
971 def bookmark(ui, repo, *names, **opts):
973 '''create a new bookmark or list existing bookmarks
972 '''create a new bookmark or list existing bookmarks
974
973
975 Bookmarks are labels on changesets to help track lines of development.
974 Bookmarks are labels on changesets to help track lines of development.
976 Bookmarks are unversioned and can be moved, renamed and deleted.
975 Bookmarks are unversioned and can be moved, renamed and deleted.
977 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.
978
977
979 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'.
980 The active bookmark is indicated with a '*'.
979 The active bookmark is indicated with a '*'.
981 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.
982 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.
983 Updating away from a bookmark will cause it to be deactivated.
982 Updating away from a bookmark will cause it to be deactivated.
984
983
985 Bookmarks can be pushed and pulled between repositories (see
984 Bookmarks can be pushed and pulled between repositories (see
986 :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
987 diverged, a new 'divergent bookmark' of the form 'name@path' will
986 diverged, a new 'divergent bookmark' of the form 'name@path' will
988 be created. Using :hg:`merge` will resolve the divergence.
987 be created. Using :hg:`merge` will resolve the divergence.
989
988
990 A bookmark named '@' has the special property that :hg:`clone` will
989 A bookmark named '@' has the special property that :hg:`clone` will
991 check it out by default if it exists.
990 check it out by default if it exists.
992
991
993 .. container:: verbose
992 .. container:: verbose
994
993
995 Examples:
994 Examples:
996
995
997 - create an active bookmark for a new line of development::
996 - create an active bookmark for a new line of development::
998
997
999 hg book new-feature
998 hg book new-feature
1000
999
1001 - create an inactive bookmark as a place marker::
1000 - create an inactive bookmark as a place marker::
1002
1001
1003 hg book -i reviewed
1002 hg book -i reviewed
1004
1003
1005 - create an inactive bookmark on another changeset::
1004 - create an inactive bookmark on another changeset::
1006
1005
1007 hg book -r .^ tested
1006 hg book -r .^ tested
1008
1007
1009 - rename bookmark turkey to dinner::
1008 - rename bookmark turkey to dinner::
1010
1009
1011 hg book -m turkey dinner
1010 hg book -m turkey dinner
1012
1011
1013 - move the '@' bookmark from another branch::
1012 - move the '@' bookmark from another branch::
1014
1013
1015 hg book -f @
1014 hg book -f @
1016 '''
1015 '''
1017 force = opts.get('force')
1016 force = opts.get('force')
1018 rev = opts.get('rev')
1017 rev = opts.get('rev')
1019 delete = opts.get('delete')
1018 delete = opts.get('delete')
1020 rename = opts.get('rename')
1019 rename = opts.get('rename')
1021 inactive = opts.get('inactive')
1020 inactive = opts.get('inactive')
1022
1021
1023 def checkformat(mark):
1022 def checkformat(mark):
1024 mark = mark.strip()
1023 mark = mark.strip()
1025 if not mark:
1024 if not mark:
1026 raise error.Abort(_("bookmark names cannot consist entirely of "
1025 raise error.Abort(_("bookmark names cannot consist entirely of "
1027 "whitespace"))
1026 "whitespace"))
1028 scmutil.checknewlabel(repo, mark, 'bookmark')
1027 scmutil.checknewlabel(repo, mark, 'bookmark')
1029 return mark
1028 return mark
1030
1029
1031 def checkconflict(repo, mark, cur, force=False, target=None):
1030 def checkconflict(repo, mark, cur, force=False, target=None):
1032 if mark in marks and not force:
1031 if mark in marks and not force:
1033 if target:
1032 if target:
1034 if marks[mark] == target and target == cur:
1033 if marks[mark] == target and target == cur:
1035 # re-activating a bookmark
1034 # re-activating a bookmark
1036 return
1035 return
1037 anc = repo.changelog.ancestors([repo[target].rev()])
1036 anc = repo.changelog.ancestors([repo[target].rev()])
1038 bmctx = repo[marks[mark]]
1037 bmctx = repo[marks[mark]]
1039 divs = [repo[b].node() for b in marks
1038 divs = [repo[b].node() for b in marks
1040 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1039 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1041
1040
1042 # allow resolving a single divergent bookmark even if moving
1041 # allow resolving a single divergent bookmark even if moving
1043 # the bookmark across branches when a revision is specified
1042 # the bookmark across branches when a revision is specified
1044 # that contains a divergent bookmark
1043 # that contains a divergent bookmark
1045 if bmctx.rev() not in anc and target in divs:
1044 if bmctx.rev() not in anc and target in divs:
1046 bookmarks.deletedivergent(repo, [target], mark)
1045 bookmarks.deletedivergent(repo, [target], mark)
1047 return
1046 return
1048
1047
1049 deletefrom = [b for b in divs
1048 deletefrom = [b for b in divs
1050 if repo[b].rev() in anc or b == target]
1049 if repo[b].rev() in anc or b == target]
1051 bookmarks.deletedivergent(repo, deletefrom, mark)
1050 bookmarks.deletedivergent(repo, deletefrom, mark)
1052 if bookmarks.validdest(repo, bmctx, repo[target]):
1051 if bookmarks.validdest(repo, bmctx, repo[target]):
1053 ui.status(_("moving bookmark '%s' forward from %s\n") %
1052 ui.status(_("moving bookmark '%s' forward from %s\n") %
1054 (mark, short(bmctx.node())))
1053 (mark, short(bmctx.node())))
1055 return
1054 return
1056 raise error.Abort(_("bookmark '%s' already exists "
1055 raise error.Abort(_("bookmark '%s' already exists "
1057 "(use -f to force)") % mark)
1056 "(use -f to force)") % mark)
1058 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1057 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1059 and not force):
1058 and not force):
1060 raise error.Abort(
1059 raise error.Abort(
1061 _("a bookmark cannot have the name of an existing branch"))
1060 _("a bookmark cannot have the name of an existing branch"))
1062
1061
1063 if delete and rename:
1062 if delete and rename:
1064 raise error.Abort(_("--delete and --rename are incompatible"))
1063 raise error.Abort(_("--delete and --rename are incompatible"))
1065 if delete and rev:
1064 if delete and rev:
1066 raise error.Abort(_("--rev is incompatible with --delete"))
1065 raise error.Abort(_("--rev is incompatible with --delete"))
1067 if rename and rev:
1066 if rename and rev:
1068 raise error.Abort(_("--rev is incompatible with --rename"))
1067 raise error.Abort(_("--rev is incompatible with --rename"))
1069 if not names and (delete or rev):
1068 if not names and (delete or rev):
1070 raise error.Abort(_("bookmark name required"))
1069 raise error.Abort(_("bookmark name required"))
1071
1070
1072 if delete or rename or names or inactive:
1071 if delete or rename or names or inactive:
1073 wlock = lock = tr = None
1072 wlock = lock = tr = None
1074 try:
1073 try:
1075 wlock = repo.wlock()
1074 wlock = repo.wlock()
1076 lock = repo.lock()
1075 lock = repo.lock()
1077 cur = repo.changectx('.').node()
1076 cur = repo.changectx('.').node()
1078 marks = repo._bookmarks
1077 marks = repo._bookmarks
1079 if delete:
1078 if delete:
1080 tr = repo.transaction('bookmark')
1079 tr = repo.transaction('bookmark')
1081 for mark in names:
1080 for mark in names:
1082 if mark not in marks:
1081 if mark not in marks:
1083 raise error.Abort(_("bookmark '%s' does not exist") %
1082 raise error.Abort(_("bookmark '%s' does not exist") %
1084 mark)
1083 mark)
1085 if mark == repo._activebookmark:
1084 if mark == repo._activebookmark:
1086 bookmarks.deactivate(repo)
1085 bookmarks.deactivate(repo)
1087 del marks[mark]
1086 del marks[mark]
1088
1087
1089 elif rename:
1088 elif rename:
1090 tr = repo.transaction('bookmark')
1089 tr = repo.transaction('bookmark')
1091 if not names:
1090 if not names:
1092 raise error.Abort(_("new bookmark name required"))
1091 raise error.Abort(_("new bookmark name required"))
1093 elif len(names) > 1:
1092 elif len(names) > 1:
1094 raise error.Abort(_("only one new bookmark name allowed"))
1093 raise error.Abort(_("only one new bookmark name allowed"))
1095 mark = checkformat(names[0])
1094 mark = checkformat(names[0])
1096 if rename not in marks:
1095 if rename not in marks:
1097 raise error.Abort(_("bookmark '%s' does not exist")
1096 raise error.Abort(_("bookmark '%s' does not exist")
1098 % rename)
1097 % rename)
1099 checkconflict(repo, mark, cur, force)
1098 checkconflict(repo, mark, cur, force)
1100 marks[mark] = marks[rename]
1099 marks[mark] = marks[rename]
1101 if repo._activebookmark == rename and not inactive:
1100 if repo._activebookmark == rename and not inactive:
1102 bookmarks.activate(repo, mark)
1101 bookmarks.activate(repo, mark)
1103 del marks[rename]
1102 del marks[rename]
1104 elif names:
1103 elif names:
1105 tr = repo.transaction('bookmark')
1104 tr = repo.transaction('bookmark')
1106 newact = None
1105 newact = None
1107 for mark in names:
1106 for mark in names:
1108 mark = checkformat(mark)
1107 mark = checkformat(mark)
1109 if newact is None:
1108 if newact is None:
1110 newact = mark
1109 newact = mark
1111 if inactive and mark == repo._activebookmark:
1110 if inactive and mark == repo._activebookmark:
1112 bookmarks.deactivate(repo)
1111 bookmarks.deactivate(repo)
1113 return
1112 return
1114 tgt = cur
1113 tgt = cur
1115 if rev:
1114 if rev:
1116 tgt = scmutil.revsingle(repo, rev).node()
1115 tgt = scmutil.revsingle(repo, rev).node()
1117 checkconflict(repo, mark, cur, force, tgt)
1116 checkconflict(repo, mark, cur, force, tgt)
1118 marks[mark] = tgt
1117 marks[mark] = tgt
1119 if not inactive and cur == marks[newact] and not rev:
1118 if not inactive and cur == marks[newact] and not rev:
1120 bookmarks.activate(repo, newact)
1119 bookmarks.activate(repo, newact)
1121 elif cur != tgt and newact == repo._activebookmark:
1120 elif cur != tgt and newact == repo._activebookmark:
1122 bookmarks.deactivate(repo)
1121 bookmarks.deactivate(repo)
1123 elif inactive:
1122 elif inactive:
1124 if len(marks) == 0:
1123 if len(marks) == 0:
1125 ui.status(_("no bookmarks set\n"))
1124 ui.status(_("no bookmarks set\n"))
1126 elif not repo._activebookmark:
1125 elif not repo._activebookmark:
1127 ui.status(_("no active bookmark\n"))
1126 ui.status(_("no active bookmark\n"))
1128 else:
1127 else:
1129 bookmarks.deactivate(repo)
1128 bookmarks.deactivate(repo)
1130 if tr is not None:
1129 if tr is not None:
1131 marks.recordchange(tr)
1130 marks.recordchange(tr)
1132 tr.close()
1131 tr.close()
1133 finally:
1132 finally:
1134 lockmod.release(tr, lock, wlock)
1133 lockmod.release(tr, lock, wlock)
1135 else: # show bookmarks
1134 else: # show bookmarks
1136 fm = ui.formatter('bookmarks', opts)
1135 fm = ui.formatter('bookmarks', opts)
1137 hexfn = fm.hexfunc
1136 hexfn = fm.hexfunc
1138 marks = repo._bookmarks
1137 marks = repo._bookmarks
1139 if len(marks) == 0 and fm.isplain():
1138 if len(marks) == 0 and fm.isplain():
1140 ui.status(_("no bookmarks set\n"))
1139 ui.status(_("no bookmarks set\n"))
1141 for bmark, n in sorted(marks.iteritems()):
1140 for bmark, n in sorted(marks.iteritems()):
1142 active = repo._activebookmark
1141 active = repo._activebookmark
1143 if bmark == active:
1142 if bmark == active:
1144 prefix, label = '*', activebookmarklabel
1143 prefix, label = '*', activebookmarklabel
1145 else:
1144 else:
1146 prefix, label = ' ', ''
1145 prefix, label = ' ', ''
1147
1146
1148 fm.startitem()
1147 fm.startitem()
1149 if not ui.quiet:
1148 if not ui.quiet:
1150 fm.plain(' %s ' % prefix, label=label)
1149 fm.plain(' %s ' % prefix, label=label)
1151 fm.write('bookmark', '%s', bmark, label=label)
1150 fm.write('bookmark', '%s', bmark, label=label)
1152 pad = " " * (25 - encoding.colwidth(bmark))
1151 pad = " " * (25 - encoding.colwidth(bmark))
1153 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1152 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1154 repo.changelog.rev(n), hexfn(n), label=label)
1153 repo.changelog.rev(n), hexfn(n), label=label)
1155 fm.data(active=(bmark == active))
1154 fm.data(active=(bmark == active))
1156 fm.plain('\n')
1155 fm.plain('\n')
1157 fm.end()
1156 fm.end()
1158
1157
1159 @command('branch',
1158 @command('branch',
1160 [('f', 'force', None,
1159 [('f', 'force', None,
1161 _('set branch name even if it shadows an existing branch')),
1160 _('set branch name even if it shadows an existing branch')),
1162 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1161 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1163 _('[-fC] [NAME]'))
1162 _('[-fC] [NAME]'))
1164 def branch(ui, repo, label=None, **opts):
1163 def branch(ui, repo, label=None, **opts):
1165 """set or show the current branch name
1164 """set or show the current branch name
1166
1165
1167 .. note::
1166 .. note::
1168
1167
1169 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
1170 light-weight bookmark instead. See :hg:`help glossary` for more
1169 light-weight bookmark instead. See :hg:`help glossary` for more
1171 information about named branches and bookmarks.
1170 information about named branches and bookmarks.
1172
1171
1173 With no argument, show the current branch name. With one argument,
1172 With no argument, show the current branch name. With one argument,
1174 set the working directory branch name (the branch will not exist
1173 set the working directory branch name (the branch will not exist
1175 in the repository until the next commit). Standard practice
1174 in the repository until the next commit). Standard practice
1176 recommends that primary development take place on the 'default'
1175 recommends that primary development take place on the 'default'
1177 branch.
1176 branch.
1178
1177
1179 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
1180 branch name that already exists.
1179 branch name that already exists.
1181
1180
1182 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
1183 the parent of the working directory, negating a previous branch
1182 the parent of the working directory, negating a previous branch
1184 change.
1183 change.
1185
1184
1186 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
1187 :hg:`commit --close-branch` to mark this branch head as closed.
1186 :hg:`commit --close-branch` to mark this branch head as closed.
1188 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
1189 considered closed.
1188 considered closed.
1190
1189
1191 Returns 0 on success.
1190 Returns 0 on success.
1192 """
1191 """
1193 if label:
1192 if label:
1194 label = label.strip()
1193 label = label.strip()
1195
1194
1196 if not opts.get('clean') and not label:
1195 if not opts.get('clean') and not label:
1197 ui.write("%s\n" % repo.dirstate.branch())
1196 ui.write("%s\n" % repo.dirstate.branch())
1198 return
1197 return
1199
1198
1200 with repo.wlock():
1199 with repo.wlock():
1201 if opts.get('clean'):
1200 if opts.get('clean'):
1202 label = repo[None].p1().branch()
1201 label = repo[None].p1().branch()
1203 repo.dirstate.setbranch(label)
1202 repo.dirstate.setbranch(label)
1204 ui.status(_('reset working directory to branch %s\n') % label)
1203 ui.status(_('reset working directory to branch %s\n') % label)
1205 elif label:
1204 elif label:
1206 if not opts.get('force') and label in repo.branchmap():
1205 if not opts.get('force') and label in repo.branchmap():
1207 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()]:
1208 raise error.Abort(_('a branch of the same name already'
1207 raise error.Abort(_('a branch of the same name already'
1209 ' exists'),
1208 ' exists'),
1210 # i18n: "it" refers to an existing branch
1209 # i18n: "it" refers to an existing branch
1211 hint=_("use 'hg update' to switch to it"))
1210 hint=_("use 'hg update' to switch to it"))
1212 scmutil.checknewlabel(repo, label, 'branch')
1211 scmutil.checknewlabel(repo, label, 'branch')
1213 repo.dirstate.setbranch(label)
1212 repo.dirstate.setbranch(label)
1214 ui.status(_('marked working directory as branch %s\n') % label)
1213 ui.status(_('marked working directory as branch %s\n') % label)
1215
1214
1216 # find any open named branches aside from default
1215 # find any open named branches aside from default
1217 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1216 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1218 if n != "default" and not c]
1217 if n != "default" and not c]
1219 if not others:
1218 if not others:
1220 ui.status(_('(branches are permanent and global, '
1219 ui.status(_('(branches are permanent and global, '
1221 'did you want a bookmark?)\n'))
1220 'did you want a bookmark?)\n'))
1222
1221
1223 @command('branches',
1222 @command('branches',
1224 [('a', 'active', False,
1223 [('a', 'active', False,
1225 _('show only branches that have unmerged heads (DEPRECATED)')),
1224 _('show only branches that have unmerged heads (DEPRECATED)')),
1226 ('c', 'closed', False, _('show normal and closed branches')),
1225 ('c', 'closed', False, _('show normal and closed branches')),
1227 ] + formatteropts,
1226 ] + formatteropts,
1228 _('[-c]'))
1227 _('[-c]'))
1229 def branches(ui, repo, active=False, closed=False, **opts):
1228 def branches(ui, repo, active=False, closed=False, **opts):
1230 """list repository named branches
1229 """list repository named branches
1231
1230
1232 List the repository's named branches, indicating which ones are
1231 List the repository's named branches, indicating which ones are
1233 inactive. If -c/--closed is specified, also list branches which have
1232 inactive. If -c/--closed is specified, also list branches which have
1234 been marked closed (see :hg:`commit --close-branch`).
1233 been marked closed (see :hg:`commit --close-branch`).
1235
1234
1236 Use the command :hg:`update` to switch to an existing branch.
1235 Use the command :hg:`update` to switch to an existing branch.
1237
1236
1238 Returns 0.
1237 Returns 0.
1239 """
1238 """
1240
1239
1241 fm = ui.formatter('branches', opts)
1240 fm = ui.formatter('branches', opts)
1242 hexfunc = fm.hexfunc
1241 hexfunc = fm.hexfunc
1243
1242
1244 allheads = set(repo.heads())
1243 allheads = set(repo.heads())
1245 branches = []
1244 branches = []
1246 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1245 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1247 isactive = not isclosed and bool(set(heads) & allheads)
1246 isactive = not isclosed and bool(set(heads) & allheads)
1248 branches.append((tag, repo[tip], isactive, not isclosed))
1247 branches.append((tag, repo[tip], isactive, not isclosed))
1249 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]),
1250 reverse=True)
1249 reverse=True)
1251
1250
1252 for tag, ctx, isactive, isopen in branches:
1251 for tag, ctx, isactive, isopen in branches:
1253 if active and not isactive:
1252 if active and not isactive:
1254 continue
1253 continue
1255 if isactive:
1254 if isactive:
1256 label = 'branches.active'
1255 label = 'branches.active'
1257 notice = ''
1256 notice = ''
1258 elif not isopen:
1257 elif not isopen:
1259 if not closed:
1258 if not closed:
1260 continue
1259 continue
1261 label = 'branches.closed'
1260 label = 'branches.closed'
1262 notice = _(' (closed)')
1261 notice = _(' (closed)')
1263 else:
1262 else:
1264 label = 'branches.inactive'
1263 label = 'branches.inactive'
1265 notice = _(' (inactive)')
1264 notice = _(' (inactive)')
1266 current = (tag == repo.dirstate.branch())
1265 current = (tag == repo.dirstate.branch())
1267 if current:
1266 if current:
1268 label = 'branches.current'
1267 label = 'branches.current'
1269
1268
1270 fm.startitem()
1269 fm.startitem()
1271 fm.write('branch', '%s', tag, label=label)
1270 fm.write('branch', '%s', tag, label=label)
1272 rev = ctx.rev()
1271 rev = ctx.rev()
1273 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1272 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1274 fmt = ' ' * padsize + ' %d:%s'
1273 fmt = ' ' * padsize + ' %d:%s'
1275 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()),
1276 label='log.changeset changeset.%s' % ctx.phasestr())
1275 label='log.changeset changeset.%s' % ctx.phasestr())
1277 fm.data(active=isactive, closed=not isopen, current=current)
1276 fm.data(active=isactive, closed=not isopen, current=current)
1278 if not ui.quiet:
1277 if not ui.quiet:
1279 fm.plain(notice)
1278 fm.plain(notice)
1280 fm.plain('\n')
1279 fm.plain('\n')
1281 fm.end()
1280 fm.end()
1282
1281
1283 @command('bundle',
1282 @command('bundle',
1284 [('f', 'force', None, _('run even when the destination is unrelated')),
1283 [('f', 'force', None, _('run even when the destination is unrelated')),
1285 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1284 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1286 _('REV')),
1285 _('REV')),
1287 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1286 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1288 _('BRANCH')),
1287 _('BRANCH')),
1289 ('', 'base', [],
1288 ('', 'base', [],
1290 _('a base changeset assumed to be available at the destination'),
1289 _('a base changeset assumed to be available at the destination'),
1291 _('REV')),
1290 _('REV')),
1292 ('a', 'all', None, _('bundle all changesets in the repository')),
1291 ('a', 'all', None, _('bundle all changesets in the repository')),
1293 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1292 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1294 ] + remoteopts,
1293 ] + remoteopts,
1295 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1294 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1296 def bundle(ui, repo, fname, dest=None, **opts):
1295 def bundle(ui, repo, fname, dest=None, **opts):
1297 """create a changegroup file
1296 """create a changegroup file
1298
1297
1299 Generate a changegroup file collecting changesets to be added
1298 Generate a changegroup file collecting changesets to be added
1300 to a repository.
1299 to a repository.
1301
1300
1302 To create a bundle containing all changesets, use -a/--all
1301 To create a bundle containing all changesets, use -a/--all
1303 (or --base null). Otherwise, hg assumes the destination will have
1302 (or --base null). Otherwise, hg assumes the destination will have
1304 all the nodes you specify with --base parameters. Otherwise, hg
1303 all the nodes you specify with --base parameters. Otherwise, hg
1305 will assume the repository has all the nodes in destination, or
1304 will assume the repository has all the nodes in destination, or
1306 default-push/default if no destination is specified.
1305 default-push/default if no destination is specified.
1307
1306
1308 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
1309 specify a compression, a bundle version or both using a dash
1308 specify a compression, a bundle version or both using a dash
1310 (comp-version). The available compression methods are: none, bzip2,
1309 (comp-version). The available compression methods are: none, bzip2,
1311 and gzip (by default, bundles are compressed using bzip2). The
1310 and gzip (by default, bundles are compressed using bzip2). The
1312 available formats are: v1, v2 (default to most suitable).
1311 available formats are: v1, v2 (default to most suitable).
1313
1312
1314 The bundle file can then be transferred using conventional means
1313 The bundle file can then be transferred using conventional means
1315 and applied to another repository with the unbundle or pull
1314 and applied to another repository with the unbundle or pull
1316 command. This is useful when direct push and pull are not
1315 command. This is useful when direct push and pull are not
1317 available or when exporting an entire repository is undesirable.
1316 available or when exporting an entire repository is undesirable.
1318
1317
1319 Applying bundles preserves all changeset contents including
1318 Applying bundles preserves all changeset contents including
1320 permissions, copy/rename information, and revision history.
1319 permissions, copy/rename information, and revision history.
1321
1320
1322 Returns 0 on success, 1 if no changes found.
1321 Returns 0 on success, 1 if no changes found.
1323 """
1322 """
1324 revs = None
1323 revs = None
1325 if 'rev' in opts:
1324 if 'rev' in opts:
1326 revstrings = opts['rev']
1325 revstrings = opts['rev']
1327 revs = scmutil.revrange(repo, revstrings)
1326 revs = scmutil.revrange(repo, revstrings)
1328 if revstrings and not revs:
1327 if revstrings and not revs:
1329 raise error.Abort(_('no commits to bundle'))
1328 raise error.Abort(_('no commits to bundle'))
1330
1329
1331 bundletype = opts.get('type', 'bzip2').lower()
1330 bundletype = opts.get('type', 'bzip2').lower()
1332 try:
1331 try:
1333 bcompression, cgversion, params = exchange.parsebundlespec(
1332 bcompression, cgversion, params = exchange.parsebundlespec(
1334 repo, bundletype, strict=False)
1333 repo, bundletype, strict=False)
1335 except error.UnsupportedBundleSpecification as e:
1334 except error.UnsupportedBundleSpecification as e:
1336 raise error.Abort(str(e),
1335 raise error.Abort(str(e),
1337 hint=_("see 'hg help bundle' for supported "
1336 hint=_("see 'hg help bundle' for supported "
1338 "values for --type"))
1337 "values for --type"))
1339
1338
1340 # Packed bundles are a pseudo bundle format for now.
1339 # Packed bundles are a pseudo bundle format for now.
1341 if cgversion == 's1':
1340 if cgversion == 's1':
1342 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1341 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1343 hint=_("use 'hg debugcreatestreamclonebundle'"))
1342 hint=_("use 'hg debugcreatestreamclonebundle'"))
1344
1343
1345 if opts.get('all'):
1344 if opts.get('all'):
1346 if dest:
1345 if dest:
1347 raise error.Abort(_("--all is incompatible with specifying "
1346 raise error.Abort(_("--all is incompatible with specifying "
1348 "a destination"))
1347 "a destination"))
1349 if opts.get('base'):
1348 if opts.get('base'):
1350 ui.warn(_("ignoring --base because --all was specified\n"))
1349 ui.warn(_("ignoring --base because --all was specified\n"))
1351 base = ['null']
1350 base = ['null']
1352 else:
1351 else:
1353 base = scmutil.revrange(repo, opts.get('base'))
1352 base = scmutil.revrange(repo, opts.get('base'))
1354 # TODO: get desired bundlecaps from command line.
1353 # TODO: get desired bundlecaps from command line.
1355 bundlecaps = None
1354 bundlecaps = None
1356 if cgversion not in changegroup.supportedoutgoingversions(repo):
1355 if cgversion not in changegroup.supportedoutgoingversions(repo):
1357 raise error.Abort(_("repository does not support bundle version %s") %
1356 raise error.Abort(_("repository does not support bundle version %s") %
1358 cgversion)
1357 cgversion)
1359
1358
1360 if base:
1359 if base:
1361 if dest:
1360 if dest:
1362 raise error.Abort(_("--base is incompatible with specifying "
1361 raise error.Abort(_("--base is incompatible with specifying "
1363 "a destination"))
1362 "a destination"))
1364 common = [repo.lookup(rev) for rev in base]
1363 common = [repo.lookup(rev) for rev in base]
1365 heads = revs and map(repo.lookup, revs) or None
1364 heads = revs and map(repo.lookup, revs) or None
1366 outgoing = discovery.outgoing(repo, common, heads)
1365 outgoing = discovery.outgoing(repo, common, heads)
1367 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1366 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1368 bundlecaps=bundlecaps,
1367 bundlecaps=bundlecaps,
1369 version=cgversion)
1368 version=cgversion)
1370 outgoing = None
1369 outgoing = None
1371 else:
1370 else:
1372 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1371 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1373 dest, branches = hg.parseurl(dest, opts.get('branch'))
1372 dest, branches = hg.parseurl(dest, opts.get('branch'))
1374 other = hg.peer(repo, opts, dest)
1373 other = hg.peer(repo, opts, dest)
1375 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1374 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1376 heads = revs and map(repo.lookup, revs) or revs
1375 heads = revs and map(repo.lookup, revs) or revs
1377 outgoing = discovery.findcommonoutgoing(repo, other,
1376 outgoing = discovery.findcommonoutgoing(repo, other,
1378 onlyheads=heads,
1377 onlyheads=heads,
1379 force=opts.get('force'),
1378 force=opts.get('force'),
1380 portable=True)
1379 portable=True)
1381 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1380 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1382 bundlecaps, version=cgversion)
1381 bundlecaps, version=cgversion)
1383 if not cg:
1382 if not cg:
1384 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1383 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1385 return 1
1384 return 1
1386
1385
1387 if cgversion == '01': #bundle1
1386 if cgversion == '01': #bundle1
1388 if bcompression is None:
1387 if bcompression is None:
1389 bcompression = 'UN'
1388 bcompression = 'UN'
1390 bversion = 'HG10' + bcompression
1389 bversion = 'HG10' + bcompression
1391 bcompression = None
1390 bcompression = None
1392 else:
1391 else:
1393 assert cgversion == '02'
1392 assert cgversion == '02'
1394 bversion = 'HG20'
1393 bversion = 'HG20'
1395
1394
1396 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1395 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1397
1396
1398 @command('cat',
1397 @command('cat',
1399 [('o', 'output', '',
1398 [('o', 'output', '',
1400 _('print output to file with formatted name'), _('FORMAT')),
1399 _('print output to file with formatted name'), _('FORMAT')),
1401 ('r', 'rev', '', _('print the given revision'), _('REV')),
1400 ('r', 'rev', '', _('print the given revision'), _('REV')),
1402 ('', 'decode', None, _('apply any matching decode filter')),
1401 ('', 'decode', None, _('apply any matching decode filter')),
1403 ] + walkopts,
1402 ] + walkopts,
1404 _('[OPTION]... FILE...'),
1403 _('[OPTION]... FILE...'),
1405 inferrepo=True)
1404 inferrepo=True)
1406 def cat(ui, repo, file1, *pats, **opts):
1405 def cat(ui, repo, file1, *pats, **opts):
1407 """output the current or given revision of files
1406 """output the current or given revision of files
1408
1407
1409 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
1410 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.
1411
1410
1412 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
1413 given using a format string. The formatting rules as follows:
1412 given using a format string. The formatting rules as follows:
1414
1413
1415 :``%%``: literal "%" character
1414 :``%%``: literal "%" character
1416 :``%s``: basename of file being printed
1415 :``%s``: basename of file being printed
1417 :``%d``: dirname of file being printed, or '.' if in repository root
1416 :``%d``: dirname of file being printed, or '.' if in repository root
1418 :``%p``: root-relative path name of file being printed
1417 :``%p``: root-relative path name of file being printed
1419 :``%H``: changeset hash (40 hexadecimal digits)
1418 :``%H``: changeset hash (40 hexadecimal digits)
1420 :``%R``: changeset revision number
1419 :``%R``: changeset revision number
1421 :``%h``: short-form changeset hash (12 hexadecimal digits)
1420 :``%h``: short-form changeset hash (12 hexadecimal digits)
1422 :``%r``: zero-padded changeset revision number
1421 :``%r``: zero-padded changeset revision number
1423 :``%b``: basename of the exporting repository
1422 :``%b``: basename of the exporting repository
1424
1423
1425 Returns 0 on success.
1424 Returns 0 on success.
1426 """
1425 """
1427 ctx = scmutil.revsingle(repo, opts.get('rev'))
1426 ctx = scmutil.revsingle(repo, opts.get('rev'))
1428 m = scmutil.match(ctx, (file1,) + pats, opts)
1427 m = scmutil.match(ctx, (file1,) + pats, opts)
1429
1428
1430 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1429 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1431
1430
1432 @command('^clone',
1431 @command('^clone',
1433 [('U', 'noupdate', None, _('the clone will include an empty working '
1432 [('U', 'noupdate', None, _('the clone will include an empty working '
1434 'directory (only a repository)')),
1433 'directory (only a repository)')),
1435 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1434 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1436 _('REV')),
1435 _('REV')),
1437 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1436 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1438 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1437 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1439 ('', 'pull', None, _('use pull protocol to copy metadata')),
1438 ('', 'pull', None, _('use pull protocol to copy metadata')),
1440 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1439 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1441 ] + remoteopts,
1440 ] + remoteopts,
1442 _('[OPTION]... SOURCE [DEST]'),
1441 _('[OPTION]... SOURCE [DEST]'),
1443 norepo=True)
1442 norepo=True)
1444 def clone(ui, source, dest=None, **opts):
1443 def clone(ui, source, dest=None, **opts):
1445 """make a copy of an existing repository
1444 """make a copy of an existing repository
1446
1445
1447 Create a copy of an existing repository in a new directory.
1446 Create a copy of an existing repository in a new directory.
1448
1447
1449 If no destination directory name is specified, it defaults to the
1448 If no destination directory name is specified, it defaults to the
1450 basename of the source.
1449 basename of the source.
1451
1450
1452 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
1453 ``.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.
1454
1453
1455 Only local paths and ``ssh://`` URLs are supported as
1454 Only local paths and ``ssh://`` URLs are supported as
1456 destinations. For ``ssh://`` destinations, no working directory or
1455 destinations. For ``ssh://`` destinations, no working directory or
1457 ``.hg/hgrc`` will be created on the remote side.
1456 ``.hg/hgrc`` will be created on the remote side.
1458
1457
1459 If the source repository has a bookmark called '@' set, that
1458 If the source repository has a bookmark called '@' set, that
1460 revision will be checked out in the new repository by default.
1459 revision will be checked out in the new repository by default.
1461
1460
1462 To check out a particular version, use -u/--update, or
1461 To check out a particular version, use -u/--update, or
1463 -U/--noupdate to create a clone with no working directory.
1462 -U/--noupdate to create a clone with no working directory.
1464
1463
1465 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
1466 identifiers with -r/--rev or branches with -b/--branch. The
1465 identifiers with -r/--rev or branches with -b/--branch. The
1467 resulting clone will contain only the specified changesets and
1466 resulting clone will contain only the specified changesets and
1468 their ancestors. These options (or 'clone src#rev dest') imply
1467 their ancestors. These options (or 'clone src#rev dest') imply
1469 --pull, even for local source repositories.
1468 --pull, even for local source repositories.
1470
1469
1471 .. note::
1470 .. note::
1472
1471
1473 Specifying a tag will include the tagged changeset but not the
1472 Specifying a tag will include the tagged changeset but not the
1474 changeset containing the tag.
1473 changeset containing the tag.
1475
1474
1476 .. container:: verbose
1475 .. container:: verbose
1477
1476
1478 For efficiency, hardlinks are used for cloning whenever the
1477 For efficiency, hardlinks are used for cloning whenever the
1479 source and destination are on the same filesystem (note this
1478 source and destination are on the same filesystem (note this
1480 applies only to the repository data, not to the working
1479 applies only to the repository data, not to the working
1481 directory). Some filesystems, such as AFS, implement hardlinking
1480 directory). Some filesystems, such as AFS, implement hardlinking
1482 incorrectly, but do not report errors. In these cases, use the
1481 incorrectly, but do not report errors. In these cases, use the
1483 --pull option to avoid hardlinking.
1482 --pull option to avoid hardlinking.
1484
1483
1485 In some cases, you can clone repositories and the working
1484 In some cases, you can clone repositories and the working
1486 directory using full hardlinks with ::
1485 directory using full hardlinks with ::
1487
1486
1488 $ cp -al REPO REPOCLONE
1487 $ cp -al REPO REPOCLONE
1489
1488
1490 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
1491 operation is not atomic (making sure REPO is not modified during
1490 operation is not atomic (making sure REPO is not modified during
1492 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
1493 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1492 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1494 so). Also, this is not compatible with certain extensions that
1493 so). Also, this is not compatible with certain extensions that
1495 place their metadata under the .hg directory, such as mq.
1494 place their metadata under the .hg directory, such as mq.
1496
1495
1497 Mercurial will update the working directory to the first applicable
1496 Mercurial will update the working directory to the first applicable
1498 revision from this list:
1497 revision from this list:
1499
1498
1500 a) null if -U or the source repository has no changesets
1499 a) null if -U or the source repository has no changesets
1501 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
1502 the source repository's working directory
1501 the source repository's working directory
1503 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
1504 latest head of that branch)
1503 latest head of that branch)
1505 d) the changeset specified with -r
1504 d) the changeset specified with -r
1506 e) the tipmost head specified with -b
1505 e) the tipmost head specified with -b
1507 f) the tipmost head specified with the url#branch source syntax
1506 f) the tipmost head specified with the url#branch source syntax
1508 g) the revision marked with the '@' bookmark, if present
1507 g) the revision marked with the '@' bookmark, if present
1509 h) the tipmost head of the default branch
1508 h) the tipmost head of the default branch
1510 i) tip
1509 i) tip
1511
1510
1512 When cloning from servers that support it, Mercurial may fetch
1511 When cloning from servers that support it, Mercurial may fetch
1513 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,
1514 hooks operating on incoming changesets and changegroups may fire twice,
1513 hooks operating on incoming changesets and changegroups may fire twice,
1515 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
1516 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
1517 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
1518 change in future releases. See :hg:`help -e clonebundles` for more.
1517 change in future releases. See :hg:`help -e clonebundles` for more.
1519
1518
1520 Examples:
1519 Examples:
1521
1520
1522 - clone a remote repository to a new directory named hg/::
1521 - clone a remote repository to a new directory named hg/::
1523
1522
1524 hg clone https://www.mercurial-scm.org/repo/hg/
1523 hg clone https://www.mercurial-scm.org/repo/hg/
1525
1524
1526 - create a lightweight local clone::
1525 - create a lightweight local clone::
1527
1526
1528 hg clone project/ project-feature/
1527 hg clone project/ project-feature/
1529
1528
1530 - 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)::
1531
1530
1532 hg clone ssh://user@server//home/projects/alpha/
1531 hg clone ssh://user@server//home/projects/alpha/
1533
1532
1534 - 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
1535 specified version::
1534 specified version::
1536
1535
1537 hg clone --uncompressed http://server/repo -u 1.5
1536 hg clone --uncompressed http://server/repo -u 1.5
1538
1537
1539 - create a repository without changesets after a particular revision::
1538 - create a repository without changesets after a particular revision::
1540
1539
1541 hg clone -r 04e544 experimental/ good/
1540 hg clone -r 04e544 experimental/ good/
1542
1541
1543 - clone (and track) a particular named branch::
1542 - clone (and track) a particular named branch::
1544
1543
1545 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1544 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1546
1545
1547 See :hg:`help urls` for details on specifying URLs.
1546 See :hg:`help urls` for details on specifying URLs.
1548
1547
1549 Returns 0 on success.
1548 Returns 0 on success.
1550 """
1549 """
1551 if opts.get('noupdate') and opts.get('updaterev'):
1550 if opts.get('noupdate') and opts.get('updaterev'):
1552 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1551 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1553
1552
1554 r = hg.clone(ui, opts, source, dest,
1553 r = hg.clone(ui, opts, source, dest,
1555 pull=opts.get('pull'),
1554 pull=opts.get('pull'),
1556 stream=opts.get('uncompressed'),
1555 stream=opts.get('uncompressed'),
1557 rev=opts.get('rev'),
1556 rev=opts.get('rev'),
1558 update=opts.get('updaterev') or not opts.get('noupdate'),
1557 update=opts.get('updaterev') or not opts.get('noupdate'),
1559 branch=opts.get('branch'),
1558 branch=opts.get('branch'),
1560 shareopts=opts.get('shareopts'))
1559 shareopts=opts.get('shareopts'))
1561
1560
1562 return r is None
1561 return r is None
1563
1562
1564 @command('^commit|ci',
1563 @command('^commit|ci',
1565 [('A', 'addremove', None,
1564 [('A', 'addremove', None,
1566 _('mark new/missing files as added/removed before committing')),
1565 _('mark new/missing files as added/removed before committing')),
1567 ('', 'close-branch', None,
1566 ('', 'close-branch', None,
1568 _('mark a branch head as closed')),
1567 _('mark a branch head as closed')),
1569 ('', 'amend', None, _('amend the parent of the working directory')),
1568 ('', 'amend', None, _('amend the parent of the working directory')),
1570 ('s', 'secret', None, _('use the secret phase for committing')),
1569 ('s', 'secret', None, _('use the secret phase for committing')),
1571 ('e', 'edit', None, _('invoke editor on commit messages')),
1570 ('e', 'edit', None, _('invoke editor on commit messages')),
1572 ('i', 'interactive', None, _('use interactive mode')),
1571 ('i', 'interactive', None, _('use interactive mode')),
1573 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1572 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1574 _('[OPTION]... [FILE]...'),
1573 _('[OPTION]... [FILE]...'),
1575 inferrepo=True)
1574 inferrepo=True)
1576 def commit(ui, repo, *pats, **opts):
1575 def commit(ui, repo, *pats, **opts):
1577 """commit the specified files or all outstanding changes
1576 """commit the specified files or all outstanding changes
1578
1577
1579 Commit changes to the given files into the repository. Unlike a
1578 Commit changes to the given files into the repository. Unlike a
1580 centralized SCM, this operation is a local operation. See
1579 centralized SCM, this operation is a local operation. See
1581 :hg:`push` for a way to actively distribute your changes.
1580 :hg:`push` for a way to actively distribute your changes.
1582
1581
1583 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`
1584 will be committed.
1583 will be committed.
1585
1584
1586 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
1587 filenames or -I/-X filters.
1586 filenames or -I/-X filters.
1588
1587
1589 If no commit message is specified, Mercurial starts your
1588 If no commit message is specified, Mercurial starts your
1590 configured editor where you can enter a message. In case your
1589 configured editor where you can enter a message. In case your
1591 commit fails, you will find a backup of your message in
1590 commit fails, you will find a backup of your message in
1592 ``.hg/last-message.txt``.
1591 ``.hg/last-message.txt``.
1593
1592
1594 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
1595 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
1596 will be considered closed and no longer listed.
1595 will be considered closed and no longer listed.
1597
1596
1598 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
1599 working directory with a new commit that contains the changes
1598 working directory with a new commit that contains the changes
1600 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`,
1601 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
1602 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1601 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1603 on how to restore it).
1602 on how to restore it).
1604
1603
1605 Message, user and date are taken from the amended commit unless
1604 Message, user and date are taken from the amended commit unless
1606 specified. When a message isn't specified on the command line,
1605 specified. When a message isn't specified on the command line,
1607 the editor will open with the message of the amended commit.
1606 the editor will open with the message of the amended commit.
1608
1607
1609 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`)
1610 or changesets that have children.
1609 or changesets that have children.
1611
1610
1612 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.
1613
1612
1614 Returns 0 on success, 1 if nothing changed.
1613 Returns 0 on success, 1 if nothing changed.
1615
1614
1616 .. container:: verbose
1615 .. container:: verbose
1617
1616
1618 Examples:
1617 Examples:
1619
1618
1620 - commit all files ending in .py::
1619 - commit all files ending in .py::
1621
1620
1622 hg commit --include "set:**.py"
1621 hg commit --include "set:**.py"
1623
1622
1624 - commit all non-binary files::
1623 - commit all non-binary files::
1625
1624
1626 hg commit --exclude "set:binary()"
1625 hg commit --exclude "set:binary()"
1627
1626
1628 - amend the current commit and set the date to now::
1627 - amend the current commit and set the date to now::
1629
1628
1630 hg commit --amend --date now
1629 hg commit --amend --date now
1631 """
1630 """
1632 wlock = lock = None
1631 wlock = lock = None
1633 try:
1632 try:
1634 wlock = repo.wlock()
1633 wlock = repo.wlock()
1635 lock = repo.lock()
1634 lock = repo.lock()
1636 return _docommit(ui, repo, *pats, **opts)
1635 return _docommit(ui, repo, *pats, **opts)
1637 finally:
1636 finally:
1638 release(lock, wlock)
1637 release(lock, wlock)
1639
1638
1640 def _docommit(ui, repo, *pats, **opts):
1639 def _docommit(ui, repo, *pats, **opts):
1641 if opts.get('interactive'):
1640 if opts.get('interactive'):
1642 opts.pop('interactive')
1641 opts.pop('interactive')
1643 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1642 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1644 cmdutil.recordfilter, *pats, **opts)
1643 cmdutil.recordfilter, *pats, **opts)
1645 # 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
1646 # commit(), 1 if nothing changed or None on success.
1645 # commit(), 1 if nothing changed or None on success.
1647 return 1 if ret == 0 else ret
1646 return 1 if ret == 0 else ret
1648
1647
1649 if opts.get('subrepos'):
1648 if opts.get('subrepos'):
1650 if opts.get('amend'):
1649 if opts.get('amend'):
1651 raise error.Abort(_('cannot amend with --subrepos'))
1650 raise error.Abort(_('cannot amend with --subrepos'))
1652 # Let --subrepos on the command line override config setting.
1651 # Let --subrepos on the command line override config setting.
1653 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1652 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1654
1653
1655 cmdutil.checkunfinished(repo, commit=True)
1654 cmdutil.checkunfinished(repo, commit=True)
1656
1655
1657 branch = repo[None].branch()
1656 branch = repo[None].branch()
1658 bheads = repo.branchheads(branch)
1657 bheads = repo.branchheads(branch)
1659
1658
1660 extra = {}
1659 extra = {}
1661 if opts.get('close_branch'):
1660 if opts.get('close_branch'):
1662 extra['close'] = 1
1661 extra['close'] = 1
1663
1662
1664 if not bheads:
1663 if not bheads:
1665 raise error.Abort(_('can only close branch heads'))
1664 raise error.Abort(_('can only close branch heads'))
1666 elif opts.get('amend'):
1665 elif opts.get('amend'):
1667 if repo[None].parents()[0].p1().branch() != branch and \
1666 if repo[None].parents()[0].p1().branch() != branch and \
1668 repo[None].parents()[0].p2().branch() != branch:
1667 repo[None].parents()[0].p2().branch() != branch:
1669 raise error.Abort(_('can only close branch heads'))
1668 raise error.Abort(_('can only close branch heads'))
1670
1669
1671 if opts.get('amend'):
1670 if opts.get('amend'):
1672 if ui.configbool('ui', 'commitsubrepos'):
1671 if ui.configbool('ui', 'commitsubrepos'):
1673 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1672 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1674
1673
1675 old = repo['.']
1674 old = repo['.']
1676 if not old.mutable():
1675 if not old.mutable():
1677 raise error.Abort(_('cannot amend public changesets'))
1676 raise error.Abort(_('cannot amend public changesets'))
1678 if len(repo[None].parents()) > 1:
1677 if len(repo[None].parents()) > 1:
1679 raise error.Abort(_('cannot amend while merging'))
1678 raise error.Abort(_('cannot amend while merging'))
1680 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1679 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1681 if not allowunstable and old.children():
1680 if not allowunstable and old.children():
1682 raise error.Abort(_('cannot amend changeset with children'))
1681 raise error.Abort(_('cannot amend changeset with children'))
1683
1682
1684 # Currently histedit gets confused if an amend happens while histedit
1683 # Currently histedit gets confused if an amend happens while histedit
1685 # is in progress. Since we have a checkunfinished command, we are
1684 # is in progress. Since we have a checkunfinished command, we are
1686 # temporarily honoring it.
1685 # temporarily honoring it.
1687 #
1686 #
1688 # Note: eventually this guard will be removed. Please do not expect
1687 # Note: eventually this guard will be removed. Please do not expect
1689 # this behavior to remain.
1688 # this behavior to remain.
1690 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1689 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1691 cmdutil.checkunfinished(repo)
1690 cmdutil.checkunfinished(repo)
1692
1691
1693 # commitfunc is used only for temporary amend commit by cmdutil.amend
1692 # commitfunc is used only for temporary amend commit by cmdutil.amend
1694 def commitfunc(ui, repo, message, match, opts):
1693 def commitfunc(ui, repo, message, match, opts):
1695 return repo.commit(message,
1694 return repo.commit(message,
1696 opts.get('user') or old.user(),
1695 opts.get('user') or old.user(),
1697 opts.get('date') or old.date(),
1696 opts.get('date') or old.date(),
1698 match,
1697 match,
1699 extra=extra)
1698 extra=extra)
1700
1699
1701 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1700 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1702 if node == old.node():
1701 if node == old.node():
1703 ui.status(_("nothing changed\n"))
1702 ui.status(_("nothing changed\n"))
1704 return 1
1703 return 1
1705 else:
1704 else:
1706 def commitfunc(ui, repo, message, match, opts):
1705 def commitfunc(ui, repo, message, match, opts):
1707 backup = ui.backupconfig('phases', 'new-commit')
1706 backup = ui.backupconfig('phases', 'new-commit')
1708 baseui = repo.baseui
1707 baseui = repo.baseui
1709 basebackup = baseui.backupconfig('phases', 'new-commit')
1708 basebackup = baseui.backupconfig('phases', 'new-commit')
1710 try:
1709 try:
1711 if opts.get('secret'):
1710 if opts.get('secret'):
1712 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1711 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1713 # Propagate to subrepos
1712 # Propagate to subrepos
1714 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1713 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1715
1714
1716 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1715 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1717 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1716 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1718 return repo.commit(message, opts.get('user'), opts.get('date'),
1717 return repo.commit(message, opts.get('user'), opts.get('date'),
1719 match,
1718 match,
1720 editor=editor,
1719 editor=editor,
1721 extra=extra)
1720 extra=extra)
1722 finally:
1721 finally:
1723 ui.restoreconfig(backup)
1722 ui.restoreconfig(backup)
1724 repo.baseui.restoreconfig(basebackup)
1723 repo.baseui.restoreconfig(basebackup)
1725
1724
1726
1725
1727 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1726 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1728
1727
1729 if not node:
1728 if not node:
1730 stat = cmdutil.postcommitstatus(repo, pats, opts)
1729 stat = cmdutil.postcommitstatus(repo, pats, opts)
1731 if stat[3]:
1730 if stat[3]:
1732 ui.status(_("nothing changed (%d missing files, see "
1731 ui.status(_("nothing changed (%d missing files, see "
1733 "'hg status')\n") % len(stat[3]))
1732 "'hg status')\n") % len(stat[3]))
1734 else:
1733 else:
1735 ui.status(_("nothing changed\n"))
1734 ui.status(_("nothing changed\n"))
1736 return 1
1735 return 1
1737
1736
1738 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1737 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1739
1738
1740 @command('config|showconfig|debugconfig',
1739 @command('config|showconfig|debugconfig',
1741 [('u', 'untrusted', None, _('show untrusted configuration options')),
1740 [('u', 'untrusted', None, _('show untrusted configuration options')),
1742 ('e', 'edit', None, _('edit user config')),
1741 ('e', 'edit', None, _('edit user config')),
1743 ('l', 'local', None, _('edit repository config')),
1742 ('l', 'local', None, _('edit repository config')),
1744 ('g', 'global', None, _('edit global config'))] + formatteropts,
1743 ('g', 'global', None, _('edit global config'))] + formatteropts,
1745 _('[-u] [NAME]...'),
1744 _('[-u] [NAME]...'),
1746 optionalrepo=True)
1745 optionalrepo=True)
1747 def config(ui, repo, *values, **opts):
1746 def config(ui, repo, *values, **opts):
1748 """show combined config settings from all hgrc files
1747 """show combined config settings from all hgrc files
1749
1748
1750 With no arguments, print names and values of all config items.
1749 With no arguments, print names and values of all config items.
1751
1750
1752 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
1753 of that config item.
1752 of that config item.
1754
1753
1755 With multiple arguments, print names and values of all config
1754 With multiple arguments, print names and values of all config
1756 items with matching section names.
1755 items with matching section names.
1757
1756
1758 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
1759 --global, edit the system-wide config file. With --local, edit the
1758 --global, edit the system-wide config file. With --local, edit the
1760 repository-level config file.
1759 repository-level config file.
1761
1760
1762 With --debug, the source (filename and line number) is printed
1761 With --debug, the source (filename and line number) is printed
1763 for each config item.
1762 for each config item.
1764
1763
1765 See :hg:`help config` for more information about config files.
1764 See :hg:`help config` for more information about config files.
1766
1765
1767 Returns 0 on success, 1 if NAME does not exist.
1766 Returns 0 on success, 1 if NAME does not exist.
1768
1767
1769 """
1768 """
1770
1769
1771 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'):
1772 if opts.get('local') and opts.get('global'):
1771 if opts.get('local') and opts.get('global'):
1773 raise error.Abort(_("can't use --local and --global together"))
1772 raise error.Abort(_("can't use --local and --global together"))
1774
1773
1775 if opts.get('local'):
1774 if opts.get('local'):
1776 if not repo:
1775 if not repo:
1777 raise error.Abort(_("can't use --local outside a repository"))
1776 raise error.Abort(_("can't use --local outside a repository"))
1778 paths = [repo.join('hgrc')]
1777 paths = [repo.join('hgrc')]
1779 elif opts.get('global'):
1778 elif opts.get('global'):
1780 paths = scmutil.systemrcpath()
1779 paths = scmutil.systemrcpath()
1781 else:
1780 else:
1782 paths = scmutil.userrcpath()
1781 paths = scmutil.userrcpath()
1783
1782
1784 for f in paths:
1783 for f in paths:
1785 if os.path.exists(f):
1784 if os.path.exists(f):
1786 break
1785 break
1787 else:
1786 else:
1788 if opts.get('global'):
1787 if opts.get('global'):
1789 samplehgrc = uimod.samplehgrcs['global']
1788 samplehgrc = uimod.samplehgrcs['global']
1790 elif opts.get('local'):
1789 elif opts.get('local'):
1791 samplehgrc = uimod.samplehgrcs['local']
1790 samplehgrc = uimod.samplehgrcs['local']
1792 else:
1791 else:
1793 samplehgrc = uimod.samplehgrcs['user']
1792 samplehgrc = uimod.samplehgrcs['user']
1794
1793
1795 f = paths[0]
1794 f = paths[0]
1796 fp = open(f, "w")
1795 fp = open(f, "w")
1797 fp.write(samplehgrc)
1796 fp.write(samplehgrc)
1798 fp.close()
1797 fp.close()
1799
1798
1800 editor = ui.geteditor()
1799 editor = ui.geteditor()
1801 ui.system("%s \"%s\"" % (editor, f),
1800 ui.system("%s \"%s\"" % (editor, f),
1802 onerr=error.Abort, errprefix=_("edit failed"))
1801 onerr=error.Abort, errprefix=_("edit failed"))
1803 return
1802 return
1804
1803
1805 fm = ui.formatter('config', opts)
1804 fm = ui.formatter('config', opts)
1806 for f in scmutil.rcpath():
1805 for f in scmutil.rcpath():
1807 ui.debug('read config from: %s\n' % f)
1806 ui.debug('read config from: %s\n' % f)
1808 untrusted = bool(opts.get('untrusted'))
1807 untrusted = bool(opts.get('untrusted'))
1809 if values:
1808 if values:
1810 sections = [v for v in values if '.' not in v]
1809 sections = [v for v in values if '.' not in v]
1811 items = [v for v in values if '.' in v]
1810 items = [v for v in values if '.' in v]
1812 if len(items) > 1 or items and sections:
1811 if len(items) > 1 or items and sections:
1813 raise error.Abort(_('only one config item permitted'))
1812 raise error.Abort(_('only one config item permitted'))
1814 matched = False
1813 matched = False
1815 for section, name, value in ui.walkconfig(untrusted=untrusted):
1814 for section, name, value in ui.walkconfig(untrusted=untrusted):
1816 value = str(value)
1815 value = str(value)
1817 if fm.isplain():
1816 if fm.isplain():
1818 value = value.replace('\n', '\\n')
1817 value = value.replace('\n', '\\n')
1819 entryname = section + '.' + name
1818 entryname = section + '.' + name
1820 if values:
1819 if values:
1821 for v in values:
1820 for v in values:
1822 if v == section:
1821 if v == section:
1823 fm.startitem()
1822 fm.startitem()
1824 fm.condwrite(ui.debugflag, 'source', '%s: ',
1823 fm.condwrite(ui.debugflag, 'source', '%s: ',
1825 ui.configsource(section, name, untrusted))
1824 ui.configsource(section, name, untrusted))
1826 fm.write('name value', '%s=%s\n', entryname, value)
1825 fm.write('name value', '%s=%s\n', entryname, value)
1827 matched = True
1826 matched = True
1828 elif v == entryname:
1827 elif v == entryname:
1829 fm.startitem()
1828 fm.startitem()
1830 fm.condwrite(ui.debugflag, 'source', '%s: ',
1829 fm.condwrite(ui.debugflag, 'source', '%s: ',
1831 ui.configsource(section, name, untrusted))
1830 ui.configsource(section, name, untrusted))
1832 fm.write('value', '%s\n', value)
1831 fm.write('value', '%s\n', value)
1833 fm.data(name=entryname)
1832 fm.data(name=entryname)
1834 matched = True
1833 matched = True
1835 else:
1834 else:
1836 fm.startitem()
1835 fm.startitem()
1837 fm.condwrite(ui.debugflag, 'source', '%s: ',
1836 fm.condwrite(ui.debugflag, 'source', '%s: ',
1838 ui.configsource(section, name, untrusted))
1837 ui.configsource(section, name, untrusted))
1839 fm.write('name value', '%s=%s\n', entryname, value)
1838 fm.write('name value', '%s=%s\n', entryname, value)
1840 matched = True
1839 matched = True
1841 fm.end()
1840 fm.end()
1842 if matched:
1841 if matched:
1843 return 0
1842 return 0
1844 return 1
1843 return 1
1845
1844
1846 @command('copy|cp',
1845 @command('copy|cp',
1847 [('A', 'after', None, _('record a copy that has already occurred')),
1846 [('A', 'after', None, _('record a copy that has already occurred')),
1848 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1847 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1849 ] + walkopts + dryrunopts,
1848 ] + walkopts + dryrunopts,
1850 _('[OPTION]... [SOURCE]... DEST'))
1849 _('[OPTION]... [SOURCE]... DEST'))
1851 def copy(ui, repo, *pats, **opts):
1850 def copy(ui, repo, *pats, **opts):
1852 """mark files as copied for the next commit
1851 """mark files as copied for the next commit
1853
1852
1854 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
1855 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,
1856 the source must be a single file.
1855 the source must be a single file.
1857
1856
1858 By default, this command copies the contents of files as they
1857 By default, this command copies the contents of files as they
1859 exist in the working directory. If invoked with -A/--after, the
1858 exist in the working directory. If invoked with -A/--after, the
1860 operation is recorded, but no copying is performed.
1859 operation is recorded, but no copying is performed.
1861
1860
1862 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
1863 before that, see :hg:`revert`.
1862 before that, see :hg:`revert`.
1864
1863
1865 Returns 0 on success, 1 if errors are encountered.
1864 Returns 0 on success, 1 if errors are encountered.
1866 """
1865 """
1867 with repo.wlock(False):
1866 with repo.wlock(False):
1868 return cmdutil.copy(ui, repo, pats, opts)
1867 return cmdutil.copy(ui, repo, pats, opts)
1869
1868
1870 @command('debugdag',
1869 @command('debugdag',
1871 [('t', 'tags', None, _('use tags as labels')),
1870 [('t', 'tags', None, _('use tags as labels')),
1872 ('b', 'branches', None, _('annotate with branch names')),
1871 ('b', 'branches', None, _('annotate with branch names')),
1873 ('', 'dots', None, _('use dots for runs')),
1872 ('', 'dots', None, _('use dots for runs')),
1874 ('s', 'spaces', None, _('separate elements by spaces'))],
1873 ('s', 'spaces', None, _('separate elements by spaces'))],
1875 _('[OPTION]... [FILE [REV]...]'),
1874 _('[OPTION]... [FILE [REV]...]'),
1876 optionalrepo=True)
1875 optionalrepo=True)
1877 def debugdag(ui, repo, file_=None, *revs, **opts):
1876 def debugdag(ui, repo, file_=None, *revs, **opts):
1878 """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
1879
1878
1880 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
1881 revision numbers, they get labeled in the output as rN.
1880 revision numbers, they get labeled in the output as rN.
1882
1881
1883 Otherwise, the changelog DAG of the current repo is emitted.
1882 Otherwise, the changelog DAG of the current repo is emitted.
1884 """
1883 """
1885 spaces = opts.get('spaces')
1884 spaces = opts.get('spaces')
1886 dots = opts.get('dots')
1885 dots = opts.get('dots')
1887 if file_:
1886 if file_:
1888 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1887 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1889 revs = set((int(r) for r in revs))
1888 revs = set((int(r) for r in revs))
1890 def events():
1889 def events():
1891 for r in rlog:
1890 for r in rlog:
1892 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1891 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1893 if p != -1))
1892 if p != -1))
1894 if r in revs:
1893 if r in revs:
1895 yield 'l', (r, "r%i" % r)
1894 yield 'l', (r, "r%i" % r)
1896 elif repo:
1895 elif repo:
1897 cl = repo.changelog
1896 cl = repo.changelog
1898 tags = opts.get('tags')
1897 tags = opts.get('tags')
1899 branches = opts.get('branches')
1898 branches = opts.get('branches')
1900 if tags:
1899 if tags:
1901 labels = {}
1900 labels = {}
1902 for l, n in repo.tags().items():
1901 for l, n in repo.tags().items():
1903 labels.setdefault(cl.rev(n), []).append(l)
1902 labels.setdefault(cl.rev(n), []).append(l)
1904 def events():
1903 def events():
1905 b = "default"
1904 b = "default"
1906 for r in cl:
1905 for r in cl:
1907 if branches:
1906 if branches:
1908 newb = cl.read(cl.node(r))[5]['branch']
1907 newb = cl.read(cl.node(r))[5]['branch']
1909 if newb != b:
1908 if newb != b:
1910 yield 'a', newb
1909 yield 'a', newb
1911 b = newb
1910 b = newb
1912 yield 'n', (r, list(p for p in cl.parentrevs(r)
1911 yield 'n', (r, list(p for p in cl.parentrevs(r)
1913 if p != -1))
1912 if p != -1))
1914 if tags:
1913 if tags:
1915 ls = labels.get(r)
1914 ls = labels.get(r)
1916 if ls:
1915 if ls:
1917 for l in ls:
1916 for l in ls:
1918 yield 'l', (r, l)
1917 yield 'l', (r, l)
1919 else:
1918 else:
1920 raise error.Abort(_('need repo for changelog dag'))
1919 raise error.Abort(_('need repo for changelog dag'))
1921
1920
1922 for line in dagparser.dagtextlines(events(),
1921 for line in dagparser.dagtextlines(events(),
1923 addspaces=spaces,
1922 addspaces=spaces,
1924 wraplabels=True,
1923 wraplabels=True,
1925 wrapannotations=True,
1924 wrapannotations=True,
1926 wrapnonlinear=dots,
1925 wrapnonlinear=dots,
1927 usedots=dots,
1926 usedots=dots,
1928 maxlinewidth=70):
1927 maxlinewidth=70):
1929 ui.write(line)
1928 ui.write(line)
1930 ui.write("\n")
1929 ui.write("\n")
1931
1930
1932 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
1931 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
1933 def debugdata(ui, repo, file_, rev=None, **opts):
1932 def debugdata(ui, repo, file_, rev=None, **opts):
1934 """dump the contents of a data file revision"""
1933 """dump the contents of a data file revision"""
1935 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'):
1936 if rev is not None:
1935 if rev is not None:
1937 raise error.CommandError('debugdata', _('invalid arguments'))
1936 raise error.CommandError('debugdata', _('invalid arguments'))
1938 file_, rev = None, file_
1937 file_, rev = None, file_
1939 elif rev is None:
1938 elif rev is None:
1940 raise error.CommandError('debugdata', _('invalid arguments'))
1939 raise error.CommandError('debugdata', _('invalid arguments'))
1941 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1940 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1942 try:
1941 try:
1943 ui.write(r.revision(r.lookup(rev)))
1942 ui.write(r.revision(r.lookup(rev)))
1944 except KeyError:
1943 except KeyError:
1945 raise error.Abort(_('invalid revision identifier %s') % rev)
1944 raise error.Abort(_('invalid revision identifier %s') % rev)
1946
1945
1947 @command('debugdate',
1946 @command('debugdate',
1948 [('e', 'extended', None, _('try extended date formats'))],
1947 [('e', 'extended', None, _('try extended date formats'))],
1949 _('[-e] DATE [RANGE]'),
1948 _('[-e] DATE [RANGE]'),
1950 norepo=True, optionalrepo=True)
1949 norepo=True, optionalrepo=True)
1951 def debugdate(ui, date, range=None, **opts):
1950 def debugdate(ui, date, range=None, **opts):
1952 """parse and display a date"""
1951 """parse and display a date"""
1953 if opts["extended"]:
1952 if opts["extended"]:
1954 d = util.parsedate(date, util.extendeddateformats)
1953 d = util.parsedate(date, util.extendeddateformats)
1955 else:
1954 else:
1956 d = util.parsedate(date)
1955 d = util.parsedate(date)
1957 ui.write(("internal: %s %s\n") % d)
1956 ui.write(("internal: %s %s\n") % d)
1958 ui.write(("standard: %s\n") % util.datestr(d))
1957 ui.write(("standard: %s\n") % util.datestr(d))
1959 if range:
1958 if range:
1960 m = util.matchdate(range)
1959 m = util.matchdate(range)
1961 ui.write(("match: %s\n") % m(d[0]))
1960 ui.write(("match: %s\n") % m(d[0]))
1962
1961
1963 @command('debugdiscovery',
1962 @command('debugdiscovery',
1964 [('', 'old', None, _('use old-style discovery')),
1963 [('', 'old', None, _('use old-style discovery')),
1965 ('', 'nonheads', None,
1964 ('', 'nonheads', None,
1966 _('use old-style discovery with non-heads included')),
1965 _('use old-style discovery with non-heads included')),
1967 ] + remoteopts,
1966 ] + remoteopts,
1968 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1967 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1969 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1968 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1970 """runs the changeset discovery protocol in isolation"""
1969 """runs the changeset discovery protocol in isolation"""
1971 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1970 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1972 opts.get('branch'))
1971 opts.get('branch'))
1973 remote = hg.peer(repo, opts, remoteurl)
1972 remote = hg.peer(repo, opts, remoteurl)
1974 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1973 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1975
1974
1976 # make sure tests are repeatable
1975 # make sure tests are repeatable
1977 random.seed(12323)
1976 random.seed(12323)
1978
1977
1979 def doit(localheads, remoteheads, remote=remote):
1978 def doit(localheads, remoteheads, remote=remote):
1980 if opts.get('old'):
1979 if opts.get('old'):
1981 if localheads:
1980 if localheads:
1982 raise error.Abort('cannot use localheads with old style '
1981 raise error.Abort('cannot use localheads with old style '
1983 'discovery')
1982 'discovery')
1984 if not util.safehasattr(remote, 'branches'):
1983 if not util.safehasattr(remote, 'branches'):
1985 # enable in-client legacy support
1984 # enable in-client legacy support
1986 remote = localrepo.locallegacypeer(remote.local())
1985 remote = localrepo.locallegacypeer(remote.local())
1987 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1986 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1988 force=True)
1987 force=True)
1989 common = set(common)
1988 common = set(common)
1990 if not opts.get('nonheads'):
1989 if not opts.get('nonheads'):
1991 ui.write(("unpruned common: %s\n") %
1990 ui.write(("unpruned common: %s\n") %
1992 " ".join(sorted(short(n) for n in common)))
1991 " ".join(sorted(short(n) for n in common)))
1993 dag = dagutil.revlogdag(repo.changelog)
1992 dag = dagutil.revlogdag(repo.changelog)
1994 all = dag.ancestorset(dag.internalizeall(common))
1993 all = dag.ancestorset(dag.internalizeall(common))
1995 common = dag.externalizeall(dag.headsetofconnecteds(all))
1994 common = dag.externalizeall(dag.headsetofconnecteds(all))
1996 else:
1995 else:
1997 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1996 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1998 common = set(common)
1997 common = set(common)
1999 rheads = set(hds)
1998 rheads = set(hds)
2000 lheads = set(repo.heads())
1999 lheads = set(repo.heads())
2001 ui.write(("common heads: %s\n") %
2000 ui.write(("common heads: %s\n") %
2002 " ".join(sorted(short(n) for n in common)))
2001 " ".join(sorted(short(n) for n in common)))
2003 if lheads <= common:
2002 if lheads <= common:
2004 ui.write(("local is subset\n"))
2003 ui.write(("local is subset\n"))
2005 elif rheads <= common:
2004 elif rheads <= common:
2006 ui.write(("remote is subset\n"))
2005 ui.write(("remote is subset\n"))
2007
2006
2008 serverlogs = opts.get('serverlog')
2007 serverlogs = opts.get('serverlog')
2009 if serverlogs:
2008 if serverlogs:
2010 for filename in serverlogs:
2009 for filename in serverlogs:
2011 with open(filename, 'r') as logfile:
2010 with open(filename, 'r') as logfile:
2012 line = logfile.readline()
2011 line = logfile.readline()
2013 while line:
2012 while line:
2014 parts = line.strip().split(';')
2013 parts = line.strip().split(';')
2015 op = parts[1]
2014 op = parts[1]
2016 if op == 'cg':
2015 if op == 'cg':
2017 pass
2016 pass
2018 elif op == 'cgss':
2017 elif op == 'cgss':
2019 doit(parts[2].split(' '), parts[3].split(' '))
2018 doit(parts[2].split(' '), parts[3].split(' '))
2020 elif op == 'unb':
2019 elif op == 'unb':
2021 doit(parts[3].split(' '), parts[2].split(' '))
2020 doit(parts[3].split(' '), parts[2].split(' '))
2022 line = logfile.readline()
2021 line = logfile.readline()
2023 else:
2022 else:
2024 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2023 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2025 opts.get('remote_head'))
2024 opts.get('remote_head'))
2026 localrevs = opts.get('local_head')
2025 localrevs = opts.get('local_head')
2027 doit(localrevs, remoterevs)
2026 doit(localrevs, remoterevs)
2028
2027
2029 @command('debugextensions', formatteropts, [], norepo=True)
2028 @command('debugextensions', formatteropts, [], norepo=True)
2030 def debugextensions(ui, **opts):
2029 def debugextensions(ui, **opts):
2031 '''show information about active extensions'''
2030 '''show information about active extensions'''
2032 exts = extensions.extensions(ui)
2031 exts = extensions.extensions(ui)
2033 hgver = util.version()
2032 hgver = util.version()
2034 fm = ui.formatter('debugextensions', opts)
2033 fm = ui.formatter('debugextensions', opts)
2035 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2034 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2036 isinternal = extensions.ismoduleinternal(extmod)
2035 isinternal = extensions.ismoduleinternal(extmod)
2037 extsource = extmod.__file__
2036 extsource = extmod.__file__
2038 if isinternal:
2037 if isinternal:
2039 exttestedwith = [] # never expose magic string to users
2038 exttestedwith = [] # never expose magic string to users
2040 else:
2039 else:
2041 exttestedwith = getattr(extmod, 'testedwith', '').split()
2040 exttestedwith = getattr(extmod, 'testedwith', '').split()
2042 extbuglink = getattr(extmod, 'buglink', None)
2041 extbuglink = getattr(extmod, 'buglink', None)
2043
2042
2044 fm.startitem()
2043 fm.startitem()
2045
2044
2046 if ui.quiet or ui.verbose:
2045 if ui.quiet or ui.verbose:
2047 fm.write('name', '%s\n', extname)
2046 fm.write('name', '%s\n', extname)
2048 else:
2047 else:
2049 fm.write('name', '%s', extname)
2048 fm.write('name', '%s', extname)
2050 if isinternal or hgver in exttestedwith:
2049 if isinternal or hgver in exttestedwith:
2051 fm.plain('\n')
2050 fm.plain('\n')
2052 elif not exttestedwith:
2051 elif not exttestedwith:
2053 fm.plain(_(' (untested!)\n'))
2052 fm.plain(_(' (untested!)\n'))
2054 else:
2053 else:
2055 lasttestedversion = exttestedwith[-1]
2054 lasttestedversion = exttestedwith[-1]
2056 fm.plain(' (%s!)\n' % lasttestedversion)
2055 fm.plain(' (%s!)\n' % lasttestedversion)
2057
2056
2058 fm.condwrite(ui.verbose and extsource, 'source',
2057 fm.condwrite(ui.verbose and extsource, 'source',
2059 _(' location: %s\n'), extsource or "")
2058 _(' location: %s\n'), extsource or "")
2060
2059
2061 if ui.verbose:
2060 if ui.verbose:
2062 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2061 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
2063 fm.data(bundled=isinternal)
2062 fm.data(bundled=isinternal)
2064
2063
2065 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2064 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2066 _(' tested with: %s\n'),
2065 _(' tested with: %s\n'),
2067 fm.formatlist(exttestedwith, name='ver'))
2066 fm.formatlist(exttestedwith, name='ver'))
2068
2067
2069 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2068 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2070 _(' bug reporting: %s\n'), extbuglink or "")
2069 _(' bug reporting: %s\n'), extbuglink or "")
2071
2070
2072 fm.end()
2071 fm.end()
2073
2072
2074 @command('debugfileset',
2073 @command('debugfileset',
2075 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2074 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2076 _('[-r REV] FILESPEC'))
2075 _('[-r REV] FILESPEC'))
2077 def debugfileset(ui, repo, expr, **opts):
2076 def debugfileset(ui, repo, expr, **opts):
2078 '''parse and apply a fileset specification'''
2077 '''parse and apply a fileset specification'''
2079 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2078 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2080 if ui.verbose:
2079 if ui.verbose:
2081 tree = fileset.parse(expr)
2080 tree = fileset.parse(expr)
2082 ui.note(fileset.prettyformat(tree), "\n")
2081 ui.note(fileset.prettyformat(tree), "\n")
2083
2082
2084 for f in ctx.getfileset(expr):
2083 for f in ctx.getfileset(expr):
2085 ui.write("%s\n" % f)
2084 ui.write("%s\n" % f)
2086
2085
2087 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2086 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2088 def debugfsinfo(ui, path="."):
2087 def debugfsinfo(ui, path="."):
2089 """show information detected about current filesystem"""
2088 """show information detected about current filesystem"""
2090 util.writefile('.debugfsinfo', '')
2089 util.writefile('.debugfsinfo', '')
2091 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'))
2092 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'))
2093 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'))
2094 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2093 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
2095 and 'yes' or 'no'))
2094 and 'yes' or 'no'))
2096 os.unlink('.debugfsinfo')
2095 os.unlink('.debugfsinfo')
2097
2096
2098 @command('debuggetbundle',
2097 @command('debuggetbundle',
2099 [('H', 'head', [], _('id of head node'), _('ID')),
2098 [('H', 'head', [], _('id of head node'), _('ID')),
2100 ('C', 'common', [], _('id of common node'), _('ID')),
2099 ('C', 'common', [], _('id of common node'), _('ID')),
2101 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2100 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2102 _('REPO FILE [-H|-C ID]...'),
2101 _('REPO FILE [-H|-C ID]...'),
2103 norepo=True)
2102 norepo=True)
2104 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2103 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2105 """retrieves a bundle from a repo
2104 """retrieves a bundle from a repo
2106
2105
2107 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
2108 given file.
2107 given file.
2109 """
2108 """
2110 repo = hg.peer(ui, opts, repopath)
2109 repo = hg.peer(ui, opts, repopath)
2111 if not repo.capable('getbundle'):
2110 if not repo.capable('getbundle'):
2112 raise error.Abort("getbundle() not supported by target repository")
2111 raise error.Abort("getbundle() not supported by target repository")
2113 args = {}
2112 args = {}
2114 if common:
2113 if common:
2115 args['common'] = [bin(s) for s in common]
2114 args['common'] = [bin(s) for s in common]
2116 if head:
2115 if head:
2117 args['heads'] = [bin(s) for s in head]
2116 args['heads'] = [bin(s) for s in head]
2118 # TODO: get desired bundlecaps from command line.
2117 # TODO: get desired bundlecaps from command line.
2119 args['bundlecaps'] = None
2118 args['bundlecaps'] = None
2120 bundle = repo.getbundle('debug', **args)
2119 bundle = repo.getbundle('debug', **args)
2121
2120
2122 bundletype = opts.get('type', 'bzip2').lower()
2121 bundletype = opts.get('type', 'bzip2').lower()
2123 btypes = {'none': 'HG10UN',
2122 btypes = {'none': 'HG10UN',
2124 'bzip2': 'HG10BZ',
2123 'bzip2': 'HG10BZ',
2125 'gzip': 'HG10GZ',
2124 'gzip': 'HG10GZ',
2126 'bundle2': 'HG20'}
2125 'bundle2': 'HG20'}
2127 bundletype = btypes.get(bundletype)
2126 bundletype = btypes.get(bundletype)
2128 if bundletype not in bundle2.bundletypes:
2127 if bundletype not in bundle2.bundletypes:
2129 raise error.Abort(_('unknown bundle type specified with --type'))
2128 raise error.Abort(_('unknown bundle type specified with --type'))
2130 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2129 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2131
2130
2132 @command('debugignore', [], '[FILE]')
2131 @command('debugignore', [], '[FILE]')
2133 def debugignore(ui, repo, *files, **opts):
2132 def debugignore(ui, repo, *files, **opts):
2134 """display the combined ignore pattern and information about ignored files
2133 """display the combined ignore pattern and information about ignored files
2135
2134
2136 With no argument display the combined ignore pattern.
2135 With no argument display the combined ignore pattern.
2137
2136
2138 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
2139 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.
2140 """
2139 """
2141 ignore = repo.dirstate._ignore
2140 ignore = repo.dirstate._ignore
2142 if not files:
2141 if not files:
2143 # Show all the patterns
2142 # Show all the patterns
2144 includepat = getattr(ignore, 'includepat', None)
2143 includepat = getattr(ignore, 'includepat', None)
2145 if includepat is not None:
2144 if includepat is not None:
2146 ui.write("%s\n" % includepat)
2145 ui.write("%s\n" % includepat)
2147 else:
2146 else:
2148 raise error.Abort(_("no ignore patterns found"))
2147 raise error.Abort(_("no ignore patterns found"))
2149 else:
2148 else:
2150 for f in files:
2149 for f in files:
2151 nf = util.normpath(f)
2150 nf = util.normpath(f)
2152 ignored = None
2151 ignored = None
2153 ignoredata = None
2152 ignoredata = None
2154 if nf != '.':
2153 if nf != '.':
2155 if ignore(nf):
2154 if ignore(nf):
2156 ignored = nf
2155 ignored = nf
2157 ignoredata = repo.dirstate._ignorefileandline(nf)
2156 ignoredata = repo.dirstate._ignorefileandline(nf)
2158 else:
2157 else:
2159 for p in util.finddirs(nf):
2158 for p in util.finddirs(nf):
2160 if ignore(p):
2159 if ignore(p):
2161 ignored = p
2160 ignored = p
2162 ignoredata = repo.dirstate._ignorefileandline(p)
2161 ignoredata = repo.dirstate._ignorefileandline(p)
2163 break
2162 break
2164 if ignored:
2163 if ignored:
2165 if ignored == nf:
2164 if ignored == nf:
2166 ui.write(_("%s is ignored\n") % f)
2165 ui.write(_("%s is ignored\n") % f)
2167 else:
2166 else:
2168 ui.write(_("%s is ignored because of "
2167 ui.write(_("%s is ignored because of "
2169 "containing folder %s\n")
2168 "containing folder %s\n")
2170 % (f, ignored))
2169 % (f, ignored))
2171 ignorefile, lineno, line = ignoredata
2170 ignorefile, lineno, line = ignoredata
2172 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2171 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2173 % (ignorefile, lineno, line))
2172 % (ignorefile, lineno, line))
2174 else:
2173 else:
2175 ui.write(_("%s is not ignored\n") % f)
2174 ui.write(_("%s is not ignored\n") % f)
2176
2175
2177 @command('debugindex', debugrevlogopts +
2176 @command('debugindex', debugrevlogopts +
2178 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2177 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2179 _('[-f FORMAT] -c|-m|FILE'),
2178 _('[-f FORMAT] -c|-m|FILE'),
2180 optionalrepo=True)
2179 optionalrepo=True)
2181 def debugindex(ui, repo, file_=None, **opts):
2180 def debugindex(ui, repo, file_=None, **opts):
2182 """dump the contents of an index file"""
2181 """dump the contents of an index file"""
2183 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2182 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2184 format = opts.get('format', 0)
2183 format = opts.get('format', 0)
2185 if format not in (0, 1):
2184 if format not in (0, 1):
2186 raise error.Abort(_("unknown format %d") % format)
2185 raise error.Abort(_("unknown format %d") % format)
2187
2186
2188 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2187 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2189 if generaldelta:
2188 if generaldelta:
2190 basehdr = ' delta'
2189 basehdr = ' delta'
2191 else:
2190 else:
2192 basehdr = ' base'
2191 basehdr = ' base'
2193
2192
2194 if ui.debugflag:
2193 if ui.debugflag:
2195 shortfn = hex
2194 shortfn = hex
2196 else:
2195 else:
2197 shortfn = short
2196 shortfn = short
2198
2197
2199 # 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
2200 idlen = 12
2199 idlen = 12
2201 for i in r:
2200 for i in r:
2202 idlen = len(shortfn(r.node(i)))
2201 idlen = len(shortfn(r.node(i)))
2203 break
2202 break
2204
2203
2205 if format == 0:
2204 if format == 0:
2206 ui.write((" rev offset length " + basehdr + " linkrev"
2205 ui.write((" rev offset length " + basehdr + " linkrev"
2207 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2206 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2208 elif format == 1:
2207 elif format == 1:
2209 ui.write((" rev flag offset length"
2208 ui.write((" rev flag offset length"
2210 " size " + basehdr + " link p1 p2"
2209 " size " + basehdr + " link p1 p2"
2211 " %s\n") % "nodeid".rjust(idlen))
2210 " %s\n") % "nodeid".rjust(idlen))
2212
2211
2213 for i in r:
2212 for i in r:
2214 node = r.node(i)
2213 node = r.node(i)
2215 if generaldelta:
2214 if generaldelta:
2216 base = r.deltaparent(i)
2215 base = r.deltaparent(i)
2217 else:
2216 else:
2218 base = r.chainbase(i)
2217 base = r.chainbase(i)
2219 if format == 0:
2218 if format == 0:
2220 try:
2219 try:
2221 pp = r.parents(node)
2220 pp = r.parents(node)
2222 except Exception:
2221 except Exception:
2223 pp = [nullid, nullid]
2222 pp = [nullid, nullid]
2224 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2223 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2225 i, r.start(i), r.length(i), base, r.linkrev(i),
2224 i, r.start(i), r.length(i), base, r.linkrev(i),
2226 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2225 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2227 elif format == 1:
2226 elif format == 1:
2228 pr = r.parentrevs(i)
2227 pr = r.parentrevs(i)
2229 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" % (
2230 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),
2231 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2230 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2232
2231
2233 @command('debugindexdot', debugrevlogopts,
2232 @command('debugindexdot', debugrevlogopts,
2234 _('-c|-m|FILE'), optionalrepo=True)
2233 _('-c|-m|FILE'), optionalrepo=True)
2235 def debugindexdot(ui, repo, file_=None, **opts):
2234 def debugindexdot(ui, repo, file_=None, **opts):
2236 """dump an index DAG as a graphviz dot file"""
2235 """dump an index DAG as a graphviz dot file"""
2237 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2236 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2238 ui.write(("digraph G {\n"))
2237 ui.write(("digraph G {\n"))
2239 for i in r:
2238 for i in r:
2240 node = r.node(i)
2239 node = r.node(i)
2241 pp = r.parents(node)
2240 pp = r.parents(node)
2242 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2241 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2243 if pp[1] != nullid:
2242 if pp[1] != nullid:
2244 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2243 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2245 ui.write("}\n")
2244 ui.write("}\n")
2246
2245
2247 @command('debugdeltachain',
2246 @command('debugdeltachain',
2248 debugrevlogopts + formatteropts,
2247 debugrevlogopts + formatteropts,
2249 _('-c|-m|FILE'),
2248 _('-c|-m|FILE'),
2250 optionalrepo=True)
2249 optionalrepo=True)
2251 def debugdeltachain(ui, repo, file_=None, **opts):
2250 def debugdeltachain(ui, repo, file_=None, **opts):
2252 """dump information about delta chains in a revlog
2251 """dump information about delta chains in a revlog
2253
2252
2254 Output can be templatized. Available template keywords are:
2253 Output can be templatized. Available template keywords are:
2255
2254
2256 :``rev``: revision number
2255 :``rev``: revision number
2257 :``chainid``: delta chain identifier (numbered by unique base)
2256 :``chainid``: delta chain identifier (numbered by unique base)
2258 :``chainlen``: delta chain length to this revision
2257 :``chainlen``: delta chain length to this revision
2259 :``prevrev``: previous revision in delta chain
2258 :``prevrev``: previous revision in delta chain
2260 :``deltatype``: role of delta / how it was computed
2259 :``deltatype``: role of delta / how it was computed
2261 :``compsize``: compressed size of revision
2260 :``compsize``: compressed size of revision
2262 :``uncompsize``: uncompressed size of revision
2261 :``uncompsize``: uncompressed size of revision
2263 :``chainsize``: total size of compressed revisions in chain
2262 :``chainsize``: total size of compressed revisions in chain
2264 :``chainratio``: total chain size divided by uncompressed revision size
2263 :``chainratio``: total chain size divided by uncompressed revision size
2265 (new delta chains typically start at ratio 2.00)
2264 (new delta chains typically start at ratio 2.00)
2266 :``lindist``: linear distance from base revision in delta chain to end
2265 :``lindist``: linear distance from base revision in delta chain to end
2267 of this revision
2266 of this revision
2268 :``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
2269 base of delta chain to end of this revision; a measurement
2268 base of delta chain to end of this revision; a measurement
2270 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
2271 the delta chain for this revision
2270 the delta chain for this revision
2272 :``extraratio``: extradist divided by chainsize; another representation of
2271 :``extraratio``: extradist divided by chainsize; another representation of
2273 how much unrelated data is needed to load this delta chain
2272 how much unrelated data is needed to load this delta chain
2274 """
2273 """
2275 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2274 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2276 index = r.index
2275 index = r.index
2277 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2276 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2278
2277
2279 def revinfo(rev):
2278 def revinfo(rev):
2280 e = index[rev]
2279 e = index[rev]
2281 compsize = e[1]
2280 compsize = e[1]
2282 uncompsize = e[2]
2281 uncompsize = e[2]
2283 chainsize = 0
2282 chainsize = 0
2284
2283
2285 if generaldelta:
2284 if generaldelta:
2286 if e[3] == e[5]:
2285 if e[3] == e[5]:
2287 deltatype = 'p1'
2286 deltatype = 'p1'
2288 elif e[3] == e[6]:
2287 elif e[3] == e[6]:
2289 deltatype = 'p2'
2288 deltatype = 'p2'
2290 elif e[3] == rev - 1:
2289 elif e[3] == rev - 1:
2291 deltatype = 'prev'
2290 deltatype = 'prev'
2292 elif e[3] == rev:
2291 elif e[3] == rev:
2293 deltatype = 'base'
2292 deltatype = 'base'
2294 else:
2293 else:
2295 deltatype = 'other'
2294 deltatype = 'other'
2296 else:
2295 else:
2297 if e[3] == rev:
2296 if e[3] == rev:
2298 deltatype = 'base'
2297 deltatype = 'base'
2299 else:
2298 else:
2300 deltatype = 'prev'
2299 deltatype = 'prev'
2301
2300
2302 chain = r._deltachain(rev)[0]
2301 chain = r._deltachain(rev)[0]
2303 for iterrev in chain:
2302 for iterrev in chain:
2304 e = index[iterrev]
2303 e = index[iterrev]
2305 chainsize += e[1]
2304 chainsize += e[1]
2306
2305
2307 return compsize, uncompsize, deltatype, chain, chainsize
2306 return compsize, uncompsize, deltatype, chain, chainsize
2308
2307
2309 fm = ui.formatter('debugdeltachain', opts)
2308 fm = ui.formatter('debugdeltachain', opts)
2310
2309
2311 fm.plain(' rev chain# chainlen prev delta '
2310 fm.plain(' rev chain# chainlen prev delta '
2312 'size rawsize chainsize ratio lindist extradist '
2311 'size rawsize chainsize ratio lindist extradist '
2313 'extraratio\n')
2312 'extraratio\n')
2314
2313
2315 chainbases = {}
2314 chainbases = {}
2316 for rev in r:
2315 for rev in r:
2317 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2316 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2318 chainbase = chain[0]
2317 chainbase = chain[0]
2319 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2318 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2320 basestart = r.start(chainbase)
2319 basestart = r.start(chainbase)
2321 revstart = r.start(rev)
2320 revstart = r.start(rev)
2322 lineardist = revstart + comp - basestart
2321 lineardist = revstart + comp - basestart
2323 extradist = lineardist - chainsize
2322 extradist = lineardist - chainsize
2324 try:
2323 try:
2325 prevrev = chain[-2]
2324 prevrev = chain[-2]
2326 except IndexError:
2325 except IndexError:
2327 prevrev = -1
2326 prevrev = -1
2328
2327
2329 chainratio = float(chainsize) / float(uncomp)
2328 chainratio = float(chainsize) / float(uncomp)
2330 extraratio = float(extradist) / float(chainsize)
2329 extraratio = float(extradist) / float(chainsize)
2331
2330
2332 fm.startitem()
2331 fm.startitem()
2333 fm.write('rev chainid chainlen prevrev deltatype compsize '
2332 fm.write('rev chainid chainlen prevrev deltatype compsize '
2334 'uncompsize chainsize chainratio lindist extradist '
2333 'uncompsize chainsize chainratio lindist extradist '
2335 'extraratio',
2334 'extraratio',
2336 '%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',
2337 rev, chainid, len(chain), prevrev, deltatype, comp,
2336 rev, chainid, len(chain), prevrev, deltatype, comp,
2338 uncomp, chainsize, chainratio, lineardist, extradist,
2337 uncomp, chainsize, chainratio, lineardist, extradist,
2339 extraratio,
2338 extraratio,
2340 rev=rev, chainid=chainid, chainlen=len(chain),
2339 rev=rev, chainid=chainid, chainlen=len(chain),
2341 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2340 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2342 uncompsize=uncomp, chainsize=chainsize,
2341 uncompsize=uncomp, chainsize=chainsize,
2343 chainratio=chainratio, lindist=lineardist,
2342 chainratio=chainratio, lindist=lineardist,
2344 extradist=extradist, extraratio=extraratio)
2343 extradist=extradist, extraratio=extraratio)
2345
2344
2346 fm.end()
2345 fm.end()
2347
2346
2348 @command('debuginstall', [] + formatteropts, '', norepo=True)
2347 @command('debuginstall', [] + formatteropts, '', norepo=True)
2349 def debuginstall(ui, **opts):
2348 def debuginstall(ui, **opts):
2350 '''test Mercurial installation
2349 '''test Mercurial installation
2351
2350
2352 Returns 0 on success.
2351 Returns 0 on success.
2353 '''
2352 '''
2354
2353
2355 def writetemp(contents):
2354 def writetemp(contents):
2356 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2355 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2357 f = os.fdopen(fd, "wb")
2356 f = os.fdopen(fd, "wb")
2358 f.write(contents)
2357 f.write(contents)
2359 f.close()
2358 f.close()
2360 return name
2359 return name
2361
2360
2362 problems = 0
2361 problems = 0
2363
2362
2364 fm = ui.formatter('debuginstall', opts)
2363 fm = ui.formatter('debuginstall', opts)
2365 fm.startitem()
2364 fm.startitem()
2366
2365
2367 # encoding
2366 # encoding
2368 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2367 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2369 err = None
2368 err = None
2370 try:
2369 try:
2371 encoding.fromlocal("test")
2370 encoding.fromlocal("test")
2372 except error.Abort as inst:
2371 except error.Abort as inst:
2373 err = inst
2372 err = inst
2374 problems += 1
2373 problems += 1
2375 fm.condwrite(err, 'encodingerror', _(" %s\n"
2374 fm.condwrite(err, 'encodingerror', _(" %s\n"
2376 " (check that your locale is properly set)\n"), err)
2375 " (check that your locale is properly set)\n"), err)
2377
2376
2378 # Python
2377 # Python
2379 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2378 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2380 sys.executable)
2379 sys.executable)
2381 fm.write('pythonver', _("checking Python version (%s)\n"),
2380 fm.write('pythonver', _("checking Python version (%s)\n"),
2382 ("%s.%s.%s" % sys.version_info[:3]))
2381 ("%s.%s.%s" % sys.version_info[:3]))
2383 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2382 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2384 os.path.dirname(os.__file__))
2383 os.path.dirname(os.__file__))
2385
2384
2386 security = set(sslutil.supportedprotocols)
2385 security = set(sslutil.supportedprotocols)
2387 if sslutil.hassni:
2386 if sslutil.hassni:
2388 security.add('sni')
2387 security.add('sni')
2389
2388
2390 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
2389 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
2391 fm.formatlist(sorted(security), name='protocol',
2390 fm.formatlist(sorted(security), name='protocol',
2392 fmt='%s', sep=','))
2391 fmt='%s', sep=','))
2393
2392
2394 # 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
2395 # may change in the future.
2394 # may change in the future.
2396 if 'tls1.2' not in security:
2395 if 'tls1.2' not in security:
2397 fm.plain(_(' TLS 1.2 not supported by Python install; '
2396 fm.plain(_(' TLS 1.2 not supported by Python install; '
2398 'network connections lack modern security\n'))
2397 'network connections lack modern security\n'))
2399 if 'sni' not in security:
2398 if 'sni' not in security:
2400 fm.plain(_(' SNI not supported by Python install; may have '
2399 fm.plain(_(' SNI not supported by Python install; may have '
2401 'connectivity issues with some servers\n'))
2400 'connectivity issues with some servers\n'))
2402
2401
2403 # TODO print CA cert info
2402 # TODO print CA cert info
2404
2403
2405 # hg version
2404 # hg version
2406 hgver = util.version()
2405 hgver = util.version()
2407 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2406 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2408 hgver.split('+')[0])
2407 hgver.split('+')[0])
2409 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2408 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2410 '+'.join(hgver.split('+')[1:]))
2409 '+'.join(hgver.split('+')[1:]))
2411
2410
2412 # compiled modules
2411 # compiled modules
2413 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2412 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2414 policy.policy)
2413 policy.policy)
2415 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2414 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2416 os.path.dirname(__file__))
2415 os.path.dirname(__file__))
2417
2416
2418 err = None
2417 err = None
2419 try:
2418 try:
2420 from . import (
2419 from . import (
2421 base85,
2420 base85,
2422 bdiff,
2421 bdiff,
2423 mpatch,
2422 mpatch,
2424 osutil,
2423 osutil,
2425 )
2424 )
2426 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2425 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2427 except Exception as inst:
2426 except Exception as inst:
2428 err = inst
2427 err = inst
2429 problems += 1
2428 problems += 1
2430 fm.condwrite(err, 'extensionserror', " %s\n", err)
2429 fm.condwrite(err, 'extensionserror', " %s\n", err)
2431
2430
2432 compengines = util.compengines._engines.values()
2431 compengines = util.compengines._engines.values()
2433 fm.write('compengines', _('checking registered compression engines (%s)\n'),
2432 fm.write('compengines', _('checking registered compression engines (%s)\n'),
2434 fm.formatlist(sorted(e.name() for e in compengines),
2433 fm.formatlist(sorted(e.name() for e in compengines),
2435 name='compengine', fmt='%s', sep=', '))
2434 name='compengine', fmt='%s', sep=', '))
2436 fm.write('compenginesavail', _('checking available compression engines '
2435 fm.write('compenginesavail', _('checking available compression engines '
2437 '(%s)\n'),
2436 '(%s)\n'),
2438 fm.formatlist(sorted(e.name() for e in compengines
2437 fm.formatlist(sorted(e.name() for e in compengines
2439 if e.available()),
2438 if e.available()),
2440 name='compengine', fmt='%s', sep=', '))
2439 name='compengine', fmt='%s', sep=', '))
2441
2440
2442 # templates
2441 # templates
2443 p = templater.templatepaths()
2442 p = templater.templatepaths()
2444 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2443 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2445 fm.condwrite(not p, '', _(" no template directories found\n"))
2444 fm.condwrite(not p, '', _(" no template directories found\n"))
2446 if p:
2445 if p:
2447 m = templater.templatepath("map-cmdline.default")
2446 m = templater.templatepath("map-cmdline.default")
2448 if m:
2447 if m:
2449 # template found, check if it is working
2448 # template found, check if it is working
2450 err = None
2449 err = None
2451 try:
2450 try:
2452 templater.templater.frommapfile(m)
2451 templater.templater.frommapfile(m)
2453 except Exception as inst:
2452 except Exception as inst:
2454 err = inst
2453 err = inst
2455 p = None
2454 p = None
2456 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2455 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2457 else:
2456 else:
2458 p = None
2457 p = None
2459 fm.condwrite(p, 'defaulttemplate',
2458 fm.condwrite(p, 'defaulttemplate',
2460 _("checking default template (%s)\n"), m)
2459 _("checking default template (%s)\n"), m)
2461 fm.condwrite(not m, 'defaulttemplatenotfound',
2460 fm.condwrite(not m, 'defaulttemplatenotfound',
2462 _(" template '%s' not found\n"), "default")
2461 _(" template '%s' not found\n"), "default")
2463 if not p:
2462 if not p:
2464 problems += 1
2463 problems += 1
2465 fm.condwrite(not p, '',
2464 fm.condwrite(not p, '',
2466 _(" (templates seem to have been installed incorrectly)\n"))
2465 _(" (templates seem to have been installed incorrectly)\n"))
2467
2466
2468 # editor
2467 # editor
2469 editor = ui.geteditor()
2468 editor = ui.geteditor()
2470 editor = util.expandpath(editor)
2469 editor = util.expandpath(editor)
2471 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2470 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2472 cmdpath = util.findexe(shlex.split(editor)[0])
2471 cmdpath = util.findexe(shlex.split(editor)[0])
2473 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2472 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2474 _(" 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"
2475 " (specify a commit editor in your configuration"
2474 " (specify a commit editor in your configuration"
2476 " file)\n"), not cmdpath and editor == 'vi' and editor)
2475 " file)\n"), not cmdpath and editor == 'vi' and editor)
2477 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2476 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2478 _(" Can't find editor '%s' in PATH\n"
2477 _(" Can't find editor '%s' in PATH\n"
2479 " (specify a commit editor in your configuration"
2478 " (specify a commit editor in your configuration"
2480 " file)\n"), not cmdpath and editor)
2479 " file)\n"), not cmdpath and editor)
2481 if not cmdpath and editor != 'vi':
2480 if not cmdpath and editor != 'vi':
2482 problems += 1
2481 problems += 1
2483
2482
2484 # check username
2483 # check username
2485 username = None
2484 username = None
2486 err = None
2485 err = None
2487 try:
2486 try:
2488 username = ui.username()
2487 username = ui.username()
2489 except error.Abort as e:
2488 except error.Abort as e:
2490 err = e
2489 err = e
2491 problems += 1
2490 problems += 1
2492
2491
2493 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2492 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2494 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2493 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2495 " (specify a username in your configuration file)\n"), err)
2494 " (specify a username in your configuration file)\n"), err)
2496
2495
2497 fm.condwrite(not problems, '',
2496 fm.condwrite(not problems, '',
2498 _("no problems detected\n"))
2497 _("no problems detected\n"))
2499 if not problems:
2498 if not problems:
2500 fm.data(problems=problems)
2499 fm.data(problems=problems)
2501 fm.condwrite(problems, 'problems',
2500 fm.condwrite(problems, 'problems',
2502 _("%d problems detected,"
2501 _("%d problems detected,"
2503 " please check your install!\n"), problems)
2502 " please check your install!\n"), problems)
2504 fm.end()
2503 fm.end()
2505
2504
2506 return problems
2505 return problems
2507
2506
2508 @command('debugknown', [], _('REPO ID...'), norepo=True)
2507 @command('debugknown', [], _('REPO ID...'), norepo=True)
2509 def debugknown(ui, repopath, *ids, **opts):
2508 def debugknown(ui, repopath, *ids, **opts):
2510 """test whether node ids are known to a repo
2509 """test whether node ids are known to a repo
2511
2510
2512 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
2513 and 1s indicating unknown/known.
2512 and 1s indicating unknown/known.
2514 """
2513 """
2515 repo = hg.peer(ui, opts, repopath)
2514 repo = hg.peer(ui, opts, repopath)
2516 if not repo.capable('known'):
2515 if not repo.capable('known'):
2517 raise error.Abort("known() not supported by target repository")
2516 raise error.Abort("known() not supported by target repository")
2518 flags = repo.known([bin(s) for s in ids])
2517 flags = repo.known([bin(s) for s in ids])
2519 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])))
2520
2519
2521 @command('debuglabelcomplete', [], _('LABEL...'))
2520 @command('debuglabelcomplete', [], _('LABEL...'))
2522 def debuglabelcomplete(ui, repo, *args):
2521 def debuglabelcomplete(ui, repo, *args):
2523 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2522 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2524 debugnamecomplete(ui, repo, *args)
2523 debugnamecomplete(ui, repo, *args)
2525
2524
2526 @command('debugmergestate', [], '')
2525 @command('debugmergestate', [], '')
2527 def debugmergestate(ui, repo, *args):
2526 def debugmergestate(ui, repo, *args):
2528 """print merge state
2527 """print merge state
2529
2528
2530 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
2531 was chosen."""
2530 was chosen."""
2532 def _hashornull(h):
2531 def _hashornull(h):
2533 if h == nullhex:
2532 if h == nullhex:
2534 return 'null'
2533 return 'null'
2535 else:
2534 else:
2536 return h
2535 return h
2537
2536
2538 def printrecords(version):
2537 def printrecords(version):
2539 ui.write(('* version %s records\n') % version)
2538 ui.write(('* version %s records\n') % version)
2540 if version == 1:
2539 if version == 1:
2541 records = v1records
2540 records = v1records
2542 else:
2541 else:
2543 records = v2records
2542 records = v2records
2544
2543
2545 for rtype, record in records:
2544 for rtype, record in records:
2546 # pretty print some record types
2545 # pretty print some record types
2547 if rtype == 'L':
2546 if rtype == 'L':
2548 ui.write(('local: %s\n') % record)
2547 ui.write(('local: %s\n') % record)
2549 elif rtype == 'O':
2548 elif rtype == 'O':
2550 ui.write(('other: %s\n') % record)
2549 ui.write(('other: %s\n') % record)
2551 elif rtype == 'm':
2550 elif rtype == 'm':
2552 driver, mdstate = record.split('\0', 1)
2551 driver, mdstate = record.split('\0', 1)
2553 ui.write(('merge driver: %s (state "%s")\n')
2552 ui.write(('merge driver: %s (state "%s")\n')
2554 % (driver, mdstate))
2553 % (driver, mdstate))
2555 elif rtype in 'FDC':
2554 elif rtype in 'FDC':
2556 r = record.split('\0')
2555 r = record.split('\0')
2557 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2556 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2558 if version == 1:
2557 if version == 1:
2559 onode = 'not stored in v1 format'
2558 onode = 'not stored in v1 format'
2560 flags = r[7]
2559 flags = r[7]
2561 else:
2560 else:
2562 onode, flags = r[7:9]
2561 onode, flags = r[7:9]
2563 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')
2564 % (f, rtype, state, _hashornull(hash)))
2563 % (f, rtype, state, _hashornull(hash)))
2565 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2564 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2566 ui.write((' ancestor path: %s (node %s)\n')
2565 ui.write((' ancestor path: %s (node %s)\n')
2567 % (afile, _hashornull(anode)))
2566 % (afile, _hashornull(anode)))
2568 ui.write((' other path: %s (node %s)\n')
2567 ui.write((' other path: %s (node %s)\n')
2569 % (ofile, _hashornull(onode)))
2568 % (ofile, _hashornull(onode)))
2570 elif rtype == 'f':
2569 elif rtype == 'f':
2571 filename, rawextras = record.split('\0', 1)
2570 filename, rawextras = record.split('\0', 1)
2572 extras = rawextras.split('\0')
2571 extras = rawextras.split('\0')
2573 i = 0
2572 i = 0
2574 extrastrings = []
2573 extrastrings = []
2575 while i < len(extras):
2574 while i < len(extras):
2576 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2575 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2577 i += 2
2576 i += 2
2578
2577
2579 ui.write(('file extras: %s (%s)\n')
2578 ui.write(('file extras: %s (%s)\n')
2580 % (filename, ', '.join(extrastrings)))
2579 % (filename, ', '.join(extrastrings)))
2581 elif rtype == 'l':
2580 elif rtype == 'l':
2582 labels = record.split('\0', 2)
2581 labels = record.split('\0', 2)
2583 labels = [l for l in labels if len(l) > 0]
2582 labels = [l for l in labels if len(l) > 0]
2584 ui.write(('labels:\n'))
2583 ui.write(('labels:\n'))
2585 ui.write((' local: %s\n' % labels[0]))
2584 ui.write((' local: %s\n' % labels[0]))
2586 ui.write((' other: %s\n' % labels[1]))
2585 ui.write((' other: %s\n' % labels[1]))
2587 if len(labels) > 2:
2586 if len(labels) > 2:
2588 ui.write((' base: %s\n' % labels[2]))
2587 ui.write((' base: %s\n' % labels[2]))
2589 else:
2588 else:
2590 ui.write(('unrecognized entry: %s\t%s\n')
2589 ui.write(('unrecognized entry: %s\t%s\n')
2591 % (rtype, record.replace('\0', '\t')))
2590 % (rtype, record.replace('\0', '\t')))
2592
2591
2593 # Avoid mergestate.read() since it may raise an exception for unsupported
2592 # Avoid mergestate.read() since it may raise an exception for unsupported
2594 # 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
2595 # command is pretty low-level.
2594 # command is pretty low-level.
2596 ms = mergemod.mergestate(repo)
2595 ms = mergemod.mergestate(repo)
2597
2596
2598 # sort so that reasonable information is on top
2597 # sort so that reasonable information is on top
2599 v1records = ms._readrecordsv1()
2598 v1records = ms._readrecordsv1()
2600 v2records = ms._readrecordsv2()
2599 v2records = ms._readrecordsv2()
2601 order = 'LOml'
2600 order = 'LOml'
2602 def key(r):
2601 def key(r):
2603 idx = order.find(r[0])
2602 idx = order.find(r[0])
2604 if idx == -1:
2603 if idx == -1:
2605 return (1, r[1])
2604 return (1, r[1])
2606 else:
2605 else:
2607 return (0, idx)
2606 return (0, idx)
2608 v1records.sort(key=key)
2607 v1records.sort(key=key)
2609 v2records.sort(key=key)
2608 v2records.sort(key=key)
2610
2609
2611 if not v1records and not v2records:
2610 if not v1records and not v2records:
2612 ui.write(('no merge state found\n'))
2611 ui.write(('no merge state found\n'))
2613 elif not v2records:
2612 elif not v2records:
2614 ui.note(('no version 2 merge state\n'))
2613 ui.note(('no version 2 merge state\n'))
2615 printrecords(1)
2614 printrecords(1)
2616 elif ms._v1v2match(v1records, v2records):
2615 elif ms._v1v2match(v1records, v2records):
2617 ui.note(('v1 and v2 states match: using v2\n'))
2616 ui.note(('v1 and v2 states match: using v2\n'))
2618 printrecords(2)
2617 printrecords(2)
2619 else:
2618 else:
2620 ui.note(('v1 and v2 states mismatch: using v1\n'))
2619 ui.note(('v1 and v2 states mismatch: using v1\n'))
2621 printrecords(1)
2620 printrecords(1)
2622 if ui.verbose:
2621 if ui.verbose:
2623 printrecords(2)
2622 printrecords(2)
2624
2623
2625 @command('debugnamecomplete', [], _('NAME...'))
2624 @command('debugnamecomplete', [], _('NAME...'))
2626 def debugnamecomplete(ui, repo, *args):
2625 def debugnamecomplete(ui, repo, *args):
2627 '''complete "names" - tags, open branch names, bookmark names'''
2626 '''complete "names" - tags, open branch names, bookmark names'''
2628
2627
2629 names = set()
2628 names = set()
2630 # since we previously only listed open branches, we will handle that
2629 # since we previously only listed open branches, we will handle that
2631 # specially (after this for loop)
2630 # specially (after this for loop)
2632 for name, ns in repo.names.iteritems():
2631 for name, ns in repo.names.iteritems():
2633 if name != 'branches':
2632 if name != 'branches':
2634 names.update(ns.listnames(repo))
2633 names.update(ns.listnames(repo))
2635 names.update(tag for (tag, heads, tip, closed)
2634 names.update(tag for (tag, heads, tip, closed)
2636 in repo.branchmap().iterbranches() if not closed)
2635 in repo.branchmap().iterbranches() if not closed)
2637 completions = set()
2636 completions = set()
2638 if not args:
2637 if not args:
2639 args = ['']
2638 args = ['']
2640 for a in args:
2639 for a in args:
2641 completions.update(n for n in names if n.startswith(a))
2640 completions.update(n for n in names if n.startswith(a))
2642 ui.write('\n'.join(sorted(completions)))
2641 ui.write('\n'.join(sorted(completions)))
2643 ui.write('\n')
2642 ui.write('\n')
2644
2643
2645 @command('debuglocks',
2644 @command('debuglocks',
2646 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2645 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2647 ('W', 'force-wlock', None,
2646 ('W', 'force-wlock', None,
2648 _('free the working state lock (DANGEROUS)'))],
2647 _('free the working state lock (DANGEROUS)'))],
2649 _('[OPTION]...'))
2648 _('[OPTION]...'))
2650 def debuglocks(ui, repo, **opts):
2649 def debuglocks(ui, repo, **opts):
2651 """show or modify state of locks
2650 """show or modify state of locks
2652
2651
2653 By default, this command will show which locks are held. This
2652 By default, this command will show which locks are held. This
2654 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
2655 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
2656 running if it's not local.
2655 running if it's not local.
2657
2656
2658 Locks protect the integrity of Mercurial's data, so should be
2657 Locks protect the integrity of Mercurial's data, so should be
2659 treated with care. System crashes or other interruptions may cause
2658 treated with care. System crashes or other interruptions may cause
2660 locks to not be properly released, though Mercurial will usually
2659 locks to not be properly released, though Mercurial will usually
2661 detect and remove such stale locks automatically.
2660 detect and remove such stale locks automatically.
2662
2661
2663 However, detecting stale locks may not always be possible (for
2662 However, detecting stale locks may not always be possible (for
2664 instance, on a shared filesystem). Removing locks may also be
2663 instance, on a shared filesystem). Removing locks may also be
2665 blocked by filesystem permissions.
2664 blocked by filesystem permissions.
2666
2665
2667 Returns 0 if no locks are held.
2666 Returns 0 if no locks are held.
2668
2667
2669 """
2668 """
2670
2669
2671 if opts.get('force_lock'):
2670 if opts.get('force_lock'):
2672 repo.svfs.unlink('lock')
2671 repo.svfs.unlink('lock')
2673 if opts.get('force_wlock'):
2672 if opts.get('force_wlock'):
2674 repo.vfs.unlink('wlock')
2673 repo.vfs.unlink('wlock')
2675 if opts.get('force_lock') or opts.get('force_lock'):
2674 if opts.get('force_lock') or opts.get('force_lock'):
2676 return 0
2675 return 0
2677
2676
2678 now = time.time()
2677 now = time.time()
2679 held = 0
2678 held = 0
2680
2679
2681 def report(vfs, name, method):
2680 def report(vfs, name, method):
2682 # this causes stale locks to get reaped for more accurate reporting
2681 # this causes stale locks to get reaped for more accurate reporting
2683 try:
2682 try:
2684 l = method(False)
2683 l = method(False)
2685 except error.LockHeld:
2684 except error.LockHeld:
2686 l = None
2685 l = None
2687
2686
2688 if l:
2687 if l:
2689 l.release()
2688 l.release()
2690 else:
2689 else:
2691 try:
2690 try:
2692 stat = vfs.lstat(name)
2691 stat = vfs.lstat(name)
2693 age = now - stat.st_mtime
2692 age = now - stat.st_mtime
2694 user = util.username(stat.st_uid)
2693 user = util.username(stat.st_uid)
2695 locker = vfs.readlock(name)
2694 locker = vfs.readlock(name)
2696 if ":" in locker:
2695 if ":" in locker:
2697 host, pid = locker.split(':')
2696 host, pid = locker.split(':')
2698 if host == socket.gethostname():
2697 if host == socket.gethostname():
2699 locker = 'user %s, process %s' % (user, pid)
2698 locker = 'user %s, process %s' % (user, pid)
2700 else:
2699 else:
2701 locker = 'user %s, process %s, host %s' \
2700 locker = 'user %s, process %s, host %s' \
2702 % (user, pid, host)
2701 % (user, pid, host)
2703 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2702 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
2704 return 1
2703 return 1
2705 except OSError as e:
2704 except OSError as e:
2706 if e.errno != errno.ENOENT:
2705 if e.errno != errno.ENOENT:
2707 raise
2706 raise
2708
2707
2709 ui.write(("%-6s free\n") % (name + ":"))
2708 ui.write(("%-6s free\n") % (name + ":"))
2710 return 0
2709 return 0
2711
2710
2712 held += report(repo.svfs, "lock", repo.lock)
2711 held += report(repo.svfs, "lock", repo.lock)
2713 held += report(repo.vfs, "wlock", repo.wlock)
2712 held += report(repo.vfs, "wlock", repo.wlock)
2714
2713
2715 return held
2714 return held
2716
2715
2717 @command('debugobsolete',
2716 @command('debugobsolete',
2718 [('', 'flags', 0, _('markers flag')),
2717 [('', 'flags', 0, _('markers flag')),
2719 ('', 'record-parents', False,
2718 ('', 'record-parents', False,
2720 _('record parent information for the precursor')),
2719 _('record parent information for the precursor')),
2721 ('r', 'rev', [], _('display markers relevant to REV')),
2720 ('r', 'rev', [], _('display markers relevant to REV')),
2722 ('', 'index', False, _('display index of the marker')),
2721 ('', 'index', False, _('display index of the marker')),
2723 ('', 'delete', [], _('delete markers specified by indices')),
2722 ('', 'delete', [], _('delete markers specified by indices')),
2724 ] + commitopts2 + formatteropts,
2723 ] + commitopts2 + formatteropts,
2725 _('[OBSOLETED [REPLACEMENT ...]]'))
2724 _('[OBSOLETED [REPLACEMENT ...]]'))
2726 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2725 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2727 """create arbitrary obsolete marker
2726 """create arbitrary obsolete marker
2728
2727
2729 With no arguments, displays the list of obsolescence markers."""
2728 With no arguments, displays the list of obsolescence markers."""
2730
2729
2731 def parsenodeid(s):
2730 def parsenodeid(s):
2732 try:
2731 try:
2733 # We do not use revsingle/revrange functions here to accept
2732 # We do not use revsingle/revrange functions here to accept
2734 # arbitrary node identifiers, possibly not present in the
2733 # arbitrary node identifiers, possibly not present in the
2735 # local repository.
2734 # local repository.
2736 n = bin(s)
2735 n = bin(s)
2737 if len(n) != len(nullid):
2736 if len(n) != len(nullid):
2738 raise TypeError()
2737 raise TypeError()
2739 return n
2738 return n
2740 except TypeError:
2739 except TypeError:
2741 raise error.Abort('changeset references must be full hexadecimal '
2740 raise error.Abort('changeset references must be full hexadecimal '
2742 'node identifiers')
2741 'node identifiers')
2743
2742
2744 if opts.get('delete'):
2743 if opts.get('delete'):
2745 indices = []
2744 indices = []
2746 for v in opts.get('delete'):
2745 for v in opts.get('delete'):
2747 try:
2746 try:
2748 indices.append(int(v))
2747 indices.append(int(v))
2749 except ValueError:
2748 except ValueError:
2750 raise error.Abort(_('invalid index value: %r') % v,
2749 raise error.Abort(_('invalid index value: %r') % v,
2751 hint=_('use integers for indices'))
2750 hint=_('use integers for indices'))
2752
2751
2753 if repo.currenttransaction():
2752 if repo.currenttransaction():
2754 raise error.Abort(_('cannot delete obsmarkers in the middle '
2753 raise error.Abort(_('cannot delete obsmarkers in the middle '
2755 'of transaction.'))
2754 'of transaction.'))
2756
2755
2757 with repo.lock():
2756 with repo.lock():
2758 n = repair.deleteobsmarkers(repo.obsstore, indices)
2757 n = repair.deleteobsmarkers(repo.obsstore, indices)
2759 ui.write(_('deleted %i obsolescence markers\n') % n)
2758 ui.write(_('deleted %i obsolescence markers\n') % n)
2760
2759
2761 return
2760 return
2762
2761
2763 if precursor is not None:
2762 if precursor is not None:
2764 if opts['rev']:
2763 if opts['rev']:
2765 raise error.Abort('cannot select revision when creating marker')
2764 raise error.Abort('cannot select revision when creating marker')
2766 metadata = {}
2765 metadata = {}
2767 metadata['user'] = opts['user'] or ui.username()
2766 metadata['user'] = opts['user'] or ui.username()
2768 succs = tuple(parsenodeid(succ) for succ in successors)
2767 succs = tuple(parsenodeid(succ) for succ in successors)
2769 l = repo.lock()
2768 l = repo.lock()
2770 try:
2769 try:
2771 tr = repo.transaction('debugobsolete')
2770 tr = repo.transaction('debugobsolete')
2772 try:
2771 try:
2773 date = opts.get('date')
2772 date = opts.get('date')
2774 if date:
2773 if date:
2775 date = util.parsedate(date)
2774 date = util.parsedate(date)
2776 else:
2775 else:
2777 date = None
2776 date = None
2778 prec = parsenodeid(precursor)
2777 prec = parsenodeid(precursor)
2779 parents = None
2778 parents = None
2780 if opts['record_parents']:
2779 if opts['record_parents']:
2781 if prec not in repo.unfiltered():
2780 if prec not in repo.unfiltered():
2782 raise error.Abort('cannot used --record-parents on '
2781 raise error.Abort('cannot used --record-parents on '
2783 'unknown changesets')
2782 'unknown changesets')
2784 parents = repo.unfiltered()[prec].parents()
2783 parents = repo.unfiltered()[prec].parents()
2785 parents = tuple(p.node() for p in parents)
2784 parents = tuple(p.node() for p in parents)
2786 repo.obsstore.create(tr, prec, succs, opts['flags'],
2785 repo.obsstore.create(tr, prec, succs, opts['flags'],
2787 parents=parents, date=date,
2786 parents=parents, date=date,
2788 metadata=metadata)
2787 metadata=metadata)
2789 tr.close()
2788 tr.close()
2790 except ValueError as exc:
2789 except ValueError as exc:
2791 raise error.Abort(_('bad obsmarker input: %s') % exc)
2790 raise error.Abort(_('bad obsmarker input: %s') % exc)
2792 finally:
2791 finally:
2793 tr.release()
2792 tr.release()
2794 finally:
2793 finally:
2795 l.release()
2794 l.release()
2796 else:
2795 else:
2797 if opts['rev']:
2796 if opts['rev']:
2798 revs = scmutil.revrange(repo, opts['rev'])
2797 revs = scmutil.revrange(repo, opts['rev'])
2799 nodes = [repo[r].node() for r in revs]
2798 nodes = [repo[r].node() for r in revs]
2800 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2799 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2801 markers.sort(key=lambda x: x._data)
2800 markers.sort(key=lambda x: x._data)
2802 else:
2801 else:
2803 markers = obsolete.getmarkers(repo)
2802 markers = obsolete.getmarkers(repo)
2804
2803
2805 markerstoiter = markers
2804 markerstoiter = markers
2806 isrelevant = lambda m: True
2805 isrelevant = lambda m: True
2807 if opts.get('rev') and opts.get('index'):
2806 if opts.get('rev') and opts.get('index'):
2808 markerstoiter = obsolete.getmarkers(repo)
2807 markerstoiter = obsolete.getmarkers(repo)
2809 markerset = set(markers)
2808 markerset = set(markers)
2810 isrelevant = lambda m: m in markerset
2809 isrelevant = lambda m: m in markerset
2811
2810
2812 fm = ui.formatter('debugobsolete', opts)
2811 fm = ui.formatter('debugobsolete', opts)
2813 for i, m in enumerate(markerstoiter):
2812 for i, m in enumerate(markerstoiter):
2814 if not isrelevant(m):
2813 if not isrelevant(m):
2815 # marker can be irrelevant when we're iterating over a set
2814 # marker can be irrelevant when we're iterating over a set
2816 # of markers (markerstoiter) which is bigger than the set
2815 # of markers (markerstoiter) which is bigger than the set
2817 # of markers we want to display (markers)
2816 # of markers we want to display (markers)
2818 # this can happen if both --index and --rev options are
2817 # this can happen if both --index and --rev options are
2819 # 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
2820 # to get the correct indices, but only display the ones that
2819 # to get the correct indices, but only display the ones that
2821 # are relevant to --rev value
2820 # are relevant to --rev value
2822 continue
2821 continue
2823 fm.startitem()
2822 fm.startitem()
2824 ind = i if opts.get('index') else None
2823 ind = i if opts.get('index') else None
2825 cmdutil.showmarker(fm, m, index=ind)
2824 cmdutil.showmarker(fm, m, index=ind)
2826 fm.end()
2825 fm.end()
2827
2826
2828 @command('debugpathcomplete',
2827 @command('debugpathcomplete',
2829 [('f', 'full', None, _('complete an entire path')),
2828 [('f', 'full', None, _('complete an entire path')),
2830 ('n', 'normal', None, _('show only normal files')),
2829 ('n', 'normal', None, _('show only normal files')),
2831 ('a', 'added', None, _('show only added files')),
2830 ('a', 'added', None, _('show only added files')),
2832 ('r', 'removed', None, _('show only removed files'))],
2831 ('r', 'removed', None, _('show only removed files'))],
2833 _('FILESPEC...'))
2832 _('FILESPEC...'))
2834 def debugpathcomplete(ui, repo, *specs, **opts):
2833 def debugpathcomplete(ui, repo, *specs, **opts):
2835 '''complete part or all of a tracked path
2834 '''complete part or all of a tracked path
2836
2835
2837 This command supports shells that offer path name completion. It
2836 This command supports shells that offer path name completion. It
2838 currently completes only files already known to the dirstate.
2837 currently completes only files already known to the dirstate.
2839
2838
2840 Completion extends only to the next path segment unless
2839 Completion extends only to the next path segment unless
2841 --full is specified, in which case entire paths are used.'''
2840 --full is specified, in which case entire paths are used.'''
2842
2841
2843 def complete(path, acceptable):
2842 def complete(path, acceptable):
2844 dirstate = repo.dirstate
2843 dirstate = repo.dirstate
2845 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2844 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2846 rootdir = repo.root + os.sep
2845 rootdir = repo.root + os.sep
2847 if spec != repo.root and not spec.startswith(rootdir):
2846 if spec != repo.root and not spec.startswith(rootdir):
2848 return [], []
2847 return [], []
2849 if os.path.isdir(spec):
2848 if os.path.isdir(spec):
2850 spec += '/'
2849 spec += '/'
2851 spec = spec[len(rootdir):]
2850 spec = spec[len(rootdir):]
2852 fixpaths = pycompat.ossep != '/'
2851 fixpaths = pycompat.ossep != '/'
2853 if fixpaths:
2852 if fixpaths:
2854 spec = spec.replace(os.sep, '/')
2853 spec = spec.replace(os.sep, '/')
2855 speclen = len(spec)
2854 speclen = len(spec)
2856 fullpaths = opts['full']
2855 fullpaths = opts['full']
2857 files, dirs = set(), set()
2856 files, dirs = set(), set()
2858 adddir, addfile = dirs.add, files.add
2857 adddir, addfile = dirs.add, files.add
2859 for f, st in dirstate.iteritems():
2858 for f, st in dirstate.iteritems():
2860 if f.startswith(spec) and st[0] in acceptable:
2859 if f.startswith(spec) and st[0] in acceptable:
2861 if fixpaths:
2860 if fixpaths:
2862 f = f.replace('/', os.sep)
2861 f = f.replace('/', os.sep)
2863 if fullpaths:
2862 if fullpaths:
2864 addfile(f)
2863 addfile(f)
2865 continue
2864 continue
2866 s = f.find(os.sep, speclen)
2865 s = f.find(os.sep, speclen)
2867 if s >= 0:
2866 if s >= 0:
2868 adddir(f[:s])
2867 adddir(f[:s])
2869 else:
2868 else:
2870 addfile(f)
2869 addfile(f)
2871 return files, dirs
2870 return files, dirs
2872
2871
2873 acceptable = ''
2872 acceptable = ''
2874 if opts['normal']:
2873 if opts['normal']:
2875 acceptable += 'nm'
2874 acceptable += 'nm'
2876 if opts['added']:
2875 if opts['added']:
2877 acceptable += 'a'
2876 acceptable += 'a'
2878 if opts['removed']:
2877 if opts['removed']:
2879 acceptable += 'r'
2878 acceptable += 'r'
2880 cwd = repo.getcwd()
2879 cwd = repo.getcwd()
2881 if not specs:
2880 if not specs:
2882 specs = ['.']
2881 specs = ['.']
2883
2882
2884 files, dirs = set(), set()
2883 files, dirs = set(), set()
2885 for spec in specs:
2884 for spec in specs:
2886 f, d = complete(spec, acceptable or 'nmar')
2885 f, d = complete(spec, acceptable or 'nmar')
2887 files.update(f)
2886 files.update(f)
2888 dirs.update(d)
2887 dirs.update(d)
2889 files.update(dirs)
2888 files.update(dirs)
2890 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)))
2891 ui.write('\n')
2890 ui.write('\n')
2892
2891
2893 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2892 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2894 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2893 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2895 '''access the pushkey key/value protocol
2894 '''access the pushkey key/value protocol
2896
2895
2897 With two args, list the keys in the given namespace.
2896 With two args, list the keys in the given namespace.
2898
2897
2899 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.
2900 Reports success or failure.
2899 Reports success or failure.
2901 '''
2900 '''
2902
2901
2903 target = hg.peer(ui, {}, repopath)
2902 target = hg.peer(ui, {}, repopath)
2904 if keyinfo:
2903 if keyinfo:
2905 key, old, new = keyinfo
2904 key, old, new = keyinfo
2906 r = target.pushkey(namespace, key, old, new)
2905 r = target.pushkey(namespace, key, old, new)
2907 ui.status(str(r) + '\n')
2906 ui.status(str(r) + '\n')
2908 return not r
2907 return not r
2909 else:
2908 else:
2910 for k, v in sorted(target.listkeys(namespace).iteritems()):
2909 for k, v in sorted(target.listkeys(namespace).iteritems()):
2911 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2910 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2912 v.encode('string-escape')))
2911 v.encode('string-escape')))
2913
2912
2914 @command('debugpvec', [], _('A B'))
2913 @command('debugpvec', [], _('A B'))
2915 def debugpvec(ui, repo, a, b=None):
2914 def debugpvec(ui, repo, a, b=None):
2916 ca = scmutil.revsingle(repo, a)
2915 ca = scmutil.revsingle(repo, a)
2917 cb = scmutil.revsingle(repo, b)
2916 cb = scmutil.revsingle(repo, b)
2918 pa = pvec.ctxpvec(ca)
2917 pa = pvec.ctxpvec(ca)
2919 pb = pvec.ctxpvec(cb)
2918 pb = pvec.ctxpvec(cb)
2920 if pa == pb:
2919 if pa == pb:
2921 rel = "="
2920 rel = "="
2922 elif pa > pb:
2921 elif pa > pb:
2923 rel = ">"
2922 rel = ">"
2924 elif pa < pb:
2923 elif pa < pb:
2925 rel = "<"
2924 rel = "<"
2926 elif pa | pb:
2925 elif pa | pb:
2927 rel = "|"
2926 rel = "|"
2928 ui.write(_("a: %s\n") % pa)
2927 ui.write(_("a: %s\n") % pa)
2929 ui.write(_("b: %s\n") % pb)
2928 ui.write(_("b: %s\n") % pb)
2930 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))
2931 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2930 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2932 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2931 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2933 pa.distance(pb), rel))
2932 pa.distance(pb), rel))
2934
2933
2935 @command('debugrebuilddirstate|debugrebuildstate',
2934 @command('debugrebuilddirstate|debugrebuildstate',
2936 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2935 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2937 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2936 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2938 'the working copy parent')),
2937 'the working copy parent')),
2939 ],
2938 ],
2940 _('[-r REV]'))
2939 _('[-r REV]'))
2941 def debugrebuilddirstate(ui, repo, rev, **opts):
2940 def debugrebuilddirstate(ui, repo, rev, **opts):
2942 """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
2943
2942
2944 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.
2945
2944
2946 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.
2947 The actual working directory content or existing dirstate
2946 The actual working directory content or existing dirstate
2948 information such as adds or removes is not considered.
2947 information such as adds or removes is not considered.
2949
2948
2950 ``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
2951 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
2952 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
2953 modified files that are in the working copy parent.
2952 modified files that are in the working copy parent.
2954
2953
2955 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
2956 check the actual file content.
2955 check the actual file content.
2957 """
2956 """
2958 ctx = scmutil.revsingle(repo, rev)
2957 ctx = scmutil.revsingle(repo, rev)
2959 with repo.wlock():
2958 with repo.wlock():
2960 dirstate = repo.dirstate
2959 dirstate = repo.dirstate
2961 changedfiles = None
2960 changedfiles = None
2962 # See command doc for what minimal does.
2961 # See command doc for what minimal does.
2963 if opts.get('minimal'):
2962 if opts.get('minimal'):
2964 manifestfiles = set(ctx.manifest().keys())
2963 manifestfiles = set(ctx.manifest().keys())
2965 dirstatefiles = set(dirstate)
2964 dirstatefiles = set(dirstate)
2966 manifestonly = manifestfiles - dirstatefiles
2965 manifestonly = manifestfiles - dirstatefiles
2967 dsonly = dirstatefiles - manifestfiles
2966 dsonly = dirstatefiles - manifestfiles
2968 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
2967 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
2969 changedfiles = manifestonly | dsnotadded
2968 changedfiles = manifestonly | dsnotadded
2970
2969
2971 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2970 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2972
2971
2973 @command('debugrebuildfncache', [], '')
2972 @command('debugrebuildfncache', [], '')
2974 def debugrebuildfncache(ui, repo):
2973 def debugrebuildfncache(ui, repo):
2975 """rebuild the fncache file"""
2974 """rebuild the fncache file"""
2976 repair.rebuildfncache(ui, repo)
2975 repair.rebuildfncache(ui, repo)
2977
2976
2978 @command('debugrename',
2977 @command('debugrename',
2979 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2978 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2980 _('[-r REV] FILE'))
2979 _('[-r REV] FILE'))
2981 def debugrename(ui, repo, file1, *pats, **opts):
2980 def debugrename(ui, repo, file1, *pats, **opts):
2982 """dump rename information"""
2981 """dump rename information"""
2983
2982
2984 ctx = scmutil.revsingle(repo, opts.get('rev'))
2983 ctx = scmutil.revsingle(repo, opts.get('rev'))
2985 m = scmutil.match(ctx, (file1,) + pats, opts)
2984 m = scmutil.match(ctx, (file1,) + pats, opts)
2986 for abs in ctx.walk(m):
2985 for abs in ctx.walk(m):
2987 fctx = ctx[abs]
2986 fctx = ctx[abs]
2988 o = fctx.filelog().renamed(fctx.filenode())
2987 o = fctx.filelog().renamed(fctx.filenode())
2989 rel = m.rel(abs)
2988 rel = m.rel(abs)
2990 if o:
2989 if o:
2991 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])))
2992 else:
2991 else:
2993 ui.write(_("%s not renamed\n") % rel)
2992 ui.write(_("%s not renamed\n") % rel)
2994
2993
2995 @command('debugrevlog', debugrevlogopts +
2994 @command('debugrevlog', debugrevlogopts +
2996 [('d', 'dump', False, _('dump index data'))],
2995 [('d', 'dump', False, _('dump index data'))],
2997 _('-c|-m|FILE'),
2996 _('-c|-m|FILE'),
2998 optionalrepo=True)
2997 optionalrepo=True)
2999 def debugrevlog(ui, repo, file_=None, **opts):
2998 def debugrevlog(ui, repo, file_=None, **opts):
3000 """show data and statistics about a revlog"""
2999 """show data and statistics about a revlog"""
3001 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3000 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3002
3001
3003 if opts.get("dump"):
3002 if opts.get("dump"):
3004 numrevs = len(r)
3003 numrevs = len(r)
3005 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3004 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
3006 " rawsize totalsize compression heads chainlen\n"))
3005 " rawsize totalsize compression heads chainlen\n"))
3007 ts = 0
3006 ts = 0
3008 heads = set()
3007 heads = set()
3009
3008
3010 for rev in xrange(numrevs):
3009 for rev in xrange(numrevs):
3011 dbase = r.deltaparent(rev)
3010 dbase = r.deltaparent(rev)
3012 if dbase == -1:
3011 if dbase == -1:
3013 dbase = rev
3012 dbase = rev
3014 cbase = r.chainbase(rev)
3013 cbase = r.chainbase(rev)
3015 clen = r.chainlen(rev)
3014 clen = r.chainlen(rev)
3016 p1, p2 = r.parentrevs(rev)
3015 p1, p2 = r.parentrevs(rev)
3017 rs = r.rawsize(rev)
3016 rs = r.rawsize(rev)
3018 ts = ts + rs
3017 ts = ts + rs
3019 heads -= set(r.parentrevs(rev))
3018 heads -= set(r.parentrevs(rev))
3020 heads.add(rev)
3019 heads.add(rev)
3021 try:
3020 try:
3022 compression = ts / r.end(rev)
3021 compression = ts / r.end(rev)
3023 except ZeroDivisionError:
3022 except ZeroDivisionError:
3024 compression = 0
3023 compression = 0
3025 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 "
3026 "%11d %5d %8d\n" %
3025 "%11d %5d %8d\n" %
3027 (rev, p1, p2, r.start(rev), r.end(rev),
3026 (rev, p1, p2, r.start(rev), r.end(rev),
3028 r.start(dbase), r.start(cbase),
3027 r.start(dbase), r.start(cbase),
3029 r.start(p1), r.start(p2),
3028 r.start(p1), r.start(p2),
3030 rs, ts, compression, len(heads), clen))
3029 rs, ts, compression, len(heads), clen))
3031 return 0
3030 return 0
3032
3031
3033 v = r.version
3032 v = r.version
3034 format = v & 0xFFFF
3033 format = v & 0xFFFF
3035 flags = []
3034 flags = []
3036 gdelta = False
3035 gdelta = False
3037 if v & revlog.REVLOGNGINLINEDATA:
3036 if v & revlog.REVLOGNGINLINEDATA:
3038 flags.append('inline')
3037 flags.append('inline')
3039 if v & revlog.REVLOGGENERALDELTA:
3038 if v & revlog.REVLOGGENERALDELTA:
3040 gdelta = True
3039 gdelta = True
3041 flags.append('generaldelta')
3040 flags.append('generaldelta')
3042 if not flags:
3041 if not flags:
3043 flags = ['(none)']
3042 flags = ['(none)']
3044
3043
3045 nummerges = 0
3044 nummerges = 0
3046 numfull = 0
3045 numfull = 0
3047 numprev = 0
3046 numprev = 0
3048 nump1 = 0
3047 nump1 = 0
3049 nump2 = 0
3048 nump2 = 0
3050 numother = 0
3049 numother = 0
3051 nump1prev = 0
3050 nump1prev = 0
3052 nump2prev = 0
3051 nump2prev = 0
3053 chainlengths = []
3052 chainlengths = []
3054
3053
3055 datasize = [None, 0, 0]
3054 datasize = [None, 0, 0]
3056 fullsize = [None, 0, 0]
3055 fullsize = [None, 0, 0]
3057 deltasize = [None, 0, 0]
3056 deltasize = [None, 0, 0]
3058 chunktypecounts = {}
3057 chunktypecounts = {}
3059 chunktypesizes = {}
3058 chunktypesizes = {}
3060
3059
3061 def addsize(size, l):
3060 def addsize(size, l):
3062 if l[0] is None or size < l[0]:
3061 if l[0] is None or size < l[0]:
3063 l[0] = size
3062 l[0] = size
3064 if size > l[1]:
3063 if size > l[1]:
3065 l[1] = size
3064 l[1] = size
3066 l[2] += size
3065 l[2] += size
3067
3066
3068 numrevs = len(r)
3067 numrevs = len(r)
3069 for rev in xrange(numrevs):
3068 for rev in xrange(numrevs):
3070 p1, p2 = r.parentrevs(rev)
3069 p1, p2 = r.parentrevs(rev)
3071 delta = r.deltaparent(rev)
3070 delta = r.deltaparent(rev)
3072 if format > 0:
3071 if format > 0:
3073 addsize(r.rawsize(rev), datasize)
3072 addsize(r.rawsize(rev), datasize)
3074 if p2 != nullrev:
3073 if p2 != nullrev:
3075 nummerges += 1
3074 nummerges += 1
3076 size = r.length(rev)
3075 size = r.length(rev)
3077 if delta == nullrev:
3076 if delta == nullrev:
3078 chainlengths.append(0)
3077 chainlengths.append(0)
3079 numfull += 1
3078 numfull += 1
3080 addsize(size, fullsize)
3079 addsize(size, fullsize)
3081 else:
3080 else:
3082 chainlengths.append(chainlengths[delta] + 1)
3081 chainlengths.append(chainlengths[delta] + 1)
3083 addsize(size, deltasize)
3082 addsize(size, deltasize)
3084 if delta == rev - 1:
3083 if delta == rev - 1:
3085 numprev += 1
3084 numprev += 1
3086 if delta == p1:
3085 if delta == p1:
3087 nump1prev += 1
3086 nump1prev += 1
3088 elif delta == p2:
3087 elif delta == p2:
3089 nump2prev += 1
3088 nump2prev += 1
3090 elif delta == p1:
3089 elif delta == p1:
3091 nump1 += 1
3090 nump1 += 1
3092 elif delta == p2:
3091 elif delta == p2:
3093 nump2 += 1
3092 nump2 += 1
3094 elif delta != nullrev:
3093 elif delta != nullrev:
3095 numother += 1
3094 numother += 1
3096
3095
3097 # Obtain data on the raw chunks in the revlog.
3096 # Obtain data on the raw chunks in the revlog.
3098 chunk = r._chunkraw(rev, rev)[1]
3097 chunk = r._chunkraw(rev, rev)[1]
3099 if chunk:
3098 if chunk:
3100 chunktype = chunk[0]
3099 chunktype = chunk[0]
3101 else:
3100 else:
3102 chunktype = 'empty'
3101 chunktype = 'empty'
3103
3102
3104 if chunktype not in chunktypecounts:
3103 if chunktype not in chunktypecounts:
3105 chunktypecounts[chunktype] = 0
3104 chunktypecounts[chunktype] = 0
3106 chunktypesizes[chunktype] = 0
3105 chunktypesizes[chunktype] = 0
3107
3106
3108 chunktypecounts[chunktype] += 1
3107 chunktypecounts[chunktype] += 1
3109 chunktypesizes[chunktype] += size
3108 chunktypesizes[chunktype] += size
3110
3109
3111 # Adjust size min value for empty cases
3110 # Adjust size min value for empty cases
3112 for size in (datasize, fullsize, deltasize):
3111 for size in (datasize, fullsize, deltasize):
3113 if size[0] is None:
3112 if size[0] is None:
3114 size[0] = 0
3113 size[0] = 0
3115
3114
3116 numdeltas = numrevs - numfull
3115 numdeltas = numrevs - numfull
3117 numoprev = numprev - nump1prev - nump2prev
3116 numoprev = numprev - nump1prev - nump2prev
3118 totalrawsize = datasize[2]
3117 totalrawsize = datasize[2]
3119 datasize[2] /= numrevs
3118 datasize[2] /= numrevs
3120 fulltotal = fullsize[2]
3119 fulltotal = fullsize[2]
3121 fullsize[2] /= numfull
3120 fullsize[2] /= numfull
3122 deltatotal = deltasize[2]
3121 deltatotal = deltasize[2]
3123 if numrevs - numfull > 0:
3122 if numrevs - numfull > 0:
3124 deltasize[2] /= numrevs - numfull
3123 deltasize[2] /= numrevs - numfull
3125 totalsize = fulltotal + deltatotal
3124 totalsize = fulltotal + deltatotal
3126 avgchainlen = sum(chainlengths) / numrevs
3125 avgchainlen = sum(chainlengths) / numrevs
3127 maxchainlen = max(chainlengths)
3126 maxchainlen = max(chainlengths)
3128 compratio = 1
3127 compratio = 1
3129 if totalsize:
3128 if totalsize:
3130 compratio = totalrawsize / totalsize
3129 compratio = totalrawsize / totalsize
3131
3130
3132 basedfmtstr = '%%%dd\n'
3131 basedfmtstr = '%%%dd\n'
3133 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3132 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3134
3133
3135 def dfmtstr(max):
3134 def dfmtstr(max):
3136 return basedfmtstr % len(str(max))
3135 return basedfmtstr % len(str(max))
3137 def pcfmtstr(max, padding=0):
3136 def pcfmtstr(max, padding=0):
3138 return basepcfmtstr % (len(str(max)), ' ' * padding)
3137 return basepcfmtstr % (len(str(max)), ' ' * padding)
3139
3138
3140 def pcfmt(value, total):
3139 def pcfmt(value, total):
3141 if total:
3140 if total:
3142 return (value, 100 * float(value) / total)
3141 return (value, 100 * float(value) / total)
3143 else:
3142 else:
3144 return value, 100.0
3143 return value, 100.0
3145
3144
3146 ui.write(('format : %d\n') % format)
3145 ui.write(('format : %d\n') % format)
3147 ui.write(('flags : %s\n') % ', '.join(flags))
3146 ui.write(('flags : %s\n') % ', '.join(flags))
3148
3147
3149 ui.write('\n')
3148 ui.write('\n')
3150 fmt = pcfmtstr(totalsize)
3149 fmt = pcfmtstr(totalsize)
3151 fmt2 = dfmtstr(totalsize)
3150 fmt2 = dfmtstr(totalsize)
3152 ui.write(('revisions : ') + fmt2 % numrevs)
3151 ui.write(('revisions : ') + fmt2 % numrevs)
3153 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3152 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3154 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3153 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3155 ui.write(('revisions : ') + fmt2 % numrevs)
3154 ui.write(('revisions : ') + fmt2 % numrevs)
3156 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3155 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3157 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3156 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3158 ui.write(('revision size : ') + fmt2 % totalsize)
3157 ui.write(('revision size : ') + fmt2 % totalsize)
3159 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3158 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3160 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3159 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3161
3160
3162 def fmtchunktype(chunktype):
3161 def fmtchunktype(chunktype):
3163 if chunktype == 'empty':
3162 if chunktype == 'empty':
3164 return ' %s : ' % chunktype
3163 return ' %s : ' % chunktype
3165 elif chunktype in string.ascii_letters:
3164 elif chunktype in string.ascii_letters:
3166 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
3165 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
3167 else:
3166 else:
3168 return ' 0x%s : ' % hex(chunktype)
3167 return ' 0x%s : ' % hex(chunktype)
3169
3168
3170 ui.write('\n')
3169 ui.write('\n')
3171 ui.write(('chunks : ') + fmt2 % numrevs)
3170 ui.write(('chunks : ') + fmt2 % numrevs)
3172 for chunktype in sorted(chunktypecounts):
3171 for chunktype in sorted(chunktypecounts):
3173 ui.write(fmtchunktype(chunktype))
3172 ui.write(fmtchunktype(chunktype))
3174 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
3173 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
3175 ui.write(('chunks size : ') + fmt2 % totalsize)
3174 ui.write(('chunks size : ') + fmt2 % totalsize)
3176 for chunktype in sorted(chunktypecounts):
3175 for chunktype in sorted(chunktypecounts):
3177 ui.write(fmtchunktype(chunktype))
3176 ui.write(fmtchunktype(chunktype))
3178 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
3177 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
3179
3178
3180 ui.write('\n')
3179 ui.write('\n')
3181 fmt = dfmtstr(max(avgchainlen, compratio))
3180 fmt = dfmtstr(max(avgchainlen, compratio))
3182 ui.write(('avg chain length : ') + fmt % avgchainlen)
3181 ui.write(('avg chain length : ') + fmt % avgchainlen)
3183 ui.write(('max chain length : ') + fmt % maxchainlen)
3182 ui.write(('max chain length : ') + fmt % maxchainlen)
3184 ui.write(('compression ratio : ') + fmt % compratio)
3183 ui.write(('compression ratio : ') + fmt % compratio)
3185
3184
3186 if format > 0:
3185 if format > 0:
3187 ui.write('\n')
3186 ui.write('\n')
3188 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')
3189 % tuple(datasize))
3188 % tuple(datasize))
3190 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')
3191 % tuple(fullsize))
3190 % tuple(fullsize))
3192 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3191 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3193 % tuple(deltasize))
3192 % tuple(deltasize))
3194
3193
3195 if numdeltas > 0:
3194 if numdeltas > 0:
3196 ui.write('\n')
3195 ui.write('\n')
3197 fmt = pcfmtstr(numdeltas)
3196 fmt = pcfmtstr(numdeltas)
3198 fmt2 = pcfmtstr(numdeltas, 4)
3197 fmt2 = pcfmtstr(numdeltas, 4)
3199 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3198 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3200 if numprev > 0:
3199 if numprev > 0:
3201 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3200 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3202 numprev))
3201 numprev))
3203 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3202 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3204 numprev))
3203 numprev))
3205 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3204 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3206 numprev))
3205 numprev))
3207 if gdelta:
3206 if gdelta:
3208 ui.write(('deltas against p1 : ')
3207 ui.write(('deltas against p1 : ')
3209 + fmt % pcfmt(nump1, numdeltas))
3208 + fmt % pcfmt(nump1, numdeltas))
3210 ui.write(('deltas against p2 : ')
3209 ui.write(('deltas against p2 : ')
3211 + fmt % pcfmt(nump2, numdeltas))
3210 + fmt % pcfmt(nump2, numdeltas))
3212 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3211 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3213 numdeltas))
3212 numdeltas))
3214
3213
3215 @command('debugrevspec',
3214 @command('debugrevspec',
3216 [('', 'optimize', None,
3215 [('', 'optimize', None,
3217 _('print parsed tree after optimizing (DEPRECATED)')),
3216 _('print parsed tree after optimizing (DEPRECATED)')),
3218 ('p', 'show-stage', [],
3217 ('p', 'show-stage', [],
3219 _('print parsed tree at the given stage'), _('NAME')),
3218 _('print parsed tree at the given stage'), _('NAME')),
3220 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3219 ('', 'no-optimized', False, _('evaluate tree without optimization')),
3221 ('', 'verify-optimized', False, _('verify optimized result')),
3220 ('', 'verify-optimized', False, _('verify optimized result')),
3222 ],
3221 ],
3223 ('REVSPEC'))
3222 ('REVSPEC'))
3224 def debugrevspec(ui, repo, expr, **opts):
3223 def debugrevspec(ui, repo, expr, **opts):
3225 """parse and apply a revision specification
3224 """parse and apply a revision specification
3226
3225
3227 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.
3228 Use -p all to print tree at every stage.
3227 Use -p all to print tree at every stage.
3229
3228
3230 Use --verify-optimized to compare the optimized result with the unoptimized
3229 Use --verify-optimized to compare the optimized result with the unoptimized
3231 one. Returns 1 if the optimized result differs.
3230 one. Returns 1 if the optimized result differs.
3232 """
3231 """
3233 stages = [
3232 stages = [
3234 ('parsed', lambda tree: tree),
3233 ('parsed', lambda tree: tree),
3235 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3234 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
3236 ('concatenated', revset.foldconcat),
3235 ('concatenated', revset.foldconcat),
3237 ('analyzed', revset.analyze),
3236 ('analyzed', revset.analyze),
3238 ('optimized', revset.optimize),
3237 ('optimized', revset.optimize),
3239 ]
3238 ]
3240 if opts['no_optimized']:
3239 if opts['no_optimized']:
3241 stages = stages[:-1]
3240 stages = stages[:-1]
3242 if opts['verify_optimized'] and opts['no_optimized']:
3241 if opts['verify_optimized'] and opts['no_optimized']:
3243 raise error.Abort(_('cannot use --verify-optimized with '
3242 raise error.Abort(_('cannot use --verify-optimized with '
3244 '--no-optimized'))
3243 '--no-optimized'))
3245 stagenames = set(n for n, f in stages)
3244 stagenames = set(n for n, f in stages)
3246
3245
3247 showalways = set()
3246 showalways = set()
3248 showchanged = set()
3247 showchanged = set()
3249 if ui.verbose and not opts['show_stage']:
3248 if ui.verbose and not opts['show_stage']:
3250 # show parsed tree by --verbose (deprecated)
3249 # show parsed tree by --verbose (deprecated)
3251 showalways.add('parsed')
3250 showalways.add('parsed')
3252 showchanged.update(['expanded', 'concatenated'])
3251 showchanged.update(['expanded', 'concatenated'])
3253 if opts['optimize']:
3252 if opts['optimize']:
3254 showalways.add('optimized')
3253 showalways.add('optimized')
3255 if opts['show_stage'] and opts['optimize']:
3254 if opts['show_stage'] and opts['optimize']:
3256 raise error.Abort(_('cannot use --optimize with --show-stage'))
3255 raise error.Abort(_('cannot use --optimize with --show-stage'))
3257 if opts['show_stage'] == ['all']:
3256 if opts['show_stage'] == ['all']:
3258 showalways.update(stagenames)
3257 showalways.update(stagenames)
3259 else:
3258 else:
3260 for n in opts['show_stage']:
3259 for n in opts['show_stage']:
3261 if n not in stagenames:
3260 if n not in stagenames:
3262 raise error.Abort(_('invalid stage name: %s') % n)
3261 raise error.Abort(_('invalid stage name: %s') % n)
3263 showalways.update(opts['show_stage'])
3262 showalways.update(opts['show_stage'])
3264
3263
3265 treebystage = {}
3264 treebystage = {}
3266 printedtree = None
3265 printedtree = None
3267 tree = revset.parse(expr, lookup=repo.__contains__)
3266 tree = revset.parse(expr, lookup=repo.__contains__)
3268 for n, f in stages:
3267 for n, f in stages:
3269 treebystage[n] = tree = f(tree)
3268 treebystage[n] = tree = f(tree)
3270 if n in showalways or (n in showchanged and tree != printedtree):
3269 if n in showalways or (n in showchanged and tree != printedtree):
3271 if opts['show_stage'] or n != 'parsed':
3270 if opts['show_stage'] or n != 'parsed':
3272 ui.write(("* %s:\n") % n)
3271 ui.write(("* %s:\n") % n)
3273 ui.write(revset.prettyformat(tree), "\n")
3272 ui.write(revset.prettyformat(tree), "\n")
3274 printedtree = tree
3273 printedtree = tree
3275
3274
3276 if opts['verify_optimized']:
3275 if opts['verify_optimized']:
3277 arevs = revset.makematcher(treebystage['analyzed'])(repo)
3276 arevs = revset.makematcher(treebystage['analyzed'])(repo)
3278 brevs = revset.makematcher(treebystage['optimized'])(repo)
3277 brevs = revset.makematcher(treebystage['optimized'])(repo)
3279 if ui.verbose:
3278 if ui.verbose:
3280 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
3279 ui.note(("* analyzed set:\n"), revset.prettyformatset(arevs), "\n")
3281 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
3280 ui.note(("* optimized set:\n"), revset.prettyformatset(brevs), "\n")
3282 arevs = list(arevs)
3281 arevs = list(arevs)
3283 brevs = list(brevs)
3282 brevs = list(brevs)
3284 if arevs == brevs:
3283 if arevs == brevs:
3285 return 0
3284 return 0
3286 ui.write(('--- analyzed\n'), label='diff.file_a')
3285 ui.write(('--- analyzed\n'), label='diff.file_a')
3287 ui.write(('+++ optimized\n'), label='diff.file_b')
3286 ui.write(('+++ optimized\n'), label='diff.file_b')
3288 sm = difflib.SequenceMatcher(None, arevs, brevs)
3287 sm = difflib.SequenceMatcher(None, arevs, brevs)
3289 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3288 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3290 if tag in ('delete', 'replace'):
3289 if tag in ('delete', 'replace'):
3291 for c in arevs[alo:ahi]:
3290 for c in arevs[alo:ahi]:
3292 ui.write('-%s\n' % c, label='diff.deleted')
3291 ui.write('-%s\n' % c, label='diff.deleted')
3293 if tag in ('insert', 'replace'):
3292 if tag in ('insert', 'replace'):
3294 for c in brevs[blo:bhi]:
3293 for c in brevs[blo:bhi]:
3295 ui.write('+%s\n' % c, label='diff.inserted')
3294 ui.write('+%s\n' % c, label='diff.inserted')
3296 if tag == 'equal':
3295 if tag == 'equal':
3297 for c in arevs[alo:ahi]:
3296 for c in arevs[alo:ahi]:
3298 ui.write(' %s\n' % c)
3297 ui.write(' %s\n' % c)
3299 return 1
3298 return 1
3300
3299
3301 func = revset.makematcher(tree)
3300 func = revset.makematcher(tree)
3302 revs = func(repo)
3301 revs = func(repo)
3303 if ui.verbose:
3302 if ui.verbose:
3304 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3303 ui.note(("* set:\n"), revset.prettyformatset(revs), "\n")
3305 for c in revs:
3304 for c in revs:
3306 ui.write("%s\n" % c)
3305 ui.write("%s\n" % c)
3307
3306
3308 @command('debugsetparents', [], _('REV1 [REV2]'))
3307 @command('debugsetparents', [], _('REV1 [REV2]'))
3309 def debugsetparents(ui, repo, rev1, rev2=None):
3308 def debugsetparents(ui, repo, rev1, rev2=None):
3310 """manually set the parents of the current working directory
3309 """manually set the parents of the current working directory
3311
3310
3312 This is useful for writing repository conversion tools, but should
3311 This is useful for writing repository conversion tools, but should
3313 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
3314 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
3315 command.
3314 command.
3316
3315
3317 Returns 0 on success.
3316 Returns 0 on success.
3318 """
3317 """
3319
3318
3320 r1 = scmutil.revsingle(repo, rev1).node()
3319 r1 = scmutil.revsingle(repo, rev1).node()
3321 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3320 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3322
3321
3323 with repo.wlock():
3322 with repo.wlock():
3324 repo.setparents(r1, r2)
3323 repo.setparents(r1, r2)
3325
3324
3326 @command('debugdirstate|debugstate',
3325 @command('debugdirstate|debugstate',
3327 [('', 'nodates', None, _('do not display the saved mtime')),
3326 [('', 'nodates', None, _('do not display the saved mtime')),
3328 ('', 'datesort', None, _('sort by saved mtime'))],
3327 ('', 'datesort', None, _('sort by saved mtime'))],
3329 _('[OPTION]...'))
3328 _('[OPTION]...'))
3330 def debugstate(ui, repo, **opts):
3329 def debugstate(ui, repo, **opts):
3331 """show the contents of the current dirstate"""
3330 """show the contents of the current dirstate"""
3332
3331
3333 nodates = opts.get('nodates')
3332 nodates = opts.get('nodates')
3334 datesort = opts.get('datesort')
3333 datesort = opts.get('datesort')
3335
3334
3336 timestr = ""
3335 timestr = ""
3337 if datesort:
3336 if datesort:
3338 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
3339 else:
3338 else:
3340 keyfunc = None # sort by filename
3339 keyfunc = None # sort by filename
3341 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3340 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3342 if ent[3] == -1:
3341 if ent[3] == -1:
3343 timestr = 'unset '
3342 timestr = 'unset '
3344 elif nodates:
3343 elif nodates:
3345 timestr = 'set '
3344 timestr = 'set '
3346 else:
3345 else:
3347 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3346 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3348 time.localtime(ent[3]))
3347 time.localtime(ent[3]))
3349 if ent[1] & 0o20000:
3348 if ent[1] & 0o20000:
3350 mode = 'lnk'
3349 mode = 'lnk'
3351 else:
3350 else:
3352 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3351 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3353 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_))
3354 for f in repo.dirstate.copies():
3353 for f in repo.dirstate.copies():
3355 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3354 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3356
3355
3357 @command('debugsub',
3356 @command('debugsub',
3358 [('r', 'rev', '',
3357 [('r', 'rev', '',
3359 _('revision to check'), _('REV'))],
3358 _('revision to check'), _('REV'))],
3360 _('[-r REV] [REV]'))
3359 _('[-r REV] [REV]'))
3361 def debugsub(ui, repo, rev=None):
3360 def debugsub(ui, repo, rev=None):
3362 ctx = scmutil.revsingle(repo, rev, None)
3361 ctx = scmutil.revsingle(repo, rev, None)
3363 for k, v in sorted(ctx.substate.items()):
3362 for k, v in sorted(ctx.substate.items()):
3364 ui.write(('path %s\n') % k)
3363 ui.write(('path %s\n') % k)
3365 ui.write((' source %s\n') % v[0])
3364 ui.write((' source %s\n') % v[0])
3366 ui.write((' revision %s\n') % v[1])
3365 ui.write((' revision %s\n') % v[1])
3367
3366
3368 @command('debugsuccessorssets',
3367 @command('debugsuccessorssets',
3369 [],
3368 [],
3370 _('[REV]'))
3369 _('[REV]'))
3371 def debugsuccessorssets(ui, repo, *revs):
3370 def debugsuccessorssets(ui, repo, *revs):
3372 """show set of successors for revision
3371 """show set of successors for revision
3373
3372
3374 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
3375 succeed A. It contains non-obsolete changesets only.
3374 succeed A. It contains non-obsolete changesets only.
3376
3375
3377 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
3378 successor (changeset A replaced by A').
3377 successor (changeset A replaced by A').
3379
3378
3380 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".
3381 Such changesets have no successors sets at all.
3380 Such changesets have no successors sets at all.
3382
3381
3383 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
3384 more than one successor.
3383 more than one successor.
3385
3384
3386 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
3387 "divergent". Such changesets have multiple successor sets (each of which
3386 "divergent". Such changesets have multiple successor sets (each of which
3388 may also be split, i.e. have multiple successors).
3387 may also be split, i.e. have multiple successors).
3389
3388
3390 Results are displayed as follows::
3389 Results are displayed as follows::
3391
3390
3392 <rev1>
3391 <rev1>
3393 <successors-1A>
3392 <successors-1A>
3394 <rev2>
3393 <rev2>
3395 <successors-2A>
3394 <successors-2A>
3396 <successors-2B1> <successors-2B2> <successors-2B3>
3395 <successors-2B1> <successors-2B2> <successors-2B3>
3397
3396
3398 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
3399 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
3400 been split).
3399 been split).
3401 """
3400 """
3402 # passed to successorssets caching computation from one call to another
3401 # passed to successorssets caching computation from one call to another
3403 cache = {}
3402 cache = {}
3404 ctx2str = str
3403 ctx2str = str
3405 node2str = short
3404 node2str = short
3406 if ui.debug():
3405 if ui.debug():
3407 def ctx2str(ctx):
3406 def ctx2str(ctx):
3408 return ctx.hex()
3407 return ctx.hex()
3409 node2str = hex
3408 node2str = hex
3410 for rev in scmutil.revrange(repo, revs):
3409 for rev in scmutil.revrange(repo, revs):
3411 ctx = repo[rev]
3410 ctx = repo[rev]
3412 ui.write('%s\n'% ctx2str(ctx))
3411 ui.write('%s\n'% ctx2str(ctx))
3413 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3412 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3414 if succsset:
3413 if succsset:
3415 ui.write(' ')
3414 ui.write(' ')
3416 ui.write(node2str(succsset[0]))
3415 ui.write(node2str(succsset[0]))
3417 for node in succsset[1:]:
3416 for node in succsset[1:]:
3418 ui.write(' ')
3417 ui.write(' ')
3419 ui.write(node2str(node))
3418 ui.write(node2str(node))
3420 ui.write('\n')
3419 ui.write('\n')
3421
3420
3422 @command('debugtemplate',
3421 @command('debugtemplate',
3423 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3422 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3424 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3423 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3425 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3424 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3426 optionalrepo=True)
3425 optionalrepo=True)
3427 def debugtemplate(ui, repo, tmpl, **opts):
3426 def debugtemplate(ui, repo, tmpl, **opts):
3428 """parse and apply a template
3427 """parse and apply a template
3429
3428
3430 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
3431 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
3432 template.
3431 template.
3433
3432
3434 Use --verbose to print the parsed tree.
3433 Use --verbose to print the parsed tree.
3435 """
3434 """
3436 revs = None
3435 revs = None
3437 if opts['rev']:
3436 if opts['rev']:
3438 if repo is None:
3437 if repo is None:
3439 raise error.RepoError(_('there is no Mercurial repository here '
3438 raise error.RepoError(_('there is no Mercurial repository here '
3440 '(.hg not found)'))
3439 '(.hg not found)'))
3441 revs = scmutil.revrange(repo, opts['rev'])
3440 revs = scmutil.revrange(repo, opts['rev'])
3442
3441
3443 props = {}
3442 props = {}
3444 for d in opts['define']:
3443 for d in opts['define']:
3445 try:
3444 try:
3446 k, v = (e.strip() for e in d.split('=', 1))
3445 k, v = (e.strip() for e in d.split('=', 1))
3447 if not k:
3446 if not k:
3448 raise ValueError
3447 raise ValueError
3449 props[k] = v
3448 props[k] = v
3450 except ValueError:
3449 except ValueError:
3451 raise error.Abort(_('malformed keyword definition: %s') % d)
3450 raise error.Abort(_('malformed keyword definition: %s') % d)
3452
3451
3453 if ui.verbose:
3452 if ui.verbose:
3454 aliases = ui.configitems('templatealias')
3453 aliases = ui.configitems('templatealias')
3455 tree = templater.parse(tmpl)
3454 tree = templater.parse(tmpl)
3456 ui.note(templater.prettyformat(tree), '\n')
3455 ui.note(templater.prettyformat(tree), '\n')
3457 newtree = templater.expandaliases(tree, aliases)
3456 newtree = templater.expandaliases(tree, aliases)
3458 if newtree != tree:
3457 if newtree != tree:
3459 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3458 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
3460
3459
3461 mapfile = None
3460 mapfile = None
3462 if revs is None:
3461 if revs is None:
3463 k = 'debugtemplate'
3462 k = 'debugtemplate'
3464 t = formatter.maketemplater(ui, k, tmpl)
3463 t = formatter.maketemplater(ui, k, tmpl)
3465 ui.write(templater.stringify(t(k, **props)))
3464 ui.write(templater.stringify(t(k, **props)))
3466 else:
3465 else:
3467 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3466 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3468 mapfile, buffered=False)
3467 mapfile, buffered=False)
3469 for r in revs:
3468 for r in revs:
3470 displayer.show(repo[r], **props)
3469 displayer.show(repo[r], **props)
3471 displayer.close()
3470 displayer.close()
3472
3471
3473 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3472 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3474 def debugwalk(ui, repo, *pats, **opts):
3473 def debugwalk(ui, repo, *pats, **opts):
3475 """show how files match on given patterns"""
3474 """show how files match on given patterns"""
3476 m = scmutil.match(repo[None], pats, opts)
3475 m = scmutil.match(repo[None], pats, opts)
3477 items = list(repo.walk(m))
3476 items = list(repo.walk(m))
3478 if not items:
3477 if not items:
3479 return
3478 return
3480 f = lambda fn: fn
3479 f = lambda fn: fn
3481 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
3480 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
3482 f = lambda fn: util.normpath(fn)
3481 f = lambda fn: util.normpath(fn)
3483 fmt = 'f %%-%ds %%-%ds %%s' % (
3482 fmt = 'f %%-%ds %%-%ds %%s' % (
3484 max([len(abs) for abs in items]),
3483 max([len(abs) for abs in items]),
3485 max([len(m.rel(abs)) for abs in items]))
3484 max([len(m.rel(abs)) for abs in items]))
3486 for abs in items:
3485 for abs in items:
3487 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 '')
3488 ui.write("%s\n" % line.rstrip())
3487 ui.write("%s\n" % line.rstrip())
3489
3488
3490 @command('debugwireargs',
3489 @command('debugwireargs',
3491 [('', 'three', '', 'three'),
3490 [('', 'three', '', 'three'),
3492 ('', 'four', '', 'four'),
3491 ('', 'four', '', 'four'),
3493 ('', 'five', '', 'five'),
3492 ('', 'five', '', 'five'),
3494 ] + remoteopts,
3493 ] + remoteopts,
3495 _('REPO [OPTIONS]... [ONE [TWO]]'),
3494 _('REPO [OPTIONS]... [ONE [TWO]]'),
3496 norepo=True)
3495 norepo=True)
3497 def debugwireargs(ui, repopath, *vals, **opts):
3496 def debugwireargs(ui, repopath, *vals, **opts):
3498 repo = hg.peer(ui, opts, repopath)
3497 repo = hg.peer(ui, opts, repopath)
3499 for opt in remoteopts:
3498 for opt in remoteopts:
3500 del opts[opt[1]]
3499 del opts[opt[1]]
3501 args = {}
3500 args = {}
3502 for k, v in opts.iteritems():
3501 for k, v in opts.iteritems():
3503 if v:
3502 if v:
3504 args[k] = v
3503 args[k] = v
3505 # 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
3506 res1 = repo.debugwireargs(*vals, **args)
3505 res1 = repo.debugwireargs(*vals, **args)
3507 res2 = repo.debugwireargs(*vals, **args)
3506 res2 = repo.debugwireargs(*vals, **args)
3508 ui.write("%s\n" % res1)
3507 ui.write("%s\n" % res1)
3509 if res1 != res2:
3508 if res1 != res2:
3510 ui.warn("%s\n" % res2)
3509 ui.warn("%s\n" % res2)
3511
3510
3512 @command('^diff',
3511 @command('^diff',
3513 [('r', 'rev', [], _('revision'), _('REV')),
3512 [('r', 'rev', [], _('revision'), _('REV')),
3514 ('c', 'change', '', _('change made by revision'), _('REV'))
3513 ('c', 'change', '', _('change made by revision'), _('REV'))
3515 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3514 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3516 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3515 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3517 inferrepo=True)
3516 inferrepo=True)
3518 def diff(ui, repo, *pats, **opts):
3517 def diff(ui, repo, *pats, **opts):
3519 """diff repository (or selected files)
3518 """diff repository (or selected files)
3520
3519
3521 Show differences between revisions for the specified files.
3520 Show differences between revisions for the specified files.
3522
3521
3523 Differences between files are shown using the unified diff format.
3522 Differences between files are shown using the unified diff format.
3524
3523
3525 .. note::
3524 .. note::
3526
3525
3527 :hg:`diff` may generate unexpected results for merges, as it will
3526 :hg:`diff` may generate unexpected results for merges, as it will
3528 default to comparing against the working directory's first
3527 default to comparing against the working directory's first
3529 parent changeset if no revisions are specified.
3528 parent changeset if no revisions are specified.
3530
3529
3531 When two revision arguments are given, then changes are shown
3530 When two revision arguments are given, then changes are shown
3532 between those revisions. If only one revision is specified then
3531 between those revisions. If only one revision is specified then
3533 that revision is compared to the working directory, and, when no
3532 that revision is compared to the working directory, and, when no
3534 revisions are specified, the working directory files are compared
3533 revisions are specified, the working directory files are compared
3535 to its first parent.
3534 to its first parent.
3536
3535
3537 Alternatively you can specify -c/--change with a revision to see
3536 Alternatively you can specify -c/--change with a revision to see
3538 the changes in that changeset relative to its first parent.
3537 the changes in that changeset relative to its first parent.
3539
3538
3540 Without the -a/--text option, diff will avoid generating diffs of
3539 Without the -a/--text option, diff will avoid generating diffs of
3541 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
3542 anyway, probably with undesirable results.
3541 anyway, probably with undesirable results.
3543
3542
3544 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
3545 format. For more information, read :hg:`help diffs`.
3544 format. For more information, read :hg:`help diffs`.
3546
3545
3547 .. container:: verbose
3546 .. container:: verbose
3548
3547
3549 Examples:
3548 Examples:
3550
3549
3551 - compare a file in the current working directory to its parent::
3550 - compare a file in the current working directory to its parent::
3552
3551
3553 hg diff foo.c
3552 hg diff foo.c
3554
3553
3555 - compare two historical versions of a directory, with rename info::
3554 - compare two historical versions of a directory, with rename info::
3556
3555
3557 hg diff --git -r 1.0:1.2 lib/
3556 hg diff --git -r 1.0:1.2 lib/
3558
3557
3559 - get change stats relative to the last change on some date::
3558 - get change stats relative to the last change on some date::
3560
3559
3561 hg diff --stat -r "date('may 2')"
3560 hg diff --stat -r "date('may 2')"
3562
3561
3563 - diff all newly-added files that contain a keyword::
3562 - diff all newly-added files that contain a keyword::
3564
3563
3565 hg diff "set:added() and grep(GNU)"
3564 hg diff "set:added() and grep(GNU)"
3566
3565
3567 - compare a revision and its parents::
3566 - compare a revision and its parents::
3568
3567
3569 hg diff -c 9353 # compare against first parent
3568 hg diff -c 9353 # compare against first parent
3570 hg diff -r 9353^:9353 # same using revset syntax
3569 hg diff -r 9353^:9353 # same using revset syntax
3571 hg diff -r 9353^2:9353 # compare against the second parent
3570 hg diff -r 9353^2:9353 # compare against the second parent
3572
3571
3573 Returns 0 on success.
3572 Returns 0 on success.
3574 """
3573 """
3575
3574
3576 revs = opts.get('rev')
3575 revs = opts.get('rev')
3577 change = opts.get('change')
3576 change = opts.get('change')
3578 stat = opts.get('stat')
3577 stat = opts.get('stat')
3579 reverse = opts.get('reverse')
3578 reverse = opts.get('reverse')
3580
3579
3581 if revs and change:
3580 if revs and change:
3582 msg = _('cannot specify --rev and --change at the same time')
3581 msg = _('cannot specify --rev and --change at the same time')
3583 raise error.Abort(msg)
3582 raise error.Abort(msg)
3584 elif change:
3583 elif change:
3585 node2 = scmutil.revsingle(repo, change, None).node()
3584 node2 = scmutil.revsingle(repo, change, None).node()
3586 node1 = repo[node2].p1().node()
3585 node1 = repo[node2].p1().node()
3587 else:
3586 else:
3588 node1, node2 = scmutil.revpair(repo, revs)
3587 node1, node2 = scmutil.revpair(repo, revs)
3589
3588
3590 if reverse:
3589 if reverse:
3591 node1, node2 = node2, node1
3590 node1, node2 = node2, node1
3592
3591
3593 diffopts = patch.diffallopts(ui, opts)
3592 diffopts = patch.diffallopts(ui, opts)
3594 m = scmutil.match(repo[node2], pats, opts)
3593 m = scmutil.match(repo[node2], pats, opts)
3595 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3594 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3596 listsubrepos=opts.get('subrepos'),
3595 listsubrepos=opts.get('subrepos'),
3597 root=opts.get('root'))
3596 root=opts.get('root'))
3598
3597
3599 @command('^export',
3598 @command('^export',
3600 [('o', 'output', '',
3599 [('o', 'output', '',
3601 _('print output to file with formatted name'), _('FORMAT')),
3600 _('print output to file with formatted name'), _('FORMAT')),
3602 ('', 'switch-parent', None, _('diff against the second parent')),
3601 ('', 'switch-parent', None, _('diff against the second parent')),
3603 ('r', 'rev', [], _('revisions to export'), _('REV')),
3602 ('r', 'rev', [], _('revisions to export'), _('REV')),
3604 ] + diffopts,
3603 ] + diffopts,
3605 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3604 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3606 def export(ui, repo, *changesets, **opts):
3605 def export(ui, repo, *changesets, **opts):
3607 """dump the header and diffs for one or more changesets
3606 """dump the header and diffs for one or more changesets
3608
3607
3609 Print the changeset header and diffs for one or more revisions.
3608 Print the changeset header and diffs for one or more revisions.
3610 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.
3611
3610
3612 The information shown in the changeset header is: author, date,
3611 The information shown in the changeset header is: author, date,
3613 branch name (if non-default), changeset hash, parent(s) and commit
3612 branch name (if non-default), changeset hash, parent(s) and commit
3614 comment.
3613 comment.
3615
3614
3616 .. note::
3615 .. note::
3617
3616
3618 :hg:`export` may generate unexpected diff output for merge
3617 :hg:`export` may generate unexpected diff output for merge
3619 changesets, as it will compare the merge changeset against its
3618 changesets, as it will compare the merge changeset against its
3620 first parent only.
3619 first parent only.
3621
3620
3622 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
3623 given using a format string. The formatting rules are as follows:
3622 given using a format string. The formatting rules are as follows:
3624
3623
3625 :``%%``: literal "%" character
3624 :``%%``: literal "%" character
3626 :``%H``: changeset hash (40 hexadecimal digits)
3625 :``%H``: changeset hash (40 hexadecimal digits)
3627 :``%N``: number of patches being generated
3626 :``%N``: number of patches being generated
3628 :``%R``: changeset revision number
3627 :``%R``: changeset revision number
3629 :``%b``: basename of the exporting repository
3628 :``%b``: basename of the exporting repository
3630 :``%h``: short-form changeset hash (12 hexadecimal digits)
3629 :``%h``: short-form changeset hash (12 hexadecimal digits)
3631 :``%m``: first line of the commit message (only alphanumeric characters)
3630 :``%m``: first line of the commit message (only alphanumeric characters)
3632 :``%n``: zero-padded sequence number, starting at 1
3631 :``%n``: zero-padded sequence number, starting at 1
3633 :``%r``: zero-padded changeset revision number
3632 :``%r``: zero-padded changeset revision number
3634
3633
3635 Without the -a/--text option, export will avoid generating diffs
3634 Without the -a/--text option, export will avoid generating diffs
3636 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
3637 diff anyway, probably with undesirable results.
3636 diff anyway, probably with undesirable results.
3638
3637
3639 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
3640 format. See :hg:`help diffs` for more information.
3639 format. See :hg:`help diffs` for more information.
3641
3640
3642 With the --switch-parent option, the diff will be against the
3641 With the --switch-parent option, the diff will be against the
3643 second parent. It can be useful to review a merge.
3642 second parent. It can be useful to review a merge.
3644
3643
3645 .. container:: verbose
3644 .. container:: verbose
3646
3645
3647 Examples:
3646 Examples:
3648
3647
3649 - use export and import to transplant a bugfix to the current
3648 - use export and import to transplant a bugfix to the current
3650 branch::
3649 branch::
3651
3650
3652 hg export -r 9353 | hg import -
3651 hg export -r 9353 | hg import -
3653
3652
3654 - export all the changesets between two revisions to a file with
3653 - export all the changesets between two revisions to a file with
3655 rename information::
3654 rename information::
3656
3655
3657 hg export --git -r 123:150 > changes.txt
3656 hg export --git -r 123:150 > changes.txt
3658
3657
3659 - split outgoing changes into a series of patches with
3658 - split outgoing changes into a series of patches with
3660 descriptive names::
3659 descriptive names::
3661
3660
3662 hg export -r "outgoing()" -o "%n-%m.patch"
3661 hg export -r "outgoing()" -o "%n-%m.patch"
3663
3662
3664 Returns 0 on success.
3663 Returns 0 on success.
3665 """
3664 """
3666 changesets += tuple(opts.get('rev', []))
3665 changesets += tuple(opts.get('rev', []))
3667 if not changesets:
3666 if not changesets:
3668 changesets = ['.']
3667 changesets = ['.']
3669 revs = scmutil.revrange(repo, changesets)
3668 revs = scmutil.revrange(repo, changesets)
3670 if not revs:
3669 if not revs:
3671 raise error.Abort(_("export requires at least one changeset"))
3670 raise error.Abort(_("export requires at least one changeset"))
3672 if len(revs) > 1:
3671 if len(revs) > 1:
3673 ui.note(_('exporting patches:\n'))
3672 ui.note(_('exporting patches:\n'))
3674 else:
3673 else:
3675 ui.note(_('exporting patch:\n'))
3674 ui.note(_('exporting patch:\n'))
3676 cmdutil.export(repo, revs, template=opts.get('output'),
3675 cmdutil.export(repo, revs, template=opts.get('output'),
3677 switch_parent=opts.get('switch_parent'),
3676 switch_parent=opts.get('switch_parent'),
3678 opts=patch.diffallopts(ui, opts))
3677 opts=patch.diffallopts(ui, opts))
3679
3678
3680 @command('files',
3679 @command('files',
3681 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3680 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3682 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3681 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3683 ] + walkopts + formatteropts + subrepoopts,
3682 ] + walkopts + formatteropts + subrepoopts,
3684 _('[OPTION]... [FILE]...'))
3683 _('[OPTION]... [FILE]...'))
3685 def files(ui, repo, *pats, **opts):
3684 def files(ui, repo, *pats, **opts):
3686 """list tracked files
3685 """list tracked files
3687
3686
3688 Print files under Mercurial control in the working directory or
3687 Print files under Mercurial control in the working directory or
3689 specified revision for given files (excluding removed files).
3688 specified revision for given files (excluding removed files).
3690 Files can be specified as filenames or filesets.
3689 Files can be specified as filenames or filesets.
3691
3690
3692 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
3693 of all files under Mercurial control.
3692 of all files under Mercurial control.
3694
3693
3695 .. container:: verbose
3694 .. container:: verbose
3696
3695
3697 Examples:
3696 Examples:
3698
3697
3699 - list all files under the current directory::
3698 - list all files under the current directory::
3700
3699
3701 hg files .
3700 hg files .
3702
3701
3703 - shows sizes and flags for current revision::
3702 - shows sizes and flags for current revision::
3704
3703
3705 hg files -vr .
3704 hg files -vr .
3706
3705
3707 - list all files named README::
3706 - list all files named README::
3708
3707
3709 hg files -I "**/README"
3708 hg files -I "**/README"
3710
3709
3711 - list all binary files::
3710 - list all binary files::
3712
3711
3713 hg files "set:binary()"
3712 hg files "set:binary()"
3714
3713
3715 - find files containing a regular expression::
3714 - find files containing a regular expression::
3716
3715
3717 hg files "set:grep('bob')"
3716 hg files "set:grep('bob')"
3718
3717
3719 - search tracked file contents with xargs and grep::
3718 - search tracked file contents with xargs and grep::
3720
3719
3721 hg files -0 | xargs -0 grep foo
3720 hg files -0 | xargs -0 grep foo
3722
3721
3723 See :hg:`help patterns` and :hg:`help filesets` for more information
3722 See :hg:`help patterns` and :hg:`help filesets` for more information
3724 on specifying file patterns.
3723 on specifying file patterns.
3725
3724
3726 Returns 0 if a match is found, 1 otherwise.
3725 Returns 0 if a match is found, 1 otherwise.
3727
3726
3728 """
3727 """
3729 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3728 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3730
3729
3731 end = '\n'
3730 end = '\n'
3732 if opts.get('print0'):
3731 if opts.get('print0'):
3733 end = '\0'
3732 end = '\0'
3734 fmt = '%s' + end
3733 fmt = '%s' + end
3735
3734
3736 m = scmutil.match(ctx, pats, opts)
3735 m = scmutil.match(ctx, pats, opts)
3737 with ui.formatter('files', opts) as fm:
3736 with ui.formatter('files', opts) as fm:
3738 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3737 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3739
3738
3740 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3739 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3741 def forget(ui, repo, *pats, **opts):
3740 def forget(ui, repo, *pats, **opts):
3742 """forget the specified files on the next commit
3741 """forget the specified files on the next commit
3743
3742
3744 Mark the specified files so they will no longer be tracked
3743 Mark the specified files so they will no longer be tracked
3745 after the next commit.
3744 after the next commit.
3746
3745
3747 This only removes files from the current branch, not from the
3746 This only removes files from the current branch, not from the
3748 entire project history, and it does not delete them from the
3747 entire project history, and it does not delete them from the
3749 working directory.
3748 working directory.
3750
3749
3751 To delete the file from the working directory, see :hg:`remove`.
3750 To delete the file from the working directory, see :hg:`remove`.
3752
3751
3753 To undo a forget before the next commit, see :hg:`add`.
3752 To undo a forget before the next commit, see :hg:`add`.
3754
3753
3755 .. container:: verbose
3754 .. container:: verbose
3756
3755
3757 Examples:
3756 Examples:
3758
3757
3759 - forget newly-added binary files::
3758 - forget newly-added binary files::
3760
3759
3761 hg forget "set:added() and binary()"
3760 hg forget "set:added() and binary()"
3762
3761
3763 - forget files that would be excluded by .hgignore::
3762 - forget files that would be excluded by .hgignore::
3764
3763
3765 hg forget "set:hgignore()"
3764 hg forget "set:hgignore()"
3766
3765
3767 Returns 0 on success.
3766 Returns 0 on success.
3768 """
3767 """
3769
3768
3770 if not pats:
3769 if not pats:
3771 raise error.Abort(_('no files specified'))
3770 raise error.Abort(_('no files specified'))
3772
3771
3773 m = scmutil.match(repo[None], pats, opts)
3772 m = scmutil.match(repo[None], pats, opts)
3774 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3773 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3775 return rejected and 1 or 0
3774 return rejected and 1 or 0
3776
3775
3777 @command(
3776 @command(
3778 'graft',
3777 'graft',
3779 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3778 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3780 ('c', 'continue', False, _('resume interrupted graft')),
3779 ('c', 'continue', False, _('resume interrupted graft')),
3781 ('e', 'edit', False, _('invoke editor on commit messages')),
3780 ('e', 'edit', False, _('invoke editor on commit messages')),
3782 ('', 'log', None, _('append graft info to log message')),
3781 ('', 'log', None, _('append graft info to log message')),
3783 ('f', 'force', False, _('force graft')),
3782 ('f', 'force', False, _('force graft')),
3784 ('D', 'currentdate', False,
3783 ('D', 'currentdate', False,
3785 _('record the current date as commit date')),
3784 _('record the current date as commit date')),
3786 ('U', 'currentuser', False,
3785 ('U', 'currentuser', False,
3787 _('record the current user as committer'), _('DATE'))]
3786 _('record the current user as committer'), _('DATE'))]
3788 + commitopts2 + mergetoolopts + dryrunopts,
3787 + commitopts2 + mergetoolopts + dryrunopts,
3789 _('[OPTION]... [-r REV]... REV...'))
3788 _('[OPTION]... [-r REV]... REV...'))
3790 def graft(ui, repo, *revs, **opts):
3789 def graft(ui, repo, *revs, **opts):
3791 '''copy changes from other branches onto the current branch
3790 '''copy changes from other branches onto the current branch
3792
3791
3793 This command uses Mercurial's merge logic to copy individual
3792 This command uses Mercurial's merge logic to copy individual
3794 changes from other branches without merging branches in the
3793 changes from other branches without merging branches in the
3795 history graph. This is sometimes known as 'backporting' or
3794 history graph. This is sometimes known as 'backporting' or
3796 'cherry-picking'. By default, graft will copy user, date, and
3795 'cherry-picking'. By default, graft will copy user, date, and
3797 description from the source changesets.
3796 description from the source changesets.
3798
3797
3799 Changesets that are ancestors of the current revision, that have
3798 Changesets that are ancestors of the current revision, that have
3800 already been grafted, or that are merges will be skipped.
3799 already been grafted, or that are merges will be skipped.
3801
3800
3802 If --log is specified, log messages will have a comment appended
3801 If --log is specified, log messages will have a comment appended
3803 of the form::
3802 of the form::
3804
3803
3805 (grafted from CHANGESETHASH)
3804 (grafted from CHANGESETHASH)
3806
3805
3807 If --force is specified, revisions will be grafted even if they
3806 If --force is specified, revisions will be grafted even if they
3808 are already ancestors of or have been grafted to the destination.
3807 are already ancestors of or have been grafted to the destination.
3809 This is useful when the revisions have since been backed out.
3808 This is useful when the revisions have since been backed out.
3810
3809
3811 If a graft merge results in conflicts, the graft process is
3810 If a graft merge results in conflicts, the graft process is
3812 interrupted so that the current merge can be manually resolved.
3811 interrupted so that the current merge can be manually resolved.
3813 Once all conflicts are addressed, the graft process can be
3812 Once all conflicts are addressed, the graft process can be
3814 continued with the -c/--continue option.
3813 continued with the -c/--continue option.
3815
3814
3816 .. note::
3815 .. note::
3817
3816
3818 The -c/--continue option does not reapply earlier options, except
3817 The -c/--continue option does not reapply earlier options, except
3819 for --force.
3818 for --force.
3820
3819
3821 .. container:: verbose
3820 .. container:: verbose
3822
3821
3823 Examples:
3822 Examples:
3824
3823
3825 - 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::
3826
3825
3827 hg update stable
3826 hg update stable
3828 hg graft --edit 9393
3827 hg graft --edit 9393
3829
3828
3830 - graft a range of changesets with one exception, updating dates::
3829 - graft a range of changesets with one exception, updating dates::
3831
3830
3832 hg graft -D "2085::2093 and not 2091"
3831 hg graft -D "2085::2093 and not 2091"
3833
3832
3834 - continue a graft after resolving conflicts::
3833 - continue a graft after resolving conflicts::
3835
3834
3836 hg graft -c
3835 hg graft -c
3837
3836
3838 - show the source of a grafted changeset::
3837 - show the source of a grafted changeset::
3839
3838
3840 hg log --debug -r .
3839 hg log --debug -r .
3841
3840
3842 - show revisions sorted by date::
3841 - show revisions sorted by date::
3843
3842
3844 hg log -r "sort(all(), date)"
3843 hg log -r "sort(all(), date)"
3845
3844
3846 See :hg:`help revisions` and :hg:`help revsets` for more about
3845 See :hg:`help revisions` and :hg:`help revsets` for more about
3847 specifying revisions.
3846 specifying revisions.
3848
3847
3849 Returns 0 on successful completion.
3848 Returns 0 on successful completion.
3850 '''
3849 '''
3851 with repo.wlock():
3850 with repo.wlock():
3852 return _dograft(ui, repo, *revs, **opts)
3851 return _dograft(ui, repo, *revs, **opts)
3853
3852
3854 def _dograft(ui, repo, *revs, **opts):
3853 def _dograft(ui, repo, *revs, **opts):
3855 if revs and opts.get('rev'):
3854 if revs and opts.get('rev'):
3856 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3855 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3857 'revision ordering!\n'))
3856 'revision ordering!\n'))
3858
3857
3859 revs = list(revs)
3858 revs = list(revs)
3860 revs.extend(opts.get('rev'))
3859 revs.extend(opts.get('rev'))
3861
3860
3862 if not opts.get('user') and opts.get('currentuser'):
3861 if not opts.get('user') and opts.get('currentuser'):
3863 opts['user'] = ui.username()
3862 opts['user'] = ui.username()
3864 if not opts.get('date') and opts.get('currentdate'):
3863 if not opts.get('date') and opts.get('currentdate'):
3865 opts['date'] = "%d %d" % util.makedate()
3864 opts['date'] = "%d %d" % util.makedate()
3866
3865
3867 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3866 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3868
3867
3869 cont = False
3868 cont = False
3870 if opts.get('continue'):
3869 if opts.get('continue'):
3871 cont = True
3870 cont = True
3872 if revs:
3871 if revs:
3873 raise error.Abort(_("can't specify --continue and revisions"))
3872 raise error.Abort(_("can't specify --continue and revisions"))
3874 # read in unfinished revisions
3873 # read in unfinished revisions
3875 try:
3874 try:
3876 nodes = repo.vfs.read('graftstate').splitlines()
3875 nodes = repo.vfs.read('graftstate').splitlines()
3877 revs = [repo[node].rev() for node in nodes]
3876 revs = [repo[node].rev() for node in nodes]
3878 except IOError as inst:
3877 except IOError as inst:
3879 if inst.errno != errno.ENOENT:
3878 if inst.errno != errno.ENOENT:
3880 raise
3879 raise
3881 cmdutil.wrongtooltocontinue(repo, _('graft'))
3880 cmdutil.wrongtooltocontinue(repo, _('graft'))
3882 else:
3881 else:
3883 cmdutil.checkunfinished(repo)
3882 cmdutil.checkunfinished(repo)
3884 cmdutil.bailifchanged(repo)
3883 cmdutil.bailifchanged(repo)
3885 if not revs:
3884 if not revs:
3886 raise error.Abort(_('no revisions specified'))
3885 raise error.Abort(_('no revisions specified'))
3887 revs = scmutil.revrange(repo, revs)
3886 revs = scmutil.revrange(repo, revs)
3888
3887
3889 skipped = set()
3888 skipped = set()
3890 # check for merges
3889 # check for merges
3891 for rev in repo.revs('%ld and merge()', revs):
3890 for rev in repo.revs('%ld and merge()', revs):
3892 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3891 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3893 skipped.add(rev)
3892 skipped.add(rev)
3894 revs = [r for r in revs if r not in skipped]
3893 revs = [r for r in revs if r not in skipped]
3895 if not revs:
3894 if not revs:
3896 return -1
3895 return -1
3897
3896
3898 # 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
3899 # --continues. That's because without --force, any revisions we decided to
3898 # --continues. That's because without --force, any revisions we decided to
3900 # 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
3901 # 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
3902 # 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
3903 # already, they'd have been in the graftstate.
3902 # already, they'd have been in the graftstate.
3904 if not (cont or opts.get('force')):
3903 if not (cont or opts.get('force')):
3905 # check for ancestors of dest branch
3904 # check for ancestors of dest branch
3906 crev = repo['.'].rev()
3905 crev = repo['.'].rev()
3907 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3906 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3908 # XXX make this lazy in the future
3907 # XXX make this lazy in the future
3909 # don't mutate while iterating, create a copy
3908 # don't mutate while iterating, create a copy
3910 for rev in list(revs):
3909 for rev in list(revs):
3911 if rev in ancestors:
3910 if rev in ancestors:
3912 ui.warn(_('skipping ancestor revision %d:%s\n') %
3911 ui.warn(_('skipping ancestor revision %d:%s\n') %
3913 (rev, repo[rev]))
3912 (rev, repo[rev]))
3914 # XXX remove on list is slow
3913 # XXX remove on list is slow
3915 revs.remove(rev)
3914 revs.remove(rev)
3916 if not revs:
3915 if not revs:
3917 return -1
3916 return -1
3918
3917
3919 # analyze revs for earlier grafts
3918 # analyze revs for earlier grafts
3920 ids = {}
3919 ids = {}
3921 for ctx in repo.set("%ld", revs):
3920 for ctx in repo.set("%ld", revs):
3922 ids[ctx.hex()] = ctx.rev()
3921 ids[ctx.hex()] = ctx.rev()
3923 n = ctx.extra().get('source')
3922 n = ctx.extra().get('source')
3924 if n:
3923 if n:
3925 ids[n] = ctx.rev()
3924 ids[n] = ctx.rev()
3926
3925
3927 # check ancestors for earlier grafts
3926 # check ancestors for earlier grafts
3928 ui.debug('scanning for duplicate grafts\n')
3927 ui.debug('scanning for duplicate grafts\n')
3929
3928
3930 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3929 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3931 ctx = repo[rev]
3930 ctx = repo[rev]
3932 n = ctx.extra().get('source')
3931 n = ctx.extra().get('source')
3933 if n in ids:
3932 if n in ids:
3934 try:
3933 try:
3935 r = repo[n].rev()
3934 r = repo[n].rev()
3936 except error.RepoLookupError:
3935 except error.RepoLookupError:
3937 r = None
3936 r = None
3938 if r in revs:
3937 if r in revs:
3939 ui.warn(_('skipping revision %d:%s '
3938 ui.warn(_('skipping revision %d:%s '
3940 '(already grafted to %d:%s)\n')
3939 '(already grafted to %d:%s)\n')
3941 % (r, repo[r], rev, ctx))
3940 % (r, repo[r], rev, ctx))
3942 revs.remove(r)
3941 revs.remove(r)
3943 elif ids[n] in revs:
3942 elif ids[n] in revs:
3944 if r is None:
3943 if r is None:
3945 ui.warn(_('skipping already grafted revision %d:%s '
3944 ui.warn(_('skipping already grafted revision %d:%s '
3946 '(%d:%s also has unknown origin %s)\n')
3945 '(%d:%s also has unknown origin %s)\n')
3947 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3946 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3948 else:
3947 else:
3949 ui.warn(_('skipping already grafted revision %d:%s '
3948 ui.warn(_('skipping already grafted revision %d:%s '
3950 '(%d:%s also has origin %d:%s)\n')
3949 '(%d:%s also has origin %d:%s)\n')
3951 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3950 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3952 revs.remove(ids[n])
3951 revs.remove(ids[n])
3953 elif ctx.hex() in ids:
3952 elif ctx.hex() in ids:
3954 r = ids[ctx.hex()]
3953 r = ids[ctx.hex()]
3955 ui.warn(_('skipping already grafted revision %d:%s '
3954 ui.warn(_('skipping already grafted revision %d:%s '
3956 '(was grafted from %d:%s)\n') %
3955 '(was grafted from %d:%s)\n') %
3957 (r, repo[r], rev, ctx))
3956 (r, repo[r], rev, ctx))
3958 revs.remove(r)
3957 revs.remove(r)
3959 if not revs:
3958 if not revs:
3960 return -1
3959 return -1
3961
3960
3962 for pos, ctx in enumerate(repo.set("%ld", revs)):
3961 for pos, ctx in enumerate(repo.set("%ld", revs)):
3963 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3962 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3964 ctx.description().split('\n', 1)[0])
3963 ctx.description().split('\n', 1)[0])
3965 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3964 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3966 if names:
3965 if names:
3967 desc += ' (%s)' % ' '.join(names)
3966 desc += ' (%s)' % ' '.join(names)
3968 ui.status(_('grafting %s\n') % desc)
3967 ui.status(_('grafting %s\n') % desc)
3969 if opts.get('dry_run'):
3968 if opts.get('dry_run'):
3970 continue
3969 continue
3971
3970
3972 source = ctx.extra().get('source')
3971 source = ctx.extra().get('source')
3973 extra = {}
3972 extra = {}
3974 if source:
3973 if source:
3975 extra['source'] = source
3974 extra['source'] = source
3976 extra['intermediate-source'] = ctx.hex()
3975 extra['intermediate-source'] = ctx.hex()
3977 else:
3976 else:
3978 extra['source'] = ctx.hex()
3977 extra['source'] = ctx.hex()
3979 user = ctx.user()
3978 user = ctx.user()
3980 if opts.get('user'):
3979 if opts.get('user'):
3981 user = opts['user']
3980 user = opts['user']
3982 date = ctx.date()
3981 date = ctx.date()
3983 if opts.get('date'):
3982 if opts.get('date'):
3984 date = opts['date']
3983 date = opts['date']
3985 message = ctx.description()
3984 message = ctx.description()
3986 if opts.get('log'):
3985 if opts.get('log'):
3987 message += '\n(grafted from %s)' % ctx.hex()
3986 message += '\n(grafted from %s)' % ctx.hex()
3988
3987
3989 # we don't merge the first commit when continuing
3988 # we don't merge the first commit when continuing
3990 if not cont:
3989 if not cont:
3991 # perform the graft merge with p1(rev) as 'ancestor'
3990 # perform the graft merge with p1(rev) as 'ancestor'
3992 try:
3991 try:
3993 # ui.forcemerge is an internal variable, do not document
3992 # ui.forcemerge is an internal variable, do not document
3994 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3993 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3995 'graft')
3994 'graft')
3996 stats = mergemod.graft(repo, ctx, ctx.p1(),
3995 stats = mergemod.graft(repo, ctx, ctx.p1(),
3997 ['local', 'graft'])
3996 ['local', 'graft'])
3998 finally:
3997 finally:
3999 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3998 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4000 # report any conflicts
3999 # report any conflicts
4001 if stats and stats[3] > 0:
4000 if stats and stats[3] > 0:
4002 # write out state for --continue
4001 # write out state for --continue
4003 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4002 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4004 repo.vfs.write('graftstate', ''.join(nodelines))
4003 repo.vfs.write('graftstate', ''.join(nodelines))
4005 extra = ''
4004 extra = ''
4006 if opts.get('user'):
4005 if opts.get('user'):
4007 extra += ' --user %s' % util.shellquote(opts['user'])
4006 extra += ' --user %s' % util.shellquote(opts['user'])
4008 if opts.get('date'):
4007 if opts.get('date'):
4009 extra += ' --date %s' % util.shellquote(opts['date'])
4008 extra += ' --date %s' % util.shellquote(opts['date'])
4010 if opts.get('log'):
4009 if opts.get('log'):
4011 extra += ' --log'
4010 extra += ' --log'
4012 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4011 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4013 raise error.Abort(
4012 raise error.Abort(
4014 _("unresolved conflicts, can't continue"),
4013 _("unresolved conflicts, can't continue"),
4015 hint=hint)
4014 hint=hint)
4016 else:
4015 else:
4017 cont = False
4016 cont = False
4018
4017
4019 # commit
4018 # commit
4020 node = repo.commit(text=message, user=user,
4019 node = repo.commit(text=message, user=user,
4021 date=date, extra=extra, editor=editor)
4020 date=date, extra=extra, editor=editor)
4022 if node is None:
4021 if node is None:
4023 ui.warn(
4022 ui.warn(
4024 _('note: graft of %d:%s created no changes to commit\n') %
4023 _('note: graft of %d:%s created no changes to commit\n') %
4025 (ctx.rev(), ctx))
4024 (ctx.rev(), ctx))
4026
4025
4027 # remove state when we complete successfully
4026 # remove state when we complete successfully
4028 if not opts.get('dry_run'):
4027 if not opts.get('dry_run'):
4029 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4028 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4030
4029
4031 return 0
4030 return 0
4032
4031
4033 @command('grep',
4032 @command('grep',
4034 [('0', 'print0', None, _('end fields with NUL')),
4033 [('0', 'print0', None, _('end fields with NUL')),
4035 ('', 'all', None, _('print all revisions that match')),
4034 ('', 'all', None, _('print all revisions that match')),
4036 ('a', 'text', None, _('treat all files as text')),
4035 ('a', 'text', None, _('treat all files as text')),
4037 ('f', 'follow', None,
4036 ('f', 'follow', None,
4038 _('follow changeset history,'
4037 _('follow changeset history,'
4039 ' or file history across copies and renames')),
4038 ' or file history across copies and renames')),
4040 ('i', 'ignore-case', None, _('ignore case when matching')),
4039 ('i', 'ignore-case', None, _('ignore case when matching')),
4041 ('l', 'files-with-matches', None,
4040 ('l', 'files-with-matches', None,
4042 _('print only filenames and revisions that match')),
4041 _('print only filenames and revisions that match')),
4043 ('n', 'line-number', None, _('print matching line numbers')),
4042 ('n', 'line-number', None, _('print matching line numbers')),
4044 ('r', 'rev', [],
4043 ('r', 'rev', [],
4045 _('only search files changed within revision range'), _('REV')),
4044 _('only search files changed within revision range'), _('REV')),
4046 ('u', 'user', None, _('list the author (long with -v)')),
4045 ('u', 'user', None, _('list the author (long with -v)')),
4047 ('d', 'date', None, _('list the date (short with -q)')),
4046 ('d', 'date', None, _('list the date (short with -q)')),
4048 ] + formatteropts + walkopts,
4047 ] + formatteropts + walkopts,
4049 _('[OPTION]... PATTERN [FILE]...'),
4048 _('[OPTION]... PATTERN [FILE]...'),
4050 inferrepo=True)
4049 inferrepo=True)
4051 def grep(ui, repo, pattern, *pats, **opts):
4050 def grep(ui, repo, pattern, *pats, **opts):
4052 """search revision history for a pattern in specified files
4051 """search revision history for a pattern in specified files
4053
4052
4054 Search revision history for a regular expression in the specified
4053 Search revision history for a regular expression in the specified
4055 files or the entire project.
4054 files or the entire project.
4056
4055
4057 By default, grep prints the most recent revision number for each
4056 By default, grep prints the most recent revision number for each
4058 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
4059 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
4060 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
4061 --all flag.
4060 --all flag.
4062
4061
4063 PATTERN can be any Python (roughly Perl-compatible) regular
4062 PATTERN can be any Python (roughly Perl-compatible) regular
4064 expression.
4063 expression.
4065
4064
4066 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
4067 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
4068 current branch or have been deleted in a prior changeset.
4067 current branch or have been deleted in a prior changeset.
4069
4068
4070 Returns 0 if a match is found, 1 otherwise.
4069 Returns 0 if a match is found, 1 otherwise.
4071 """
4070 """
4072 reflags = re.M
4071 reflags = re.M
4073 if opts.get('ignore_case'):
4072 if opts.get('ignore_case'):
4074 reflags |= re.I
4073 reflags |= re.I
4075 try:
4074 try:
4076 regexp = util.re.compile(pattern, reflags)
4075 regexp = util.re.compile(pattern, reflags)
4077 except re.error as inst:
4076 except re.error as inst:
4078 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4077 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4079 return 1
4078 return 1
4080 sep, eol = ':', '\n'
4079 sep, eol = ':', '\n'
4081 if opts.get('print0'):
4080 if opts.get('print0'):
4082 sep = eol = '\0'
4081 sep = eol = '\0'
4083
4082
4084 getfile = util.lrucachefunc(repo.file)
4083 getfile = util.lrucachefunc(repo.file)
4085
4084
4086 def matchlines(body):
4085 def matchlines(body):
4087 begin = 0
4086 begin = 0
4088 linenum = 0
4087 linenum = 0
4089 while begin < len(body):
4088 while begin < len(body):
4090 match = regexp.search(body, begin)
4089 match = regexp.search(body, begin)
4091 if not match:
4090 if not match:
4092 break
4091 break
4093 mstart, mend = match.span()
4092 mstart, mend = match.span()
4094 linenum += body.count('\n', begin, mstart) + 1
4093 linenum += body.count('\n', begin, mstart) + 1
4095 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4094 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4096 begin = body.find('\n', mend) + 1 or len(body) + 1
4095 begin = body.find('\n', mend) + 1 or len(body) + 1
4097 lend = begin - 1
4096 lend = begin - 1
4098 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4097 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4099
4098
4100 class linestate(object):
4099 class linestate(object):
4101 def __init__(self, line, linenum, colstart, colend):
4100 def __init__(self, line, linenum, colstart, colend):
4102 self.line = line
4101 self.line = line
4103 self.linenum = linenum
4102 self.linenum = linenum
4104 self.colstart = colstart
4103 self.colstart = colstart
4105 self.colend = colend
4104 self.colend = colend
4106
4105
4107 def __hash__(self):
4106 def __hash__(self):
4108 return hash((self.linenum, self.line))
4107 return hash((self.linenum, self.line))
4109
4108
4110 def __eq__(self, other):
4109 def __eq__(self, other):
4111 return self.line == other.line
4110 return self.line == other.line
4112
4111
4113 def findpos(self):
4112 def findpos(self):
4114 """Iterate all (start, end) indices of matches"""
4113 """Iterate all (start, end) indices of matches"""
4115 yield self.colstart, self.colend
4114 yield self.colstart, self.colend
4116 p = self.colend
4115 p = self.colend
4117 while p < len(self.line):
4116 while p < len(self.line):
4118 m = regexp.search(self.line, p)
4117 m = regexp.search(self.line, p)
4119 if not m:
4118 if not m:
4120 break
4119 break
4121 yield m.span()
4120 yield m.span()
4122 p = m.end()
4121 p = m.end()
4123
4122
4124 matches = {}
4123 matches = {}
4125 copies = {}
4124 copies = {}
4126 def grepbody(fn, rev, body):
4125 def grepbody(fn, rev, body):
4127 matches[rev].setdefault(fn, [])
4126 matches[rev].setdefault(fn, [])
4128 m = matches[rev][fn]
4127 m = matches[rev][fn]
4129 for lnum, cstart, cend, line in matchlines(body):
4128 for lnum, cstart, cend, line in matchlines(body):
4130 s = linestate(line, lnum, cstart, cend)
4129 s = linestate(line, lnum, cstart, cend)
4131 m.append(s)
4130 m.append(s)
4132
4131
4133 def difflinestates(a, b):
4132 def difflinestates(a, b):
4134 sm = difflib.SequenceMatcher(None, a, b)
4133 sm = difflib.SequenceMatcher(None, a, b)
4135 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4134 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4136 if tag == 'insert':
4135 if tag == 'insert':
4137 for i in xrange(blo, bhi):
4136 for i in xrange(blo, bhi):
4138 yield ('+', b[i])
4137 yield ('+', b[i])
4139 elif tag == 'delete':
4138 elif tag == 'delete':
4140 for i in xrange(alo, ahi):
4139 for i in xrange(alo, ahi):
4141 yield ('-', a[i])
4140 yield ('-', a[i])
4142 elif tag == 'replace':
4141 elif tag == 'replace':
4143 for i in xrange(alo, ahi):
4142 for i in xrange(alo, ahi):
4144 yield ('-', a[i])
4143 yield ('-', a[i])
4145 for i in xrange(blo, bhi):
4144 for i in xrange(blo, bhi):
4146 yield ('+', b[i])
4145 yield ('+', b[i])
4147
4146
4148 def display(fm, fn, ctx, pstates, states):
4147 def display(fm, fn, ctx, pstates, states):
4149 rev = ctx.rev()
4148 rev = ctx.rev()
4150 if fm.isplain():
4149 if fm.isplain():
4151 formatuser = ui.shortuser
4150 formatuser = ui.shortuser
4152 else:
4151 else:
4153 formatuser = str
4152 formatuser = str
4154 if ui.quiet:
4153 if ui.quiet:
4155 datefmt = '%Y-%m-%d'
4154 datefmt = '%Y-%m-%d'
4156 else:
4155 else:
4157 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4156 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
4158 found = False
4157 found = False
4159 @util.cachefunc
4158 @util.cachefunc
4160 def binary():
4159 def binary():
4161 flog = getfile(fn)
4160 flog = getfile(fn)
4162 return util.binary(flog.read(ctx.filenode(fn)))
4161 return util.binary(flog.read(ctx.filenode(fn)))
4163
4162
4164 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4163 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
4165 if opts.get('all'):
4164 if opts.get('all'):
4166 iter = difflinestates(pstates, states)
4165 iter = difflinestates(pstates, states)
4167 else:
4166 else:
4168 iter = [('', l) for l in states]
4167 iter = [('', l) for l in states]
4169 for change, l in iter:
4168 for change, l in iter:
4170 fm.startitem()
4169 fm.startitem()
4171 fm.data(node=fm.hexfunc(ctx.node()))
4170 fm.data(node=fm.hexfunc(ctx.node()))
4172 cols = [
4171 cols = [
4173 ('filename', fn, True),
4172 ('filename', fn, True),
4174 ('rev', rev, True),
4173 ('rev', rev, True),
4175 ('linenumber', l.linenum, opts.get('line_number')),
4174 ('linenumber', l.linenum, opts.get('line_number')),
4176 ]
4175 ]
4177 if opts.get('all'):
4176 if opts.get('all'):
4178 cols.append(('change', change, True))
4177 cols.append(('change', change, True))
4179 cols.extend([
4178 cols.extend([
4180 ('user', formatuser(ctx.user()), opts.get('user')),
4179 ('user', formatuser(ctx.user()), opts.get('user')),
4181 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4180 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
4182 ])
4181 ])
4183 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)
4184 for name, data, cond in cols:
4183 for name, data, cond in cols:
4185 field = fieldnamemap.get(name, name)
4184 field = fieldnamemap.get(name, name)
4186 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4185 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
4187 if cond and name != lastcol:
4186 if cond and name != lastcol:
4188 fm.plain(sep, label='grep.sep')
4187 fm.plain(sep, label='grep.sep')
4189 if not opts.get('files_with_matches'):
4188 if not opts.get('files_with_matches'):
4190 fm.plain(sep, label='grep.sep')
4189 fm.plain(sep, label='grep.sep')
4191 if not opts.get('text') and binary():
4190 if not opts.get('text') and binary():
4192 fm.plain(_(" Binary file matches"))
4191 fm.plain(_(" Binary file matches"))
4193 else:
4192 else:
4194 displaymatches(fm.nested('texts'), l)
4193 displaymatches(fm.nested('texts'), l)
4195 fm.plain(eol)
4194 fm.plain(eol)
4196 found = True
4195 found = True
4197 if opts.get('files_with_matches'):
4196 if opts.get('files_with_matches'):
4198 break
4197 break
4199 return found
4198 return found
4200
4199
4201 def displaymatches(fm, l):
4200 def displaymatches(fm, l):
4202 p = 0
4201 p = 0
4203 for s, e in l.findpos():
4202 for s, e in l.findpos():
4204 if p < s:
4203 if p < s:
4205 fm.startitem()
4204 fm.startitem()
4206 fm.write('text', '%s', l.line[p:s])
4205 fm.write('text', '%s', l.line[p:s])
4207 fm.data(matched=False)
4206 fm.data(matched=False)
4208 fm.startitem()
4207 fm.startitem()
4209 fm.write('text', '%s', l.line[s:e], label='grep.match')
4208 fm.write('text', '%s', l.line[s:e], label='grep.match')
4210 fm.data(matched=True)
4209 fm.data(matched=True)
4211 p = e
4210 p = e
4212 if p < len(l.line):
4211 if p < len(l.line):
4213 fm.startitem()
4212 fm.startitem()
4214 fm.write('text', '%s', l.line[p:])
4213 fm.write('text', '%s', l.line[p:])
4215 fm.data(matched=False)
4214 fm.data(matched=False)
4216 fm.end()
4215 fm.end()
4217
4216
4218 skip = {}
4217 skip = {}
4219 revfiles = {}
4218 revfiles = {}
4220 matchfn = scmutil.match(repo[None], pats, opts)
4219 matchfn = scmutil.match(repo[None], pats, opts)
4221 found = False
4220 found = False
4222 follow = opts.get('follow')
4221 follow = opts.get('follow')
4223
4222
4224 def prep(ctx, fns):
4223 def prep(ctx, fns):
4225 rev = ctx.rev()
4224 rev = ctx.rev()
4226 pctx = ctx.p1()
4225 pctx = ctx.p1()
4227 parent = pctx.rev()
4226 parent = pctx.rev()
4228 matches.setdefault(rev, {})
4227 matches.setdefault(rev, {})
4229 matches.setdefault(parent, {})
4228 matches.setdefault(parent, {})
4230 files = revfiles.setdefault(rev, [])
4229 files = revfiles.setdefault(rev, [])
4231 for fn in fns:
4230 for fn in fns:
4232 flog = getfile(fn)
4231 flog = getfile(fn)
4233 try:
4232 try:
4234 fnode = ctx.filenode(fn)
4233 fnode = ctx.filenode(fn)
4235 except error.LookupError:
4234 except error.LookupError:
4236 continue
4235 continue
4237
4236
4238 copied = flog.renamed(fnode)
4237 copied = flog.renamed(fnode)
4239 copy = follow and copied and copied[0]
4238 copy = follow and copied and copied[0]
4240 if copy:
4239 if copy:
4241 copies.setdefault(rev, {})[fn] = copy
4240 copies.setdefault(rev, {})[fn] = copy
4242 if fn in skip:
4241 if fn in skip:
4243 if copy:
4242 if copy:
4244 skip[copy] = True
4243 skip[copy] = True
4245 continue
4244 continue
4246 files.append(fn)
4245 files.append(fn)
4247
4246
4248 if fn not in matches[rev]:
4247 if fn not in matches[rev]:
4249 grepbody(fn, rev, flog.read(fnode))
4248 grepbody(fn, rev, flog.read(fnode))
4250
4249
4251 pfn = copy or fn
4250 pfn = copy or fn
4252 if pfn not in matches[parent]:
4251 if pfn not in matches[parent]:
4253 try:
4252 try:
4254 fnode = pctx.filenode(pfn)
4253 fnode = pctx.filenode(pfn)
4255 grepbody(pfn, parent, flog.read(fnode))
4254 grepbody(pfn, parent, flog.read(fnode))
4256 except error.LookupError:
4255 except error.LookupError:
4257 pass
4256 pass
4258
4257
4259 fm = ui.formatter('grep', opts)
4258 fm = ui.formatter('grep', opts)
4260 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4259 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4261 rev = ctx.rev()
4260 rev = ctx.rev()
4262 parent = ctx.p1().rev()
4261 parent = ctx.p1().rev()
4263 for fn in sorted(revfiles.get(rev, [])):
4262 for fn in sorted(revfiles.get(rev, [])):
4264 states = matches[rev][fn]
4263 states = matches[rev][fn]
4265 copy = copies.get(rev, {}).get(fn)
4264 copy = copies.get(rev, {}).get(fn)
4266 if fn in skip:
4265 if fn in skip:
4267 if copy:
4266 if copy:
4268 skip[copy] = True
4267 skip[copy] = True
4269 continue
4268 continue
4270 pstates = matches.get(parent, {}).get(copy or fn, [])
4269 pstates = matches.get(parent, {}).get(copy or fn, [])
4271 if pstates or states:
4270 if pstates or states:
4272 r = display(fm, fn, ctx, pstates, states)
4271 r = display(fm, fn, ctx, pstates, states)
4273 found = found or r
4272 found = found or r
4274 if r and not opts.get('all'):
4273 if r and not opts.get('all'):
4275 skip[fn] = True
4274 skip[fn] = True
4276 if copy:
4275 if copy:
4277 skip[copy] = True
4276 skip[copy] = True
4278 del matches[rev]
4277 del matches[rev]
4279 del revfiles[rev]
4278 del revfiles[rev]
4280 fm.end()
4279 fm.end()
4281
4280
4282 return not found
4281 return not found
4283
4282
4284 @command('heads',
4283 @command('heads',
4285 [('r', 'rev', '',
4284 [('r', 'rev', '',
4286 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4285 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4287 ('t', 'topo', False, _('show topological heads only')),
4286 ('t', 'topo', False, _('show topological heads only')),
4288 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4287 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4289 ('c', 'closed', False, _('show normal and closed branch heads')),
4288 ('c', 'closed', False, _('show normal and closed branch heads')),
4290 ] + templateopts,
4289 ] + templateopts,
4291 _('[-ct] [-r STARTREV] [REV]...'))
4290 _('[-ct] [-r STARTREV] [REV]...'))
4292 def heads(ui, repo, *branchrevs, **opts):
4291 def heads(ui, repo, *branchrevs, **opts):
4293 """show branch heads
4292 """show branch heads
4294
4293
4295 With no arguments, show all open branch heads in the repository.
4294 With no arguments, show all open branch heads in the repository.
4296 Branch heads are changesets that have no descendants on the
4295 Branch heads are changesets that have no descendants on the
4297 same branch. They are where development generally takes place and
4296 same branch. They are where development generally takes place and
4298 are the usual targets for update and merge operations.
4297 are the usual targets for update and merge operations.
4299
4298
4300 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
4301 branches associated with the specified changesets are shown. This
4300 branches associated with the specified changesets are shown. This
4302 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
4303 currently checked-out branch.
4302 currently checked-out branch.
4304
4303
4305 If -c/--closed is specified, also show branch heads marked closed
4304 If -c/--closed is specified, also show branch heads marked closed
4306 (see :hg:`commit --close-branch`).
4305 (see :hg:`commit --close-branch`).
4307
4306
4308 If STARTREV is specified, only those heads that are descendants of
4307 If STARTREV is specified, only those heads that are descendants of
4309 STARTREV will be displayed.
4308 STARTREV will be displayed.
4310
4309
4311 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
4312 topological heads (changesets with no children) will be shown.
4311 topological heads (changesets with no children) will be shown.
4313
4312
4314 Returns 0 if matching heads are found, 1 if not.
4313 Returns 0 if matching heads are found, 1 if not.
4315 """
4314 """
4316
4315
4317 start = None
4316 start = None
4318 if 'rev' in opts:
4317 if 'rev' in opts:
4319 start = scmutil.revsingle(repo, opts['rev'], None).node()
4318 start = scmutil.revsingle(repo, opts['rev'], None).node()
4320
4319
4321 if opts.get('topo'):
4320 if opts.get('topo'):
4322 heads = [repo[h] for h in repo.heads(start)]
4321 heads = [repo[h] for h in repo.heads(start)]
4323 else:
4322 else:
4324 heads = []
4323 heads = []
4325 for branch in repo.branchmap():
4324 for branch in repo.branchmap():
4326 heads += repo.branchheads(branch, start, opts.get('closed'))
4325 heads += repo.branchheads(branch, start, opts.get('closed'))
4327 heads = [repo[h] for h in heads]
4326 heads = [repo[h] for h in heads]
4328
4327
4329 if branchrevs:
4328 if branchrevs:
4330 branches = set(repo[br].branch() for br in branchrevs)
4329 branches = set(repo[br].branch() for br in branchrevs)
4331 heads = [h for h in heads if h.branch() in branches]
4330 heads = [h for h in heads if h.branch() in branches]
4332
4331
4333 if opts.get('active') and branchrevs:
4332 if opts.get('active') and branchrevs:
4334 dagheads = repo.heads(start)
4333 dagheads = repo.heads(start)
4335 heads = [h for h in heads if h.node() in dagheads]
4334 heads = [h for h in heads if h.node() in dagheads]
4336
4335
4337 if branchrevs:
4336 if branchrevs:
4338 haveheads = set(h.branch() for h in heads)
4337 haveheads = set(h.branch() for h in heads)
4339 if branches - haveheads:
4338 if branches - haveheads:
4340 headless = ', '.join(b for b in branches - haveheads)
4339 headless = ', '.join(b for b in branches - haveheads)
4341 msg = _('no open branch heads found on branches %s')
4340 msg = _('no open branch heads found on branches %s')
4342 if opts.get('rev'):
4341 if opts.get('rev'):
4343 msg += _(' (started at %s)') % opts['rev']
4342 msg += _(' (started at %s)') % opts['rev']
4344 ui.warn((msg + '\n') % headless)
4343 ui.warn((msg + '\n') % headless)
4345
4344
4346 if not heads:
4345 if not heads:
4347 return 1
4346 return 1
4348
4347
4349 heads = sorted(heads, key=lambda x: -x.rev())
4348 heads = sorted(heads, key=lambda x: -x.rev())
4350 displayer = cmdutil.show_changeset(ui, repo, opts)
4349 displayer = cmdutil.show_changeset(ui, repo, opts)
4351 for ctx in heads:
4350 for ctx in heads:
4352 displayer.show(ctx)
4351 displayer.show(ctx)
4353 displayer.close()
4352 displayer.close()
4354
4353
4355 @command('help',
4354 @command('help',
4356 [('e', 'extension', None, _('show only help for extensions')),
4355 [('e', 'extension', None, _('show only help for extensions')),
4357 ('c', 'command', None, _('show only help for commands')),
4356 ('c', 'command', None, _('show only help for commands')),
4358 ('k', 'keyword', None, _('show topics matching keyword')),
4357 ('k', 'keyword', None, _('show topics matching keyword')),
4359 ('s', 'system', [], _('show help for specific platform(s)')),
4358 ('s', 'system', [], _('show help for specific platform(s)')),
4360 ],
4359 ],
4361 _('[-ecks] [TOPIC]'),
4360 _('[-ecks] [TOPIC]'),
4362 norepo=True)
4361 norepo=True)
4363 def help_(ui, name=None, **opts):
4362 def help_(ui, name=None, **opts):
4364 """show help for a given topic or a help overview
4363 """show help for a given topic or a help overview
4365
4364
4366 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.
4367
4366
4368 Given a topic, extension, or command name, print help for that
4367 Given a topic, extension, or command name, print help for that
4369 topic.
4368 topic.
4370
4369
4371 Returns 0 if successful.
4370 Returns 0 if successful.
4372 """
4371 """
4373
4372
4374 textwidth = ui.configint('ui', 'textwidth', 78)
4373 textwidth = ui.configint('ui', 'textwidth', 78)
4375 termwidth = ui.termwidth() - 2
4374 termwidth = ui.termwidth() - 2
4376 if textwidth <= 0 or termwidth < textwidth:
4375 if textwidth <= 0 or termwidth < textwidth:
4377 textwidth = termwidth
4376 textwidth = termwidth
4378
4377
4379 keep = opts.get('system') or []
4378 keep = opts.get('system') or []
4380 if len(keep) == 0:
4379 if len(keep) == 0:
4381 if sys.platform.startswith('win'):
4380 if sys.platform.startswith('win'):
4382 keep.append('windows')
4381 keep.append('windows')
4383 elif sys.platform == 'OpenVMS':
4382 elif sys.platform == 'OpenVMS':
4384 keep.append('vms')
4383 keep.append('vms')
4385 elif sys.platform == 'plan9':
4384 elif sys.platform == 'plan9':
4386 keep.append('plan9')
4385 keep.append('plan9')
4387 else:
4386 else:
4388 keep.append('unix')
4387 keep.append('unix')
4389 keep.append(sys.platform.lower())
4388 keep.append(sys.platform.lower())
4390 if ui.verbose:
4389 if ui.verbose:
4391 keep.append('verbose')
4390 keep.append('verbose')
4392
4391
4393 section = None
4392 section = None
4394 subtopic = None
4393 subtopic = None
4395 if name and '.' in name:
4394 if name and '.' in name:
4396 name, remaining = name.split('.', 1)
4395 name, remaining = name.split('.', 1)
4397 remaining = encoding.lower(remaining)
4396 remaining = encoding.lower(remaining)
4398 if '.' in remaining:
4397 if '.' in remaining:
4399 subtopic, section = remaining.split('.', 1)
4398 subtopic, section = remaining.split('.', 1)
4400 else:
4399 else:
4401 if name in help.subtopics:
4400 if name in help.subtopics:
4402 subtopic = remaining
4401 subtopic = remaining
4403 else:
4402 else:
4404 section = remaining
4403 section = remaining
4405
4404
4406 text = help.help_(ui, name, subtopic=subtopic, **opts)
4405 text = help.help_(ui, name, subtopic=subtopic, **opts)
4407
4406
4408 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4407 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4409 section=section)
4408 section=section)
4410
4409
4411 # 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
4412 # 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"
4413 # because bar isn't a section of foo
4412 # because bar isn't a section of foo
4414 if section and not (formatted and name):
4413 if section and not (formatted and name):
4415 raise error.Abort(_("help section not found"))
4414 raise error.Abort(_("help section not found"))
4416
4415
4417 if 'verbose' in pruned:
4416 if 'verbose' in pruned:
4418 keep.append('omitted')
4417 keep.append('omitted')
4419 else:
4418 else:
4420 keep.append('notomitted')
4419 keep.append('notomitted')
4421 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4420 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4422 section=section)
4421 section=section)
4423 ui.write(formatted)
4422 ui.write(formatted)
4424
4423
4425
4424
4426 @command('identify|id',
4425 @command('identify|id',
4427 [('r', 'rev', '',
4426 [('r', 'rev', '',
4428 _('identify the specified revision'), _('REV')),
4427 _('identify the specified revision'), _('REV')),
4429 ('n', 'num', None, _('show local revision number')),
4428 ('n', 'num', None, _('show local revision number')),
4430 ('i', 'id', None, _('show global revision id')),
4429 ('i', 'id', None, _('show global revision id')),
4431 ('b', 'branch', None, _('show branch')),
4430 ('b', 'branch', None, _('show branch')),
4432 ('t', 'tags', None, _('show tags')),
4431 ('t', 'tags', None, _('show tags')),
4433 ('B', 'bookmarks', None, _('show bookmarks')),
4432 ('B', 'bookmarks', None, _('show bookmarks')),
4434 ] + remoteopts,
4433 ] + remoteopts,
4435 _('[-nibtB] [-r REV] [SOURCE]'),
4434 _('[-nibtB] [-r REV] [SOURCE]'),
4436 optionalrepo=True)
4435 optionalrepo=True)
4437 def identify(ui, repo, source=None, rev=None,
4436 def identify(ui, repo, source=None, rev=None,
4438 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4437 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4439 """identify the working directory or specified revision
4438 """identify the working directory or specified revision
4440
4439
4441 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
4442 two parent hash identifiers, followed by a "+" if the working
4441 two parent hash identifiers, followed by a "+" if the working
4443 directory has uncommitted changes, the branch name (if not default),
4442 directory has uncommitted changes, the branch name (if not default),
4444 a list of tags, and a list of bookmarks.
4443 a list of tags, and a list of bookmarks.
4445
4444
4446 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
4447 repository.
4446 repository.
4448
4447
4449 Specifying a path to a repository root or Mercurial bundle will
4448 Specifying a path to a repository root or Mercurial bundle will
4450 cause lookup to operate on that repository/bundle.
4449 cause lookup to operate on that repository/bundle.
4451
4450
4452 .. container:: verbose
4451 .. container:: verbose
4453
4452
4454 Examples:
4453 Examples:
4455
4454
4456 - generate a build identifier for the working directory::
4455 - generate a build identifier for the working directory::
4457
4456
4458 hg id --id > build-id.dat
4457 hg id --id > build-id.dat
4459
4458
4460 - find the revision corresponding to a tag::
4459 - find the revision corresponding to a tag::
4461
4460
4462 hg id -n -r 1.3
4461 hg id -n -r 1.3
4463
4462
4464 - check the most recent revision of a remote repository::
4463 - check the most recent revision of a remote repository::
4465
4464
4466 hg id -r tip https://www.mercurial-scm.org/repo/hg/
4465 hg id -r tip https://www.mercurial-scm.org/repo/hg/
4467
4466
4468 See :hg:`log` for generating more information about specific revisions,
4467 See :hg:`log` for generating more information about specific revisions,
4469 including full hash identifiers.
4468 including full hash identifiers.
4470
4469
4471 Returns 0 if successful.
4470 Returns 0 if successful.
4472 """
4471 """
4473
4472
4474 if not repo and not source:
4473 if not repo and not source:
4475 raise error.Abort(_("there is no Mercurial repository here "
4474 raise error.Abort(_("there is no Mercurial repository here "
4476 "(.hg not found)"))
4475 "(.hg not found)"))
4477
4476
4478 if ui.debugflag:
4477 if ui.debugflag:
4479 hexfunc = hex
4478 hexfunc = hex
4480 else:
4479 else:
4481 hexfunc = short
4480 hexfunc = short
4482 default = not (num or id or branch or tags or bookmarks)
4481 default = not (num or id or branch or tags or bookmarks)
4483 output = []
4482 output = []
4484 revs = []
4483 revs = []
4485
4484
4486 if source:
4485 if source:
4487 source, branches = hg.parseurl(ui.expandpath(source))
4486 source, branches = hg.parseurl(ui.expandpath(source))
4488 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
4489 repo = peer.local()
4488 repo = peer.local()
4490 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4489 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4491
4490
4492 if not repo:
4491 if not repo:
4493 if num or branch or tags:
4492 if num or branch or tags:
4494 raise error.Abort(
4493 raise error.Abort(
4495 _("can't query remote revision number, branch, or tags"))
4494 _("can't query remote revision number, branch, or tags"))
4496 if not rev and revs:
4495 if not rev and revs:
4497 rev = revs[0]
4496 rev = revs[0]
4498 if not rev:
4497 if not rev:
4499 rev = "tip"
4498 rev = "tip"
4500
4499
4501 remoterev = peer.lookup(rev)
4500 remoterev = peer.lookup(rev)
4502 if default or id:
4501 if default or id:
4503 output = [hexfunc(remoterev)]
4502 output = [hexfunc(remoterev)]
4504
4503
4505 def getbms():
4504 def getbms():
4506 bms = []
4505 bms = []
4507
4506
4508 if 'bookmarks' in peer.listkeys('namespaces'):
4507 if 'bookmarks' in peer.listkeys('namespaces'):
4509 hexremoterev = hex(remoterev)
4508 hexremoterev = hex(remoterev)
4510 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4509 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4511 if bmr == hexremoterev]
4510 if bmr == hexremoterev]
4512
4511
4513 return sorted(bms)
4512 return sorted(bms)
4514
4513
4515 if bookmarks:
4514 if bookmarks:
4516 output.extend(getbms())
4515 output.extend(getbms())
4517 elif default and not ui.quiet:
4516 elif default and not ui.quiet:
4518 # multiple bookmarks for a single parent separated by '/'
4517 # multiple bookmarks for a single parent separated by '/'
4519 bm = '/'.join(getbms())
4518 bm = '/'.join(getbms())
4520 if bm:
4519 if bm:
4521 output.append(bm)
4520 output.append(bm)
4522 else:
4521 else:
4523 ctx = scmutil.revsingle(repo, rev, None)
4522 ctx = scmutil.revsingle(repo, rev, None)
4524
4523
4525 if ctx.rev() is None:
4524 if ctx.rev() is None:
4526 ctx = repo[None]
4525 ctx = repo[None]
4527 parents = ctx.parents()
4526 parents = ctx.parents()
4528 taglist = []
4527 taglist = []
4529 for p in parents:
4528 for p in parents:
4530 taglist.extend(p.tags())
4529 taglist.extend(p.tags())
4531
4530
4532 changed = ""
4531 changed = ""
4533 if default or id or num:
4532 if default or id or num:
4534 if (any(repo.status())
4533 if (any(repo.status())
4535 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4534 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4536 changed = '+'
4535 changed = '+'
4537 if default or id:
4536 if default or id:
4538 output = ["%s%s" %
4537 output = ["%s%s" %
4539 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4538 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4540 if num:
4539 if num:
4541 output.append("%s%s" %
4540 output.append("%s%s" %
4542 ('+'.join([str(p.rev()) for p in parents]), changed))
4541 ('+'.join([str(p.rev()) for p in parents]), changed))
4543 else:
4542 else:
4544 if default or id:
4543 if default or id:
4545 output = [hexfunc(ctx.node())]
4544 output = [hexfunc(ctx.node())]
4546 if num:
4545 if num:
4547 output.append(str(ctx.rev()))
4546 output.append(str(ctx.rev()))
4548 taglist = ctx.tags()
4547 taglist = ctx.tags()
4549
4548
4550 if default and not ui.quiet:
4549 if default and not ui.quiet:
4551 b = ctx.branch()
4550 b = ctx.branch()
4552 if b != 'default':
4551 if b != 'default':
4553 output.append("(%s)" % b)
4552 output.append("(%s)" % b)
4554
4553
4555 # multiple tags for a single parent separated by '/'
4554 # multiple tags for a single parent separated by '/'
4556 t = '/'.join(taglist)
4555 t = '/'.join(taglist)
4557 if t:
4556 if t:
4558 output.append(t)
4557 output.append(t)
4559
4558
4560 # multiple bookmarks for a single parent separated by '/'
4559 # multiple bookmarks for a single parent separated by '/'
4561 bm = '/'.join(ctx.bookmarks())
4560 bm = '/'.join(ctx.bookmarks())
4562 if bm:
4561 if bm:
4563 output.append(bm)
4562 output.append(bm)
4564 else:
4563 else:
4565 if branch:
4564 if branch:
4566 output.append(ctx.branch())
4565 output.append(ctx.branch())
4567
4566
4568 if tags:
4567 if tags:
4569 output.extend(taglist)
4568 output.extend(taglist)
4570
4569
4571 if bookmarks:
4570 if bookmarks:
4572 output.extend(ctx.bookmarks())
4571 output.extend(ctx.bookmarks())
4573
4572
4574 ui.write("%s\n" % ' '.join(output))
4573 ui.write("%s\n" % ' '.join(output))
4575
4574
4576 @command('import|patch',
4575 @command('import|patch',
4577 [('p', 'strip', 1,
4576 [('p', 'strip', 1,
4578 _('directory strip option for patch. This has the same '
4577 _('directory strip option for patch. This has the same '
4579 'meaning as the corresponding patch option'), _('NUM')),
4578 'meaning as the corresponding patch option'), _('NUM')),
4580 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4579 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4581 ('e', 'edit', False, _('invoke editor on commit messages')),
4580 ('e', 'edit', False, _('invoke editor on commit messages')),
4582 ('f', 'force', None,
4581 ('f', 'force', None,
4583 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4582 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4584 ('', 'no-commit', None,
4583 ('', 'no-commit', None,
4585 _("don't commit, just update the working directory")),
4584 _("don't commit, just update the working directory")),
4586 ('', 'bypass', None,
4585 ('', 'bypass', None,
4587 _("apply patch without touching the working directory")),
4586 _("apply patch without touching the working directory")),
4588 ('', 'partial', None,
4587 ('', 'partial', None,
4589 _('commit even if some hunks fail')),
4588 _('commit even if some hunks fail')),
4590 ('', 'exact', None,
4589 ('', 'exact', None,
4591 _('abort if patch would apply lossily')),
4590 _('abort if patch would apply lossily')),
4592 ('', 'prefix', '',
4591 ('', 'prefix', '',
4593 _('apply patch to subdirectory'), _('DIR')),
4592 _('apply patch to subdirectory'), _('DIR')),
4594 ('', 'import-branch', None,
4593 ('', 'import-branch', None,
4595 _('use any branch information in patch (implied by --exact)'))] +
4594 _('use any branch information in patch (implied by --exact)'))] +
4596 commitopts + commitopts2 + similarityopts,
4595 commitopts + commitopts2 + similarityopts,
4597 _('[OPTION]... PATCH...'))
4596 _('[OPTION]... PATCH...'))
4598 def import_(ui, repo, patch1=None, *patches, **opts):
4597 def import_(ui, repo, patch1=None, *patches, **opts):
4599 """import an ordered set of patches
4598 """import an ordered set of patches
4600
4599
4601 Import a list of patches and commit them individually (unless
4600 Import a list of patches and commit them individually (unless
4602 --no-commit is specified).
4601 --no-commit is specified).
4603
4602
4604 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
4605 a URL is specified, the patch will be downloaded from there.
4604 a URL is specified, the patch will be downloaded from there.
4606
4605
4607 Import first applies changes to the working directory (unless
4606 Import first applies changes to the working directory (unless
4608 --bypass is specified), import will abort if there are outstanding
4607 --bypass is specified), import will abort if there are outstanding
4609 changes.
4608 changes.
4610
4609
4611 Use --bypass to apply and commit patches directly to the
4610 Use --bypass to apply and commit patches directly to the
4612 repository, without affecting the working directory. Without
4611 repository, without affecting the working directory. Without
4613 --exact, patches will be applied on top of the working directory
4612 --exact, patches will be applied on top of the working directory
4614 parent revision.
4613 parent revision.
4615
4614
4616 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
4617 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
4618 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
4619 message are used as default committer and commit message. All
4618 message are used as default committer and commit message. All
4620 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
4621 message.
4620 message.
4622
4621
4623 If the imported patch was generated by :hg:`export`, user and
4622 If the imported patch was generated by :hg:`export`, user and
4624 description from patch override values from message headers and
4623 description from patch override values from message headers and
4625 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
4626 override these.
4625 override these.
4627
4626
4628 If --exact is specified, import will set the working directory to
4627 If --exact is specified, import will set the working directory to
4629 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
4630 resulting changeset has a different ID than the one recorded in
4629 resulting changeset has a different ID than the one recorded in
4631 the patch. This will guard against various ways that portable
4630 the patch. This will guard against various ways that portable
4632 patch formats and mail systems might fail to transfer Mercurial
4631 patch formats and mail systems might fail to transfer Mercurial
4633 data or metadata. See :hg:`bundle` for lossless transmission.
4632 data or metadata. See :hg:`bundle` for lossless transmission.
4634
4633
4635 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
4636 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
4637 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
4638 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
4639 changeset. This flag exists to let people import patches that
4638 changeset. This flag exists to let people import patches that
4640 partially apply without losing the associated metadata (author,
4639 partially apply without losing the associated metadata (author,
4641 date, description, ...).
4640 date, description, ...).
4642
4641
4643 .. note::
4642 .. note::
4644
4643
4645 When no hunks apply cleanly, :hg:`import --partial` will create
4644 When no hunks apply cleanly, :hg:`import --partial` will create
4646 an empty changeset, importing only the patch metadata.
4645 an empty changeset, importing only the patch metadata.
4647
4646
4648 With -s/--similarity, hg will attempt to discover renames and
4647 With -s/--similarity, hg will attempt to discover renames and
4649 copies in the patch in the same way as :hg:`addremove`.
4648 copies in the patch in the same way as :hg:`addremove`.
4650
4649
4651 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
4652 by setting the ``ui.patch`` configuration option. For the default
4651 by setting the ``ui.patch`` configuration option. For the default
4653 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4652 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4654 See :hg:`help config` for more information about configuration
4653 See :hg:`help config` for more information about configuration
4655 files and how to use these options.
4654 files and how to use these options.
4656
4655
4657 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.
4658
4657
4659 .. container:: verbose
4658 .. container:: verbose
4660
4659
4661 Examples:
4660 Examples:
4662
4661
4663 - import a traditional patch from a website and detect renames::
4662 - import a traditional patch from a website and detect renames::
4664
4663
4665 hg import -s 80 http://example.com/bugfix.patch
4664 hg import -s 80 http://example.com/bugfix.patch
4666
4665
4667 - import a changeset from an hgweb server::
4666 - import a changeset from an hgweb server::
4668
4667
4669 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4668 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4670
4669
4671 - import all the patches in an Unix-style mbox::
4670 - import all the patches in an Unix-style mbox::
4672
4671
4673 hg import incoming-patches.mbox
4672 hg import incoming-patches.mbox
4674
4673
4675 - attempt to exactly restore an exported changeset (not always
4674 - attempt to exactly restore an exported changeset (not always
4676 possible)::
4675 possible)::
4677
4676
4678 hg import --exact proposed-fix.patch
4677 hg import --exact proposed-fix.patch
4679
4678
4680 - 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
4681 the default internal tool.
4680 the default internal tool.
4682
4681
4683 hg import --config ui.patch="patch --merge" fuzzy.patch
4682 hg import --config ui.patch="patch --merge" fuzzy.patch
4684
4683
4685 - change the default fuzzing from 2 to a less strict 7
4684 - change the default fuzzing from 2 to a less strict 7
4686
4685
4687 hg import --config ui.fuzz=7 fuzz.patch
4686 hg import --config ui.fuzz=7 fuzz.patch
4688
4687
4689 Returns 0 on success, 1 on partial success (see --partial).
4688 Returns 0 on success, 1 on partial success (see --partial).
4690 """
4689 """
4691
4690
4692 if not patch1:
4691 if not patch1:
4693 raise error.Abort(_('need at least one patch to import'))
4692 raise error.Abort(_('need at least one patch to import'))
4694
4693
4695 patches = (patch1,) + patches
4694 patches = (patch1,) + patches
4696
4695
4697 date = opts.get('date')
4696 date = opts.get('date')
4698 if date:
4697 if date:
4699 opts['date'] = util.parsedate(date)
4698 opts['date'] = util.parsedate(date)
4700
4699
4701 exact = opts.get('exact')
4700 exact = opts.get('exact')
4702 update = not opts.get('bypass')
4701 update = not opts.get('bypass')
4703 if not update and opts.get('no_commit'):
4702 if not update and opts.get('no_commit'):
4704 raise error.Abort(_('cannot use --no-commit with --bypass'))
4703 raise error.Abort(_('cannot use --no-commit with --bypass'))
4705 try:
4704 try:
4706 sim = float(opts.get('similarity') or 0)
4705 sim = float(opts.get('similarity') or 0)
4707 except ValueError:
4706 except ValueError:
4708 raise error.Abort(_('similarity must be a number'))
4707 raise error.Abort(_('similarity must be a number'))
4709 if sim < 0 or sim > 100:
4708 if sim < 0 or sim > 100:
4710 raise error.Abort(_('similarity must be between 0 and 100'))
4709 raise error.Abort(_('similarity must be between 0 and 100'))
4711 if sim and not update:
4710 if sim and not update:
4712 raise error.Abort(_('cannot use --similarity with --bypass'))
4711 raise error.Abort(_('cannot use --similarity with --bypass'))
4713 if exact:
4712 if exact:
4714 if opts.get('edit'):
4713 if opts.get('edit'):
4715 raise error.Abort(_('cannot use --exact with --edit'))
4714 raise error.Abort(_('cannot use --exact with --edit'))
4716 if opts.get('prefix'):
4715 if opts.get('prefix'):
4717 raise error.Abort(_('cannot use --exact with --prefix'))
4716 raise error.Abort(_('cannot use --exact with --prefix'))
4718
4717
4719 base = opts["base"]
4718 base = opts["base"]
4720 wlock = dsguard = lock = tr = None
4719 wlock = dsguard = lock = tr = None
4721 msgs = []
4720 msgs = []
4722 ret = 0
4721 ret = 0
4723
4722
4724
4723
4725 try:
4724 try:
4726 wlock = repo.wlock()
4725 wlock = repo.wlock()
4727
4726
4728 if update:
4727 if update:
4729 cmdutil.checkunfinished(repo)
4728 cmdutil.checkunfinished(repo)
4730 if (exact or not opts.get('force')):
4729 if (exact or not opts.get('force')):
4731 cmdutil.bailifchanged(repo)
4730 cmdutil.bailifchanged(repo)
4732
4731
4733 if not opts.get('no_commit'):
4732 if not opts.get('no_commit'):
4734 lock = repo.lock()
4733 lock = repo.lock()
4735 tr = repo.transaction('import')
4734 tr = repo.transaction('import')
4736 else:
4735 else:
4737 dsguard = dirstateguard.dirstateguard(repo, 'import')
4736 dsguard = dirstateguard.dirstateguard(repo, 'import')
4738 parents = repo[None].parents()
4737 parents = repo[None].parents()
4739 for patchurl in patches:
4738 for patchurl in patches:
4740 if patchurl == '-':
4739 if patchurl == '-':
4741 ui.status(_('applying patch from stdin\n'))
4740 ui.status(_('applying patch from stdin\n'))
4742 patchfile = ui.fin
4741 patchfile = ui.fin
4743 patchurl = 'stdin' # for error message
4742 patchurl = 'stdin' # for error message
4744 else:
4743 else:
4745 patchurl = os.path.join(base, patchurl)
4744 patchurl = os.path.join(base, patchurl)
4746 ui.status(_('applying %s\n') % patchurl)
4745 ui.status(_('applying %s\n') % patchurl)
4747 patchfile = hg.openpath(ui, patchurl)
4746 patchfile = hg.openpath(ui, patchurl)
4748
4747
4749 haspatch = False
4748 haspatch = False
4750 for hunk in patch.split(patchfile):
4749 for hunk in patch.split(patchfile):
4751 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4750 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4752 parents, opts,
4751 parents, opts,
4753 msgs, hg.clean)
4752 msgs, hg.clean)
4754 if msg:
4753 if msg:
4755 haspatch = True
4754 haspatch = True
4756 ui.note(msg + '\n')
4755 ui.note(msg + '\n')
4757 if update or exact:
4756 if update or exact:
4758 parents = repo[None].parents()
4757 parents = repo[None].parents()
4759 else:
4758 else:
4760 parents = [repo[node]]
4759 parents = [repo[node]]
4761 if rej:
4760 if rej:
4762 ui.write_err(_("patch applied partially\n"))
4761 ui.write_err(_("patch applied partially\n"))
4763 ui.write_err(_("(fix the .rej files and run "
4762 ui.write_err(_("(fix the .rej files and run "
4764 "`hg commit --amend`)\n"))
4763 "`hg commit --amend`)\n"))
4765 ret = 1
4764 ret = 1
4766 break
4765 break
4767
4766
4768 if not haspatch:
4767 if not haspatch:
4769 raise error.Abort(_('%s: no diffs found') % patchurl)
4768 raise error.Abort(_('%s: no diffs found') % patchurl)
4770
4769
4771 if tr:
4770 if tr:
4772 tr.close()
4771 tr.close()
4773 if msgs:
4772 if msgs:
4774 repo.savecommitmessage('\n* * *\n'.join(msgs))
4773 repo.savecommitmessage('\n* * *\n'.join(msgs))
4775 if dsguard:
4774 if dsguard:
4776 dsguard.close()
4775 dsguard.close()
4777 return ret
4776 return ret
4778 finally:
4777 finally:
4779 if tr:
4778 if tr:
4780 tr.release()
4779 tr.release()
4781 release(lock, dsguard, wlock)
4780 release(lock, dsguard, wlock)
4782
4781
4783 @command('incoming|in',
4782 @command('incoming|in',
4784 [('f', 'force', None,
4783 [('f', 'force', None,
4785 _('run even if remote repository is unrelated')),
4784 _('run even if remote repository is unrelated')),
4786 ('n', 'newest-first', None, _('show newest record first')),
4785 ('n', 'newest-first', None, _('show newest record first')),
4787 ('', 'bundle', '',
4786 ('', 'bundle', '',
4788 _('file to store the bundles into'), _('FILE')),
4787 _('file to store the bundles into'), _('FILE')),
4789 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4788 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4790 ('B', 'bookmarks', False, _("compare bookmarks")),
4789 ('B', 'bookmarks', False, _("compare bookmarks")),
4791 ('b', 'branch', [],
4790 ('b', 'branch', [],
4792 _('a specific branch you would like to pull'), _('BRANCH')),
4791 _('a specific branch you would like to pull'), _('BRANCH')),
4793 ] + logopts + remoteopts + subrepoopts,
4792 ] + logopts + remoteopts + subrepoopts,
4794 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4793 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4795 def incoming(ui, repo, source="default", **opts):
4794 def incoming(ui, repo, source="default", **opts):
4796 """show new changesets found in source
4795 """show new changesets found in source
4797
4796
4798 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
4799 pull location. These are the changesets that would have been pulled
4798 pull location. These are the changesets that would have been pulled
4800 if a pull at the time you issued this command.
4799 if a pull at the time you issued this command.
4801
4800
4802 See pull for valid source format details.
4801 See pull for valid source format details.
4803
4802
4804 .. container:: verbose
4803 .. container:: verbose
4805
4804
4806 With -B/--bookmarks, the result of bookmark comparison between
4805 With -B/--bookmarks, the result of bookmark comparison between
4807 local and remote repositories is displayed. With -v/--verbose,
4806 local and remote repositories is displayed. With -v/--verbose,
4808 status is also displayed for each bookmark like below::
4807 status is also displayed for each bookmark like below::
4809
4808
4810 BM1 01234567890a added
4809 BM1 01234567890a added
4811 BM2 1234567890ab advanced
4810 BM2 1234567890ab advanced
4812 BM3 234567890abc diverged
4811 BM3 234567890abc diverged
4813 BM4 34567890abcd changed
4812 BM4 34567890abcd changed
4814
4813
4815 The action taken locally when pulling depends on the
4814 The action taken locally when pulling depends on the
4816 status of each bookmark:
4815 status of each bookmark:
4817
4816
4818 :``added``: pull will create it
4817 :``added``: pull will create it
4819 :``advanced``: pull will update it
4818 :``advanced``: pull will update it
4820 :``diverged``: pull will create a divergent bookmark
4819 :``diverged``: pull will create a divergent bookmark
4821 :``changed``: result depends on remote changesets
4820 :``changed``: result depends on remote changesets
4822
4821
4823 From the point of view of pulling behavior, bookmark
4822 From the point of view of pulling behavior, bookmark
4824 existing only in the remote repository are treated as ``added``,
4823 existing only in the remote repository are treated as ``added``,
4825 even if it is in fact locally deleted.
4824 even if it is in fact locally deleted.
4826
4825
4827 .. container:: verbose
4826 .. container:: verbose
4828
4827
4829 For remote repository, using --bundle avoids downloading the
4828 For remote repository, using --bundle avoids downloading the
4830 changesets twice if the incoming is followed by a pull.
4829 changesets twice if the incoming is followed by a pull.
4831
4830
4832 Examples:
4831 Examples:
4833
4832
4834 - show incoming changes with patches and full description::
4833 - show incoming changes with patches and full description::
4835
4834
4836 hg incoming -vp
4835 hg incoming -vp
4837
4836
4838 - show incoming changes excluding merges, store a bundle::
4837 - show incoming changes excluding merges, store a bundle::
4839
4838
4840 hg in -vpM --bundle incoming.hg
4839 hg in -vpM --bundle incoming.hg
4841 hg pull incoming.hg
4840 hg pull incoming.hg
4842
4841
4843 - briefly list changes inside a bundle::
4842 - briefly list changes inside a bundle::
4844
4843
4845 hg in changes.hg -T "{desc|firstline}\\n"
4844 hg in changes.hg -T "{desc|firstline}\\n"
4846
4845
4847 Returns 0 if there are incoming changes, 1 otherwise.
4846 Returns 0 if there are incoming changes, 1 otherwise.
4848 """
4847 """
4849 if opts.get('graph'):
4848 if opts.get('graph'):
4850 cmdutil.checkunsupportedgraphflags([], opts)
4849 cmdutil.checkunsupportedgraphflags([], opts)
4851 def display(other, chlist, displayer):
4850 def display(other, chlist, displayer):
4852 revdag = cmdutil.graphrevs(other, chlist, opts)
4851 revdag = cmdutil.graphrevs(other, chlist, opts)
4853 cmdutil.displaygraph(ui, repo, revdag, displayer,
4852 cmdutil.displaygraph(ui, repo, revdag, displayer,
4854 graphmod.asciiedges)
4853 graphmod.asciiedges)
4855
4854
4856 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4855 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4857 return 0
4856 return 0
4858
4857
4859 if opts.get('bundle') and opts.get('subrepos'):
4858 if opts.get('bundle') and opts.get('subrepos'):
4860 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4859 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4861
4860
4862 if opts.get('bookmarks'):
4861 if opts.get('bookmarks'):
4863 source, branches = hg.parseurl(ui.expandpath(source),
4862 source, branches = hg.parseurl(ui.expandpath(source),
4864 opts.get('branch'))
4863 opts.get('branch'))
4865 other = hg.peer(repo, opts, source)
4864 other = hg.peer(repo, opts, source)
4866 if 'bookmarks' not in other.listkeys('namespaces'):
4865 if 'bookmarks' not in other.listkeys('namespaces'):
4867 ui.warn(_("remote doesn't support bookmarks\n"))
4866 ui.warn(_("remote doesn't support bookmarks\n"))
4868 return 0
4867 return 0
4869 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4868 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4870 return bookmarks.incoming(ui, repo, other)
4869 return bookmarks.incoming(ui, repo, other)
4871
4870
4872 repo._subtoppath = ui.expandpath(source)
4871 repo._subtoppath = ui.expandpath(source)
4873 try:
4872 try:
4874 return hg.incoming(ui, repo, source, opts)
4873 return hg.incoming(ui, repo, source, opts)
4875 finally:
4874 finally:
4876 del repo._subtoppath
4875 del repo._subtoppath
4877
4876
4878
4877
4879 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4878 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4880 norepo=True)
4879 norepo=True)
4881 def init(ui, dest=".", **opts):
4880 def init(ui, dest=".", **opts):
4882 """create a new repository in the given directory
4881 """create a new repository in the given directory
4883
4882
4884 Initialize a new repository in the given directory. If the given
4883 Initialize a new repository in the given directory. If the given
4885 directory does not exist, it will be created.
4884 directory does not exist, it will be created.
4886
4885
4887 If no directory is given, the current directory is used.
4886 If no directory is given, the current directory is used.
4888
4887
4889 It is possible to specify an ``ssh://`` URL as the destination.
4888 It is possible to specify an ``ssh://`` URL as the destination.
4890 See :hg:`help urls` for more information.
4889 See :hg:`help urls` for more information.
4891
4890
4892 Returns 0 on success.
4891 Returns 0 on success.
4893 """
4892 """
4894 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4893 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4895
4894
4896 @command('locate',
4895 @command('locate',
4897 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4896 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4898 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4897 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4899 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4898 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4900 ] + walkopts,
4899 ] + walkopts,
4901 _('[OPTION]... [PATTERN]...'))
4900 _('[OPTION]... [PATTERN]...'))
4902 def locate(ui, repo, *pats, **opts):
4901 def locate(ui, repo, *pats, **opts):
4903 """locate files matching specific patterns (DEPRECATED)
4902 """locate files matching specific patterns (DEPRECATED)
4904
4903
4905 Print files under Mercurial control in the working directory whose
4904 Print files under Mercurial control in the working directory whose
4906 names match the given patterns.
4905 names match the given patterns.
4907
4906
4908 By default, this command searches all directories in the working
4907 By default, this command searches all directories in the working
4909 directory. To search just the current directory and its
4908 directory. To search just the current directory and its
4910 subdirectories, use "--include .".
4909 subdirectories, use "--include .".
4911
4910
4912 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
4913 of all files under Mercurial control in the working directory.
4912 of all files under Mercurial control in the working directory.
4914
4913
4915 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"
4916 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
4917 will avoid the problem of "xargs" treating single filenames that
4916 will avoid the problem of "xargs" treating single filenames that
4918 contain whitespace as multiple filenames.
4917 contain whitespace as multiple filenames.
4919
4918
4920 See :hg:`help files` for a more versatile command.
4919 See :hg:`help files` for a more versatile command.
4921
4920
4922 Returns 0 if a match is found, 1 otherwise.
4921 Returns 0 if a match is found, 1 otherwise.
4923 """
4922 """
4924 if opts.get('print0'):
4923 if opts.get('print0'):
4925 end = '\0'
4924 end = '\0'
4926 else:
4925 else:
4927 end = '\n'
4926 end = '\n'
4928 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4927 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4929
4928
4930 ret = 1
4929 ret = 1
4931 ctx = repo[rev]
4930 ctx = repo[rev]
4932 m = scmutil.match(ctx, pats, opts, default='relglob',
4931 m = scmutil.match(ctx, pats, opts, default='relglob',
4933 badfn=lambda x, y: False)
4932 badfn=lambda x, y: False)
4934
4933
4935 for abs in ctx.matches(m):
4934 for abs in ctx.matches(m):
4936 if opts.get('fullpath'):
4935 if opts.get('fullpath'):
4937 ui.write(repo.wjoin(abs), end)
4936 ui.write(repo.wjoin(abs), end)
4938 else:
4937 else:
4939 ui.write(((pats and m.rel(abs)) or abs), end)
4938 ui.write(((pats and m.rel(abs)) or abs), end)
4940 ret = 0
4939 ret = 0
4941
4940
4942 return ret
4941 return ret
4943
4942
4944 @command('^log|history',
4943 @command('^log|history',
4945 [('f', 'follow', None,
4944 [('f', 'follow', None,
4946 _('follow changeset history, or file history across copies and renames')),
4945 _('follow changeset history, or file history across copies and renames')),
4947 ('', 'follow-first', None,
4946 ('', 'follow-first', None,
4948 _('only follow the first parent of merge changesets (DEPRECATED)')),
4947 _('only follow the first parent of merge changesets (DEPRECATED)')),
4949 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4948 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4950 ('C', 'copies', None, _('show copied files')),
4949 ('C', 'copies', None, _('show copied files')),
4951 ('k', 'keyword', [],
4950 ('k', 'keyword', [],
4952 _('do case-insensitive search for a given text'), _('TEXT')),
4951 _('do case-insensitive search for a given text'), _('TEXT')),
4953 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4952 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4954 ('', 'removed', None, _('include revisions where files were removed')),
4953 ('', 'removed', None, _('include revisions where files were removed')),
4955 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4954 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4956 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4955 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4957 ('', 'only-branch', [],
4956 ('', 'only-branch', [],
4958 _('show only changesets within the given named branch (DEPRECATED)'),
4957 _('show only changesets within the given named branch (DEPRECATED)'),
4959 _('BRANCH')),
4958 _('BRANCH')),
4960 ('b', 'branch', [],
4959 ('b', 'branch', [],
4961 _('show changesets within the given named branch'), _('BRANCH')),
4960 _('show changesets within the given named branch'), _('BRANCH')),
4962 ('P', 'prune', [],
4961 ('P', 'prune', [],
4963 _('do not display revision or any of its ancestors'), _('REV')),
4962 _('do not display revision or any of its ancestors'), _('REV')),
4964 ] + logopts + walkopts,
4963 ] + logopts + walkopts,
4965 _('[OPTION]... [FILE]'),
4964 _('[OPTION]... [FILE]'),
4966 inferrepo=True)
4965 inferrepo=True)
4967 def log(ui, repo, *pats, **opts):
4966 def log(ui, repo, *pats, **opts):
4968 """show revision history of entire repository or files
4967 """show revision history of entire repository or files
4969
4968
4970 Print the revision history of the specified files or the entire
4969 Print the revision history of the specified files or the entire
4971 project.
4970 project.
4972
4971
4973 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
4974 --follow is set, in which case the working directory parent is
4973 --follow is set, in which case the working directory parent is
4975 used as the starting revision.
4974 used as the starting revision.
4976
4975
4977 File history is shown without following rename or copy history of
4976 File history is shown without following rename or copy history of
4978 files. Use -f/--follow with a filename to follow history across
4977 files. Use -f/--follow with a filename to follow history across
4979 renames and copies. --follow without a filename will only show
4978 renames and copies. --follow without a filename will only show
4980 ancestors or descendants of the starting revision.
4979 ancestors or descendants of the starting revision.
4981
4980
4982 By default this command prints revision number and changeset id,
4981 By default this command prints revision number and changeset id,
4983 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
4984 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
4985 changed files and full commit message are shown.
4984 changed files and full commit message are shown.
4986
4985
4987 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
4988 recent changeset at the top.
4987 recent changeset at the top.
4989 '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,
4990 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
4991 parent of the 'o' merge on the same line.
4990 parent of the 'o' merge on the same line.
4992
4991
4993 .. note::
4992 .. note::
4994
4993
4995 :hg:`log --patch` may generate unexpected diff output for merge
4994 :hg:`log --patch` may generate unexpected diff output for merge
4996 changesets, as it will only compare the merge changeset against
4995 changesets, as it will only compare the merge changeset against
4997 its first parent. Also, only files different from BOTH parents
4996 its first parent. Also, only files different from BOTH parents
4998 will appear in files:.
4997 will appear in files:.
4999
4998
5000 .. note::
4999 .. note::
5001
5000
5002 For performance reasons, :hg:`log FILE` may omit duplicate changes
5001 For performance reasons, :hg:`log FILE` may omit duplicate changes
5003 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
5004 see all such changes, use the --removed switch.
5003 see all such changes, use the --removed switch.
5005
5004
5006 .. container:: verbose
5005 .. container:: verbose
5007
5006
5008 Some examples:
5007 Some examples:
5009
5008
5010 - changesets with full descriptions and file lists::
5009 - changesets with full descriptions and file lists::
5011
5010
5012 hg log -v
5011 hg log -v
5013
5012
5014 - changesets ancestral to the working directory::
5013 - changesets ancestral to the working directory::
5015
5014
5016 hg log -f
5015 hg log -f
5017
5016
5018 - last 10 commits on the current branch::
5017 - last 10 commits on the current branch::
5019
5018
5020 hg log -l 10 -b .
5019 hg log -l 10 -b .
5021
5020
5022 - changesets showing all modifications of a file, including removals::
5021 - changesets showing all modifications of a file, including removals::
5023
5022
5024 hg log --removed file.c
5023 hg log --removed file.c
5025
5024
5026 - all changesets that touch a directory, with diffs, excluding merges::
5025 - all changesets that touch a directory, with diffs, excluding merges::
5027
5026
5028 hg log -Mp lib/
5027 hg log -Mp lib/
5029
5028
5030 - all revision numbers that match a keyword::
5029 - all revision numbers that match a keyword::
5031
5030
5032 hg log -k bug --template "{rev}\\n"
5031 hg log -k bug --template "{rev}\\n"
5033
5032
5034 - the full hash identifier of the working directory parent::
5033 - the full hash identifier of the working directory parent::
5035
5034
5036 hg log -r . --template "{node}\\n"
5035 hg log -r . --template "{node}\\n"
5037
5036
5038 - list available log templates::
5037 - list available log templates::
5039
5038
5040 hg log -T list
5039 hg log -T list
5041
5040
5042 - check if a given changeset is included in a tagged release::
5041 - check if a given changeset is included in a tagged release::
5043
5042
5044 hg log -r "a21ccf and ancestor(1.9)"
5043 hg log -r "a21ccf and ancestor(1.9)"
5045
5044
5046 - find all changesets by some user in a date range::
5045 - find all changesets by some user in a date range::
5047
5046
5048 hg log -k alice -d "may 2008 to jul 2008"
5047 hg log -k alice -d "may 2008 to jul 2008"
5049
5048
5050 - summary of all changesets after the last tag::
5049 - summary of all changesets after the last tag::
5051
5050
5052 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5051 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5053
5052
5054 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.
5055
5054
5056 See :hg:`help revisions` and :hg:`help revsets` for more about
5055 See :hg:`help revisions` and :hg:`help revsets` for more about
5057 specifying and ordering revisions.
5056 specifying and ordering revisions.
5058
5057
5059 See :hg:`help templates` for more about pre-packaged styles and
5058 See :hg:`help templates` for more about pre-packaged styles and
5060 specifying custom templates.
5059 specifying custom templates.
5061
5060
5062 Returns 0 on success.
5061 Returns 0 on success.
5063
5062
5064 """
5063 """
5065 if opts.get('follow') and opts.get('rev'):
5064 if opts.get('follow') and opts.get('rev'):
5066 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5065 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5067 del opts['follow']
5066 del opts['follow']
5068
5067
5069 if opts.get('graph'):
5068 if opts.get('graph'):
5070 return cmdutil.graphlog(ui, repo, *pats, **opts)
5069 return cmdutil.graphlog(ui, repo, *pats, **opts)
5071
5070
5072 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5071 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5073 limit = cmdutil.loglimit(opts)
5072 limit = cmdutil.loglimit(opts)
5074 count = 0
5073 count = 0
5075
5074
5076 getrenamed = None
5075 getrenamed = None
5077 if opts.get('copies'):
5076 if opts.get('copies'):
5078 endrev = None
5077 endrev = None
5079 if opts.get('rev'):
5078 if opts.get('rev'):
5080 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5079 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5081 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5080 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5082
5081
5083 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5082 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5084 for rev in revs:
5083 for rev in revs:
5085 if count == limit:
5084 if count == limit:
5086 break
5085 break
5087 ctx = repo[rev]
5086 ctx = repo[rev]
5088 copies = None
5087 copies = None
5089 if getrenamed is not None and rev:
5088 if getrenamed is not None and rev:
5090 copies = []
5089 copies = []
5091 for fn in ctx.files():
5090 for fn in ctx.files():
5092 rename = getrenamed(fn, rev)
5091 rename = getrenamed(fn, rev)
5093 if rename:
5092 if rename:
5094 copies.append((fn, rename[0]))
5093 copies.append((fn, rename[0]))
5095 if filematcher:
5094 if filematcher:
5096 revmatchfn = filematcher(ctx.rev())
5095 revmatchfn = filematcher(ctx.rev())
5097 else:
5096 else:
5098 revmatchfn = None
5097 revmatchfn = None
5099 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5098 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5100 if displayer.flush(ctx):
5099 if displayer.flush(ctx):
5101 count += 1
5100 count += 1
5102
5101
5103 displayer.close()
5102 displayer.close()
5104
5103
5105 @command('manifest',
5104 @command('manifest',
5106 [('r', 'rev', '', _('revision to display'), _('REV')),
5105 [('r', 'rev', '', _('revision to display'), _('REV')),
5107 ('', 'all', False, _("list files from all revisions"))]
5106 ('', 'all', False, _("list files from all revisions"))]
5108 + formatteropts,
5107 + formatteropts,
5109 _('[-r REV]'))
5108 _('[-r REV]'))
5110 def manifest(ui, repo, node=None, rev=None, **opts):
5109 def manifest(ui, repo, node=None, rev=None, **opts):
5111 """output the current or given revision of the project manifest
5110 """output the current or given revision of the project manifest
5112
5111
5113 Print a list of version controlled files for the given revision.
5112 Print a list of version controlled files for the given revision.
5114 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
5115 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.
5116
5115
5117 With -v, print file permissions, symlink and executable bits.
5116 With -v, print file permissions, symlink and executable bits.
5118 With --debug, print file revision hashes.
5117 With --debug, print file revision hashes.
5119
5118
5120 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
5121 is printed. This includes deleted and renamed files.
5120 is printed. This includes deleted and renamed files.
5122
5121
5123 Returns 0 on success.
5122 Returns 0 on success.
5124 """
5123 """
5125
5124
5126 fm = ui.formatter('manifest', opts)
5125 fm = ui.formatter('manifest', opts)
5127
5126
5128 if opts.get('all'):
5127 if opts.get('all'):
5129 if rev or node:
5128 if rev or node:
5130 raise error.Abort(_("can't specify a revision with --all"))
5129 raise error.Abort(_("can't specify a revision with --all"))
5131
5130
5132 res = []
5131 res = []
5133 prefix = "data/"
5132 prefix = "data/"
5134 suffix = ".i"
5133 suffix = ".i"
5135 plen = len(prefix)
5134 plen = len(prefix)
5136 slen = len(suffix)
5135 slen = len(suffix)
5137 with repo.lock():
5136 with repo.lock():
5138 for fn, b, size in repo.store.datafiles():
5137 for fn, b, size in repo.store.datafiles():
5139 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5138 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5140 res.append(fn[plen:-slen])
5139 res.append(fn[plen:-slen])
5141 for f in res:
5140 for f in res:
5142 fm.startitem()
5141 fm.startitem()
5143 fm.write("path", '%s\n', f)
5142 fm.write("path", '%s\n', f)
5144 fm.end()
5143 fm.end()
5145 return
5144 return
5146
5145
5147 if rev and node:
5146 if rev and node:
5148 raise error.Abort(_("please specify just one revision"))
5147 raise error.Abort(_("please specify just one revision"))
5149
5148
5150 if not node:
5149 if not node:
5151 node = rev
5150 node = rev
5152
5151
5153 char = {'l': '@', 'x': '*', '': ''}
5152 char = {'l': '@', 'x': '*', '': ''}
5154 mode = {'l': '644', 'x': '755', '': '644'}
5153 mode = {'l': '644', 'x': '755', '': '644'}
5155 ctx = scmutil.revsingle(repo, node)
5154 ctx = scmutil.revsingle(repo, node)
5156 mf = ctx.manifest()
5155 mf = ctx.manifest()
5157 for f in ctx:
5156 for f in ctx:
5158 fm.startitem()
5157 fm.startitem()
5159 fl = ctx[f].flags()
5158 fl = ctx[f].flags()
5160 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5159 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5161 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])
5162 fm.write('path', '%s\n', f)
5161 fm.write('path', '%s\n', f)
5163 fm.end()
5162 fm.end()
5164
5163
5165 @command('^merge',
5164 @command('^merge',
5166 [('f', 'force', None,
5165 [('f', 'force', None,
5167 _('force a merge including outstanding changes (DEPRECATED)')),
5166 _('force a merge including outstanding changes (DEPRECATED)')),
5168 ('r', 'rev', '', _('revision to merge'), _('REV')),
5167 ('r', 'rev', '', _('revision to merge'), _('REV')),
5169 ('P', 'preview', None,
5168 ('P', 'preview', None,
5170 _('review revisions to merge (no merge is performed)'))
5169 _('review revisions to merge (no merge is performed)'))
5171 ] + mergetoolopts,
5170 ] + mergetoolopts,
5172 _('[-P] [[-r] REV]'))
5171 _('[-P] [[-r] REV]'))
5173 def merge(ui, repo, node=None, **opts):
5172 def merge(ui, repo, node=None, **opts):
5174 """merge another revision into working directory
5173 """merge another revision into working directory
5175
5174
5176 The current working directory is updated with all changes made in
5175 The current working directory is updated with all changes made in
5177 the requested revision since the last common predecessor revision.
5176 the requested revision since the last common predecessor revision.
5178
5177
5179 Files that changed between either parent are marked as changed for
5178 Files that changed between either parent are marked as changed for
5180 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
5181 updates to the repository are allowed. The next commit will have
5180 updates to the repository are allowed. The next commit will have
5182 two parents.
5181 two parents.
5183
5182
5184 ``--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
5185 merges. It overrides the HGMERGE environment variable and your
5184 merges. It overrides the HGMERGE environment variable and your
5186 configuration files. See :hg:`help merge-tools` for options.
5185 configuration files. See :hg:`help merge-tools` for options.
5187
5186
5188 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
5189 head revision, and the current branch contains exactly one other
5188 head revision, and the current branch contains exactly one other
5190 head, the other head is merged with by default. Otherwise, an
5189 head, the other head is merged with by default. Otherwise, an
5191 explicit revision with which to merge with must be provided.
5190 explicit revision with which to merge with must be provided.
5192
5191
5193 See :hg:`help resolve` for information on handling file conflicts.
5192 See :hg:`help resolve` for information on handling file conflicts.
5194
5193
5195 To undo an uncommitted merge, use :hg:`update --clean .` which
5194 To undo an uncommitted merge, use :hg:`update --clean .` which
5196 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
5197 all changes.
5196 all changes.
5198
5197
5199 Returns 0 on success, 1 if there are unresolved files.
5198 Returns 0 on success, 1 if there are unresolved files.
5200 """
5199 """
5201
5200
5202 if opts.get('rev') and node:
5201 if opts.get('rev') and node:
5203 raise error.Abort(_("please specify just one revision"))
5202 raise error.Abort(_("please specify just one revision"))
5204 if not node:
5203 if not node:
5205 node = opts.get('rev')
5204 node = opts.get('rev')
5206
5205
5207 if node:
5206 if node:
5208 node = scmutil.revsingle(repo, node).node()
5207 node = scmutil.revsingle(repo, node).node()
5209
5208
5210 if not node:
5209 if not node:
5211 node = repo[destutil.destmerge(repo)].node()
5210 node = repo[destutil.destmerge(repo)].node()
5212
5211
5213 if opts.get('preview'):
5212 if opts.get('preview'):
5214 # find nodes that are ancestors of p2 but not of p1
5213 # find nodes that are ancestors of p2 but not of p1
5215 p1 = repo.lookup('.')
5214 p1 = repo.lookup('.')
5216 p2 = repo.lookup(node)
5215 p2 = repo.lookup(node)
5217 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5216 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5218
5217
5219 displayer = cmdutil.show_changeset(ui, repo, opts)
5218 displayer = cmdutil.show_changeset(ui, repo, opts)
5220 for node in nodes:
5219 for node in nodes:
5221 displayer.show(repo[node])
5220 displayer.show(repo[node])
5222 displayer.close()
5221 displayer.close()
5223 return 0
5222 return 0
5224
5223
5225 try:
5224 try:
5226 # ui.forcemerge is an internal variable, do not document
5225 # ui.forcemerge is an internal variable, do not document
5227 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5226 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5228 force = opts.get('force')
5227 force = opts.get('force')
5229 labels = ['working copy', 'merge rev']
5228 labels = ['working copy', 'merge rev']
5230 return hg.merge(repo, node, force=force, mergeforce=force,
5229 return hg.merge(repo, node, force=force, mergeforce=force,
5231 labels=labels)
5230 labels=labels)
5232 finally:
5231 finally:
5233 ui.setconfig('ui', 'forcemerge', '', 'merge')
5232 ui.setconfig('ui', 'forcemerge', '', 'merge')
5234
5233
5235 @command('outgoing|out',
5234 @command('outgoing|out',
5236 [('f', 'force', None, _('run even when the destination is unrelated')),
5235 [('f', 'force', None, _('run even when the destination is unrelated')),
5237 ('r', 'rev', [],
5236 ('r', 'rev', [],
5238 _('a changeset intended to be included in the destination'), _('REV')),
5237 _('a changeset intended to be included in the destination'), _('REV')),
5239 ('n', 'newest-first', None, _('show newest record first')),
5238 ('n', 'newest-first', None, _('show newest record first')),
5240 ('B', 'bookmarks', False, _('compare bookmarks')),
5239 ('B', 'bookmarks', False, _('compare bookmarks')),
5241 ('b', 'branch', [], _('a specific branch you would like to push'),
5240 ('b', 'branch', [], _('a specific branch you would like to push'),
5242 _('BRANCH')),
5241 _('BRANCH')),
5243 ] + logopts + remoteopts + subrepoopts,
5242 ] + logopts + remoteopts + subrepoopts,
5244 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5243 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5245 def outgoing(ui, repo, dest=None, **opts):
5244 def outgoing(ui, repo, dest=None, **opts):
5246 """show changesets not found in the destination
5245 """show changesets not found in the destination
5247
5246
5248 Show changesets not found in the specified destination repository
5247 Show changesets not found in the specified destination repository
5249 or the default push location. These are the changesets that would
5248 or the default push location. These are the changesets that would
5250 be pushed if a push was requested.
5249 be pushed if a push was requested.
5251
5250
5252 See pull for details of valid destination formats.
5251 See pull for details of valid destination formats.
5253
5252
5254 .. container:: verbose
5253 .. container:: verbose
5255
5254
5256 With -B/--bookmarks, the result of bookmark comparison between
5255 With -B/--bookmarks, the result of bookmark comparison between
5257 local and remote repositories is displayed. With -v/--verbose,
5256 local and remote repositories is displayed. With -v/--verbose,
5258 status is also displayed for each bookmark like below::
5257 status is also displayed for each bookmark like below::
5259
5258
5260 BM1 01234567890a added
5259 BM1 01234567890a added
5261 BM2 deleted
5260 BM2 deleted
5262 BM3 234567890abc advanced
5261 BM3 234567890abc advanced
5263 BM4 34567890abcd diverged
5262 BM4 34567890abcd diverged
5264 BM5 4567890abcde changed
5263 BM5 4567890abcde changed
5265
5264
5266 The action taken when pushing depends on the
5265 The action taken when pushing depends on the
5267 status of each bookmark:
5266 status of each bookmark:
5268
5267
5269 :``added``: push with ``-B`` will create it
5268 :``added``: push with ``-B`` will create it
5270 :``deleted``: push with ``-B`` will delete it
5269 :``deleted``: push with ``-B`` will delete it
5271 :``advanced``: push will update it
5270 :``advanced``: push will update it
5272 :``diverged``: push with ``-B`` will update it
5271 :``diverged``: push with ``-B`` will update it
5273 :``changed``: push with ``-B`` will update it
5272 :``changed``: push with ``-B`` will update it
5274
5273
5275 From the point of view of pushing behavior, bookmarks
5274 From the point of view of pushing behavior, bookmarks
5276 existing only in the remote repository are treated as
5275 existing only in the remote repository are treated as
5277 ``deleted``, even if it is in fact added remotely.
5276 ``deleted``, even if it is in fact added remotely.
5278
5277
5279 Returns 0 if there are outgoing changes, 1 otherwise.
5278 Returns 0 if there are outgoing changes, 1 otherwise.
5280 """
5279 """
5281 if opts.get('graph'):
5280 if opts.get('graph'):
5282 cmdutil.checkunsupportedgraphflags([], opts)
5281 cmdutil.checkunsupportedgraphflags([], opts)
5283 o, other = hg._outgoing(ui, repo, dest, opts)
5282 o, other = hg._outgoing(ui, repo, dest, opts)
5284 if not o:
5283 if not o:
5285 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5284 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5286 return
5285 return
5287
5286
5288 revdag = cmdutil.graphrevs(repo, o, opts)
5287 revdag = cmdutil.graphrevs(repo, o, opts)
5289 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5288 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5290 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5289 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5291 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5290 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5292 return 0
5291 return 0
5293
5292
5294 if opts.get('bookmarks'):
5293 if opts.get('bookmarks'):
5295 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5294 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5296 dest, branches = hg.parseurl(dest, opts.get('branch'))
5295 dest, branches = hg.parseurl(dest, opts.get('branch'))
5297 other = hg.peer(repo, opts, dest)
5296 other = hg.peer(repo, opts, dest)
5298 if 'bookmarks' not in other.listkeys('namespaces'):
5297 if 'bookmarks' not in other.listkeys('namespaces'):
5299 ui.warn(_("remote doesn't support bookmarks\n"))
5298 ui.warn(_("remote doesn't support bookmarks\n"))
5300 return 0
5299 return 0
5301 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5300 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5302 return bookmarks.outgoing(ui, repo, other)
5301 return bookmarks.outgoing(ui, repo, other)
5303
5302
5304 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5303 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5305 try:
5304 try:
5306 return hg.outgoing(ui, repo, dest, opts)
5305 return hg.outgoing(ui, repo, dest, opts)
5307 finally:
5306 finally:
5308 del repo._subtoppath
5307 del repo._subtoppath
5309
5308
5310 @command('parents',
5309 @command('parents',
5311 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5310 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5312 ] + templateopts,
5311 ] + templateopts,
5313 _('[-r REV] [FILE]'),
5312 _('[-r REV] [FILE]'),
5314 inferrepo=True)
5313 inferrepo=True)
5315 def parents(ui, repo, file_=None, **opts):
5314 def parents(ui, repo, file_=None, **opts):
5316 """show the parents of the working directory or revision (DEPRECATED)
5315 """show the parents of the working directory or revision (DEPRECATED)
5317
5316
5318 Print the working directory's parent revisions. If a revision is
5317 Print the working directory's parent revisions. If a revision is
5319 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.
5320 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
5321 last changed (before the working directory revision or the
5320 last changed (before the working directory revision or the
5322 argument to --rev if given) is printed.
5321 argument to --rev if given) is printed.
5323
5322
5324 This command is equivalent to::
5323 This command is equivalent to::
5325
5324
5326 hg log -r "p1()+p2()" or
5325 hg log -r "p1()+p2()" or
5327 hg log -r "p1(REV)+p2(REV)" or
5326 hg log -r "p1(REV)+p2(REV)" or
5328 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
5329 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))"
5330
5329
5331 See :hg:`summary` and :hg:`help revsets` for related information.
5330 See :hg:`summary` and :hg:`help revsets` for related information.
5332
5331
5333 Returns 0 on success.
5332 Returns 0 on success.
5334 """
5333 """
5335
5334
5336 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5335 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5337
5336
5338 if file_:
5337 if file_:
5339 m = scmutil.match(ctx, (file_,), opts)
5338 m = scmutil.match(ctx, (file_,), opts)
5340 if m.anypats() or len(m.files()) != 1:
5339 if m.anypats() or len(m.files()) != 1:
5341 raise error.Abort(_('can only specify an explicit filename'))
5340 raise error.Abort(_('can only specify an explicit filename'))
5342 file_ = m.files()[0]
5341 file_ = m.files()[0]
5343 filenodes = []
5342 filenodes = []
5344 for cp in ctx.parents():
5343 for cp in ctx.parents():
5345 if not cp:
5344 if not cp:
5346 continue
5345 continue
5347 try:
5346 try:
5348 filenodes.append(cp.filenode(file_))
5347 filenodes.append(cp.filenode(file_))
5349 except error.LookupError:
5348 except error.LookupError:
5350 pass
5349 pass
5351 if not filenodes:
5350 if not filenodes:
5352 raise error.Abort(_("'%s' not found in manifest!") % file_)
5351 raise error.Abort(_("'%s' not found in manifest!") % file_)
5353 p = []
5352 p = []
5354 for fn in filenodes:
5353 for fn in filenodes:
5355 fctx = repo.filectx(file_, fileid=fn)
5354 fctx = repo.filectx(file_, fileid=fn)
5356 p.append(fctx.node())
5355 p.append(fctx.node())
5357 else:
5356 else:
5358 p = [cp.node() for cp in ctx.parents()]
5357 p = [cp.node() for cp in ctx.parents()]
5359
5358
5360 displayer = cmdutil.show_changeset(ui, repo, opts)
5359 displayer = cmdutil.show_changeset(ui, repo, opts)
5361 for n in p:
5360 for n in p:
5362 if n != nullid:
5361 if n != nullid:
5363 displayer.show(repo[n])
5362 displayer.show(repo[n])
5364 displayer.close()
5363 displayer.close()
5365
5364
5366 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5365 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5367 def paths(ui, repo, search=None, **opts):
5366 def paths(ui, repo, search=None, **opts):
5368 """show aliases for remote repositories
5367 """show aliases for remote repositories
5369
5368
5370 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,
5371 show definition of all available names.
5370 show definition of all available names.
5372
5371
5373 Option -q/--quiet suppresses all output when searching for NAME
5372 Option -q/--quiet suppresses all output when searching for NAME
5374 and shows only the path names when listing all definitions.
5373 and shows only the path names when listing all definitions.
5375
5374
5376 Path names are defined in the [paths] section of your
5375 Path names are defined in the [paths] section of your
5377 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5376 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5378 repository, ``.hg/hgrc`` is used, too.
5377 repository, ``.hg/hgrc`` is used, too.
5379
5378
5380 The path names ``default`` and ``default-push`` have a special
5379 The path names ``default`` and ``default-push`` have a special
5381 meaning. When performing a push or pull operation, they are used
5380 meaning. When performing a push or pull operation, they are used
5382 as fallbacks if no location is specified on the command-line.
5381 as fallbacks if no location is specified on the command-line.
5383 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
5384 ``default`` will be used for pull; otherwise ``default`` is used
5383 ``default`` will be used for pull; otherwise ``default`` is used
5385 as the fallback for both. When cloning a repository, the clone
5384 as the fallback for both. When cloning a repository, the clone
5386 source is written as ``default`` in ``.hg/hgrc``.
5385 source is written as ``default`` in ``.hg/hgrc``.
5387
5386
5388 .. note::
5387 .. note::
5389
5388
5390 ``default`` and ``default-push`` apply to all inbound (e.g.
5389 ``default`` and ``default-push`` apply to all inbound (e.g.
5391 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5390 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5392 and :hg:`bundle`) operations.
5391 and :hg:`bundle`) operations.
5393
5392
5394 See :hg:`help urls` for more information.
5393 See :hg:`help urls` for more information.
5395
5394
5396 Returns 0 on success.
5395 Returns 0 on success.
5397 """
5396 """
5398 if search:
5397 if search:
5399 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5398 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5400 if name == search]
5399 if name == search]
5401 else:
5400 else:
5402 pathitems = sorted(ui.paths.iteritems())
5401 pathitems = sorted(ui.paths.iteritems())
5403
5402
5404 fm = ui.formatter('paths', opts)
5403 fm = ui.formatter('paths', opts)
5405 if fm.isplain():
5404 if fm.isplain():
5406 hidepassword = util.hidepassword
5405 hidepassword = util.hidepassword
5407 else:
5406 else:
5408 hidepassword = str
5407 hidepassword = str
5409 if ui.quiet:
5408 if ui.quiet:
5410 namefmt = '%s\n'
5409 namefmt = '%s\n'
5411 else:
5410 else:
5412 namefmt = '%s = '
5411 namefmt = '%s = '
5413 showsubopts = not search and not ui.quiet
5412 showsubopts = not search and not ui.quiet
5414
5413
5415 for name, path in pathitems:
5414 for name, path in pathitems:
5416 fm.startitem()
5415 fm.startitem()
5417 fm.condwrite(not search, 'name', namefmt, name)
5416 fm.condwrite(not search, 'name', namefmt, name)
5418 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5417 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5419 for subopt, value in sorted(path.suboptions.items()):
5418 for subopt, value in sorted(path.suboptions.items()):
5420 assert subopt not in ('name', 'url')
5419 assert subopt not in ('name', 'url')
5421 if showsubopts:
5420 if showsubopts:
5422 fm.plain('%s:%s = ' % (name, subopt))
5421 fm.plain('%s:%s = ' % (name, subopt))
5423 fm.condwrite(showsubopts, subopt, '%s\n', value)
5422 fm.condwrite(showsubopts, subopt, '%s\n', value)
5424
5423
5425 fm.end()
5424 fm.end()
5426
5425
5427 if search and not pathitems:
5426 if search and not pathitems:
5428 if not ui.quiet:
5427 if not ui.quiet:
5429 ui.warn(_("not found!\n"))
5428 ui.warn(_("not found!\n"))
5430 return 1
5429 return 1
5431 else:
5430 else:
5432 return 0
5431 return 0
5433
5432
5434 @command('phase',
5433 @command('phase',
5435 [('p', 'public', False, _('set changeset phase to public')),
5434 [('p', 'public', False, _('set changeset phase to public')),
5436 ('d', 'draft', False, _('set changeset phase to draft')),
5435 ('d', 'draft', False, _('set changeset phase to draft')),
5437 ('s', 'secret', False, _('set changeset phase to secret')),
5436 ('s', 'secret', False, _('set changeset phase to secret')),
5438 ('f', 'force', False, _('allow to move boundary backward')),
5437 ('f', 'force', False, _('allow to move boundary backward')),
5439 ('r', 'rev', [], _('target revision'), _('REV')),
5438 ('r', 'rev', [], _('target revision'), _('REV')),
5440 ],
5439 ],
5441 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5440 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5442 def phase(ui, repo, *revs, **opts):
5441 def phase(ui, repo, *revs, **opts):
5443 """set or show the current phase name
5442 """set or show the current phase name
5444
5443
5445 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).
5446
5445
5447 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
5448 phase value of the specified revisions.
5447 phase value of the specified revisions.
5449
5448
5450 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
5451 lower phase to an higher phase. Phases are ordered as follows::
5450 lower phase to an higher phase. Phases are ordered as follows::
5452
5451
5453 public < draft < secret
5452 public < draft < secret
5454
5453
5455 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.
5456
5455
5457 (For more information about the phases concept, see :hg:`help phases`.)
5456 (For more information about the phases concept, see :hg:`help phases`.)
5458 """
5457 """
5459 # search for a unique phase argument
5458 # search for a unique phase argument
5460 targetphase = None
5459 targetphase = None
5461 for idx, name in enumerate(phases.phasenames):
5460 for idx, name in enumerate(phases.phasenames):
5462 if opts[name]:
5461 if opts[name]:
5463 if targetphase is not None:
5462 if targetphase is not None:
5464 raise error.Abort(_('only one phase can be specified'))
5463 raise error.Abort(_('only one phase can be specified'))
5465 targetphase = idx
5464 targetphase = idx
5466
5465
5467 # look for specified revision
5466 # look for specified revision
5468 revs = list(revs)
5467 revs = list(revs)
5469 revs.extend(opts['rev'])
5468 revs.extend(opts['rev'])
5470 if not revs:
5469 if not revs:
5471 # display both parents as the second parent phase can influence
5470 # display both parents as the second parent phase can influence
5472 # the phase of a merge commit
5471 # the phase of a merge commit
5473 revs = [c.rev() for c in repo[None].parents()]
5472 revs = [c.rev() for c in repo[None].parents()]
5474
5473
5475 revs = scmutil.revrange(repo, revs)
5474 revs = scmutil.revrange(repo, revs)
5476
5475
5477 lock = None
5476 lock = None
5478 ret = 0
5477 ret = 0
5479 if targetphase is None:
5478 if targetphase is None:
5480 # display
5479 # display
5481 for r in revs:
5480 for r in revs:
5482 ctx = repo[r]
5481 ctx = repo[r]
5483 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5482 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5484 else:
5483 else:
5485 tr = None
5484 tr = None
5486 lock = repo.lock()
5485 lock = repo.lock()
5487 try:
5486 try:
5488 tr = repo.transaction("phase")
5487 tr = repo.transaction("phase")
5489 # set phase
5488 # set phase
5490 if not revs:
5489 if not revs:
5491 raise error.Abort(_('empty revision set'))
5490 raise error.Abort(_('empty revision set'))
5492 nodes = [repo[r].node() for r in revs]
5491 nodes = [repo[r].node() for r in revs]
5493 # moving revision from public to draft may hide them
5492 # moving revision from public to draft may hide them
5494 # We have to check result on an unfiltered repository
5493 # We have to check result on an unfiltered repository
5495 unfi = repo.unfiltered()
5494 unfi = repo.unfiltered()
5496 getphase = unfi._phasecache.phase
5495 getphase = unfi._phasecache.phase
5497 olddata = [getphase(unfi, r) for r in unfi]
5496 olddata = [getphase(unfi, r) for r in unfi]
5498 phases.advanceboundary(repo, tr, targetphase, nodes)
5497 phases.advanceboundary(repo, tr, targetphase, nodes)
5499 if opts['force']:
5498 if opts['force']:
5500 phases.retractboundary(repo, tr, targetphase, nodes)
5499 phases.retractboundary(repo, tr, targetphase, nodes)
5501 tr.close()
5500 tr.close()
5502 finally:
5501 finally:
5503 if tr is not None:
5502 if tr is not None:
5504 tr.release()
5503 tr.release()
5505 lock.release()
5504 lock.release()
5506 getphase = unfi._phasecache.phase
5505 getphase = unfi._phasecache.phase
5507 newdata = [getphase(unfi, r) for r in unfi]
5506 newdata = [getphase(unfi, r) for r in unfi]
5508 changes = sum(newdata[r] != olddata[r] for r in unfi)
5507 changes = sum(newdata[r] != olddata[r] for r in unfi)
5509 cl = unfi.changelog
5508 cl = unfi.changelog
5510 rejected = [n for n in nodes
5509 rejected = [n for n in nodes
5511 if newdata[cl.rev(n)] < targetphase]
5510 if newdata[cl.rev(n)] < targetphase]
5512 if rejected:
5511 if rejected:
5513 ui.warn(_('cannot move %i changesets to a higher '
5512 ui.warn(_('cannot move %i changesets to a higher '
5514 'phase, use --force\n') % len(rejected))
5513 'phase, use --force\n') % len(rejected))
5515 ret = 1
5514 ret = 1
5516 if changes:
5515 if changes:
5517 msg = _('phase changed for %i changesets\n') % changes
5516 msg = _('phase changed for %i changesets\n') % changes
5518 if ret:
5517 if ret:
5519 ui.status(msg)
5518 ui.status(msg)
5520 else:
5519 else:
5521 ui.note(msg)
5520 ui.note(msg)
5522 else:
5521 else:
5523 ui.warn(_('no phases changed\n'))
5522 ui.warn(_('no phases changed\n'))
5524 return ret
5523 return ret
5525
5524
5526 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5525 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5527 """Run after a changegroup has been added via pull/unbundle
5526 """Run after a changegroup has been added via pull/unbundle
5528
5527
5529 This takes arguments below:
5528 This takes arguments below:
5530
5529
5531 :modheads: change of heads by pull/unbundle
5530 :modheads: change of heads by pull/unbundle
5532 :optupdate: updating working directory is needed or not
5531 :optupdate: updating working directory is needed or not
5533 :checkout: update destination revision (or None to default destination)
5532 :checkout: update destination revision (or None to default destination)
5534 :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
5535 """
5534 """
5536 if modheads == 0:
5535 if modheads == 0:
5537 return
5536 return
5538 if optupdate:
5537 if optupdate:
5539 try:
5538 try:
5540 return hg.updatetotally(ui, repo, checkout, brev)
5539 return hg.updatetotally(ui, repo, checkout, brev)
5541 except error.UpdateAbort as inst:
5540 except error.UpdateAbort as inst:
5542 msg = _("not updating: %s") % str(inst)
5541 msg = _("not updating: %s") % str(inst)
5543 hint = inst.hint
5542 hint = inst.hint
5544 raise error.UpdateAbort(msg, hint=hint)
5543 raise error.UpdateAbort(msg, hint=hint)
5545 if modheads > 1:
5544 if modheads > 1:
5546 currentbranchheads = len(repo.branchheads())
5545 currentbranchheads = len(repo.branchheads())
5547 if currentbranchheads == modheads:
5546 if currentbranchheads == modheads:
5548 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"))
5549 elif currentbranchheads > 1:
5548 elif currentbranchheads > 1:
5550 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5549 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5551 "merge)\n"))
5550 "merge)\n"))
5552 else:
5551 else:
5553 ui.status(_("(run 'hg heads' to see heads)\n"))
5552 ui.status(_("(run 'hg heads' to see heads)\n"))
5554 else:
5553 else:
5555 ui.status(_("(run 'hg update' to get a working copy)\n"))
5554 ui.status(_("(run 'hg update' to get a working copy)\n"))
5556
5555
5557 @command('^pull',
5556 @command('^pull',
5558 [('u', 'update', None,
5557 [('u', 'update', None,
5559 _('update to new branch head if changesets were pulled')),
5558 _('update to new branch head if changesets were pulled')),
5560 ('f', 'force', None, _('run even when remote repository is unrelated')),
5559 ('f', 'force', None, _('run even when remote repository is unrelated')),
5561 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5560 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5562 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5561 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5563 ('b', 'branch', [], _('a specific branch you would like to pull'),
5562 ('b', 'branch', [], _('a specific branch you would like to pull'),
5564 _('BRANCH')),
5563 _('BRANCH')),
5565 ] + remoteopts,
5564 ] + remoteopts,
5566 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5565 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5567 def pull(ui, repo, source="default", **opts):
5566 def pull(ui, repo, source="default", **opts):
5568 """pull changes from the specified source
5567 """pull changes from the specified source
5569
5568
5570 Pull changes from a remote repository to a local one.
5569 Pull changes from a remote repository to a local one.
5571
5570
5572 This finds all changes from the repository at the specified path
5571 This finds all changes from the repository at the specified path
5573 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
5574 -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
5575 project in the working directory.
5574 project in the working directory.
5576
5575
5577 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
5578 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
5579 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
5580 -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`.
5581
5580
5582 If SOURCE is omitted, the 'default' path will be used.
5581 If SOURCE is omitted, the 'default' path will be used.
5583 See :hg:`help urls` for more information.
5582 See :hg:`help urls` for more information.
5584
5583
5585 Specifying bookmark as ``.`` is equivalent to specifying the active
5584 Specifying bookmark as ``.`` is equivalent to specifying the active
5586 bookmark's name.
5585 bookmark's name.
5587
5586
5588 Returns 0 on success, 1 if an update had unresolved files.
5587 Returns 0 on success, 1 if an update had unresolved files.
5589 """
5588 """
5590 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5589 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5591 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5590 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5592 other = hg.peer(repo, opts, source)
5591 other = hg.peer(repo, opts, source)
5593 try:
5592 try:
5594 revs, checkout = hg.addbranchrevs(repo, other, branches,
5593 revs, checkout = hg.addbranchrevs(repo, other, branches,
5595 opts.get('rev'))
5594 opts.get('rev'))
5596
5595
5597
5596
5598 pullopargs = {}
5597 pullopargs = {}
5599 if opts.get('bookmark'):
5598 if opts.get('bookmark'):
5600 if not revs:
5599 if not revs:
5601 revs = []
5600 revs = []
5602 # 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
5603 # update the bookmark name. This can result in the revision pulled
5602 # update the bookmark name. This can result in the revision pulled
5604 # 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
5605 # condition on the server. (See issue 4689 for details)
5604 # condition on the server. (See issue 4689 for details)
5606 remotebookmarks = other.listkeys('bookmarks')
5605 remotebookmarks = other.listkeys('bookmarks')
5607 pullopargs['remotebookmarks'] = remotebookmarks
5606 pullopargs['remotebookmarks'] = remotebookmarks
5608 for b in opts['bookmark']:
5607 for b in opts['bookmark']:
5609 b = repo._bookmarks.expandname(b)
5608 b = repo._bookmarks.expandname(b)
5610 if b not in remotebookmarks:
5609 if b not in remotebookmarks:
5611 raise error.Abort(_('remote bookmark %s not found!') % b)
5610 raise error.Abort(_('remote bookmark %s not found!') % b)
5612 revs.append(remotebookmarks[b])
5611 revs.append(remotebookmarks[b])
5613
5612
5614 if revs:
5613 if revs:
5615 try:
5614 try:
5616 # When 'rev' is a bookmark name, we cannot guarantee that it
5615 # When 'rev' is a bookmark name, we cannot guarantee that it
5617 # will be updated with that name because of a race condition
5616 # will be updated with that name because of a race condition
5618 # server side. (See issue 4689 for details)
5617 # server side. (See issue 4689 for details)
5619 oldrevs = revs
5618 oldrevs = revs
5620 revs = [] # actually, nodes
5619 revs = [] # actually, nodes
5621 for r in oldrevs:
5620 for r in oldrevs:
5622 node = other.lookup(r)
5621 node = other.lookup(r)
5623 revs.append(node)
5622 revs.append(node)
5624 if r == checkout:
5623 if r == checkout:
5625 checkout = node
5624 checkout = node
5626 except error.CapabilityError:
5625 except error.CapabilityError:
5627 err = _("other repository doesn't support revision lookup, "
5626 err = _("other repository doesn't support revision lookup, "
5628 "so a rev cannot be specified.")
5627 "so a rev cannot be specified.")
5629 raise error.Abort(err)
5628 raise error.Abort(err)
5630
5629
5631 pullopargs.update(opts.get('opargs', {}))
5630 pullopargs.update(opts.get('opargs', {}))
5632 modheads = exchange.pull(repo, other, heads=revs,
5631 modheads = exchange.pull(repo, other, heads=revs,
5633 force=opts.get('force'),
5632 force=opts.get('force'),
5634 bookmarks=opts.get('bookmark', ()),
5633 bookmarks=opts.get('bookmark', ()),
5635 opargs=pullopargs).cgresult
5634 opargs=pullopargs).cgresult
5636
5635
5637 # 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
5638 # 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
5639 # destination of the update
5638 # destination of the update
5640 brev = None
5639 brev = None
5641
5640
5642 if checkout:
5641 if checkout:
5643 checkout = str(repo.changelog.rev(checkout))
5642 checkout = str(repo.changelog.rev(checkout))
5644
5643
5645 # order below depends on implementation of
5644 # order below depends on implementation of
5646 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5645 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5647 # because 'checkout' is determined without it.
5646 # because 'checkout' is determined without it.
5648 if opts.get('rev'):
5647 if opts.get('rev'):
5649 brev = opts['rev'][0]
5648 brev = opts['rev'][0]
5650 elif opts.get('branch'):
5649 elif opts.get('branch'):
5651 brev = opts['branch'][0]
5650 brev = opts['branch'][0]
5652 else:
5651 else:
5653 brev = branches[0]
5652 brev = branches[0]
5654 repo._subtoppath = source
5653 repo._subtoppath = source
5655 try:
5654 try:
5656 ret = postincoming(ui, repo, modheads, opts.get('update'),
5655 ret = postincoming(ui, repo, modheads, opts.get('update'),
5657 checkout, brev)
5656 checkout, brev)
5658
5657
5659 finally:
5658 finally:
5660 del repo._subtoppath
5659 del repo._subtoppath
5661
5660
5662 finally:
5661 finally:
5663 other.close()
5662 other.close()
5664 return ret
5663 return ret
5665
5664
5666 @command('^push',
5665 @command('^push',
5667 [('f', 'force', None, _('force push')),
5666 [('f', 'force', None, _('force push')),
5668 ('r', 'rev', [],
5667 ('r', 'rev', [],
5669 _('a changeset intended to be included in the destination'),
5668 _('a changeset intended to be included in the destination'),
5670 _('REV')),
5669 _('REV')),
5671 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5670 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5672 ('b', 'branch', [],
5671 ('b', 'branch', [],
5673 _('a specific branch you would like to push'), _('BRANCH')),
5672 _('a specific branch you would like to push'), _('BRANCH')),
5674 ('', 'new-branch', False, _('allow pushing a new branch')),
5673 ('', 'new-branch', False, _('allow pushing a new branch')),
5675 ] + remoteopts,
5674 ] + remoteopts,
5676 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5675 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5677 def push(ui, repo, dest=None, **opts):
5676 def push(ui, repo, dest=None, **opts):
5678 """push changes to the specified destination
5677 """push changes to the specified destination
5679
5678
5680 Push changesets from the local repository to the specified
5679 Push changesets from the local repository to the specified
5681 destination.
5680 destination.
5682
5681
5683 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
5684 in the destination repository from the current one.
5683 in the destination repository from the current one.
5685
5684
5686 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
5687 destination, since multiple heads would make it unclear which head
5686 destination, since multiple heads would make it unclear which head
5688 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
5689 before pushing.
5688 before pushing.
5690
5689
5691 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
5692 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
5693 only create a new branch without forcing other changes.
5692 only create a new branch without forcing other changes.
5694
5693
5695 .. note::
5694 .. note::
5696
5695
5697 Extra care should be taken with the -f/--force option,
5696 Extra care should be taken with the -f/--force option,
5698 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
5699 almost always cause confusion for collaborators.
5698 almost always cause confusion for collaborators.
5700
5699
5701 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
5702 will be pushed to the remote repository.
5701 will be pushed to the remote repository.
5703
5702
5704 If -B/--bookmark is used, the specified bookmarked revision, its
5703 If -B/--bookmark is used, the specified bookmarked revision, its
5705 ancestors, and the bookmark will be pushed to the remote
5704 ancestors, and the bookmark will be pushed to the remote
5706 repository. Specifying ``.`` is equivalent to specifying the active
5705 repository. Specifying ``.`` is equivalent to specifying the active
5707 bookmark's name.
5706 bookmark's name.
5708
5707
5709 Please see :hg:`help urls` for important details about ``ssh://``
5708 Please see :hg:`help urls` for important details about ``ssh://``
5710 URLs. If DESTINATION is omitted, a default path will be used.
5709 URLs. If DESTINATION is omitted, a default path will be used.
5711
5710
5712 Returns 0 if push was successful, 1 if nothing to push.
5711 Returns 0 if push was successful, 1 if nothing to push.
5713 """
5712 """
5714
5713
5715 if opts.get('bookmark'):
5714 if opts.get('bookmark'):
5716 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5715 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5717 for b in opts['bookmark']:
5716 for b in opts['bookmark']:
5718 # translate -B options to -r so changesets get pushed
5717 # translate -B options to -r so changesets get pushed
5719 b = repo._bookmarks.expandname(b)
5718 b = repo._bookmarks.expandname(b)
5720 if b in repo._bookmarks:
5719 if b in repo._bookmarks:
5721 opts.setdefault('rev', []).append(b)
5720 opts.setdefault('rev', []).append(b)
5722 else:
5721 else:
5723 # 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
5724 # this lets simultaneous -r, -b options continue working
5723 # this lets simultaneous -r, -b options continue working
5725 opts.setdefault('rev', []).append("null")
5724 opts.setdefault('rev', []).append("null")
5726
5725
5727 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5726 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5728 if not path:
5727 if not path:
5729 raise error.Abort(_('default repository not configured!'),
5728 raise error.Abort(_('default repository not configured!'),
5730 hint=_("see 'hg help config.paths'"))
5729 hint=_("see 'hg help config.paths'"))
5731 dest = path.pushloc or path.loc
5730 dest = path.pushloc or path.loc
5732 branches = (path.branch, opts.get('branch') or [])
5731 branches = (path.branch, opts.get('branch') or [])
5733 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5732 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5734 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5733 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5735 other = hg.peer(repo, opts, dest)
5734 other = hg.peer(repo, opts, dest)
5736
5735
5737 if revs:
5736 if revs:
5738 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5737 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5739 if not revs:
5738 if not revs:
5740 raise error.Abort(_("specified revisions evaluate to an empty set"),
5739 raise error.Abort(_("specified revisions evaluate to an empty set"),
5741 hint=_("use different revision arguments"))
5740 hint=_("use different revision arguments"))
5742 elif path.pushrev:
5741 elif path.pushrev:
5743 # 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
5744 # to DAG heads to make discovery simpler.
5743 # to DAG heads to make discovery simpler.
5745 expr = revset.formatspec('heads(%r)', path.pushrev)
5744 expr = revset.formatspec('heads(%r)', path.pushrev)
5746 revs = scmutil.revrange(repo, [expr])
5745 revs = scmutil.revrange(repo, [expr])
5747 revs = [repo[rev].node() for rev in revs]
5746 revs = [repo[rev].node() for rev in revs]
5748 if not revs:
5747 if not revs:
5749 raise error.Abort(_('default push revset for path evaluates to an '
5748 raise error.Abort(_('default push revset for path evaluates to an '
5750 'empty set'))
5749 'empty set'))
5751
5750
5752 repo._subtoppath = dest
5751 repo._subtoppath = dest
5753 try:
5752 try:
5754 # push subrepos depth-first for coherent ordering
5753 # push subrepos depth-first for coherent ordering
5755 c = repo['']
5754 c = repo['']
5756 subs = c.substate # only repos that are committed
5755 subs = c.substate # only repos that are committed
5757 for s in sorted(subs):
5756 for s in sorted(subs):
5758 result = c.sub(s).push(opts)
5757 result = c.sub(s).push(opts)
5759 if result == 0:
5758 if result == 0:
5760 return not result
5759 return not result
5761 finally:
5760 finally:
5762 del repo._subtoppath
5761 del repo._subtoppath
5763 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5762 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5764 newbranch=opts.get('new_branch'),
5763 newbranch=opts.get('new_branch'),
5765 bookmarks=opts.get('bookmark', ()),
5764 bookmarks=opts.get('bookmark', ()),
5766 opargs=opts.get('opargs'))
5765 opargs=opts.get('opargs'))
5767
5766
5768 result = not pushop.cgresult
5767 result = not pushop.cgresult
5769
5768
5770 if pushop.bkresult is not None:
5769 if pushop.bkresult is not None:
5771 if pushop.bkresult == 2:
5770 if pushop.bkresult == 2:
5772 result = 2
5771 result = 2
5773 elif not result and pushop.bkresult:
5772 elif not result and pushop.bkresult:
5774 result = 2
5773 result = 2
5775
5774
5776 return result
5775 return result
5777
5776
5778 @command('recover', [])
5777 @command('recover', [])
5779 def recover(ui, repo):
5778 def recover(ui, repo):
5780 """roll back an interrupted transaction
5779 """roll back an interrupted transaction
5781
5780
5782 Recover from an interrupted commit or pull.
5781 Recover from an interrupted commit or pull.
5783
5782
5784 This command tries to fix the repository status after an
5783 This command tries to fix the repository status after an
5785 interrupted operation. It should only be necessary when Mercurial
5784 interrupted operation. It should only be necessary when Mercurial
5786 suggests it.
5785 suggests it.
5787
5786
5788 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.
5789 """
5788 """
5790 if repo.recover():
5789 if repo.recover():
5791 return hg.verify(repo)
5790 return hg.verify(repo)
5792 return 1
5791 return 1
5793
5792
5794 @command('^remove|rm',
5793 @command('^remove|rm',
5795 [('A', 'after', None, _('record delete for missing files')),
5794 [('A', 'after', None, _('record delete for missing files')),
5796 ('f', 'force', None,
5795 ('f', 'force', None,
5797 _('forget added files, delete modified files')),
5796 _('forget added files, delete modified files')),
5798 ] + subrepoopts + walkopts,
5797 ] + subrepoopts + walkopts,
5799 _('[OPTION]... FILE...'),
5798 _('[OPTION]... FILE...'),
5800 inferrepo=True)
5799 inferrepo=True)
5801 def remove(ui, repo, *pats, **opts):
5800 def remove(ui, repo, *pats, **opts):
5802 """remove the specified files on the next commit
5801 """remove the specified files on the next commit
5803
5802
5804 Schedule the indicated files for removal from the current branch.
5803 Schedule the indicated files for removal from the current branch.
5805
5804
5806 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.
5807 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
5808 files, see :hg:`forget`.
5807 files, see :hg:`forget`.
5809
5808
5810 .. container:: verbose
5809 .. container:: verbose
5811
5810
5812 -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
5813 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
5814 can be used to remove files from the next revision without
5813 can be used to remove files from the next revision without
5815 deleting them from the working directory.
5814 deleting them from the working directory.
5816
5815
5817 The following table details the behavior of remove for different
5816 The following table details the behavior of remove for different
5818 file states (columns) and option combinations (rows). The file
5817 file states (columns) and option combinations (rows). The file
5819 states are Added [A], Clean [C], Modified [M] and Missing [!]
5818 states are Added [A], Clean [C], Modified [M] and Missing [!]
5820 (as reported by :hg:`status`). The actions are Warn, Remove
5819 (as reported by :hg:`status`). The actions are Warn, Remove
5821 (from branch) and Delete (from disk):
5820 (from branch) and Delete (from disk):
5822
5821
5823 ========= == == == ==
5822 ========= == == == ==
5824 opt/state A C M !
5823 opt/state A C M !
5825 ========= == == == ==
5824 ========= == == == ==
5826 none W RD W R
5825 none W RD W R
5827 -f R RD RD R
5826 -f R RD RD R
5828 -A W W W R
5827 -A W W W R
5829 -Af R R R R
5828 -Af R R R R
5830 ========= == == == ==
5829 ========= == == == ==
5831
5830
5832 .. note::
5831 .. note::
5833
5832
5834 :hg:`remove` never deletes files in Added [A] state from the
5833 :hg:`remove` never deletes files in Added [A] state from the
5835 working directory, not even if ``--force`` is specified.
5834 working directory, not even if ``--force`` is specified.
5836
5835
5837 Returns 0 on success, 1 if any warnings encountered.
5836 Returns 0 on success, 1 if any warnings encountered.
5838 """
5837 """
5839
5838
5840 after, force = opts.get('after'), opts.get('force')
5839 after, force = opts.get('after'), opts.get('force')
5841 if not pats and not after:
5840 if not pats and not after:
5842 raise error.Abort(_('no files specified'))
5841 raise error.Abort(_('no files specified'))
5843
5842
5844 m = scmutil.match(repo[None], pats, opts)
5843 m = scmutil.match(repo[None], pats, opts)
5845 subrepos = opts.get('subrepos')
5844 subrepos = opts.get('subrepos')
5846 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5845 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5847
5846
5848 @command('rename|move|mv',
5847 @command('rename|move|mv',
5849 [('A', 'after', None, _('record a rename that has already occurred')),
5848 [('A', 'after', None, _('record a rename that has already occurred')),
5850 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5849 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5851 ] + walkopts + dryrunopts,
5850 ] + walkopts + dryrunopts,
5852 _('[OPTION]... SOURCE... DEST'))
5851 _('[OPTION]... SOURCE... DEST'))
5853 def rename(ui, repo, *pats, **opts):
5852 def rename(ui, repo, *pats, **opts):
5854 """rename files; equivalent of copy + remove
5853 """rename files; equivalent of copy + remove
5855
5854
5856 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
5857 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
5858 file, there can only be one source.
5857 file, there can only be one source.
5859
5858
5860 By default, this command copies the contents of files as they
5859 By default, this command copies the contents of files as they
5861 exist in the working directory. If invoked with -A/--after, the
5860 exist in the working directory. If invoked with -A/--after, the
5862 operation is recorded, but no copying is performed.
5861 operation is recorded, but no copying is performed.
5863
5862
5864 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
5865 before that, see :hg:`revert`.
5864 before that, see :hg:`revert`.
5866
5865
5867 Returns 0 on success, 1 if errors are encountered.
5866 Returns 0 on success, 1 if errors are encountered.
5868 """
5867 """
5869 with repo.wlock(False):
5868 with repo.wlock(False):
5870 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5869 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5871
5870
5872 @command('resolve',
5871 @command('resolve',
5873 [('a', 'all', None, _('select all unresolved files')),
5872 [('a', 'all', None, _('select all unresolved files')),
5874 ('l', 'list', None, _('list state of files needing merge')),
5873 ('l', 'list', None, _('list state of files needing merge')),
5875 ('m', 'mark', None, _('mark files as resolved')),
5874 ('m', 'mark', None, _('mark files as resolved')),
5876 ('u', 'unmark', None, _('mark files as unresolved')),
5875 ('u', 'unmark', None, _('mark files as unresolved')),
5877 ('n', 'no-status', None, _('hide status prefix'))]
5876 ('n', 'no-status', None, _('hide status prefix'))]
5878 + mergetoolopts + walkopts + formatteropts,
5877 + mergetoolopts + walkopts + formatteropts,
5879 _('[OPTION]... [FILE]...'),
5878 _('[OPTION]... [FILE]...'),
5880 inferrepo=True)
5879 inferrepo=True)
5881 def resolve(ui, repo, *pats, **opts):
5880 def resolve(ui, repo, *pats, **opts):
5882 """redo merges or set/view the merge status of files
5881 """redo merges or set/view the merge status of files
5883
5882
5884 Merges with unresolved conflicts are often the result of
5883 Merges with unresolved conflicts are often the result of
5885 non-interactive merging using the ``internal:merge`` configuration
5884 non-interactive merging using the ``internal:merge`` configuration
5886 setting, or a command-line merge tool like ``diff3``. The resolve
5885 setting, or a command-line merge tool like ``diff3``. The resolve
5887 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
5888 :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
5889 working directory must have two parents). See :hg:`help
5888 working directory must have two parents). See :hg:`help
5890 merge-tools` for information on configuring merge tools.
5889 merge-tools` for information on configuring merge tools.
5891
5890
5892 The resolve command can be used in the following ways:
5891 The resolve command can be used in the following ways:
5893
5892
5894 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5893 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5895 files, discarding any previous merge attempts. Re-merging is not
5894 files, discarding any previous merge attempts. Re-merging is not
5896 performed for files already marked as resolved. Use ``--all/-a``
5895 performed for files already marked as resolved. Use ``--all/-a``
5897 to select all unresolved files. ``--tool`` can be used to specify
5896 to select all unresolved files. ``--tool`` can be used to specify
5898 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
5899 environment variable and your configuration files. Previous file
5898 environment variable and your configuration files. Previous file
5900 contents are saved with a ``.orig`` suffix.
5899 contents are saved with a ``.orig`` suffix.
5901
5900
5902 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5901 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5903 (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
5904 to mark all unresolved files.
5903 to mark all unresolved files.
5905
5904
5906 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5905 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5907 default is to mark all resolved files.
5906 default is to mark all resolved files.
5908
5907
5909 - :hg:`resolve -l`: list files which had or still have conflicts.
5908 - :hg:`resolve -l`: list files which had or still have conflicts.
5910 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5909 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5911
5910
5912 .. note::
5911 .. note::
5913
5912
5914 Mercurial will not let you commit files with unresolved merge
5913 Mercurial will not let you commit files with unresolved merge
5915 conflicts. You must use :hg:`resolve -m ...` before you can
5914 conflicts. You must use :hg:`resolve -m ...` before you can
5916 commit after a conflicting merge.
5915 commit after a conflicting merge.
5917
5916
5918 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.
5919 """
5918 """
5920
5919
5921 flaglist = 'all mark unmark list no_status'.split()
5920 flaglist = 'all mark unmark list no_status'.split()
5922 all, mark, unmark, show, nostatus = \
5921 all, mark, unmark, show, nostatus = \
5923 [opts.get(o) for o in flaglist]
5922 [opts.get(o) for o in flaglist]
5924
5923
5925 if (show and (mark or unmark)) or (mark and unmark):
5924 if (show and (mark or unmark)) or (mark and unmark):
5926 raise error.Abort(_("too many options specified"))
5925 raise error.Abort(_("too many options specified"))
5927 if pats and all:
5926 if pats and all:
5928 raise error.Abort(_("can't specify --all and patterns"))
5927 raise error.Abort(_("can't specify --all and patterns"))
5929 if not (all or pats or show or mark or unmark):
5928 if not (all or pats or show or mark or unmark):
5930 raise error.Abort(_('no files or directories specified'),
5929 raise error.Abort(_('no files or directories specified'),
5931 hint=('use --all to re-merge all unresolved files'))
5930 hint=('use --all to re-merge all unresolved files'))
5932
5931
5933 if show:
5932 if show:
5934 fm = ui.formatter('resolve', opts)
5933 fm = ui.formatter('resolve', opts)
5935 ms = mergemod.mergestate.read(repo)
5934 ms = mergemod.mergestate.read(repo)
5936 m = scmutil.match(repo[None], pats, opts)
5935 m = scmutil.match(repo[None], pats, opts)
5937 for f in ms:
5936 for f in ms:
5938 if not m(f):
5937 if not m(f):
5939 continue
5938 continue
5940 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5939 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5941 'd': 'driverresolved'}[ms[f]]
5940 'd': 'driverresolved'}[ms[f]]
5942 fm.startitem()
5941 fm.startitem()
5943 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5942 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5944 fm.write('path', '%s\n', f, label=l)
5943 fm.write('path', '%s\n', f, label=l)
5945 fm.end()
5944 fm.end()
5946 return 0
5945 return 0
5947
5946
5948 with repo.wlock():
5947 with repo.wlock():
5949 ms = mergemod.mergestate.read(repo)
5948 ms = mergemod.mergestate.read(repo)
5950
5949
5951 if not (ms.active() or repo.dirstate.p2() != nullid):
5950 if not (ms.active() or repo.dirstate.p2() != nullid):
5952 raise error.Abort(
5951 raise error.Abort(
5953 _('resolve command not applicable when not merging'))
5952 _('resolve command not applicable when not merging'))
5954
5953
5955 wctx = repo[None]
5954 wctx = repo[None]
5956
5955
5957 if ms.mergedriver and ms.mdstate() == 'u':
5956 if ms.mergedriver and ms.mdstate() == 'u':
5958 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5957 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5959 ms.commit()
5958 ms.commit()
5960 # allow mark and unmark to go through
5959 # allow mark and unmark to go through
5961 if not mark and not unmark and not proceed:
5960 if not mark and not unmark and not proceed:
5962 return 1
5961 return 1
5963
5962
5964 m = scmutil.match(wctx, pats, opts)
5963 m = scmutil.match(wctx, pats, opts)
5965 ret = 0
5964 ret = 0
5966 didwork = False
5965 didwork = False
5967 runconclude = False
5966 runconclude = False
5968
5967
5969 tocomplete = []
5968 tocomplete = []
5970 for f in ms:
5969 for f in ms:
5971 if not m(f):
5970 if not m(f):
5972 continue
5971 continue
5973
5972
5974 didwork = True
5973 didwork = True
5975
5974
5976 # 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
5977 # step if asked to resolve
5976 # step if asked to resolve
5978 if ms[f] == "d":
5977 if ms[f] == "d":
5979 exact = m.exact(f)
5978 exact = m.exact(f)
5980 if mark:
5979 if mark:
5981 if exact:
5980 if exact:
5982 ui.warn(_('not marking %s as it is driver-resolved\n')
5981 ui.warn(_('not marking %s as it is driver-resolved\n')
5983 % f)
5982 % f)
5984 elif unmark:
5983 elif unmark:
5985 if exact:
5984 if exact:
5986 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5985 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5987 % f)
5986 % f)
5988 else:
5987 else:
5989 runconclude = True
5988 runconclude = True
5990 continue
5989 continue
5991
5990
5992 if mark:
5991 if mark:
5993 ms.mark(f, "r")
5992 ms.mark(f, "r")
5994 elif unmark:
5993 elif unmark:
5995 ms.mark(f, "u")
5994 ms.mark(f, "u")
5996 else:
5995 else:
5997 # backup pre-resolve (merge uses .orig for its own purposes)
5996 # backup pre-resolve (merge uses .orig for its own purposes)
5998 a = repo.wjoin(f)
5997 a = repo.wjoin(f)
5999 try:
5998 try:
6000 util.copyfile(a, a + ".resolve")
5999 util.copyfile(a, a + ".resolve")
6001 except (IOError, OSError) as inst:
6000 except (IOError, OSError) as inst:
6002 if inst.errno != errno.ENOENT:
6001 if inst.errno != errno.ENOENT:
6003 raise
6002 raise
6004
6003
6005 try:
6004 try:
6006 # preresolve file
6005 # preresolve file
6007 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6006 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6008 'resolve')
6007 'resolve')
6009 complete, r = ms.preresolve(f, wctx)
6008 complete, r = ms.preresolve(f, wctx)
6010 if not complete:
6009 if not complete:
6011 tocomplete.append(f)
6010 tocomplete.append(f)
6012 elif r:
6011 elif r:
6013 ret = 1
6012 ret = 1
6014 finally:
6013 finally:
6015 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6014 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6016 ms.commit()
6015 ms.commit()
6017
6016
6018 # replace filemerge's .orig file with our resolve file, but only
6017 # replace filemerge's .orig file with our resolve file, but only
6019 # for merges that are complete
6018 # for merges that are complete
6020 if complete:
6019 if complete:
6021 try:
6020 try:
6022 util.rename(a + ".resolve",
6021 util.rename(a + ".resolve",
6023 scmutil.origpath(ui, repo, a))
6022 scmutil.origpath(ui, repo, a))
6024 except OSError as inst:
6023 except OSError as inst:
6025 if inst.errno != errno.ENOENT:
6024 if inst.errno != errno.ENOENT:
6026 raise
6025 raise
6027
6026
6028 for f in tocomplete:
6027 for f in tocomplete:
6029 try:
6028 try:
6030 # resolve file
6029 # resolve file
6031 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6030 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6032 'resolve')
6031 'resolve')
6033 r = ms.resolve(f, wctx)
6032 r = ms.resolve(f, wctx)
6034 if r:
6033 if r:
6035 ret = 1
6034 ret = 1
6036 finally:
6035 finally:
6037 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6036 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6038 ms.commit()
6037 ms.commit()
6039
6038
6040 # replace filemerge's .orig file with our resolve file
6039 # replace filemerge's .orig file with our resolve file
6041 a = repo.wjoin(f)
6040 a = repo.wjoin(f)
6042 try:
6041 try:
6043 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6042 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6044 except OSError as inst:
6043 except OSError as inst:
6045 if inst.errno != errno.ENOENT:
6044 if inst.errno != errno.ENOENT:
6046 raise
6045 raise
6047
6046
6048 ms.commit()
6047 ms.commit()
6049 ms.recordactions()
6048 ms.recordactions()
6050
6049
6051 if not didwork and pats:
6050 if not didwork and pats:
6052 hint = None
6051 hint = None
6053 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]):
6054 pats = ['path:%s' % p for p in pats]
6053 pats = ['path:%s' % p for p in pats]
6055 m = scmutil.match(wctx, pats, opts)
6054 m = scmutil.match(wctx, pats, opts)
6056 for f in ms:
6055 for f in ms:
6057 if not m(f):
6056 if not m(f):
6058 continue
6057 continue
6059 flags = ''.join(['-%s ' % o[0] for o in flaglist
6058 flags = ''.join(['-%s ' % o[0] for o in flaglist
6060 if opts.get(o)])
6059 if opts.get(o)])
6061 hint = _("(try: hg resolve %s%s)\n") % (
6060 hint = _("(try: hg resolve %s%s)\n") % (
6062 flags,
6061 flags,
6063 ' '.join(pats))
6062 ' '.join(pats))
6064 break
6063 break
6065 ui.warn(_("arguments do not match paths that need resolving\n"))
6064 ui.warn(_("arguments do not match paths that need resolving\n"))
6066 if hint:
6065 if hint:
6067 ui.warn(hint)
6066 ui.warn(hint)
6068 elif ms.mergedriver and ms.mdstate() != 's':
6067 elif ms.mergedriver and ms.mdstate() != 's':
6069 # run conclude step when either a driver-resolved file is requested
6068 # run conclude step when either a driver-resolved file is requested
6070 # or there are no driver-resolved files
6069 # or there are no driver-resolved files
6071 # 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
6072 # because we might not have tried to resolve some
6071 # because we might not have tried to resolve some
6073 if ((runconclude or not list(ms.driverresolved()))
6072 if ((runconclude or not list(ms.driverresolved()))
6074 and not list(ms.unresolved())):
6073 and not list(ms.unresolved())):
6075 proceed = mergemod.driverconclude(repo, ms, wctx)
6074 proceed = mergemod.driverconclude(repo, ms, wctx)
6076 ms.commit()
6075 ms.commit()
6077 if not proceed:
6076 if not proceed:
6078 return 1
6077 return 1
6079
6078
6080 # Nudge users into finishing an unfinished operation
6079 # Nudge users into finishing an unfinished operation
6081 unresolvedf = list(ms.unresolved())
6080 unresolvedf = list(ms.unresolved())
6082 driverresolvedf = list(ms.driverresolved())
6081 driverresolvedf = list(ms.driverresolved())
6083 if not unresolvedf and not driverresolvedf:
6082 if not unresolvedf and not driverresolvedf:
6084 ui.status(_('(no more unresolved files)\n'))
6083 ui.status(_('(no more unresolved files)\n'))
6085 cmdutil.checkafterresolved(repo)
6084 cmdutil.checkafterresolved(repo)
6086 elif not unresolvedf:
6085 elif not unresolvedf:
6087 ui.status(_('(no more unresolved files -- '
6086 ui.status(_('(no more unresolved files -- '
6088 'run "hg resolve --all" to conclude)\n'))
6087 'run "hg resolve --all" to conclude)\n'))
6089
6088
6090 return ret
6089 return ret
6091
6090
6092 @command('revert',
6091 @command('revert',
6093 [('a', 'all', None, _('revert all changes when no arguments given')),
6092 [('a', 'all', None, _('revert all changes when no arguments given')),
6094 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6093 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6095 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6094 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6096 ('C', 'no-backup', None, _('do not save backup copies of files')),
6095 ('C', 'no-backup', None, _('do not save backup copies of files')),
6097 ('i', 'interactive', None,
6096 ('i', 'interactive', None,
6098 _('interactively select the changes (EXPERIMENTAL)')),
6097 _('interactively select the changes (EXPERIMENTAL)')),
6099 ] + walkopts + dryrunopts,
6098 ] + walkopts + dryrunopts,
6100 _('[OPTION]... [-r REV] [NAME]...'))
6099 _('[OPTION]... [-r REV] [NAME]...'))
6101 def revert(ui, repo, *pats, **opts):
6100 def revert(ui, repo, *pats, **opts):
6102 """restore files to their checkout state
6101 """restore files to their checkout state
6103
6102
6104 .. note::
6103 .. note::
6105
6104
6106 To check out earlier revisions, you should use :hg:`update REV`.
6105 To check out earlier revisions, you should use :hg:`update REV`.
6107 To cancel an uncommitted merge (and lose your changes),
6106 To cancel an uncommitted merge (and lose your changes),
6108 use :hg:`update --clean .`.
6107 use :hg:`update --clean .`.
6109
6108
6110 With no revision specified, revert the specified files or directories
6109 With no revision specified, revert the specified files or directories
6111 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.
6112 This restores the contents of files to an unmodified
6111 This restores the contents of files to an unmodified
6113 state and unschedules adds, removes, copies, and renames. If the
6112 state and unschedules adds, removes, copies, and renames. If the
6114 working directory has two parents, you must explicitly specify a
6113 working directory has two parents, you must explicitly specify a
6115 revision.
6114 revision.
6116
6115
6117 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
6118 directories to their states as of a specific revision. Because
6117 directories to their states as of a specific revision. Because
6119 revert does not change the working directory parents, this will
6118 revert does not change the working directory parents, this will
6120 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
6121 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
6122 related method.
6121 related method.
6123
6122
6124 Modified files are saved with a .orig suffix before reverting.
6123 Modified files are saved with a .orig suffix before reverting.
6125 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
6126 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
6127 repository by setting the ``ui.origbackuppath`` configuration
6126 repository by setting the ``ui.origbackuppath`` configuration
6128 option.
6127 option.
6129
6128
6130 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.
6131
6130
6132 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
6133 earlier changeset.
6132 earlier changeset.
6134
6133
6135 Returns 0 on success.
6134 Returns 0 on success.
6136 """
6135 """
6137
6136
6138 if opts.get("date"):
6137 if opts.get("date"):
6139 if opts.get("rev"):
6138 if opts.get("rev"):
6140 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"))
6141 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6140 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6142
6141
6143 parent, p2 = repo.dirstate.parents()
6142 parent, p2 = repo.dirstate.parents()
6144 if not opts.get('rev') and p2 != nullid:
6143 if not opts.get('rev') and p2 != nullid:
6145 # revert after merge is a trap for new users (issue2915)
6144 # revert after merge is a trap for new users (issue2915)
6146 raise error.Abort(_('uncommitted merge with no revision specified'),
6145 raise error.Abort(_('uncommitted merge with no revision specified'),
6147 hint=_("use 'hg update' or see 'hg help revert'"))
6146 hint=_("use 'hg update' or see 'hg help revert'"))
6148
6147
6149 ctx = scmutil.revsingle(repo, opts.get('rev'))
6148 ctx = scmutil.revsingle(repo, opts.get('rev'))
6150
6149
6151 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
6152 opts.get('all') or opts.get('interactive'))):
6151 opts.get('all') or opts.get('interactive'))):
6153 msg = _("no files or directories specified")
6152 msg = _("no files or directories specified")
6154 if p2 != nullid:
6153 if p2 != nullid:
6155 hint = _("uncommitted merge, use --all to discard all changes,"
6154 hint = _("uncommitted merge, use --all to discard all changes,"
6156 " or 'hg update -C .' to abort the merge")
6155 " or 'hg update -C .' to abort the merge")
6157 raise error.Abort(msg, hint=hint)
6156 raise error.Abort(msg, hint=hint)
6158 dirty = any(repo.status())
6157 dirty = any(repo.status())
6159 node = ctx.node()
6158 node = ctx.node()
6160 if node != parent:
6159 if node != parent:
6161 if dirty:
6160 if dirty:
6162 hint = _("uncommitted changes, use --all to discard all"
6161 hint = _("uncommitted changes, use --all to discard all"
6163 " changes, or 'hg update %s' to update") % ctx.rev()
6162 " changes, or 'hg update %s' to update") % ctx.rev()
6164 else:
6163 else:
6165 hint = _("use --all to revert all files,"
6164 hint = _("use --all to revert all files,"
6166 " or 'hg update %s' to update") % ctx.rev()
6165 " or 'hg update %s' to update") % ctx.rev()
6167 elif dirty:
6166 elif dirty:
6168 hint = _("uncommitted changes, use --all to discard all changes")
6167 hint = _("uncommitted changes, use --all to discard all changes")
6169 else:
6168 else:
6170 hint = _("use --all to revert all files")
6169 hint = _("use --all to revert all files")
6171 raise error.Abort(msg, hint=hint)
6170 raise error.Abort(msg, hint=hint)
6172
6171
6173 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6172 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6174
6173
6175 @command('rollback', dryrunopts +
6174 @command('rollback', dryrunopts +
6176 [('f', 'force', False, _('ignore safety measures'))])
6175 [('f', 'force', False, _('ignore safety measures'))])
6177 def rollback(ui, repo, **opts):
6176 def rollback(ui, repo, **opts):
6178 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6177 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6179
6178
6180 Please use :hg:`commit --amend` instead of rollback to correct
6179 Please use :hg:`commit --amend` instead of rollback to correct
6181 mistakes in the last commit.
6180 mistakes in the last commit.
6182
6181
6183 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
6184 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
6185 restore the dirstate at the time of the last transaction, losing
6184 restore the dirstate at the time of the last transaction, losing
6186 any dirstate changes since that time. This command does not alter
6185 any dirstate changes since that time. This command does not alter
6187 the working directory.
6186 the working directory.
6188
6187
6189 Transactions are used to encapsulate the effects of all commands
6188 Transactions are used to encapsulate the effects of all commands
6190 that create new changesets or propagate existing changesets into a
6189 that create new changesets or propagate existing changesets into a
6191 repository.
6190 repository.
6192
6191
6193 .. container:: verbose
6192 .. container:: verbose
6194
6193
6195 For example, the following commands are transactional, and their
6194 For example, the following commands are transactional, and their
6196 effects can be rolled back:
6195 effects can be rolled back:
6197
6196
6198 - commit
6197 - commit
6199 - import
6198 - import
6200 - pull
6199 - pull
6201 - push (with this repository as the destination)
6200 - push (with this repository as the destination)
6202 - unbundle
6201 - unbundle
6203
6202
6204 To avoid permanent data loss, rollback will refuse to rollback a
6203 To avoid permanent data loss, rollback will refuse to rollback a
6205 commit transaction if it isn't checked out. Use --force to
6204 commit transaction if it isn't checked out. Use --force to
6206 override this protection.
6205 override this protection.
6207
6206
6208 The rollback command can be entirely disabled by setting the
6207 The rollback command can be entirely disabled by setting the
6209 ``ui.rollback`` configuration setting to false. If you're here
6208 ``ui.rollback`` configuration setting to false. If you're here
6210 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
6211 re-enable the command by setting ``ui.rollback`` to true.
6210 re-enable the command by setting ``ui.rollback`` to true.
6212
6211
6213 This command is not intended for use on public repositories. Once
6212 This command is not intended for use on public repositories. Once
6214 changes are visible for pull by other users, rolling a transaction
6213 changes are visible for pull by other users, rolling a transaction
6215 back locally is ineffective (someone else may already have pulled
6214 back locally is ineffective (someone else may already have pulled
6216 the changes). Furthermore, a race is possible with readers of the
6215 the changes). Furthermore, a race is possible with readers of the
6217 repository; for example an in-progress pull from the repository
6216 repository; for example an in-progress pull from the repository
6218 may fail if a rollback is performed.
6217 may fail if a rollback is performed.
6219
6218
6220 Returns 0 on success, 1 if no rollback data is available.
6219 Returns 0 on success, 1 if no rollback data is available.
6221 """
6220 """
6222 if not ui.configbool('ui', 'rollback', True):
6221 if not ui.configbool('ui', 'rollback', True):
6223 raise error.Abort(_('rollback is disabled because it is unsafe'),
6222 raise error.Abort(_('rollback is disabled because it is unsafe'),
6224 hint=('see `hg help -v rollback` for information'))
6223 hint=('see `hg help -v rollback` for information'))
6225 return repo.rollback(dryrun=opts.get('dry_run'),
6224 return repo.rollback(dryrun=opts.get('dry_run'),
6226 force=opts.get('force'))
6225 force=opts.get('force'))
6227
6226
6228 @command('root', [])
6227 @command('root', [])
6229 def root(ui, repo):
6228 def root(ui, repo):
6230 """print the root (top) of the current working directory
6229 """print the root (top) of the current working directory
6231
6230
6232 Print the root directory of the current repository.
6231 Print the root directory of the current repository.
6233
6232
6234 Returns 0 on success.
6233 Returns 0 on success.
6235 """
6234 """
6236 ui.write(repo.root + "\n")
6235 ui.write(repo.root + "\n")
6237
6236
6238 @command('^serve',
6237 @command('^serve',
6239 [('A', 'accesslog', '', _('name of access log file to write to'),
6238 [('A', 'accesslog', '', _('name of access log file to write to'),
6240 _('FILE')),
6239 _('FILE')),
6241 ('d', 'daemon', None, _('run server in background')),
6240 ('d', 'daemon', None, _('run server in background')),
6242 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6241 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6243 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6242 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6244 # use string type, then we can check if something was passed
6243 # use string type, then we can check if something was passed
6245 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6244 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6246 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6245 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6247 _('ADDR')),
6246 _('ADDR')),
6248 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6247 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6249 _('PREFIX')),
6248 _('PREFIX')),
6250 ('n', 'name', '',
6249 ('n', 'name', '',
6251 _('name to show in web pages (default: working directory)'), _('NAME')),
6250 _('name to show in web pages (default: working directory)'), _('NAME')),
6252 ('', 'web-conf', '',
6251 ('', 'web-conf', '',
6253 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
6252 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
6254 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6253 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6255 _('FILE')),
6254 _('FILE')),
6256 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6255 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6257 ('', 'stdio', None, _('for remote clients')),
6256 ('', 'stdio', None, _('for remote clients')),
6258 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6257 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6259 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6258 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6260 ('', 'style', '', _('template style to use'), _('STYLE')),
6259 ('', 'style', '', _('template style to use'), _('STYLE')),
6261 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6260 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6262 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6261 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6263 _('[OPTION]...'),
6262 _('[OPTION]...'),
6264 optionalrepo=True)
6263 optionalrepo=True)
6265 def serve(ui, repo, **opts):
6264 def serve(ui, repo, **opts):
6266 """start stand-alone webserver
6265 """start stand-alone webserver
6267
6266
6268 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
6269 this for ad-hoc sharing and browsing of repositories. It is
6268 this for ad-hoc sharing and browsing of repositories. It is
6270 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
6271 longer periods of time.
6270 longer periods of time.
6272
6271
6273 Please note that the server does not implement access control.
6272 Please note that the server does not implement access control.
6274 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
6275 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``
6276 option to ``*`` to allow everybody to push to the server. You
6275 option to ``*`` to allow everybody to push to the server. You
6277 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.
6278
6277
6279 By default, the server logs accesses to stdout and errors to
6278 By default, the server logs accesses to stdout and errors to
6280 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
6281 files.
6280 files.
6282
6281
6283 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
6284 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
6285 number it uses.
6284 number it uses.
6286
6285
6287 Returns 0 on success.
6286 Returns 0 on success.
6288 """
6287 """
6289
6288
6290 if opts["stdio"] and opts["cmdserver"]:
6289 if opts["stdio"] and opts["cmdserver"]:
6291 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6290 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6292
6291
6293 if opts["stdio"]:
6292 if opts["stdio"]:
6294 if repo is None:
6293 if repo is None:
6295 raise error.RepoError(_("there is no Mercurial repository here"
6294 raise error.RepoError(_("there is no Mercurial repository here"
6296 " (.hg not found)"))
6295 " (.hg not found)"))
6297 s = sshserver.sshserver(ui, repo)
6296 s = sshserver.sshserver(ui, repo)
6298 s.serve_forever()
6297 s.serve_forever()
6299
6298
6300 if opts["cmdserver"]:
6299 if opts["cmdserver"]:
6301 service = server.createcmdservice(ui, repo, opts)
6300 service = server.createcmdservice(ui, repo, opts)
6302 else:
6301 else:
6303 service = hgweb.createservice(ui, repo, opts)
6302 service = server.createhgwebservice(ui, repo, opts)
6304 return server.runservice(opts, initfn=service.init, runfn=service.run)
6303 return server.runservice(opts, initfn=service.init, runfn=service.run)
6305
6304
6306 @command('^status|st',
6305 @command('^status|st',
6307 [('A', 'all', None, _('show status of all files')),
6306 [('A', 'all', None, _('show status of all files')),
6308 ('m', 'modified', None, _('show only modified files')),
6307 ('m', 'modified', None, _('show only modified files')),
6309 ('a', 'added', None, _('show only added files')),
6308 ('a', 'added', None, _('show only added files')),
6310 ('r', 'removed', None, _('show only removed files')),
6309 ('r', 'removed', None, _('show only removed files')),
6311 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6310 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6312 ('c', 'clean', None, _('show only files without changes')),
6311 ('c', 'clean', None, _('show only files without changes')),
6313 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6312 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6314 ('i', 'ignored', None, _('show only ignored files')),
6313 ('i', 'ignored', None, _('show only ignored files')),
6315 ('n', 'no-status', None, _('hide status prefix')),
6314 ('n', 'no-status', None, _('hide status prefix')),
6316 ('C', 'copies', None, _('show source of copied files')),
6315 ('C', 'copies', None, _('show source of copied files')),
6317 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6316 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6318 ('', 'rev', [], _('show difference from revision'), _('REV')),
6317 ('', 'rev', [], _('show difference from revision'), _('REV')),
6319 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6318 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6320 ] + walkopts + subrepoopts + formatteropts,
6319 ] + walkopts + subrepoopts + formatteropts,
6321 _('[OPTION]... [FILE]...'),
6320 _('[OPTION]... [FILE]...'),
6322 inferrepo=True)
6321 inferrepo=True)
6323 def status(ui, repo, *pats, **opts):
6322 def status(ui, repo, *pats, **opts):
6324 """show changed files in the working directory
6323 """show changed files in the working directory
6325
6324
6326 Show status of files in the repository. If names are given, only
6325 Show status of files in the repository. If names are given, only
6327 files that match are shown. Files that are clean or ignored or
6326 files that match are shown. Files that are clean or ignored or
6328 the source of a copy/move operation, are not listed unless
6327 the source of a copy/move operation, are not listed unless
6329 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6328 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6330 Unless options described with "show only ..." are given, the
6329 Unless options described with "show only ..." are given, the
6331 options -mardu are used.
6330 options -mardu are used.
6332
6331
6333 Option -q/--quiet hides untracked (unknown and ignored) files
6332 Option -q/--quiet hides untracked (unknown and ignored) files
6334 unless explicitly requested with -u/--unknown or -i/--ignored.
6333 unless explicitly requested with -u/--unknown or -i/--ignored.
6335
6334
6336 .. note::
6335 .. note::
6337
6336
6338 :hg:`status` may appear to disagree with diff if permissions have
6337 :hg:`status` may appear to disagree with diff if permissions have
6339 changed or a merge has occurred. The standard diff format does
6338 changed or a merge has occurred. The standard diff format does
6340 not report permission changes and diff only reports changes
6339 not report permission changes and diff only reports changes
6341 relative to one merge parent.
6340 relative to one merge parent.
6342
6341
6343 If one revision is given, it is used as the base revision.
6342 If one revision is given, it is used as the base revision.
6344 If two revisions are given, the differences between them are
6343 If two revisions are given, the differences between them are
6345 shown. The --change option can also be used as a shortcut to list
6344 shown. The --change option can also be used as a shortcut to list
6346 the changed files of a revision from its first parent.
6345 the changed files of a revision from its first parent.
6347
6346
6348 The codes used to show the status of files are::
6347 The codes used to show the status of files are::
6349
6348
6350 M = modified
6349 M = modified
6351 A = added
6350 A = added
6352 R = removed
6351 R = removed
6353 C = clean
6352 C = clean
6354 ! = missing (deleted by non-hg command, but still tracked)
6353 ! = missing (deleted by non-hg command, but still tracked)
6355 ? = not tracked
6354 ? = not tracked
6356 I = ignored
6355 I = ignored
6357 = origin of the previous file (with --copies)
6356 = origin of the previous file (with --copies)
6358
6357
6359 .. container:: verbose
6358 .. container:: verbose
6360
6359
6361 Examples:
6360 Examples:
6362
6361
6363 - show changes in the working directory relative to a
6362 - show changes in the working directory relative to a
6364 changeset::
6363 changeset::
6365
6364
6366 hg status --rev 9353
6365 hg status --rev 9353
6367
6366
6368 - show changes in the working directory relative to the
6367 - show changes in the working directory relative to the
6369 current directory (see :hg:`help patterns` for more information)::
6368 current directory (see :hg:`help patterns` for more information)::
6370
6369
6371 hg status re:
6370 hg status re:
6372
6371
6373 - show all changes including copies in an existing changeset::
6372 - show all changes including copies in an existing changeset::
6374
6373
6375 hg status --copies --change 9353
6374 hg status --copies --change 9353
6376
6375
6377 - get a NUL separated list of added files, suitable for xargs::
6376 - get a NUL separated list of added files, suitable for xargs::
6378
6377
6379 hg status -an0
6378 hg status -an0
6380
6379
6381 Returns 0 on success.
6380 Returns 0 on success.
6382 """
6381 """
6383
6382
6384 revs = opts.get('rev')
6383 revs = opts.get('rev')
6385 change = opts.get('change')
6384 change = opts.get('change')
6386
6385
6387 if revs and change:
6386 if revs and change:
6388 msg = _('cannot specify --rev and --change at the same time')
6387 msg = _('cannot specify --rev and --change at the same time')
6389 raise error.Abort(msg)
6388 raise error.Abort(msg)
6390 elif change:
6389 elif change:
6391 node2 = scmutil.revsingle(repo, change, None).node()
6390 node2 = scmutil.revsingle(repo, change, None).node()
6392 node1 = repo[node2].p1().node()
6391 node1 = repo[node2].p1().node()
6393 else:
6392 else:
6394 node1, node2 = scmutil.revpair(repo, revs)
6393 node1, node2 = scmutil.revpair(repo, revs)
6395
6394
6396 if pats:
6395 if pats:
6397 cwd = repo.getcwd()
6396 cwd = repo.getcwd()
6398 else:
6397 else:
6399 cwd = ''
6398 cwd = ''
6400
6399
6401 if opts.get('print0'):
6400 if opts.get('print0'):
6402 end = '\0'
6401 end = '\0'
6403 else:
6402 else:
6404 end = '\n'
6403 end = '\n'
6405 copy = {}
6404 copy = {}
6406 states = 'modified added removed deleted unknown ignored clean'.split()
6405 states = 'modified added removed deleted unknown ignored clean'.split()
6407 show = [k for k in states if opts.get(k)]
6406 show = [k for k in states if opts.get(k)]
6408 if opts.get('all'):
6407 if opts.get('all'):
6409 show += ui.quiet and (states[:4] + ['clean']) or states
6408 show += ui.quiet and (states[:4] + ['clean']) or states
6410 if not show:
6409 if not show:
6411 if ui.quiet:
6410 if ui.quiet:
6412 show = states[:4]
6411 show = states[:4]
6413 else:
6412 else:
6414 show = states[:5]
6413 show = states[:5]
6415
6414
6416 m = scmutil.match(repo[node2], pats, opts)
6415 m = scmutil.match(repo[node2], pats, opts)
6417 stat = repo.status(node1, node2, m,
6416 stat = repo.status(node1, node2, m,
6418 'ignored' in show, 'clean' in show, 'unknown' in show,
6417 'ignored' in show, 'clean' in show, 'unknown' in show,
6419 opts.get('subrepos'))
6418 opts.get('subrepos'))
6420 changestates = zip(states, 'MAR!?IC', stat)
6419 changestates = zip(states, 'MAR!?IC', stat)
6421
6420
6422 if (opts.get('all') or opts.get('copies')
6421 if (opts.get('all') or opts.get('copies')
6423 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6422 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6424 copy = copies.pathcopies(repo[node1], repo[node2], m)
6423 copy = copies.pathcopies(repo[node1], repo[node2], m)
6425
6424
6426 fm = ui.formatter('status', opts)
6425 fm = ui.formatter('status', opts)
6427 fmt = '%s' + end
6426 fmt = '%s' + end
6428 showchar = not opts.get('no_status')
6427 showchar = not opts.get('no_status')
6429
6428
6430 for state, char, files in changestates:
6429 for state, char, files in changestates:
6431 if state in show:
6430 if state in show:
6432 label = 'status.' + state
6431 label = 'status.' + state
6433 for f in files:
6432 for f in files:
6434 fm.startitem()
6433 fm.startitem()
6435 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6434 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6436 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6435 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6437 if f in copy:
6436 if f in copy:
6438 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6437 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6439 label='status.copied')
6438 label='status.copied')
6440 fm.end()
6439 fm.end()
6441
6440
6442 @command('^summary|sum',
6441 @command('^summary|sum',
6443 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6442 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6444 def summary(ui, repo, **opts):
6443 def summary(ui, repo, **opts):
6445 """summarize working directory state
6444 """summarize working directory state
6446
6445
6447 This generates a brief summary of the working directory state,
6446 This generates a brief summary of the working directory state,
6448 including parents, branch, commit status, phase and available updates.
6447 including parents, branch, commit status, phase and available updates.
6449
6448
6450 With the --remote option, this will check the default paths for
6449 With the --remote option, this will check the default paths for
6451 incoming and outgoing changes. This can be time-consuming.
6450 incoming and outgoing changes. This can be time-consuming.
6452
6451
6453 Returns 0 on success.
6452 Returns 0 on success.
6454 """
6453 """
6455
6454
6456 ctx = repo[None]
6455 ctx = repo[None]
6457 parents = ctx.parents()
6456 parents = ctx.parents()
6458 pnode = parents[0].node()
6457 pnode = parents[0].node()
6459 marks = []
6458 marks = []
6460
6459
6461 ms = None
6460 ms = None
6462 try:
6461 try:
6463 ms = mergemod.mergestate.read(repo)
6462 ms = mergemod.mergestate.read(repo)
6464 except error.UnsupportedMergeRecords as e:
6463 except error.UnsupportedMergeRecords as e:
6465 s = ' '.join(e.recordtypes)
6464 s = ' '.join(e.recordtypes)
6466 ui.warn(
6465 ui.warn(
6467 _('warning: merge state has unsupported record types: %s\n') % s)
6466 _('warning: merge state has unsupported record types: %s\n') % s)
6468 unresolved = 0
6467 unresolved = 0
6469 else:
6468 else:
6470 unresolved = [f for f in ms if ms[f] == 'u']
6469 unresolved = [f for f in ms if ms[f] == 'u']
6471
6470
6472 for p in parents:
6471 for p in parents:
6473 # label with log.changeset (instead of log.parent) since this
6472 # label with log.changeset (instead of log.parent) since this
6474 # shows a working directory parent *changeset*:
6473 # shows a working directory parent *changeset*:
6475 # i18n: column positioning for "hg summary"
6474 # i18n: column positioning for "hg summary"
6476 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6475 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6477 label='log.changeset changeset.%s' % p.phasestr())
6476 label='log.changeset changeset.%s' % p.phasestr())
6478 ui.write(' '.join(p.tags()), label='log.tag')
6477 ui.write(' '.join(p.tags()), label='log.tag')
6479 if p.bookmarks():
6478 if p.bookmarks():
6480 marks.extend(p.bookmarks())
6479 marks.extend(p.bookmarks())
6481 if p.rev() == -1:
6480 if p.rev() == -1:
6482 if not len(repo):
6481 if not len(repo):
6483 ui.write(_(' (empty repository)'))
6482 ui.write(_(' (empty repository)'))
6484 else:
6483 else:
6485 ui.write(_(' (no revision checked out)'))
6484 ui.write(_(' (no revision checked out)'))
6486 ui.write('\n')
6485 ui.write('\n')
6487 if p.description():
6486 if p.description():
6488 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6487 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6489 label='log.summary')
6488 label='log.summary')
6490
6489
6491 branch = ctx.branch()
6490 branch = ctx.branch()
6492 bheads = repo.branchheads(branch)
6491 bheads = repo.branchheads(branch)
6493 # i18n: column positioning for "hg summary"
6492 # i18n: column positioning for "hg summary"
6494 m = _('branch: %s\n') % branch
6493 m = _('branch: %s\n') % branch
6495 if branch != 'default':
6494 if branch != 'default':
6496 ui.write(m, label='log.branch')
6495 ui.write(m, label='log.branch')
6497 else:
6496 else:
6498 ui.status(m, label='log.branch')
6497 ui.status(m, label='log.branch')
6499
6498
6500 if marks:
6499 if marks:
6501 active = repo._activebookmark
6500 active = repo._activebookmark
6502 # i18n: column positioning for "hg summary"
6501 # i18n: column positioning for "hg summary"
6503 ui.write(_('bookmarks:'), label='log.bookmark')
6502 ui.write(_('bookmarks:'), label='log.bookmark')
6504 if active is not None:
6503 if active is not None:
6505 if active in marks:
6504 if active in marks:
6506 ui.write(' *' + active, label=activebookmarklabel)
6505 ui.write(' *' + active, label=activebookmarklabel)
6507 marks.remove(active)
6506 marks.remove(active)
6508 else:
6507 else:
6509 ui.write(' [%s]' % active, label=activebookmarklabel)
6508 ui.write(' [%s]' % active, label=activebookmarklabel)
6510 for m in marks:
6509 for m in marks:
6511 ui.write(' ' + m, label='log.bookmark')
6510 ui.write(' ' + m, label='log.bookmark')
6512 ui.write('\n', label='log.bookmark')
6511 ui.write('\n', label='log.bookmark')
6513
6512
6514 status = repo.status(unknown=True)
6513 status = repo.status(unknown=True)
6515
6514
6516 c = repo.dirstate.copies()
6515 c = repo.dirstate.copies()
6517 copied, renamed = [], []
6516 copied, renamed = [], []
6518 for d, s in c.iteritems():
6517 for d, s in c.iteritems():
6519 if s in status.removed:
6518 if s in status.removed:
6520 status.removed.remove(s)
6519 status.removed.remove(s)
6521 renamed.append(d)
6520 renamed.append(d)
6522 else:
6521 else:
6523 copied.append(d)
6522 copied.append(d)
6524 if d in status.added:
6523 if d in status.added:
6525 status.added.remove(d)
6524 status.added.remove(d)
6526
6525
6527 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6526 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6528
6527
6529 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6528 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6530 (ui.label(_('%d added'), 'status.added'), status.added),
6529 (ui.label(_('%d added'), 'status.added'), status.added),
6531 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6530 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6532 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6531 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6533 (ui.label(_('%d copied'), 'status.copied'), copied),
6532 (ui.label(_('%d copied'), 'status.copied'), copied),
6534 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6533 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6535 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6534 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6536 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6535 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6537 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6536 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6538 t = []
6537 t = []
6539 for l, s in labels:
6538 for l, s in labels:
6540 if s:
6539 if s:
6541 t.append(l % len(s))
6540 t.append(l % len(s))
6542
6541
6543 t = ', '.join(t)
6542 t = ', '.join(t)
6544 cleanworkdir = False
6543 cleanworkdir = False
6545
6544
6546 if repo.vfs.exists('graftstate'):
6545 if repo.vfs.exists('graftstate'):
6547 t += _(' (graft in progress)')
6546 t += _(' (graft in progress)')
6548 if repo.vfs.exists('updatestate'):
6547 if repo.vfs.exists('updatestate'):
6549 t += _(' (interrupted update)')
6548 t += _(' (interrupted update)')
6550 elif len(parents) > 1:
6549 elif len(parents) > 1:
6551 t += _(' (merge)')
6550 t += _(' (merge)')
6552 elif branch != parents[0].branch():
6551 elif branch != parents[0].branch():
6553 t += _(' (new branch)')
6552 t += _(' (new branch)')
6554 elif (parents[0].closesbranch() and
6553 elif (parents[0].closesbranch() and
6555 pnode in repo.branchheads(branch, closed=True)):
6554 pnode in repo.branchheads(branch, closed=True)):
6556 t += _(' (head closed)')
6555 t += _(' (head closed)')
6557 elif not (status.modified or status.added or status.removed or renamed or
6556 elif not (status.modified or status.added or status.removed or renamed or
6558 copied or subs):
6557 copied or subs):
6559 t += _(' (clean)')
6558 t += _(' (clean)')
6560 cleanworkdir = True
6559 cleanworkdir = True
6561 elif pnode not in bheads:
6560 elif pnode not in bheads:
6562 t += _(' (new branch head)')
6561 t += _(' (new branch head)')
6563
6562
6564 if parents:
6563 if parents:
6565 pendingphase = max(p.phase() for p in parents)
6564 pendingphase = max(p.phase() for p in parents)
6566 else:
6565 else:
6567 pendingphase = phases.public
6566 pendingphase = phases.public
6568
6567
6569 if pendingphase > phases.newcommitphase(ui):
6568 if pendingphase > phases.newcommitphase(ui):
6570 t += ' (%s)' % phases.phasenames[pendingphase]
6569 t += ' (%s)' % phases.phasenames[pendingphase]
6571
6570
6572 if cleanworkdir:
6571 if cleanworkdir:
6573 # i18n: column positioning for "hg summary"
6572 # i18n: column positioning for "hg summary"
6574 ui.status(_('commit: %s\n') % t.strip())
6573 ui.status(_('commit: %s\n') % t.strip())
6575 else:
6574 else:
6576 # i18n: column positioning for "hg summary"
6575 # i18n: column positioning for "hg summary"
6577 ui.write(_('commit: %s\n') % t.strip())
6576 ui.write(_('commit: %s\n') % t.strip())
6578
6577
6579 # all ancestors of branch heads - all ancestors of parent = new csets
6578 # all ancestors of branch heads - all ancestors of parent = new csets
6580 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6579 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6581 bheads))
6580 bheads))
6582
6581
6583 if new == 0:
6582 if new == 0:
6584 # i18n: column positioning for "hg summary"
6583 # i18n: column positioning for "hg summary"
6585 ui.status(_('update: (current)\n'))
6584 ui.status(_('update: (current)\n'))
6586 elif pnode not in bheads:
6585 elif pnode not in bheads:
6587 # i18n: column positioning for "hg summary"
6586 # i18n: column positioning for "hg summary"
6588 ui.write(_('update: %d new changesets (update)\n') % new)
6587 ui.write(_('update: %d new changesets (update)\n') % new)
6589 else:
6588 else:
6590 # i18n: column positioning for "hg summary"
6589 # i18n: column positioning for "hg summary"
6591 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6590 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6592 (new, len(bheads)))
6591 (new, len(bheads)))
6593
6592
6594 t = []
6593 t = []
6595 draft = len(repo.revs('draft()'))
6594 draft = len(repo.revs('draft()'))
6596 if draft:
6595 if draft:
6597 t.append(_('%d draft') % draft)
6596 t.append(_('%d draft') % draft)
6598 secret = len(repo.revs('secret()'))
6597 secret = len(repo.revs('secret()'))
6599 if secret:
6598 if secret:
6600 t.append(_('%d secret') % secret)
6599 t.append(_('%d secret') % secret)
6601
6600
6602 if draft or secret:
6601 if draft or secret:
6603 ui.status(_('phases: %s\n') % ', '.join(t))
6602 ui.status(_('phases: %s\n') % ', '.join(t))
6604
6603
6605 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6604 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6606 for trouble in ("unstable", "divergent", "bumped"):
6605 for trouble in ("unstable", "divergent", "bumped"):
6607 numtrouble = len(repo.revs(trouble + "()"))
6606 numtrouble = len(repo.revs(trouble + "()"))
6608 # We write all the possibilities to ease translation
6607 # We write all the possibilities to ease translation
6609 troublemsg = {
6608 troublemsg = {
6610 "unstable": _("unstable: %d changesets"),
6609 "unstable": _("unstable: %d changesets"),
6611 "divergent": _("divergent: %d changesets"),
6610 "divergent": _("divergent: %d changesets"),
6612 "bumped": _("bumped: %d changesets"),
6611 "bumped": _("bumped: %d changesets"),
6613 }
6612 }
6614 if numtrouble > 0:
6613 if numtrouble > 0:
6615 ui.status(troublemsg[trouble] % numtrouble + "\n")
6614 ui.status(troublemsg[trouble] % numtrouble + "\n")
6616
6615
6617 cmdutil.summaryhooks(ui, repo)
6616 cmdutil.summaryhooks(ui, repo)
6618
6617
6619 if opts.get('remote'):
6618 if opts.get('remote'):
6620 needsincoming, needsoutgoing = True, True
6619 needsincoming, needsoutgoing = True, True
6621 else:
6620 else:
6622 needsincoming, needsoutgoing = False, False
6621 needsincoming, needsoutgoing = False, False
6623 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6622 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6624 if i:
6623 if i:
6625 needsincoming = True
6624 needsincoming = True
6626 if o:
6625 if o:
6627 needsoutgoing = True
6626 needsoutgoing = True
6628 if not needsincoming and not needsoutgoing:
6627 if not needsincoming and not needsoutgoing:
6629 return
6628 return
6630
6629
6631 def getincoming():
6630 def getincoming():
6632 source, branches = hg.parseurl(ui.expandpath('default'))
6631 source, branches = hg.parseurl(ui.expandpath('default'))
6633 sbranch = branches[0]
6632 sbranch = branches[0]
6634 try:
6633 try:
6635 other = hg.peer(repo, {}, source)
6634 other = hg.peer(repo, {}, source)
6636 except error.RepoError:
6635 except error.RepoError:
6637 if opts.get('remote'):
6636 if opts.get('remote'):
6638 raise
6637 raise
6639 return source, sbranch, None, None, None
6638 return source, sbranch, None, None, None
6640 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6639 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6641 if revs:
6640 if revs:
6642 revs = [other.lookup(rev) for rev in revs]
6641 revs = [other.lookup(rev) for rev in revs]
6643 ui.debug('comparing with %s\n' % util.hidepassword(source))
6642 ui.debug('comparing with %s\n' % util.hidepassword(source))
6644 repo.ui.pushbuffer()
6643 repo.ui.pushbuffer()
6645 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6644 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6646 repo.ui.popbuffer()
6645 repo.ui.popbuffer()
6647 return source, sbranch, other, commoninc, commoninc[1]
6646 return source, sbranch, other, commoninc, commoninc[1]
6648
6647
6649 if needsincoming:
6648 if needsincoming:
6650 source, sbranch, sother, commoninc, incoming = getincoming()
6649 source, sbranch, sother, commoninc, incoming = getincoming()
6651 else:
6650 else:
6652 source = sbranch = sother = commoninc = incoming = None
6651 source = sbranch = sother = commoninc = incoming = None
6653
6652
6654 def getoutgoing():
6653 def getoutgoing():
6655 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6654 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6656 dbranch = branches[0]
6655 dbranch = branches[0]
6657 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6656 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6658 if source != dest:
6657 if source != dest:
6659 try:
6658 try:
6660 dother = hg.peer(repo, {}, dest)
6659 dother = hg.peer(repo, {}, dest)
6661 except error.RepoError:
6660 except error.RepoError:
6662 if opts.get('remote'):
6661 if opts.get('remote'):
6663 raise
6662 raise
6664 return dest, dbranch, None, None
6663 return dest, dbranch, None, None
6665 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6664 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6666 elif sother is None:
6665 elif sother is None:
6667 # there is no explicit destination peer, but source one is invalid
6666 # there is no explicit destination peer, but source one is invalid
6668 return dest, dbranch, None, None
6667 return dest, dbranch, None, None
6669 else:
6668 else:
6670 dother = sother
6669 dother = sother
6671 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6670 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6672 common = None
6671 common = None
6673 else:
6672 else:
6674 common = commoninc
6673 common = commoninc
6675 if revs:
6674 if revs:
6676 revs = [repo.lookup(rev) for rev in revs]
6675 revs = [repo.lookup(rev) for rev in revs]
6677 repo.ui.pushbuffer()
6676 repo.ui.pushbuffer()
6678 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6677 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6679 commoninc=common)
6678 commoninc=common)
6680 repo.ui.popbuffer()
6679 repo.ui.popbuffer()
6681 return dest, dbranch, dother, outgoing
6680 return dest, dbranch, dother, outgoing
6682
6681
6683 if needsoutgoing:
6682 if needsoutgoing:
6684 dest, dbranch, dother, outgoing = getoutgoing()
6683 dest, dbranch, dother, outgoing = getoutgoing()
6685 else:
6684 else:
6686 dest = dbranch = dother = outgoing = None
6685 dest = dbranch = dother = outgoing = None
6687
6686
6688 if opts.get('remote'):
6687 if opts.get('remote'):
6689 t = []
6688 t = []
6690 if incoming:
6689 if incoming:
6691 t.append(_('1 or more incoming'))
6690 t.append(_('1 or more incoming'))
6692 o = outgoing.missing
6691 o = outgoing.missing
6693 if o:
6692 if o:
6694 t.append(_('%d outgoing') % len(o))
6693 t.append(_('%d outgoing') % len(o))
6695 other = dother or sother
6694 other = dother or sother
6696 if 'bookmarks' in other.listkeys('namespaces'):
6695 if 'bookmarks' in other.listkeys('namespaces'):
6697 counts = bookmarks.summary(repo, other)
6696 counts = bookmarks.summary(repo, other)
6698 if counts[0] > 0:
6697 if counts[0] > 0:
6699 t.append(_('%d incoming bookmarks') % counts[0])
6698 t.append(_('%d incoming bookmarks') % counts[0])
6700 if counts[1] > 0:
6699 if counts[1] > 0:
6701 t.append(_('%d outgoing bookmarks') % counts[1])
6700 t.append(_('%d outgoing bookmarks') % counts[1])
6702
6701
6703 if t:
6702 if t:
6704 # i18n: column positioning for "hg summary"
6703 # i18n: column positioning for "hg summary"
6705 ui.write(_('remote: %s\n') % (', '.join(t)))
6704 ui.write(_('remote: %s\n') % (', '.join(t)))
6706 else:
6705 else:
6707 # i18n: column positioning for "hg summary"
6706 # i18n: column positioning for "hg summary"
6708 ui.status(_('remote: (synced)\n'))
6707 ui.status(_('remote: (synced)\n'))
6709
6708
6710 cmdutil.summaryremotehooks(ui, repo, opts,
6709 cmdutil.summaryremotehooks(ui, repo, opts,
6711 ((source, sbranch, sother, commoninc),
6710 ((source, sbranch, sother, commoninc),
6712 (dest, dbranch, dother, outgoing)))
6711 (dest, dbranch, dother, outgoing)))
6713
6712
6714 @command('tag',
6713 @command('tag',
6715 [('f', 'force', None, _('force tag')),
6714 [('f', 'force', None, _('force tag')),
6716 ('l', 'local', None, _('make the tag local')),
6715 ('l', 'local', None, _('make the tag local')),
6717 ('r', 'rev', '', _('revision to tag'), _('REV')),
6716 ('r', 'rev', '', _('revision to tag'), _('REV')),
6718 ('', 'remove', None, _('remove a tag')),
6717 ('', 'remove', None, _('remove a tag')),
6719 # -l/--local is already there, commitopts cannot be used
6718 # -l/--local is already there, commitopts cannot be used
6720 ('e', 'edit', None, _('invoke editor on commit messages')),
6719 ('e', 'edit', None, _('invoke editor on commit messages')),
6721 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6720 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6722 ] + commitopts2,
6721 ] + commitopts2,
6723 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6722 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6724 def tag(ui, repo, name1, *names, **opts):
6723 def tag(ui, repo, name1, *names, **opts):
6725 """add one or more tags for the current or given revision
6724 """add one or more tags for the current or given revision
6726
6725
6727 Name a particular revision using <name>.
6726 Name a particular revision using <name>.
6728
6727
6729 Tags are used to name particular revisions of the repository and are
6728 Tags are used to name particular revisions of the repository and are
6730 very useful to compare different revisions, to go back to significant
6729 very useful to compare different revisions, to go back to significant
6731 earlier versions or to mark branch points as releases, etc. Changing
6730 earlier versions or to mark branch points as releases, etc. Changing
6732 an existing tag is normally disallowed; use -f/--force to override.
6731 an existing tag is normally disallowed; use -f/--force to override.
6733
6732
6734 If no revision is given, the parent of the working directory is
6733 If no revision is given, the parent of the working directory is
6735 used.
6734 used.
6736
6735
6737 To facilitate version control, distribution, and merging of tags,
6736 To facilitate version control, distribution, and merging of tags,
6738 they are stored as a file named ".hgtags" which is managed similarly
6737 they are stored as a file named ".hgtags" which is managed similarly
6739 to other project files and can be hand-edited if necessary. This
6738 to other project files and can be hand-edited if necessary. This
6740 also means that tagging creates a new commit. The file
6739 also means that tagging creates a new commit. The file
6741 ".hg/localtags" is used for local tags (not shared among
6740 ".hg/localtags" is used for local tags (not shared among
6742 repositories).
6741 repositories).
6743
6742
6744 Tag commits are usually made at the head of a branch. If the parent
6743 Tag commits are usually made at the head of a branch. If the parent
6745 of the working directory is not a branch head, :hg:`tag` aborts; use
6744 of the working directory is not a branch head, :hg:`tag` aborts; use
6746 -f/--force to force the tag commit to be based on a non-head
6745 -f/--force to force the tag commit to be based on a non-head
6747 changeset.
6746 changeset.
6748
6747
6749 See :hg:`help dates` for a list of formats valid for -d/--date.
6748 See :hg:`help dates` for a list of formats valid for -d/--date.
6750
6749
6751 Since tag names have priority over branch names during revision
6750 Since tag names have priority over branch names during revision
6752 lookup, using an existing branch name as a tag name is discouraged.
6751 lookup, using an existing branch name as a tag name is discouraged.
6753
6752
6754 Returns 0 on success.
6753 Returns 0 on success.
6755 """
6754 """
6756 wlock = lock = None
6755 wlock = lock = None
6757 try:
6756 try:
6758 wlock = repo.wlock()
6757 wlock = repo.wlock()
6759 lock = repo.lock()
6758 lock = repo.lock()
6760 rev_ = "."
6759 rev_ = "."
6761 names = [t.strip() for t in (name1,) + names]
6760 names = [t.strip() for t in (name1,) + names]
6762 if len(names) != len(set(names)):
6761 if len(names) != len(set(names)):
6763 raise error.Abort(_('tag names must be unique'))
6762 raise error.Abort(_('tag names must be unique'))
6764 for n in names:
6763 for n in names:
6765 scmutil.checknewlabel(repo, n, 'tag')
6764 scmutil.checknewlabel(repo, n, 'tag')
6766 if not n:
6765 if not n:
6767 raise error.Abort(_('tag names cannot consist entirely of '
6766 raise error.Abort(_('tag names cannot consist entirely of '
6768 'whitespace'))
6767 'whitespace'))
6769 if opts.get('rev') and opts.get('remove'):
6768 if opts.get('rev') and opts.get('remove'):
6770 raise error.Abort(_("--rev and --remove are incompatible"))
6769 raise error.Abort(_("--rev and --remove are incompatible"))
6771 if opts.get('rev'):
6770 if opts.get('rev'):
6772 rev_ = opts['rev']
6771 rev_ = opts['rev']
6773 message = opts.get('message')
6772 message = opts.get('message')
6774 if opts.get('remove'):
6773 if opts.get('remove'):
6775 if opts.get('local'):
6774 if opts.get('local'):
6776 expectedtype = 'local'
6775 expectedtype = 'local'
6777 else:
6776 else:
6778 expectedtype = 'global'
6777 expectedtype = 'global'
6779
6778
6780 for n in names:
6779 for n in names:
6781 if not repo.tagtype(n):
6780 if not repo.tagtype(n):
6782 raise error.Abort(_("tag '%s' does not exist") % n)
6781 raise error.Abort(_("tag '%s' does not exist") % n)
6783 if repo.tagtype(n) != expectedtype:
6782 if repo.tagtype(n) != expectedtype:
6784 if expectedtype == 'global':
6783 if expectedtype == 'global':
6785 raise error.Abort(_("tag '%s' is not a global tag") % n)
6784 raise error.Abort(_("tag '%s' is not a global tag") % n)
6786 else:
6785 else:
6787 raise error.Abort(_("tag '%s' is not a local tag") % n)
6786 raise error.Abort(_("tag '%s' is not a local tag") % n)
6788 rev_ = 'null'
6787 rev_ = 'null'
6789 if not message:
6788 if not message:
6790 # we don't translate commit messages
6789 # we don't translate commit messages
6791 message = 'Removed tag %s' % ', '.join(names)
6790 message = 'Removed tag %s' % ', '.join(names)
6792 elif not opts.get('force'):
6791 elif not opts.get('force'):
6793 for n in names:
6792 for n in names:
6794 if n in repo.tags():
6793 if n in repo.tags():
6795 raise error.Abort(_("tag '%s' already exists "
6794 raise error.Abort(_("tag '%s' already exists "
6796 "(use -f to force)") % n)
6795 "(use -f to force)") % n)
6797 if not opts.get('local'):
6796 if not opts.get('local'):
6798 p1, p2 = repo.dirstate.parents()
6797 p1, p2 = repo.dirstate.parents()
6799 if p2 != nullid:
6798 if p2 != nullid:
6800 raise error.Abort(_('uncommitted merge'))
6799 raise error.Abort(_('uncommitted merge'))
6801 bheads = repo.branchheads()
6800 bheads = repo.branchheads()
6802 if not opts.get('force') and bheads and p1 not in bheads:
6801 if not opts.get('force') and bheads and p1 not in bheads:
6803 raise error.Abort(_('working directory is not at a branch head '
6802 raise error.Abort(_('working directory is not at a branch head '
6804 '(use -f to force)'))
6803 '(use -f to force)'))
6805 r = scmutil.revsingle(repo, rev_).node()
6804 r = scmutil.revsingle(repo, rev_).node()
6806
6805
6807 if not message:
6806 if not message:
6808 # we don't translate commit messages
6807 # we don't translate commit messages
6809 message = ('Added tag %s for changeset %s' %
6808 message = ('Added tag %s for changeset %s' %
6810 (', '.join(names), short(r)))
6809 (', '.join(names), short(r)))
6811
6810
6812 date = opts.get('date')
6811 date = opts.get('date')
6813 if date:
6812 if date:
6814 date = util.parsedate(date)
6813 date = util.parsedate(date)
6815
6814
6816 if opts.get('remove'):
6815 if opts.get('remove'):
6817 editform = 'tag.remove'
6816 editform = 'tag.remove'
6818 else:
6817 else:
6819 editform = 'tag.add'
6818 editform = 'tag.add'
6820 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6819 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6821
6820
6822 # don't allow tagging the null rev
6821 # don't allow tagging the null rev
6823 if (not opts.get('remove') and
6822 if (not opts.get('remove') and
6824 scmutil.revsingle(repo, rev_).rev() == nullrev):
6823 scmutil.revsingle(repo, rev_).rev() == nullrev):
6825 raise error.Abort(_("cannot tag null revision"))
6824 raise error.Abort(_("cannot tag null revision"))
6826
6825
6827 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6826 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6828 editor=editor)
6827 editor=editor)
6829 finally:
6828 finally:
6830 release(lock, wlock)
6829 release(lock, wlock)
6831
6830
6832 @command('tags', formatteropts, '')
6831 @command('tags', formatteropts, '')
6833 def tags(ui, repo, **opts):
6832 def tags(ui, repo, **opts):
6834 """list repository tags
6833 """list repository tags
6835
6834
6836 This lists both regular and local tags. When the -v/--verbose
6835 This lists both regular and local tags. When the -v/--verbose
6837 switch is used, a third column "local" is printed for local tags.
6836 switch is used, a third column "local" is printed for local tags.
6838 When the -q/--quiet switch is used, only the tag name is printed.
6837 When the -q/--quiet switch is used, only the tag name is printed.
6839
6838
6840 Returns 0 on success.
6839 Returns 0 on success.
6841 """
6840 """
6842
6841
6843 fm = ui.formatter('tags', opts)
6842 fm = ui.formatter('tags', opts)
6844 hexfunc = fm.hexfunc
6843 hexfunc = fm.hexfunc
6845 tagtype = ""
6844 tagtype = ""
6846
6845
6847 for t, n in reversed(repo.tagslist()):
6846 for t, n in reversed(repo.tagslist()):
6848 hn = hexfunc(n)
6847 hn = hexfunc(n)
6849 label = 'tags.normal'
6848 label = 'tags.normal'
6850 tagtype = ''
6849 tagtype = ''
6851 if repo.tagtype(t) == 'local':
6850 if repo.tagtype(t) == 'local':
6852 label = 'tags.local'
6851 label = 'tags.local'
6853 tagtype = 'local'
6852 tagtype = 'local'
6854
6853
6855 fm.startitem()
6854 fm.startitem()
6856 fm.write('tag', '%s', t, label=label)
6855 fm.write('tag', '%s', t, label=label)
6857 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6856 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6858 fm.condwrite(not ui.quiet, 'rev node', fmt,
6857 fm.condwrite(not ui.quiet, 'rev node', fmt,
6859 repo.changelog.rev(n), hn, label=label)
6858 repo.changelog.rev(n), hn, label=label)
6860 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6859 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6861 tagtype, label=label)
6860 tagtype, label=label)
6862 fm.plain('\n')
6861 fm.plain('\n')
6863 fm.end()
6862 fm.end()
6864
6863
6865 @command('tip',
6864 @command('tip',
6866 [('p', 'patch', None, _('show patch')),
6865 [('p', 'patch', None, _('show patch')),
6867 ('g', 'git', None, _('use git extended diff format')),
6866 ('g', 'git', None, _('use git extended diff format')),
6868 ] + templateopts,
6867 ] + templateopts,
6869 _('[-p] [-g]'))
6868 _('[-p] [-g]'))
6870 def tip(ui, repo, **opts):
6869 def tip(ui, repo, **opts):
6871 """show the tip revision (DEPRECATED)
6870 """show the tip revision (DEPRECATED)
6872
6871
6873 The tip revision (usually just called the tip) is the changeset
6872 The tip revision (usually just called the tip) is the changeset
6874 most recently added to the repository (and therefore the most
6873 most recently added to the repository (and therefore the most
6875 recently changed head).
6874 recently changed head).
6876
6875
6877 If you have just made a commit, that commit will be the tip. If
6876 If you have just made a commit, that commit will be the tip. If
6878 you have just pulled changes from another repository, the tip of
6877 you have just pulled changes from another repository, the tip of
6879 that repository becomes the current tip. The "tip" tag is special
6878 that repository becomes the current tip. The "tip" tag is special
6880 and cannot be renamed or assigned to a different changeset.
6879 and cannot be renamed or assigned to a different changeset.
6881
6880
6882 This command is deprecated, please use :hg:`heads` instead.
6881 This command is deprecated, please use :hg:`heads` instead.
6883
6882
6884 Returns 0 on success.
6883 Returns 0 on success.
6885 """
6884 """
6886 displayer = cmdutil.show_changeset(ui, repo, opts)
6885 displayer = cmdutil.show_changeset(ui, repo, opts)
6887 displayer.show(repo['tip'])
6886 displayer.show(repo['tip'])
6888 displayer.close()
6887 displayer.close()
6889
6888
6890 @command('unbundle',
6889 @command('unbundle',
6891 [('u', 'update', None,
6890 [('u', 'update', None,
6892 _('update to new branch head if changesets were unbundled'))],
6891 _('update to new branch head if changesets were unbundled'))],
6893 _('[-u] FILE...'))
6892 _('[-u] FILE...'))
6894 def unbundle(ui, repo, fname1, *fnames, **opts):
6893 def unbundle(ui, repo, fname1, *fnames, **opts):
6895 """apply one or more changegroup files
6894 """apply one or more changegroup files
6896
6895
6897 Apply one or more compressed changegroup files generated by the
6896 Apply one or more compressed changegroup files generated by the
6898 bundle command.
6897 bundle command.
6899
6898
6900 Returns 0 on success, 1 if an update has unresolved files.
6899 Returns 0 on success, 1 if an update has unresolved files.
6901 """
6900 """
6902 fnames = (fname1,) + fnames
6901 fnames = (fname1,) + fnames
6903
6902
6904 with repo.lock():
6903 with repo.lock():
6905 for fname in fnames:
6904 for fname in fnames:
6906 f = hg.openpath(ui, fname)
6905 f = hg.openpath(ui, fname)
6907 gen = exchange.readbundle(ui, f, fname)
6906 gen = exchange.readbundle(ui, f, fname)
6908 if isinstance(gen, bundle2.unbundle20):
6907 if isinstance(gen, bundle2.unbundle20):
6909 tr = repo.transaction('unbundle')
6908 tr = repo.transaction('unbundle')
6910 try:
6909 try:
6911 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6910 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6912 url='bundle:' + fname)
6911 url='bundle:' + fname)
6913 tr.close()
6912 tr.close()
6914 except error.BundleUnknownFeatureError as exc:
6913 except error.BundleUnknownFeatureError as exc:
6915 raise error.Abort(_('%s: unknown bundle feature, %s')
6914 raise error.Abort(_('%s: unknown bundle feature, %s')
6916 % (fname, exc),
6915 % (fname, exc),
6917 hint=_("see https://mercurial-scm.org/"
6916 hint=_("see https://mercurial-scm.org/"
6918 "wiki/BundleFeature for more "
6917 "wiki/BundleFeature for more "
6919 "information"))
6918 "information"))
6920 finally:
6919 finally:
6921 if tr:
6920 if tr:
6922 tr.release()
6921 tr.release()
6923 changes = [r.get('return', 0)
6922 changes = [r.get('return', 0)
6924 for r in op.records['changegroup']]
6923 for r in op.records['changegroup']]
6925 modheads = changegroup.combineresults(changes)
6924 modheads = changegroup.combineresults(changes)
6926 elif isinstance(gen, streamclone.streamcloneapplier):
6925 elif isinstance(gen, streamclone.streamcloneapplier):
6927 raise error.Abort(
6926 raise error.Abort(
6928 _('packed bundles cannot be applied with '
6927 _('packed bundles cannot be applied with '
6929 '"hg unbundle"'),
6928 '"hg unbundle"'),
6930 hint=_('use "hg debugapplystreamclonebundle"'))
6929 hint=_('use "hg debugapplystreamclonebundle"'))
6931 else:
6930 else:
6932 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6931 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6933
6932
6934 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
6933 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
6935
6934
6936 @command('^update|up|checkout|co',
6935 @command('^update|up|checkout|co',
6937 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6936 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6938 ('c', 'check', None, _('require clean working directory')),
6937 ('c', 'check', None, _('require clean working directory')),
6939 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6938 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6940 ('r', 'rev', '', _('revision'), _('REV'))
6939 ('r', 'rev', '', _('revision'), _('REV'))
6941 ] + mergetoolopts,
6940 ] + mergetoolopts,
6942 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6941 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6943 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6942 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6944 tool=None):
6943 tool=None):
6945 """update working directory (or switch revisions)
6944 """update working directory (or switch revisions)
6946
6945
6947 Update the repository's working directory to the specified
6946 Update the repository's working directory to the specified
6948 changeset. If no changeset is specified, update to the tip of the
6947 changeset. If no changeset is specified, update to the tip of the
6949 current named branch and move the active bookmark (see :hg:`help
6948 current named branch and move the active bookmark (see :hg:`help
6950 bookmarks`).
6949 bookmarks`).
6951
6950
6952 Update sets the working directory's parent revision to the specified
6951 Update sets the working directory's parent revision to the specified
6953 changeset (see :hg:`help parents`).
6952 changeset (see :hg:`help parents`).
6954
6953
6955 If the changeset is not a descendant or ancestor of the working
6954 If the changeset is not a descendant or ancestor of the working
6956 directory's parent, the update is aborted. With the -c/--check
6955 directory's parent, the update is aborted. With the -c/--check
6957 option, the working directory is checked for uncommitted changes; if
6956 option, the working directory is checked for uncommitted changes; if
6958 none are found, the working directory is updated to the specified
6957 none are found, the working directory is updated to the specified
6959 changeset.
6958 changeset.
6960
6959
6961 .. container:: verbose
6960 .. container:: verbose
6962
6961
6963 The following rules apply when the working directory contains
6962 The following rules apply when the working directory contains
6964 uncommitted changes:
6963 uncommitted changes:
6965
6964
6966 1. If neither -c/--check nor -C/--clean is specified, and if
6965 1. If neither -c/--check nor -C/--clean is specified, and if
6967 the requested changeset is an ancestor or descendant of
6966 the requested changeset is an ancestor or descendant of
6968 the working directory's parent, the uncommitted changes
6967 the working directory's parent, the uncommitted changes
6969 are merged into the requested changeset and the merged
6968 are merged into the requested changeset and the merged
6970 result is left uncommitted. If the requested changeset is
6969 result is left uncommitted. If the requested changeset is
6971 not an ancestor or descendant (that is, it is on another
6970 not an ancestor or descendant (that is, it is on another
6972 branch), the update is aborted and the uncommitted changes
6971 branch), the update is aborted and the uncommitted changes
6973 are preserved.
6972 are preserved.
6974
6973
6975 2. With the -c/--check option, the update is aborted and the
6974 2. With the -c/--check option, the update is aborted and the
6976 uncommitted changes are preserved.
6975 uncommitted changes are preserved.
6977
6976
6978 3. With the -C/--clean option, uncommitted changes are discarded and
6977 3. With the -C/--clean option, uncommitted changes are discarded and
6979 the working directory is updated to the requested changeset.
6978 the working directory is updated to the requested changeset.
6980
6979
6981 To cancel an uncommitted merge (and lose your changes), use
6980 To cancel an uncommitted merge (and lose your changes), use
6982 :hg:`update --clean .`.
6981 :hg:`update --clean .`.
6983
6982
6984 Use null as the changeset to remove the working directory (like
6983 Use null as the changeset to remove the working directory (like
6985 :hg:`clone -U`).
6984 :hg:`clone -U`).
6986
6985
6987 If you want to revert just one file to an older revision, use
6986 If you want to revert just one file to an older revision, use
6988 :hg:`revert [-r REV] NAME`.
6987 :hg:`revert [-r REV] NAME`.
6989
6988
6990 See :hg:`help dates` for a list of formats valid for -d/--date.
6989 See :hg:`help dates` for a list of formats valid for -d/--date.
6991
6990
6992 Returns 0 on success, 1 if there are unresolved files.
6991 Returns 0 on success, 1 if there are unresolved files.
6993 """
6992 """
6994 if rev and node:
6993 if rev and node:
6995 raise error.Abort(_("please specify just one revision"))
6994 raise error.Abort(_("please specify just one revision"))
6996
6995
6997 if rev is None or rev == '':
6996 if rev is None or rev == '':
6998 rev = node
6997 rev = node
6999
6998
7000 if date and rev is not None:
6999 if date and rev is not None:
7001 raise error.Abort(_("you can't specify a revision and a date"))
7000 raise error.Abort(_("you can't specify a revision and a date"))
7002
7001
7003 if check and clean:
7002 if check and clean:
7004 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7003 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7005
7004
7006 with repo.wlock():
7005 with repo.wlock():
7007 cmdutil.clearunfinished(repo)
7006 cmdutil.clearunfinished(repo)
7008
7007
7009 if date:
7008 if date:
7010 rev = cmdutil.finddate(ui, repo, date)
7009 rev = cmdutil.finddate(ui, repo, date)
7011
7010
7012 # if we defined a bookmark, we have to remember the original name
7011 # if we defined a bookmark, we have to remember the original name
7013 brev = rev
7012 brev = rev
7014 rev = scmutil.revsingle(repo, rev, rev).rev()
7013 rev = scmutil.revsingle(repo, rev, rev).rev()
7015
7014
7016 if check:
7015 if check:
7017 cmdutil.bailifchanged(repo, merge=False)
7016 cmdutil.bailifchanged(repo, merge=False)
7018
7017
7019 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7018 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7020
7019
7021 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7020 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7022
7021
7023 @command('verify', [])
7022 @command('verify', [])
7024 def verify(ui, repo):
7023 def verify(ui, repo):
7025 """verify the integrity of the repository
7024 """verify the integrity of the repository
7026
7025
7027 Verify the integrity of the current repository.
7026 Verify the integrity of the current repository.
7028
7027
7029 This will perform an extensive check of the repository's
7028 This will perform an extensive check of the repository's
7030 integrity, validating the hashes and checksums of each entry in
7029 integrity, validating the hashes and checksums of each entry in
7031 the changelog, manifest, and tracked files, as well as the
7030 the changelog, manifest, and tracked files, as well as the
7032 integrity of their crosslinks and indices.
7031 integrity of their crosslinks and indices.
7033
7032
7034 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7033 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7035 for more information about recovery from corruption of the
7034 for more information about recovery from corruption of the
7036 repository.
7035 repository.
7037
7036
7038 Returns 0 on success, 1 if errors are encountered.
7037 Returns 0 on success, 1 if errors are encountered.
7039 """
7038 """
7040 return hg.verify(repo)
7039 return hg.verify(repo)
7041
7040
7042 @command('version', [] + formatteropts, norepo=True)
7041 @command('version', [] + formatteropts, norepo=True)
7043 def version_(ui, **opts):
7042 def version_(ui, **opts):
7044 """output version and copyright information"""
7043 """output version and copyright information"""
7045 fm = ui.formatter("version", opts)
7044 fm = ui.formatter("version", opts)
7046 fm.startitem()
7045 fm.startitem()
7047 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7046 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
7048 util.version())
7047 util.version())
7049 license = _(
7048 license = _(
7050 "(see https://mercurial-scm.org for more information)\n"
7049 "(see https://mercurial-scm.org for more information)\n"
7051 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7050 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7052 "This is free software; see the source for copying conditions. "
7051 "This is free software; see the source for copying conditions. "
7053 "There is NO\nwarranty; "
7052 "There is NO\nwarranty; "
7054 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7053 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7055 )
7054 )
7056 if not ui.quiet:
7055 if not ui.quiet:
7057 fm.plain(license)
7056 fm.plain(license)
7058
7057
7059 if ui.verbose:
7058 if ui.verbose:
7060 fm.plain(_("\nEnabled extensions:\n\n"))
7059 fm.plain(_("\nEnabled extensions:\n\n"))
7061 # format names and versions into columns
7060 # format names and versions into columns
7062 names = []
7061 names = []
7063 vers = []
7062 vers = []
7064 isinternals = []
7063 isinternals = []
7065 for name, module in extensions.extensions():
7064 for name, module in extensions.extensions():
7066 names.append(name)
7065 names.append(name)
7067 vers.append(extensions.moduleversion(module) or None)
7066 vers.append(extensions.moduleversion(module) or None)
7068 isinternals.append(extensions.ismoduleinternal(module))
7067 isinternals.append(extensions.ismoduleinternal(module))
7069 fn = fm.nested("extensions")
7068 fn = fm.nested("extensions")
7070 if names:
7069 if names:
7071 namefmt = " %%-%ds " % max(len(n) for n in names)
7070 namefmt = " %%-%ds " % max(len(n) for n in names)
7072 places = [_("external"), _("internal")]
7071 places = [_("external"), _("internal")]
7073 for n, v, p in zip(names, vers, isinternals):
7072 for n, v, p in zip(names, vers, isinternals):
7074 fn.startitem()
7073 fn.startitem()
7075 fn.condwrite(ui.verbose, "name", namefmt, n)
7074 fn.condwrite(ui.verbose, "name", namefmt, n)
7076 if ui.verbose:
7075 if ui.verbose:
7077 fn.plain("%s " % places[p])
7076 fn.plain("%s " % places[p])
7078 fn.data(bundled=p)
7077 fn.data(bundled=p)
7079 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7078 fn.condwrite(ui.verbose and v, "ver", "%s", v)
7080 if ui.verbose:
7079 if ui.verbose:
7081 fn.plain("\n")
7080 fn.plain("\n")
7082 fn.end()
7081 fn.end()
7083 fm.end()
7082 fm.end()
7084
7083
7085 def loadcmdtable(ui, name, cmdtable):
7084 def loadcmdtable(ui, name, cmdtable):
7086 """Load command functions from specified cmdtable
7085 """Load command functions from specified cmdtable
7087 """
7086 """
7088 overrides = [cmd for cmd in cmdtable if cmd in table]
7087 overrides = [cmd for cmd in cmdtable if cmd in table]
7089 if overrides:
7088 if overrides:
7090 ui.warn(_("extension '%s' overrides commands: %s\n")
7089 ui.warn(_("extension '%s' overrides commands: %s\n")
7091 % (name, " ".join(overrides)))
7090 % (name, " ".join(overrides)))
7092 table.update(cmdtable)
7091 table.update(cmdtable)
@@ -1,128 +1,95 b''
1 # hgweb/__init__.py - web interface to a mercurial repository
1 # hgweb/__init__.py - web interface to a mercurial repository
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 import os
11 import os
12
12
13 from ..i18n import _
13 from ..i18n import _
14
14
15 from .. import (
15 from .. import (
16 error,
16 error,
17 util,
17 util,
18 )
18 )
19
19
20 from . import (
20 from . import (
21 hgweb_mod,
21 hgweb_mod,
22 hgwebdir_mod,
22 hgwebdir_mod,
23 server,
23 server,
24 )
24 )
25
25
26 def hgweb(config, name=None, baseui=None):
26 def hgweb(config, name=None, baseui=None):
27 '''create an hgweb wsgi object
27 '''create an hgweb wsgi object
28
28
29 config can be one of:
29 config can be one of:
30 - repo object (single repo view)
30 - repo object (single repo view)
31 - path to repo (single repo view)
31 - path to repo (single repo view)
32 - path to config file (multi-repo view)
32 - path to config file (multi-repo view)
33 - dict of virtual:real pairs (multi-repo view)
33 - dict of virtual:real pairs (multi-repo view)
34 - list of virtual:real tuples (multi-repo view)
34 - list of virtual:real tuples (multi-repo view)
35 '''
35 '''
36
36
37 if ((isinstance(config, str) and not os.path.isdir(config)) or
37 if ((isinstance(config, str) and not os.path.isdir(config)) or
38 isinstance(config, dict) or isinstance(config, list)):
38 isinstance(config, dict) or isinstance(config, list)):
39 # create a multi-dir interface
39 # create a multi-dir interface
40 return hgwebdir_mod.hgwebdir(config, baseui=baseui)
40 return hgwebdir_mod.hgwebdir(config, baseui=baseui)
41 return hgweb_mod.hgweb(config, name=name, baseui=baseui)
41 return hgweb_mod.hgweb(config, name=name, baseui=baseui)
42
42
43 def hgwebdir(config, baseui=None):
43 def hgwebdir(config, baseui=None):
44 return hgwebdir_mod.hgwebdir(config, baseui=baseui)
44 return hgwebdir_mod.hgwebdir(config, baseui=baseui)
45
45
46 class httpservice(object):
46 class httpservice(object):
47 def __init__(self, ui, app, opts):
47 def __init__(self, ui, app, opts):
48 self.ui = ui
48 self.ui = ui
49 self.app = app
49 self.app = app
50 self.opts = opts
50 self.opts = opts
51
51
52 def init(self):
52 def init(self):
53 util.setsignalhandler()
53 util.setsignalhandler()
54 self.httpd = server.create_server(self.ui, self.app)
54 self.httpd = server.create_server(self.ui, self.app)
55
55
56 if self.opts['port'] and not self.ui.verbose:
56 if self.opts['port'] and not self.ui.verbose:
57 return
57 return
58
58
59 if self.httpd.prefix:
59 if self.httpd.prefix:
60 prefix = self.httpd.prefix.strip('/') + '/'
60 prefix = self.httpd.prefix.strip('/') + '/'
61 else:
61 else:
62 prefix = ''
62 prefix = ''
63
63
64 port = ':%d' % self.httpd.port
64 port = ':%d' % self.httpd.port
65 if port == ':80':
65 if port == ':80':
66 port = ''
66 port = ''
67
67
68 bindaddr = self.httpd.addr
68 bindaddr = self.httpd.addr
69 if bindaddr == '0.0.0.0':
69 if bindaddr == '0.0.0.0':
70 bindaddr = '*'
70 bindaddr = '*'
71 elif ':' in bindaddr: # IPv6
71 elif ':' in bindaddr: # IPv6
72 bindaddr = '[%s]' % bindaddr
72 bindaddr = '[%s]' % bindaddr
73
73
74 fqaddr = self.httpd.fqaddr
74 fqaddr = self.httpd.fqaddr
75 if ':' in fqaddr:
75 if ':' in fqaddr:
76 fqaddr = '[%s]' % fqaddr
76 fqaddr = '[%s]' % fqaddr
77 if self.opts['port']:
77 if self.opts['port']:
78 write = self.ui.status
78 write = self.ui.status
79 else:
79 else:
80 write = self.ui.write
80 write = self.ui.write
81 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
81 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
82 (fqaddr, port, prefix, bindaddr, self.httpd.port))
82 (fqaddr, port, prefix, bindaddr, self.httpd.port))
83 self.ui.flush() # avoid buffering of status message
83 self.ui.flush() # avoid buffering of status message
84
84
85 def run(self):
85 def run(self):
86 self.httpd.serve_forever()
86 self.httpd.serve_forever()
87
87
88 def createservice(ui, repo, opts):
89 # this way we can check if something was given in the command-line
90 if opts.get('port'):
91 opts['port'] = util.getport(opts.get('port'))
92
93 alluis = set([ui])
94 if repo:
95 baseui = repo.baseui
96 alluis.update([repo.baseui, repo.ui])
97 else:
98 baseui = ui
99 webconf = opts.get('web_conf') or opts.get('webdir_conf')
100 if webconf:
101 # load server settings (e.g. web.port) to "copied" ui, which allows
102 # hgwebdir to reload webconf cleanly
103 servui = ui.copy()
104 servui.readconfig(webconf, sections=['web'])
105 alluis.add(servui)
106 else:
107 servui = ui
108
109 optlist = ("name templates style address port prefix ipv6"
110 " accesslog errorlog certificate encoding")
111 for o in optlist.split():
112 val = opts.get(o, '')
113 if val in (None, ''): # should check against default options instead
114 continue
115 for u in alluis:
116 u.setconfig("web", o, val, 'serve')
117
118 app = createapp(baseui, repo, webconf)
119 return httpservice(servui, app, opts)
120
121 def createapp(baseui, repo, webconf):
88 def createapp(baseui, repo, webconf):
122 if webconf:
89 if webconf:
123 return hgwebdir_mod.hgwebdir(webconf, baseui=baseui)
90 return hgwebdir_mod.hgwebdir(webconf, baseui=baseui)
124 else:
91 else:
125 if not repo:
92 if not repo:
126 raise error.RepoError(_("there is no Mercurial repository"
93 raise error.RepoError(_("there is no Mercurial repository"
127 " here (.hg not found)"))
94 " here (.hg not found)"))
128 return hgweb_mod.hgweb(repo, baseui=baseui)
95 return hgweb_mod.hgweb(repo, baseui=baseui)
@@ -1,120 +1,154 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 util,
21 util,
21 )
22 )
22
23
23 def runservice(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
24 def runservice(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
24 runargs=None, appendpid=False):
25 runargs=None, appendpid=False):
25 '''Run a command as a service.'''
26 '''Run a command as a service.'''
26
27
27 def writepid(pid):
28 def writepid(pid):
28 if opts['pid_file']:
29 if opts['pid_file']:
29 if appendpid:
30 if appendpid:
30 mode = 'a'
31 mode = 'a'
31 else:
32 else:
32 mode = 'w'
33 mode = 'w'
33 fp = open(opts['pid_file'], mode)
34 fp = open(opts['pid_file'], mode)
34 fp.write(str(pid) + '\n')
35 fp.write(str(pid) + '\n')
35 fp.close()
36 fp.close()
36
37
37 if opts['daemon'] and not opts['daemon_postexec']:
38 if opts['daemon'] and not opts['daemon_postexec']:
38 # Signal child process startup with file removal
39 # Signal child process startup with file removal
39 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
40 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
40 os.close(lockfd)
41 os.close(lockfd)
41 try:
42 try:
42 if not runargs:
43 if not runargs:
43 runargs = util.hgcmd() + sys.argv[1:]
44 runargs = util.hgcmd() + sys.argv[1:]
44 runargs.append('--daemon-postexec=unlink:%s' % lockpath)
45 runargs.append('--daemon-postexec=unlink:%s' % lockpath)
45 # 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
46 # changed directory.
47 # changed directory.
47 for i in xrange(1, len(runargs)):
48 for i in xrange(1, len(runargs)):
48 if runargs[i].startswith('--cwd='):
49 if runargs[i].startswith('--cwd='):
49 del runargs[i]
50 del runargs[i]
50 break
51 break
51 elif runargs[i].startswith('--cwd'):
52 elif runargs[i].startswith('--cwd'):
52 del runargs[i:i + 2]
53 del runargs[i:i + 2]
53 break
54 break
54 def condfn():
55 def condfn():
55 return not os.path.exists(lockpath)
56 return not os.path.exists(lockpath)
56 pid = util.rundetached(runargs, condfn)
57 pid = util.rundetached(runargs, condfn)
57 if pid < 0:
58 if pid < 0:
58 raise error.Abort(_('child process failed to start'))
59 raise error.Abort(_('child process failed to start'))
59 writepid(pid)
60 writepid(pid)
60 finally:
61 finally:
61 try:
62 try:
62 os.unlink(lockpath)
63 os.unlink(lockpath)
63 except OSError as e:
64 except OSError as e:
64 if e.errno != errno.ENOENT:
65 if e.errno != errno.ENOENT:
65 raise
66 raise
66 if parentfn:
67 if parentfn:
67 return parentfn(pid)
68 return parentfn(pid)
68 else:
69 else:
69 return
70 return
70
71
71 if initfn:
72 if initfn:
72 initfn()
73 initfn()
73
74
74 if not opts['daemon']:
75 if not opts['daemon']:
75 writepid(util.getpid())
76 writepid(util.getpid())
76
77
77 if opts['daemon_postexec']:
78 if opts['daemon_postexec']:
78 try:
79 try:
79 os.setsid()
80 os.setsid()
80 except AttributeError:
81 except AttributeError:
81 pass
82 pass
82 for inst in opts['daemon_postexec']:
83 for inst in opts['daemon_postexec']:
83 if inst.startswith('unlink:'):
84 if inst.startswith('unlink:'):
84 lockpath = inst[7:]
85 lockpath = inst[7:]
85 os.unlink(lockpath)
86 os.unlink(lockpath)
86 elif inst.startswith('chdir:'):
87 elif inst.startswith('chdir:'):
87 os.chdir(inst[6:])
88 os.chdir(inst[6:])
88 elif inst != 'none':
89 elif inst != 'none':
89 raise error.Abort(_('invalid value for --daemon-postexec: %s')
90 raise error.Abort(_('invalid value for --daemon-postexec: %s')
90 % inst)
91 % inst)
91 util.hidewindow()
92 util.hidewindow()
92 util.stdout.flush()
93 util.stdout.flush()
93 util.stderr.flush()
94 util.stderr.flush()
94
95
95 nullfd = os.open(os.devnull, os.O_RDWR)
96 nullfd = os.open(os.devnull, os.O_RDWR)
96 logfilefd = nullfd
97 logfilefd = nullfd
97 if logfile:
98 if logfile:
98 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)
99 os.dup2(nullfd, 0)
100 os.dup2(nullfd, 0)
100 os.dup2(logfilefd, 1)
101 os.dup2(logfilefd, 1)
101 os.dup2(logfilefd, 2)
102 os.dup2(logfilefd, 2)
102 if nullfd not in (0, 1, 2):
103 if nullfd not in (0, 1, 2):
103 os.close(nullfd)
104 os.close(nullfd)
104 if logfile and logfilefd not in (0, 1, 2):
105 if logfile and logfilefd not in (0, 1, 2):
105 os.close(logfilefd)
106 os.close(logfilefd)
106
107
107 if runfn:
108 if runfn:
108 return runfn()
109 return runfn()
109
110
110 _cmdservicemap = {
111 _cmdservicemap = {
111 'pipe': commandserver.pipeservice,
112 'pipe': commandserver.pipeservice,
112 'unix': commandserver.unixforkingservice,
113 'unix': commandserver.unixforkingservice,
113 }
114 }
114
115
115 def createcmdservice(ui, repo, opts):
116 def createcmdservice(ui, repo, opts):
116 mode = opts['cmdserver']
117 mode = opts['cmdserver']
117 try:
118 try:
118 return _cmdservicemap[mode](ui, repo, opts)
119 return _cmdservicemap[mode](ui, repo, opts)
119 except KeyError:
120 except KeyError:
120 raise error.Abort(_('unknown mode %s') % mode)
121 raise error.Abort(_('unknown mode %s') % mode)
122
123 def createhgwebservice(ui, repo, opts):
124 # this way we can check if something was given in the command-line
125 if opts.get('port'):
126 opts['port'] = util.getport(opts.get('port'))
127
128 alluis = set([ui])
129 if repo:
130 baseui = repo.baseui
131 alluis.update([repo.baseui, repo.ui])
132 else:
133 baseui = ui
134 webconf = opts.get('web_conf') or opts.get('webdir_conf')
135 if webconf:
136 # load server settings (e.g. web.port) to "copied" ui, which allows
137 # hgwebdir to reload webconf cleanly
138 servui = ui.copy()
139 servui.readconfig(webconf, sections=['web'])
140 alluis.add(servui)
141 else:
142 servui = ui
143
144 optlist = ("name templates style address port prefix ipv6"
145 " accesslog errorlog certificate encoding")
146 for o in optlist.split():
147 val = opts.get(o, '')
148 if val in (None, ''): # should check against default options instead
149 continue
150 for u in alluis:
151 u.setconfig("web", o, val, 'serve')
152
153 app = hgweb.createapp(baseui, repo, webconf)
154 return hgweb.httpservice(servui, app, opts)
General Comments 0
You need to be logged in to leave comments. Login now