##// END OF EJS Templates
debugcommands: move 'debugstate' in the new module
Pierre-Yves David -
r30954:dad96892 default
parent child Browse files
Show More
@@ -1,5631 +1,5599
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import time
15
14
16 from .i18n import _
15 from .i18n import _
17 from .node import (
16 from .node import (
18 hex,
17 hex,
19 nullid,
18 nullid,
20 nullrev,
19 nullrev,
21 short,
20 short,
22 )
21 )
23 from . import (
22 from . import (
24 archival,
23 archival,
25 bookmarks,
24 bookmarks,
26 bundle2,
25 bundle2,
27 changegroup,
26 changegroup,
28 cmdutil,
27 cmdutil,
29 copies,
28 copies,
30 destutil,
29 destutil,
31 dirstateguard,
30 dirstateguard,
32 discovery,
31 discovery,
33 encoding,
32 encoding,
34 error,
33 error,
35 exchange,
34 exchange,
36 extensions,
35 extensions,
37 formatter,
36 formatter,
38 graphmod,
37 graphmod,
39 hbisect,
38 hbisect,
40 help,
39 help,
41 hg,
40 hg,
42 lock as lockmod,
41 lock as lockmod,
43 merge as mergemod,
42 merge as mergemod,
44 minirst,
43 minirst,
45 obsolete,
44 obsolete,
46 patch,
45 patch,
47 phases,
46 phases,
48 pycompat,
47 pycompat,
49 revset,
48 revset,
50 scmutil,
49 scmutil,
51 server,
50 server,
52 sshserver,
51 sshserver,
53 streamclone,
52 streamclone,
54 templatekw,
53 templatekw,
55 templater,
54 templater,
56 ui as uimod,
55 ui as uimod,
57 util,
56 util,
58 )
57 )
59
58
60 release = lockmod.release
59 release = lockmod.release
61
60
62 table = {}
61 table = {}
63
62
64 command = cmdutil.command(table)
63 command = cmdutil.command(table)
65
64
66 # label constants
65 # label constants
67 # until 3.5, bookmarks.current was the advertised name, not
66 # until 3.5, bookmarks.current was the advertised name, not
68 # bookmarks.active, so we must use both to avoid breaking old
67 # bookmarks.active, so we must use both to avoid breaking old
69 # custom styles
68 # custom styles
70 activebookmarklabel = 'bookmarks.active bookmarks.current'
69 activebookmarklabel = 'bookmarks.active bookmarks.current'
71
70
72 # common command options
71 # common command options
73
72
74 globalopts = [
73 globalopts = [
75 ('R', 'repository', '',
74 ('R', 'repository', '',
76 _('repository root directory or name of overlay bundle file'),
75 _('repository root directory or name of overlay bundle file'),
77 _('REPO')),
76 _('REPO')),
78 ('', 'cwd', '',
77 ('', 'cwd', '',
79 _('change working directory'), _('DIR')),
78 _('change working directory'), _('DIR')),
80 ('y', 'noninteractive', None,
79 ('y', 'noninteractive', None,
81 _('do not prompt, automatically pick the first choice for all prompts')),
80 _('do not prompt, automatically pick the first choice for all prompts')),
82 ('q', 'quiet', None, _('suppress output')),
81 ('q', 'quiet', None, _('suppress output')),
83 ('v', 'verbose', None, _('enable additional output')),
82 ('v', 'verbose', None, _('enable additional output')),
84 ('', 'config', [],
83 ('', 'config', [],
85 _('set/override config option (use \'section.name=value\')'),
84 _('set/override config option (use \'section.name=value\')'),
86 _('CONFIG')),
85 _('CONFIG')),
87 ('', 'debug', None, _('enable debugging output')),
86 ('', 'debug', None, _('enable debugging output')),
88 ('', 'debugger', None, _('start debugger')),
87 ('', 'debugger', None, _('start debugger')),
89 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
88 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
90 _('ENCODE')),
89 _('ENCODE')),
91 ('', 'encodingmode', encoding.encodingmode,
90 ('', 'encodingmode', encoding.encodingmode,
92 _('set the charset encoding mode'), _('MODE')),
91 _('set the charset encoding mode'), _('MODE')),
93 ('', 'traceback', None, _('always print a traceback on exception')),
92 ('', 'traceback', None, _('always print a traceback on exception')),
94 ('', 'time', None, _('time how long the command takes')),
93 ('', 'time', None, _('time how long the command takes')),
95 ('', 'profile', None, _('print command execution profile')),
94 ('', 'profile', None, _('print command execution profile')),
96 ('', 'version', None, _('output version information and exit')),
95 ('', 'version', None, _('output version information and exit')),
97 ('h', 'help', None, _('display help and exit')),
96 ('h', 'help', None, _('display help and exit')),
98 ('', 'hidden', False, _('consider hidden changesets')),
97 ('', 'hidden', False, _('consider hidden changesets')),
99 ]
98 ]
100
99
101 dryrunopts = [('n', 'dry-run', None,
100 dryrunopts = [('n', 'dry-run', None,
102 _('do not perform actions, just print output'))]
101 _('do not perform actions, just print output'))]
103
102
104 remoteopts = [
103 remoteopts = [
105 ('e', 'ssh', '',
104 ('e', 'ssh', '',
106 _('specify ssh command to use'), _('CMD')),
105 _('specify ssh command to use'), _('CMD')),
107 ('', 'remotecmd', '',
106 ('', 'remotecmd', '',
108 _('specify hg command to run on the remote side'), _('CMD')),
107 _('specify hg command to run on the remote side'), _('CMD')),
109 ('', 'insecure', None,
108 ('', 'insecure', None,
110 _('do not verify server certificate (ignoring web.cacerts config)')),
109 _('do not verify server certificate (ignoring web.cacerts config)')),
111 ]
110 ]
112
111
113 walkopts = [
112 walkopts = [
114 ('I', 'include', [],
113 ('I', 'include', [],
115 _('include names matching the given patterns'), _('PATTERN')),
114 _('include names matching the given patterns'), _('PATTERN')),
116 ('X', 'exclude', [],
115 ('X', 'exclude', [],
117 _('exclude names matching the given patterns'), _('PATTERN')),
116 _('exclude names matching the given patterns'), _('PATTERN')),
118 ]
117 ]
119
118
120 commitopts = [
119 commitopts = [
121 ('m', 'message', '',
120 ('m', 'message', '',
122 _('use text as commit message'), _('TEXT')),
121 _('use text as commit message'), _('TEXT')),
123 ('l', 'logfile', '',
122 ('l', 'logfile', '',
124 _('read commit message from file'), _('FILE')),
123 _('read commit message from file'), _('FILE')),
125 ]
124 ]
126
125
127 commitopts2 = [
126 commitopts2 = [
128 ('d', 'date', '',
127 ('d', 'date', '',
129 _('record the specified date as commit date'), _('DATE')),
128 _('record the specified date as commit date'), _('DATE')),
130 ('u', 'user', '',
129 ('u', 'user', '',
131 _('record the specified user as committer'), _('USER')),
130 _('record the specified user as committer'), _('USER')),
132 ]
131 ]
133
132
134 # hidden for now
133 # hidden for now
135 formatteropts = [
134 formatteropts = [
136 ('T', 'template', '',
135 ('T', 'template', '',
137 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
136 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
138 ]
137 ]
139
138
140 templateopts = [
139 templateopts = [
141 ('', 'style', '',
140 ('', 'style', '',
142 _('display using template map file (DEPRECATED)'), _('STYLE')),
141 _('display using template map file (DEPRECATED)'), _('STYLE')),
143 ('T', 'template', '',
142 ('T', 'template', '',
144 _('display with template'), _('TEMPLATE')),
143 _('display with template'), _('TEMPLATE')),
145 ]
144 ]
146
145
147 logopts = [
146 logopts = [
148 ('p', 'patch', None, _('show patch')),
147 ('p', 'patch', None, _('show patch')),
149 ('g', 'git', None, _('use git extended diff format')),
148 ('g', 'git', None, _('use git extended diff format')),
150 ('l', 'limit', '',
149 ('l', 'limit', '',
151 _('limit number of changes displayed'), _('NUM')),
150 _('limit number of changes displayed'), _('NUM')),
152 ('M', 'no-merges', None, _('do not show merges')),
151 ('M', 'no-merges', None, _('do not show merges')),
153 ('', 'stat', None, _('output diffstat-style summary of changes')),
152 ('', 'stat', None, _('output diffstat-style summary of changes')),
154 ('G', 'graph', None, _("show the revision DAG")),
153 ('G', 'graph', None, _("show the revision DAG")),
155 ] + templateopts
154 ] + templateopts
156
155
157 diffopts = [
156 diffopts = [
158 ('a', 'text', None, _('treat all files as text')),
157 ('a', 'text', None, _('treat all files as text')),
159 ('g', 'git', None, _('use git extended diff format')),
158 ('g', 'git', None, _('use git extended diff format')),
160 ('', 'nodates', None, _('omit dates from diff headers'))
159 ('', 'nodates', None, _('omit dates from diff headers'))
161 ]
160 ]
162
161
163 diffwsopts = [
162 diffwsopts = [
164 ('w', 'ignore-all-space', None,
163 ('w', 'ignore-all-space', None,
165 _('ignore white space when comparing lines')),
164 _('ignore white space when comparing lines')),
166 ('b', 'ignore-space-change', None,
165 ('b', 'ignore-space-change', None,
167 _('ignore changes in the amount of white space')),
166 _('ignore changes in the amount of white space')),
168 ('B', 'ignore-blank-lines', None,
167 ('B', 'ignore-blank-lines', None,
169 _('ignore changes whose lines are all blank')),
168 _('ignore changes whose lines are all blank')),
170 ]
169 ]
171
170
172 diffopts2 = [
171 diffopts2 = [
173 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
172 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
174 ('p', 'show-function', None, _('show which function each change is in')),
173 ('p', 'show-function', None, _('show which function each change is in')),
175 ('', 'reverse', None, _('produce a diff that undoes the changes')),
174 ('', 'reverse', None, _('produce a diff that undoes the changes')),
176 ] + diffwsopts + [
175 ] + diffwsopts + [
177 ('U', 'unified', '',
176 ('U', 'unified', '',
178 _('number of lines of context to show'), _('NUM')),
177 _('number of lines of context to show'), _('NUM')),
179 ('', 'stat', None, _('output diffstat-style summary of changes')),
178 ('', 'stat', None, _('output diffstat-style summary of changes')),
180 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
179 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
181 ]
180 ]
182
181
183 mergetoolopts = [
182 mergetoolopts = [
184 ('t', 'tool', '', _('specify merge tool')),
183 ('t', 'tool', '', _('specify merge tool')),
185 ]
184 ]
186
185
187 similarityopts = [
186 similarityopts = [
188 ('s', 'similarity', '',
187 ('s', 'similarity', '',
189 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
188 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
190 ]
189 ]
191
190
192 subrepoopts = [
191 subrepoopts = [
193 ('S', 'subrepos', None,
192 ('S', 'subrepos', None,
194 _('recurse into subrepositories'))
193 _('recurse into subrepositories'))
195 ]
194 ]
196
195
197 debugrevlogopts = [
196 debugrevlogopts = [
198 ('c', 'changelog', False, _('open changelog')),
197 ('c', 'changelog', False, _('open changelog')),
199 ('m', 'manifest', False, _('open manifest')),
198 ('m', 'manifest', False, _('open manifest')),
200 ('', 'dir', '', _('open directory manifest')),
199 ('', 'dir', '', _('open directory manifest')),
201 ]
200 ]
202
201
203 # Commands start here, listed alphabetically
202 # Commands start here, listed alphabetically
204
203
205 @command('^add',
204 @command('^add',
206 walkopts + subrepoopts + dryrunopts,
205 walkopts + subrepoopts + dryrunopts,
207 _('[OPTION]... [FILE]...'),
206 _('[OPTION]... [FILE]...'),
208 inferrepo=True)
207 inferrepo=True)
209 def add(ui, repo, *pats, **opts):
208 def add(ui, repo, *pats, **opts):
210 """add the specified files on the next commit
209 """add the specified files on the next commit
211
210
212 Schedule files to be version controlled and added to the
211 Schedule files to be version controlled and added to the
213 repository.
212 repository.
214
213
215 The files will be added to the repository at the next commit. To
214 The files will be added to the repository at the next commit. To
216 undo an add before that, see :hg:`forget`.
215 undo an add before that, see :hg:`forget`.
217
216
218 If no names are given, add all files to the repository (except
217 If no names are given, add all files to the repository (except
219 files matching ``.hgignore``).
218 files matching ``.hgignore``).
220
219
221 .. container:: verbose
220 .. container:: verbose
222
221
223 Examples:
222 Examples:
224
223
225 - New (unknown) files are added
224 - New (unknown) files are added
226 automatically by :hg:`add`::
225 automatically by :hg:`add`::
227
226
228 $ ls
227 $ ls
229 foo.c
228 foo.c
230 $ hg status
229 $ hg status
231 ? foo.c
230 ? foo.c
232 $ hg add
231 $ hg add
233 adding foo.c
232 adding foo.c
234 $ hg status
233 $ hg status
235 A foo.c
234 A foo.c
236
235
237 - Specific files to be added can be specified::
236 - Specific files to be added can be specified::
238
237
239 $ ls
238 $ ls
240 bar.c foo.c
239 bar.c foo.c
241 $ hg status
240 $ hg status
242 ? bar.c
241 ? bar.c
243 ? foo.c
242 ? foo.c
244 $ hg add bar.c
243 $ hg add bar.c
245 $ hg status
244 $ hg status
246 A bar.c
245 A bar.c
247 ? foo.c
246 ? foo.c
248
247
249 Returns 0 if all files are successfully added.
248 Returns 0 if all files are successfully added.
250 """
249 """
251
250
252 m = scmutil.match(repo[None], pats, opts)
251 m = scmutil.match(repo[None], pats, opts)
253 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
252 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
254 return rejected and 1 or 0
253 return rejected and 1 or 0
255
254
256 @command('addremove',
255 @command('addremove',
257 similarityopts + subrepoopts + walkopts + dryrunopts,
256 similarityopts + subrepoopts + walkopts + dryrunopts,
258 _('[OPTION]... [FILE]...'),
257 _('[OPTION]... [FILE]...'),
259 inferrepo=True)
258 inferrepo=True)
260 def addremove(ui, repo, *pats, **opts):
259 def addremove(ui, repo, *pats, **opts):
261 """add all new files, delete all missing files
260 """add all new files, delete all missing files
262
261
263 Add all new files and remove all missing files from the
262 Add all new files and remove all missing files from the
264 repository.
263 repository.
265
264
266 Unless names are given, new files are ignored if they match any of
265 Unless names are given, new files are ignored if they match any of
267 the patterns in ``.hgignore``. As with add, these changes take
266 the patterns in ``.hgignore``. As with add, these changes take
268 effect at the next commit.
267 effect at the next commit.
269
268
270 Use the -s/--similarity option to detect renamed files. This
269 Use the -s/--similarity option to detect renamed files. This
271 option takes a percentage between 0 (disabled) and 100 (files must
270 option takes a percentage between 0 (disabled) and 100 (files must
272 be identical) as its parameter. With a parameter greater than 0,
271 be identical) as its parameter. With a parameter greater than 0,
273 this compares every removed file with every added file and records
272 this compares every removed file with every added file and records
274 those similar enough as renames. Detecting renamed files this way
273 those similar enough as renames. Detecting renamed files this way
275 can be expensive. After using this option, :hg:`status -C` can be
274 can be expensive. After using this option, :hg:`status -C` can be
276 used to check which files were identified as moved or renamed. If
275 used to check which files were identified as moved or renamed. If
277 not specified, -s/--similarity defaults to 100 and only renames of
276 not specified, -s/--similarity defaults to 100 and only renames of
278 identical files are detected.
277 identical files are detected.
279
278
280 .. container:: verbose
279 .. container:: verbose
281
280
282 Examples:
281 Examples:
283
282
284 - A number of files (bar.c and foo.c) are new,
283 - A number of files (bar.c and foo.c) are new,
285 while foobar.c has been removed (without using :hg:`remove`)
284 while foobar.c has been removed (without using :hg:`remove`)
286 from the repository::
285 from the repository::
287
286
288 $ ls
287 $ ls
289 bar.c foo.c
288 bar.c foo.c
290 $ hg status
289 $ hg status
291 ! foobar.c
290 ! foobar.c
292 ? bar.c
291 ? bar.c
293 ? foo.c
292 ? foo.c
294 $ hg addremove
293 $ hg addremove
295 adding bar.c
294 adding bar.c
296 adding foo.c
295 adding foo.c
297 removing foobar.c
296 removing foobar.c
298 $ hg status
297 $ hg status
299 A bar.c
298 A bar.c
300 A foo.c
299 A foo.c
301 R foobar.c
300 R foobar.c
302
301
303 - A file foobar.c was moved to foo.c without using :hg:`rename`.
302 - A file foobar.c was moved to foo.c without using :hg:`rename`.
304 Afterwards, it was edited slightly::
303 Afterwards, it was edited slightly::
305
304
306 $ ls
305 $ ls
307 foo.c
306 foo.c
308 $ hg status
307 $ hg status
309 ! foobar.c
308 ! foobar.c
310 ? foo.c
309 ? foo.c
311 $ hg addremove --similarity 90
310 $ hg addremove --similarity 90
312 removing foobar.c
311 removing foobar.c
313 adding foo.c
312 adding foo.c
314 recording removal of foobar.c as rename to foo.c (94% similar)
313 recording removal of foobar.c as rename to foo.c (94% similar)
315 $ hg status -C
314 $ hg status -C
316 A foo.c
315 A foo.c
317 foobar.c
316 foobar.c
318 R foobar.c
317 R foobar.c
319
318
320 Returns 0 if all files are successfully added.
319 Returns 0 if all files are successfully added.
321 """
320 """
322 try:
321 try:
323 sim = float(opts.get('similarity') or 100)
322 sim = float(opts.get('similarity') or 100)
324 except ValueError:
323 except ValueError:
325 raise error.Abort(_('similarity must be a number'))
324 raise error.Abort(_('similarity must be a number'))
326 if sim < 0 or sim > 100:
325 if sim < 0 or sim > 100:
327 raise error.Abort(_('similarity must be between 0 and 100'))
326 raise error.Abort(_('similarity must be between 0 and 100'))
328 matcher = scmutil.match(repo[None], pats, opts)
327 matcher = scmutil.match(repo[None], pats, opts)
329 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
328 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
330
329
331 @command('^annotate|blame',
330 @command('^annotate|blame',
332 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
331 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
333 ('', 'follow', None,
332 ('', 'follow', None,
334 _('follow copies/renames and list the filename (DEPRECATED)')),
333 _('follow copies/renames and list the filename (DEPRECATED)')),
335 ('', 'no-follow', None, _("don't follow copies and renames")),
334 ('', 'no-follow', None, _("don't follow copies and renames")),
336 ('a', 'text', None, _('treat all files as text')),
335 ('a', 'text', None, _('treat all files as text')),
337 ('u', 'user', None, _('list the author (long with -v)')),
336 ('u', 'user', None, _('list the author (long with -v)')),
338 ('f', 'file', None, _('list the filename')),
337 ('f', 'file', None, _('list the filename')),
339 ('d', 'date', None, _('list the date (short with -q)')),
338 ('d', 'date', None, _('list the date (short with -q)')),
340 ('n', 'number', None, _('list the revision number (default)')),
339 ('n', 'number', None, _('list the revision number (default)')),
341 ('c', 'changeset', None, _('list the changeset')),
340 ('c', 'changeset', None, _('list the changeset')),
342 ('l', 'line-number', None, _('show line number at the first appearance'))
341 ('l', 'line-number', None, _('show line number at the first appearance'))
343 ] + diffwsopts + walkopts + formatteropts,
342 ] + diffwsopts + walkopts + formatteropts,
344 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
343 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
345 inferrepo=True)
344 inferrepo=True)
346 def annotate(ui, repo, *pats, **opts):
345 def annotate(ui, repo, *pats, **opts):
347 """show changeset information by line for each file
346 """show changeset information by line for each file
348
347
349 List changes in files, showing the revision id responsible for
348 List changes in files, showing the revision id responsible for
350 each line.
349 each line.
351
350
352 This command is useful for discovering when a change was made and
351 This command is useful for discovering when a change was made and
353 by whom.
352 by whom.
354
353
355 If you include --file, --user, or --date, the revision number is
354 If you include --file, --user, or --date, the revision number is
356 suppressed unless you also include --number.
355 suppressed unless you also include --number.
357
356
358 Without the -a/--text option, annotate will avoid processing files
357 Without the -a/--text option, annotate will avoid processing files
359 it detects as binary. With -a, annotate will annotate the file
358 it detects as binary. With -a, annotate will annotate the file
360 anyway, although the results will probably be neither useful
359 anyway, although the results will probably be neither useful
361 nor desirable.
360 nor desirable.
362
361
363 Returns 0 on success.
362 Returns 0 on success.
364 """
363 """
365 if not pats:
364 if not pats:
366 raise error.Abort(_('at least one filename or pattern is required'))
365 raise error.Abort(_('at least one filename or pattern is required'))
367
366
368 if opts.get('follow'):
367 if opts.get('follow'):
369 # --follow is deprecated and now just an alias for -f/--file
368 # --follow is deprecated and now just an alias for -f/--file
370 # to mimic the behavior of Mercurial before version 1.5
369 # to mimic the behavior of Mercurial before version 1.5
371 opts['file'] = True
370 opts['file'] = True
372
371
373 ctx = scmutil.revsingle(repo, opts.get('rev'))
372 ctx = scmutil.revsingle(repo, opts.get('rev'))
374
373
375 fm = ui.formatter('annotate', opts)
374 fm = ui.formatter('annotate', opts)
376 if ui.quiet:
375 if ui.quiet:
377 datefunc = util.shortdate
376 datefunc = util.shortdate
378 else:
377 else:
379 datefunc = util.datestr
378 datefunc = util.datestr
380 if ctx.rev() is None:
379 if ctx.rev() is None:
381 def hexfn(node):
380 def hexfn(node):
382 if node is None:
381 if node is None:
383 return None
382 return None
384 else:
383 else:
385 return fm.hexfunc(node)
384 return fm.hexfunc(node)
386 if opts.get('changeset'):
385 if opts.get('changeset'):
387 # omit "+" suffix which is appended to node hex
386 # omit "+" suffix which is appended to node hex
388 def formatrev(rev):
387 def formatrev(rev):
389 if rev is None:
388 if rev is None:
390 return '%d' % ctx.p1().rev()
389 return '%d' % ctx.p1().rev()
391 else:
390 else:
392 return '%d' % rev
391 return '%d' % rev
393 else:
392 else:
394 def formatrev(rev):
393 def formatrev(rev):
395 if rev is None:
394 if rev is None:
396 return '%d+' % ctx.p1().rev()
395 return '%d+' % ctx.p1().rev()
397 else:
396 else:
398 return '%d ' % rev
397 return '%d ' % rev
399 def formathex(hex):
398 def formathex(hex):
400 if hex is None:
399 if hex is None:
401 return '%s+' % fm.hexfunc(ctx.p1().node())
400 return '%s+' % fm.hexfunc(ctx.p1().node())
402 else:
401 else:
403 return '%s ' % hex
402 return '%s ' % hex
404 else:
403 else:
405 hexfn = fm.hexfunc
404 hexfn = fm.hexfunc
406 formatrev = formathex = str
405 formatrev = formathex = str
407
406
408 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
407 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
409 ('number', ' ', lambda x: x[0].rev(), formatrev),
408 ('number', ' ', lambda x: x[0].rev(), formatrev),
410 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
409 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
411 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
410 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
412 ('file', ' ', lambda x: x[0].path(), str),
411 ('file', ' ', lambda x: x[0].path(), str),
413 ('line_number', ':', lambda x: x[1], str),
412 ('line_number', ':', lambda x: x[1], str),
414 ]
413 ]
415 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
414 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
416
415
417 if (not opts.get('user') and not opts.get('changeset')
416 if (not opts.get('user') and not opts.get('changeset')
418 and not opts.get('date') and not opts.get('file')):
417 and not opts.get('date') and not opts.get('file')):
419 opts['number'] = True
418 opts['number'] = True
420
419
421 linenumber = opts.get('line_number') is not None
420 linenumber = opts.get('line_number') is not None
422 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
421 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
423 raise error.Abort(_('at least one of -n/-c is required for -l'))
422 raise error.Abort(_('at least one of -n/-c is required for -l'))
424
423
425 if fm.isplain():
424 if fm.isplain():
426 def makefunc(get, fmt):
425 def makefunc(get, fmt):
427 return lambda x: fmt(get(x))
426 return lambda x: fmt(get(x))
428 else:
427 else:
429 def makefunc(get, fmt):
428 def makefunc(get, fmt):
430 return get
429 return get
431 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
430 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
432 if opts.get(op)]
431 if opts.get(op)]
433 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
432 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
434 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
433 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
435 if opts.get(op))
434 if opts.get(op))
436
435
437 def bad(x, y):
436 def bad(x, y):
438 raise error.Abort("%s: %s" % (x, y))
437 raise error.Abort("%s: %s" % (x, y))
439
438
440 m = scmutil.match(ctx, pats, opts, badfn=bad)
439 m = scmutil.match(ctx, pats, opts, badfn=bad)
441
440
442 follow = not opts.get('no_follow')
441 follow = not opts.get('no_follow')
443 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
442 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
444 whitespace=True)
443 whitespace=True)
445 for abs in ctx.walk(m):
444 for abs in ctx.walk(m):
446 fctx = ctx[abs]
445 fctx = ctx[abs]
447 if not opts.get('text') and util.binary(fctx.data()):
446 if not opts.get('text') and util.binary(fctx.data()):
448 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
447 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
449 continue
448 continue
450
449
451 lines = fctx.annotate(follow=follow, linenumber=linenumber,
450 lines = fctx.annotate(follow=follow, linenumber=linenumber,
452 diffopts=diffopts)
451 diffopts=diffopts)
453 if not lines:
452 if not lines:
454 continue
453 continue
455 formats = []
454 formats = []
456 pieces = []
455 pieces = []
457
456
458 for f, sep in funcmap:
457 for f, sep in funcmap:
459 l = [f(n) for n, dummy in lines]
458 l = [f(n) for n, dummy in lines]
460 if fm.isplain():
459 if fm.isplain():
461 sizes = [encoding.colwidth(x) for x in l]
460 sizes = [encoding.colwidth(x) for x in l]
462 ml = max(sizes)
461 ml = max(sizes)
463 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
462 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
464 else:
463 else:
465 formats.append(['%s' for x in l])
464 formats.append(['%s' for x in l])
466 pieces.append(l)
465 pieces.append(l)
467
466
468 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
467 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
469 fm.startitem()
468 fm.startitem()
470 fm.write(fields, "".join(f), *p)
469 fm.write(fields, "".join(f), *p)
471 fm.write('line', ": %s", l[1])
470 fm.write('line', ": %s", l[1])
472
471
473 if not lines[-1][1].endswith('\n'):
472 if not lines[-1][1].endswith('\n'):
474 fm.plain('\n')
473 fm.plain('\n')
475
474
476 fm.end()
475 fm.end()
477
476
478 @command('archive',
477 @command('archive',
479 [('', 'no-decode', None, _('do not pass files through decoders')),
478 [('', 'no-decode', None, _('do not pass files through decoders')),
480 ('p', 'prefix', '', _('directory prefix for files in archive'),
479 ('p', 'prefix', '', _('directory prefix for files in archive'),
481 _('PREFIX')),
480 _('PREFIX')),
482 ('r', 'rev', '', _('revision to distribute'), _('REV')),
481 ('r', 'rev', '', _('revision to distribute'), _('REV')),
483 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
482 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
484 ] + subrepoopts + walkopts,
483 ] + subrepoopts + walkopts,
485 _('[OPTION]... DEST'))
484 _('[OPTION]... DEST'))
486 def archive(ui, repo, dest, **opts):
485 def archive(ui, repo, dest, **opts):
487 '''create an unversioned archive of a repository revision
486 '''create an unversioned archive of a repository revision
488
487
489 By default, the revision used is the parent of the working
488 By default, the revision used is the parent of the working
490 directory; use -r/--rev to specify a different revision.
489 directory; use -r/--rev to specify a different revision.
491
490
492 The archive type is automatically detected based on file
491 The archive type is automatically detected based on file
493 extension (to override, use -t/--type).
492 extension (to override, use -t/--type).
494
493
495 .. container:: verbose
494 .. container:: verbose
496
495
497 Examples:
496 Examples:
498
497
499 - create a zip file containing the 1.0 release::
498 - create a zip file containing the 1.0 release::
500
499
501 hg archive -r 1.0 project-1.0.zip
500 hg archive -r 1.0 project-1.0.zip
502
501
503 - create a tarball excluding .hg files::
502 - create a tarball excluding .hg files::
504
503
505 hg archive project.tar.gz -X ".hg*"
504 hg archive project.tar.gz -X ".hg*"
506
505
507 Valid types are:
506 Valid types are:
508
507
509 :``files``: a directory full of files (default)
508 :``files``: a directory full of files (default)
510 :``tar``: tar archive, uncompressed
509 :``tar``: tar archive, uncompressed
511 :``tbz2``: tar archive, compressed using bzip2
510 :``tbz2``: tar archive, compressed using bzip2
512 :``tgz``: tar archive, compressed using gzip
511 :``tgz``: tar archive, compressed using gzip
513 :``uzip``: zip archive, uncompressed
512 :``uzip``: zip archive, uncompressed
514 :``zip``: zip archive, compressed using deflate
513 :``zip``: zip archive, compressed using deflate
515
514
516 The exact name of the destination archive or directory is given
515 The exact name of the destination archive or directory is given
517 using a format string; see :hg:`help export` for details.
516 using a format string; see :hg:`help export` for details.
518
517
519 Each member added to an archive file has a directory prefix
518 Each member added to an archive file has a directory prefix
520 prepended. Use -p/--prefix to specify a format string for the
519 prepended. Use -p/--prefix to specify a format string for the
521 prefix. The default is the basename of the archive, with suffixes
520 prefix. The default is the basename of the archive, with suffixes
522 removed.
521 removed.
523
522
524 Returns 0 on success.
523 Returns 0 on success.
525 '''
524 '''
526
525
527 ctx = scmutil.revsingle(repo, opts.get('rev'))
526 ctx = scmutil.revsingle(repo, opts.get('rev'))
528 if not ctx:
527 if not ctx:
529 raise error.Abort(_('no working directory: please specify a revision'))
528 raise error.Abort(_('no working directory: please specify a revision'))
530 node = ctx.node()
529 node = ctx.node()
531 dest = cmdutil.makefilename(repo, dest, node)
530 dest = cmdutil.makefilename(repo, dest, node)
532 if os.path.realpath(dest) == repo.root:
531 if os.path.realpath(dest) == repo.root:
533 raise error.Abort(_('repository root cannot be destination'))
532 raise error.Abort(_('repository root cannot be destination'))
534
533
535 kind = opts.get('type') or archival.guesskind(dest) or 'files'
534 kind = opts.get('type') or archival.guesskind(dest) or 'files'
536 prefix = opts.get('prefix')
535 prefix = opts.get('prefix')
537
536
538 if dest == '-':
537 if dest == '-':
539 if kind == 'files':
538 if kind == 'files':
540 raise error.Abort(_('cannot archive plain files to stdout'))
539 raise error.Abort(_('cannot archive plain files to stdout'))
541 dest = cmdutil.makefileobj(repo, dest)
540 dest = cmdutil.makefileobj(repo, dest)
542 if not prefix:
541 if not prefix:
543 prefix = os.path.basename(repo.root) + '-%h'
542 prefix = os.path.basename(repo.root) + '-%h'
544
543
545 prefix = cmdutil.makefilename(repo, prefix, node)
544 prefix = cmdutil.makefilename(repo, prefix, node)
546 matchfn = scmutil.match(ctx, [], opts)
545 matchfn = scmutil.match(ctx, [], opts)
547 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
546 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
548 matchfn, prefix, subrepos=opts.get('subrepos'))
547 matchfn, prefix, subrepos=opts.get('subrepos'))
549
548
550 @command('backout',
549 @command('backout',
551 [('', 'merge', None, _('merge with old dirstate parent after backout')),
550 [('', 'merge', None, _('merge with old dirstate parent after backout')),
552 ('', 'commit', None,
551 ('', 'commit', None,
553 _('commit if no conflicts were encountered (DEPRECATED)')),
552 _('commit if no conflicts were encountered (DEPRECATED)')),
554 ('', 'no-commit', None, _('do not commit')),
553 ('', 'no-commit', None, _('do not commit')),
555 ('', 'parent', '',
554 ('', 'parent', '',
556 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
555 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
557 ('r', 'rev', '', _('revision to backout'), _('REV')),
556 ('r', 'rev', '', _('revision to backout'), _('REV')),
558 ('e', 'edit', False, _('invoke editor on commit messages')),
557 ('e', 'edit', False, _('invoke editor on commit messages')),
559 ] + mergetoolopts + walkopts + commitopts + commitopts2,
558 ] + mergetoolopts + walkopts + commitopts + commitopts2,
560 _('[OPTION]... [-r] REV'))
559 _('[OPTION]... [-r] REV'))
561 def backout(ui, repo, node=None, rev=None, **opts):
560 def backout(ui, repo, node=None, rev=None, **opts):
562 '''reverse effect of earlier changeset
561 '''reverse effect of earlier changeset
563
562
564 Prepare a new changeset with the effect of REV undone in the
563 Prepare a new changeset with the effect of REV undone in the
565 current working directory. If no conflicts were encountered,
564 current working directory. If no conflicts were encountered,
566 it will be committed immediately.
565 it will be committed immediately.
567
566
568 If REV is the parent of the working directory, then this new changeset
567 If REV is the parent of the working directory, then this new changeset
569 is committed automatically (unless --no-commit is specified).
568 is committed automatically (unless --no-commit is specified).
570
569
571 .. note::
570 .. note::
572
571
573 :hg:`backout` cannot be used to fix either an unwanted or
572 :hg:`backout` cannot be used to fix either an unwanted or
574 incorrect merge.
573 incorrect merge.
575
574
576 .. container:: verbose
575 .. container:: verbose
577
576
578 Examples:
577 Examples:
579
578
580 - Reverse the effect of the parent of the working directory.
579 - Reverse the effect of the parent of the working directory.
581 This backout will be committed immediately::
580 This backout will be committed immediately::
582
581
583 hg backout -r .
582 hg backout -r .
584
583
585 - Reverse the effect of previous bad revision 23::
584 - Reverse the effect of previous bad revision 23::
586
585
587 hg backout -r 23
586 hg backout -r 23
588
587
589 - Reverse the effect of previous bad revision 23 and
588 - Reverse the effect of previous bad revision 23 and
590 leave changes uncommitted::
589 leave changes uncommitted::
591
590
592 hg backout -r 23 --no-commit
591 hg backout -r 23 --no-commit
593 hg commit -m "Backout revision 23"
592 hg commit -m "Backout revision 23"
594
593
595 By default, the pending changeset will have one parent,
594 By default, the pending changeset will have one parent,
596 maintaining a linear history. With --merge, the pending
595 maintaining a linear history. With --merge, the pending
597 changeset will instead have two parents: the old parent of the
596 changeset will instead have two parents: the old parent of the
598 working directory and a new child of REV that simply undoes REV.
597 working directory and a new child of REV that simply undoes REV.
599
598
600 Before version 1.7, the behavior without --merge was equivalent
599 Before version 1.7, the behavior without --merge was equivalent
601 to specifying --merge followed by :hg:`update --clean .` to
600 to specifying --merge followed by :hg:`update --clean .` to
602 cancel the merge and leave the child of REV as a head to be
601 cancel the merge and leave the child of REV as a head to be
603 merged separately.
602 merged separately.
604
603
605 See :hg:`help dates` for a list of formats valid for -d/--date.
604 See :hg:`help dates` for a list of formats valid for -d/--date.
606
605
607 See :hg:`help revert` for a way to restore files to the state
606 See :hg:`help revert` for a way to restore files to the state
608 of another revision.
607 of another revision.
609
608
610 Returns 0 on success, 1 if nothing to backout or there are unresolved
609 Returns 0 on success, 1 if nothing to backout or there are unresolved
611 files.
610 files.
612 '''
611 '''
613 wlock = lock = None
612 wlock = lock = None
614 try:
613 try:
615 wlock = repo.wlock()
614 wlock = repo.wlock()
616 lock = repo.lock()
615 lock = repo.lock()
617 return _dobackout(ui, repo, node, rev, **opts)
616 return _dobackout(ui, repo, node, rev, **opts)
618 finally:
617 finally:
619 release(lock, wlock)
618 release(lock, wlock)
620
619
621 def _dobackout(ui, repo, node=None, rev=None, **opts):
620 def _dobackout(ui, repo, node=None, rev=None, **opts):
622 if opts.get('commit') and opts.get('no_commit'):
621 if opts.get('commit') and opts.get('no_commit'):
623 raise error.Abort(_("cannot use --commit with --no-commit"))
622 raise error.Abort(_("cannot use --commit with --no-commit"))
624 if opts.get('merge') and opts.get('no_commit'):
623 if opts.get('merge') and opts.get('no_commit'):
625 raise error.Abort(_("cannot use --merge with --no-commit"))
624 raise error.Abort(_("cannot use --merge with --no-commit"))
626
625
627 if rev and node:
626 if rev and node:
628 raise error.Abort(_("please specify just one revision"))
627 raise error.Abort(_("please specify just one revision"))
629
628
630 if not rev:
629 if not rev:
631 rev = node
630 rev = node
632
631
633 if not rev:
632 if not rev:
634 raise error.Abort(_("please specify a revision to backout"))
633 raise error.Abort(_("please specify a revision to backout"))
635
634
636 date = opts.get('date')
635 date = opts.get('date')
637 if date:
636 if date:
638 opts['date'] = util.parsedate(date)
637 opts['date'] = util.parsedate(date)
639
638
640 cmdutil.checkunfinished(repo)
639 cmdutil.checkunfinished(repo)
641 cmdutil.bailifchanged(repo)
640 cmdutil.bailifchanged(repo)
642 node = scmutil.revsingle(repo, rev).node()
641 node = scmutil.revsingle(repo, rev).node()
643
642
644 op1, op2 = repo.dirstate.parents()
643 op1, op2 = repo.dirstate.parents()
645 if not repo.changelog.isancestor(node, op1):
644 if not repo.changelog.isancestor(node, op1):
646 raise error.Abort(_('cannot backout change that is not an ancestor'))
645 raise error.Abort(_('cannot backout change that is not an ancestor'))
647
646
648 p1, p2 = repo.changelog.parents(node)
647 p1, p2 = repo.changelog.parents(node)
649 if p1 == nullid:
648 if p1 == nullid:
650 raise error.Abort(_('cannot backout a change with no parents'))
649 raise error.Abort(_('cannot backout a change with no parents'))
651 if p2 != nullid:
650 if p2 != nullid:
652 if not opts.get('parent'):
651 if not opts.get('parent'):
653 raise error.Abort(_('cannot backout a merge changeset'))
652 raise error.Abort(_('cannot backout a merge changeset'))
654 p = repo.lookup(opts['parent'])
653 p = repo.lookup(opts['parent'])
655 if p not in (p1, p2):
654 if p not in (p1, p2):
656 raise error.Abort(_('%s is not a parent of %s') %
655 raise error.Abort(_('%s is not a parent of %s') %
657 (short(p), short(node)))
656 (short(p), short(node)))
658 parent = p
657 parent = p
659 else:
658 else:
660 if opts.get('parent'):
659 if opts.get('parent'):
661 raise error.Abort(_('cannot use --parent on non-merge changeset'))
660 raise error.Abort(_('cannot use --parent on non-merge changeset'))
662 parent = p1
661 parent = p1
663
662
664 # the backout should appear on the same branch
663 # the backout should appear on the same branch
665 branch = repo.dirstate.branch()
664 branch = repo.dirstate.branch()
666 bheads = repo.branchheads(branch)
665 bheads = repo.branchheads(branch)
667 rctx = scmutil.revsingle(repo, hex(parent))
666 rctx = scmutil.revsingle(repo, hex(parent))
668 if not opts.get('merge') and op1 != node:
667 if not opts.get('merge') and op1 != node:
669 dsguard = dirstateguard.dirstateguard(repo, 'backout')
668 dsguard = dirstateguard.dirstateguard(repo, 'backout')
670 try:
669 try:
671 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
670 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
672 'backout')
671 'backout')
673 stats = mergemod.update(repo, parent, True, True, node, False)
672 stats = mergemod.update(repo, parent, True, True, node, False)
674 repo.setparents(op1, op2)
673 repo.setparents(op1, op2)
675 dsguard.close()
674 dsguard.close()
676 hg._showstats(repo, stats)
675 hg._showstats(repo, stats)
677 if stats[3]:
676 if stats[3]:
678 repo.ui.status(_("use 'hg resolve' to retry unresolved "
677 repo.ui.status(_("use 'hg resolve' to retry unresolved "
679 "file merges\n"))
678 "file merges\n"))
680 return 1
679 return 1
681 finally:
680 finally:
682 ui.setconfig('ui', 'forcemerge', '', '')
681 ui.setconfig('ui', 'forcemerge', '', '')
683 lockmod.release(dsguard)
682 lockmod.release(dsguard)
684 else:
683 else:
685 hg.clean(repo, node, show_stats=False)
684 hg.clean(repo, node, show_stats=False)
686 repo.dirstate.setbranch(branch)
685 repo.dirstate.setbranch(branch)
687 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
686 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
688
687
689 if opts.get('no_commit'):
688 if opts.get('no_commit'):
690 msg = _("changeset %s backed out, "
689 msg = _("changeset %s backed out, "
691 "don't forget to commit.\n")
690 "don't forget to commit.\n")
692 ui.status(msg % short(node))
691 ui.status(msg % short(node))
693 return 0
692 return 0
694
693
695 def commitfunc(ui, repo, message, match, opts):
694 def commitfunc(ui, repo, message, match, opts):
696 editform = 'backout'
695 editform = 'backout'
697 e = cmdutil.getcommiteditor(editform=editform, **opts)
696 e = cmdutil.getcommiteditor(editform=editform, **opts)
698 if not message:
697 if not message:
699 # we don't translate commit messages
698 # we don't translate commit messages
700 message = "Backed out changeset %s" % short(node)
699 message = "Backed out changeset %s" % short(node)
701 e = cmdutil.getcommiteditor(edit=True, editform=editform)
700 e = cmdutil.getcommiteditor(edit=True, editform=editform)
702 return repo.commit(message, opts.get('user'), opts.get('date'),
701 return repo.commit(message, opts.get('user'), opts.get('date'),
703 match, editor=e)
702 match, editor=e)
704 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
703 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
705 if not newnode:
704 if not newnode:
706 ui.status(_("nothing changed\n"))
705 ui.status(_("nothing changed\n"))
707 return 1
706 return 1
708 cmdutil.commitstatus(repo, newnode, branch, bheads)
707 cmdutil.commitstatus(repo, newnode, branch, bheads)
709
708
710 def nice(node):
709 def nice(node):
711 return '%d:%s' % (repo.changelog.rev(node), short(node))
710 return '%d:%s' % (repo.changelog.rev(node), short(node))
712 ui.status(_('changeset %s backs out changeset %s\n') %
711 ui.status(_('changeset %s backs out changeset %s\n') %
713 (nice(repo.changelog.tip()), nice(node)))
712 (nice(repo.changelog.tip()), nice(node)))
714 if opts.get('merge') and op1 != node:
713 if opts.get('merge') and op1 != node:
715 hg.clean(repo, op1, show_stats=False)
714 hg.clean(repo, op1, show_stats=False)
716 ui.status(_('merging with changeset %s\n')
715 ui.status(_('merging with changeset %s\n')
717 % nice(repo.changelog.tip()))
716 % nice(repo.changelog.tip()))
718 try:
717 try:
719 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
718 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
720 'backout')
719 'backout')
721 return hg.merge(repo, hex(repo.changelog.tip()))
720 return hg.merge(repo, hex(repo.changelog.tip()))
722 finally:
721 finally:
723 ui.setconfig('ui', 'forcemerge', '', '')
722 ui.setconfig('ui', 'forcemerge', '', '')
724 return 0
723 return 0
725
724
726 @command('bisect',
725 @command('bisect',
727 [('r', 'reset', False, _('reset bisect state')),
726 [('r', 'reset', False, _('reset bisect state')),
728 ('g', 'good', False, _('mark changeset good')),
727 ('g', 'good', False, _('mark changeset good')),
729 ('b', 'bad', False, _('mark changeset bad')),
728 ('b', 'bad', False, _('mark changeset bad')),
730 ('s', 'skip', False, _('skip testing changeset')),
729 ('s', 'skip', False, _('skip testing changeset')),
731 ('e', 'extend', False, _('extend the bisect range')),
730 ('e', 'extend', False, _('extend the bisect range')),
732 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
731 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
733 ('U', 'noupdate', False, _('do not update to target'))],
732 ('U', 'noupdate', False, _('do not update to target'))],
734 _("[-gbsr] [-U] [-c CMD] [REV]"))
733 _("[-gbsr] [-U] [-c CMD] [REV]"))
735 def bisect(ui, repo, rev=None, extra=None, command=None,
734 def bisect(ui, repo, rev=None, extra=None, command=None,
736 reset=None, good=None, bad=None, skip=None, extend=None,
735 reset=None, good=None, bad=None, skip=None, extend=None,
737 noupdate=None):
736 noupdate=None):
738 """subdivision search of changesets
737 """subdivision search of changesets
739
738
740 This command helps to find changesets which introduce problems. To
739 This command helps to find changesets which introduce problems. To
741 use, mark the earliest changeset you know exhibits the problem as
740 use, mark the earliest changeset you know exhibits the problem as
742 bad, then mark the latest changeset which is free from the problem
741 bad, then mark the latest changeset which is free from the problem
743 as good. Bisect will update your working directory to a revision
742 as good. Bisect will update your working directory to a revision
744 for testing (unless the -U/--noupdate option is specified). Once
743 for testing (unless the -U/--noupdate option is specified). Once
745 you have performed tests, mark the working directory as good or
744 you have performed tests, mark the working directory as good or
746 bad, and bisect will either update to another candidate changeset
745 bad, and bisect will either update to another candidate changeset
747 or announce that it has found the bad revision.
746 or announce that it has found the bad revision.
748
747
749 As a shortcut, you can also use the revision argument to mark a
748 As a shortcut, you can also use the revision argument to mark a
750 revision as good or bad without checking it out first.
749 revision as good or bad without checking it out first.
751
750
752 If you supply a command, it will be used for automatic bisection.
751 If you supply a command, it will be used for automatic bisection.
753 The environment variable HG_NODE will contain the ID of the
752 The environment variable HG_NODE will contain the ID of the
754 changeset being tested. The exit status of the command will be
753 changeset being tested. The exit status of the command will be
755 used to mark revisions as good or bad: status 0 means good, 125
754 used to mark revisions as good or bad: status 0 means good, 125
756 means to skip the revision, 127 (command not found) will abort the
755 means to skip the revision, 127 (command not found) will abort the
757 bisection, and any other non-zero exit status means the revision
756 bisection, and any other non-zero exit status means the revision
758 is bad.
757 is bad.
759
758
760 .. container:: verbose
759 .. container:: verbose
761
760
762 Some examples:
761 Some examples:
763
762
764 - start a bisection with known bad revision 34, and good revision 12::
763 - start a bisection with known bad revision 34, and good revision 12::
765
764
766 hg bisect --bad 34
765 hg bisect --bad 34
767 hg bisect --good 12
766 hg bisect --good 12
768
767
769 - advance the current bisection by marking current revision as good or
768 - advance the current bisection by marking current revision as good or
770 bad::
769 bad::
771
770
772 hg bisect --good
771 hg bisect --good
773 hg bisect --bad
772 hg bisect --bad
774
773
775 - mark the current revision, or a known revision, to be skipped (e.g. if
774 - mark the current revision, or a known revision, to be skipped (e.g. if
776 that revision is not usable because of another issue)::
775 that revision is not usable because of another issue)::
777
776
778 hg bisect --skip
777 hg bisect --skip
779 hg bisect --skip 23
778 hg bisect --skip 23
780
779
781 - skip all revisions that do not touch directories ``foo`` or ``bar``::
780 - skip all revisions that do not touch directories ``foo`` or ``bar``::
782
781
783 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
782 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
784
783
785 - forget the current bisection::
784 - forget the current bisection::
786
785
787 hg bisect --reset
786 hg bisect --reset
788
787
789 - use 'make && make tests' to automatically find the first broken
788 - use 'make && make tests' to automatically find the first broken
790 revision::
789 revision::
791
790
792 hg bisect --reset
791 hg bisect --reset
793 hg bisect --bad 34
792 hg bisect --bad 34
794 hg bisect --good 12
793 hg bisect --good 12
795 hg bisect --command "make && make tests"
794 hg bisect --command "make && make tests"
796
795
797 - see all changesets whose states are already known in the current
796 - see all changesets whose states are already known in the current
798 bisection::
797 bisection::
799
798
800 hg log -r "bisect(pruned)"
799 hg log -r "bisect(pruned)"
801
800
802 - see the changeset currently being bisected (especially useful
801 - see the changeset currently being bisected (especially useful
803 if running with -U/--noupdate)::
802 if running with -U/--noupdate)::
804
803
805 hg log -r "bisect(current)"
804 hg log -r "bisect(current)"
806
805
807 - see all changesets that took part in the current bisection::
806 - see all changesets that took part in the current bisection::
808
807
809 hg log -r "bisect(range)"
808 hg log -r "bisect(range)"
810
809
811 - you can even get a nice graph::
810 - you can even get a nice graph::
812
811
813 hg log --graph -r "bisect(range)"
812 hg log --graph -r "bisect(range)"
814
813
815 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
814 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
816
815
817 Returns 0 on success.
816 Returns 0 on success.
818 """
817 """
819 # backward compatibility
818 # backward compatibility
820 if rev in "good bad reset init".split():
819 if rev in "good bad reset init".split():
821 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
820 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
822 cmd, rev, extra = rev, extra, None
821 cmd, rev, extra = rev, extra, None
823 if cmd == "good":
822 if cmd == "good":
824 good = True
823 good = True
825 elif cmd == "bad":
824 elif cmd == "bad":
826 bad = True
825 bad = True
827 else:
826 else:
828 reset = True
827 reset = True
829 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
828 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
830 raise error.Abort(_('incompatible arguments'))
829 raise error.Abort(_('incompatible arguments'))
831
830
832 cmdutil.checkunfinished(repo)
831 cmdutil.checkunfinished(repo)
833
832
834 if reset:
833 if reset:
835 hbisect.resetstate(repo)
834 hbisect.resetstate(repo)
836 return
835 return
837
836
838 state = hbisect.load_state(repo)
837 state = hbisect.load_state(repo)
839
838
840 # update state
839 # update state
841 if good or bad or skip:
840 if good or bad or skip:
842 if rev:
841 if rev:
843 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
842 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
844 else:
843 else:
845 nodes = [repo.lookup('.')]
844 nodes = [repo.lookup('.')]
846 if good:
845 if good:
847 state['good'] += nodes
846 state['good'] += nodes
848 elif bad:
847 elif bad:
849 state['bad'] += nodes
848 state['bad'] += nodes
850 elif skip:
849 elif skip:
851 state['skip'] += nodes
850 state['skip'] += nodes
852 hbisect.save_state(repo, state)
851 hbisect.save_state(repo, state)
853 if not (state['good'] and state['bad']):
852 if not (state['good'] and state['bad']):
854 return
853 return
855
854
856 def mayupdate(repo, node, show_stats=True):
855 def mayupdate(repo, node, show_stats=True):
857 """common used update sequence"""
856 """common used update sequence"""
858 if noupdate:
857 if noupdate:
859 return
858 return
860 cmdutil.bailifchanged(repo)
859 cmdutil.bailifchanged(repo)
861 return hg.clean(repo, node, show_stats=show_stats)
860 return hg.clean(repo, node, show_stats=show_stats)
862
861
863 displayer = cmdutil.show_changeset(ui, repo, {})
862 displayer = cmdutil.show_changeset(ui, repo, {})
864
863
865 if command:
864 if command:
866 changesets = 1
865 changesets = 1
867 if noupdate:
866 if noupdate:
868 try:
867 try:
869 node = state['current'][0]
868 node = state['current'][0]
870 except LookupError:
869 except LookupError:
871 raise error.Abort(_('current bisect revision is unknown - '
870 raise error.Abort(_('current bisect revision is unknown - '
872 'start a new bisect to fix'))
871 'start a new bisect to fix'))
873 else:
872 else:
874 node, p2 = repo.dirstate.parents()
873 node, p2 = repo.dirstate.parents()
875 if p2 != nullid:
874 if p2 != nullid:
876 raise error.Abort(_('current bisect revision is a merge'))
875 raise error.Abort(_('current bisect revision is a merge'))
877 if rev:
876 if rev:
878 node = repo[scmutil.revsingle(repo, rev, node)].node()
877 node = repo[scmutil.revsingle(repo, rev, node)].node()
879 try:
878 try:
880 while changesets:
879 while changesets:
881 # update state
880 # update state
882 state['current'] = [node]
881 state['current'] = [node]
883 hbisect.save_state(repo, state)
882 hbisect.save_state(repo, state)
884 status = ui.system(command, environ={'HG_NODE': hex(node)})
883 status = ui.system(command, environ={'HG_NODE': hex(node)})
885 if status == 125:
884 if status == 125:
886 transition = "skip"
885 transition = "skip"
887 elif status == 0:
886 elif status == 0:
888 transition = "good"
887 transition = "good"
889 # status < 0 means process was killed
888 # status < 0 means process was killed
890 elif status == 127:
889 elif status == 127:
891 raise error.Abort(_("failed to execute %s") % command)
890 raise error.Abort(_("failed to execute %s") % command)
892 elif status < 0:
891 elif status < 0:
893 raise error.Abort(_("%s killed") % command)
892 raise error.Abort(_("%s killed") % command)
894 else:
893 else:
895 transition = "bad"
894 transition = "bad"
896 state[transition].append(node)
895 state[transition].append(node)
897 ctx = repo[node]
896 ctx = repo[node]
898 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
897 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
899 hbisect.checkstate(state)
898 hbisect.checkstate(state)
900 # bisect
899 # bisect
901 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
900 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
902 # update to next check
901 # update to next check
903 node = nodes[0]
902 node = nodes[0]
904 mayupdate(repo, node, show_stats=False)
903 mayupdate(repo, node, show_stats=False)
905 finally:
904 finally:
906 state['current'] = [node]
905 state['current'] = [node]
907 hbisect.save_state(repo, state)
906 hbisect.save_state(repo, state)
908 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
907 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
909 return
908 return
910
909
911 hbisect.checkstate(state)
910 hbisect.checkstate(state)
912
911
913 # actually bisect
912 # actually bisect
914 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
913 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
915 if extend:
914 if extend:
916 if not changesets:
915 if not changesets:
917 extendnode = hbisect.extendrange(repo, state, nodes, good)
916 extendnode = hbisect.extendrange(repo, state, nodes, good)
918 if extendnode is not None:
917 if extendnode is not None:
919 ui.write(_("Extending search to changeset %d:%s\n")
918 ui.write(_("Extending search to changeset %d:%s\n")
920 % (extendnode.rev(), extendnode))
919 % (extendnode.rev(), extendnode))
921 state['current'] = [extendnode.node()]
920 state['current'] = [extendnode.node()]
922 hbisect.save_state(repo, state)
921 hbisect.save_state(repo, state)
923 return mayupdate(repo, extendnode.node())
922 return mayupdate(repo, extendnode.node())
924 raise error.Abort(_("nothing to extend"))
923 raise error.Abort(_("nothing to extend"))
925
924
926 if changesets == 0:
925 if changesets == 0:
927 hbisect.printresult(ui, repo, state, displayer, nodes, good)
926 hbisect.printresult(ui, repo, state, displayer, nodes, good)
928 else:
927 else:
929 assert len(nodes) == 1 # only a single node can be tested next
928 assert len(nodes) == 1 # only a single node can be tested next
930 node = nodes[0]
929 node = nodes[0]
931 # compute the approximate number of remaining tests
930 # compute the approximate number of remaining tests
932 tests, size = 0, 2
931 tests, size = 0, 2
933 while size <= changesets:
932 while size <= changesets:
934 tests, size = tests + 1, size * 2
933 tests, size = tests + 1, size * 2
935 rev = repo.changelog.rev(node)
934 rev = repo.changelog.rev(node)
936 ui.write(_("Testing changeset %d:%s "
935 ui.write(_("Testing changeset %d:%s "
937 "(%d changesets remaining, ~%d tests)\n")
936 "(%d changesets remaining, ~%d tests)\n")
938 % (rev, short(node), changesets, tests))
937 % (rev, short(node), changesets, tests))
939 state['current'] = [node]
938 state['current'] = [node]
940 hbisect.save_state(repo, state)
939 hbisect.save_state(repo, state)
941 return mayupdate(repo, node)
940 return mayupdate(repo, node)
942
941
943 @command('bookmarks|bookmark',
942 @command('bookmarks|bookmark',
944 [('f', 'force', False, _('force')),
943 [('f', 'force', False, _('force')),
945 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
944 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
946 ('d', 'delete', False, _('delete a given bookmark')),
945 ('d', 'delete', False, _('delete a given bookmark')),
947 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
946 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
948 ('i', 'inactive', False, _('mark a bookmark inactive')),
947 ('i', 'inactive', False, _('mark a bookmark inactive')),
949 ] + formatteropts,
948 ] + formatteropts,
950 _('hg bookmarks [OPTIONS]... [NAME]...'))
949 _('hg bookmarks [OPTIONS]... [NAME]...'))
951 def bookmark(ui, repo, *names, **opts):
950 def bookmark(ui, repo, *names, **opts):
952 '''create a new bookmark or list existing bookmarks
951 '''create a new bookmark or list existing bookmarks
953
952
954 Bookmarks are labels on changesets to help track lines of development.
953 Bookmarks are labels on changesets to help track lines of development.
955 Bookmarks are unversioned and can be moved, renamed and deleted.
954 Bookmarks are unversioned and can be moved, renamed and deleted.
956 Deleting or moving a bookmark has no effect on the associated changesets.
955 Deleting or moving a bookmark has no effect on the associated changesets.
957
956
958 Creating or updating to a bookmark causes it to be marked as 'active'.
957 Creating or updating to a bookmark causes it to be marked as 'active'.
959 The active bookmark is indicated with a '*'.
958 The active bookmark is indicated with a '*'.
960 When a commit is made, the active bookmark will advance to the new commit.
959 When a commit is made, the active bookmark will advance to the new commit.
961 A plain :hg:`update` will also advance an active bookmark, if possible.
960 A plain :hg:`update` will also advance an active bookmark, if possible.
962 Updating away from a bookmark will cause it to be deactivated.
961 Updating away from a bookmark will cause it to be deactivated.
963
962
964 Bookmarks can be pushed and pulled between repositories (see
963 Bookmarks can be pushed and pulled between repositories (see
965 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
964 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
966 diverged, a new 'divergent bookmark' of the form 'name@path' will
965 diverged, a new 'divergent bookmark' of the form 'name@path' will
967 be created. Using :hg:`merge` will resolve the divergence.
966 be created. Using :hg:`merge` will resolve the divergence.
968
967
969 A bookmark named '@' has the special property that :hg:`clone` will
968 A bookmark named '@' has the special property that :hg:`clone` will
970 check it out by default if it exists.
969 check it out by default if it exists.
971
970
972 .. container:: verbose
971 .. container:: verbose
973
972
974 Examples:
973 Examples:
975
974
976 - create an active bookmark for a new line of development::
975 - create an active bookmark for a new line of development::
977
976
978 hg book new-feature
977 hg book new-feature
979
978
980 - create an inactive bookmark as a place marker::
979 - create an inactive bookmark as a place marker::
981
980
982 hg book -i reviewed
981 hg book -i reviewed
983
982
984 - create an inactive bookmark on another changeset::
983 - create an inactive bookmark on another changeset::
985
984
986 hg book -r .^ tested
985 hg book -r .^ tested
987
986
988 - rename bookmark turkey to dinner::
987 - rename bookmark turkey to dinner::
989
988
990 hg book -m turkey dinner
989 hg book -m turkey dinner
991
990
992 - move the '@' bookmark from another branch::
991 - move the '@' bookmark from another branch::
993
992
994 hg book -f @
993 hg book -f @
995 '''
994 '''
996 force = opts.get('force')
995 force = opts.get('force')
997 rev = opts.get('rev')
996 rev = opts.get('rev')
998 delete = opts.get('delete')
997 delete = opts.get('delete')
999 rename = opts.get('rename')
998 rename = opts.get('rename')
1000 inactive = opts.get('inactive')
999 inactive = opts.get('inactive')
1001
1000
1002 def checkformat(mark):
1001 def checkformat(mark):
1003 mark = mark.strip()
1002 mark = mark.strip()
1004 if not mark:
1003 if not mark:
1005 raise error.Abort(_("bookmark names cannot consist entirely of "
1004 raise error.Abort(_("bookmark names cannot consist entirely of "
1006 "whitespace"))
1005 "whitespace"))
1007 scmutil.checknewlabel(repo, mark, 'bookmark')
1006 scmutil.checknewlabel(repo, mark, 'bookmark')
1008 return mark
1007 return mark
1009
1008
1010 def checkconflict(repo, mark, cur, force=False, target=None):
1009 def checkconflict(repo, mark, cur, force=False, target=None):
1011 if mark in marks and not force:
1010 if mark in marks and not force:
1012 if target:
1011 if target:
1013 if marks[mark] == target and target == cur:
1012 if marks[mark] == target and target == cur:
1014 # re-activating a bookmark
1013 # re-activating a bookmark
1015 return
1014 return
1016 anc = repo.changelog.ancestors([repo[target].rev()])
1015 anc = repo.changelog.ancestors([repo[target].rev()])
1017 bmctx = repo[marks[mark]]
1016 bmctx = repo[marks[mark]]
1018 divs = [repo[b].node() for b in marks
1017 divs = [repo[b].node() for b in marks
1019 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1018 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1020
1019
1021 # allow resolving a single divergent bookmark even if moving
1020 # allow resolving a single divergent bookmark even if moving
1022 # the bookmark across branches when a revision is specified
1021 # the bookmark across branches when a revision is specified
1023 # that contains a divergent bookmark
1022 # that contains a divergent bookmark
1024 if bmctx.rev() not in anc and target in divs:
1023 if bmctx.rev() not in anc and target in divs:
1025 bookmarks.deletedivergent(repo, [target], mark)
1024 bookmarks.deletedivergent(repo, [target], mark)
1026 return
1025 return
1027
1026
1028 deletefrom = [b for b in divs
1027 deletefrom = [b for b in divs
1029 if repo[b].rev() in anc or b == target]
1028 if repo[b].rev() in anc or b == target]
1030 bookmarks.deletedivergent(repo, deletefrom, mark)
1029 bookmarks.deletedivergent(repo, deletefrom, mark)
1031 if bookmarks.validdest(repo, bmctx, repo[target]):
1030 if bookmarks.validdest(repo, bmctx, repo[target]):
1032 ui.status(_("moving bookmark '%s' forward from %s\n") %
1031 ui.status(_("moving bookmark '%s' forward from %s\n") %
1033 (mark, short(bmctx.node())))
1032 (mark, short(bmctx.node())))
1034 return
1033 return
1035 raise error.Abort(_("bookmark '%s' already exists "
1034 raise error.Abort(_("bookmark '%s' already exists "
1036 "(use -f to force)") % mark)
1035 "(use -f to force)") % mark)
1037 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1036 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1038 and not force):
1037 and not force):
1039 raise error.Abort(
1038 raise error.Abort(
1040 _("a bookmark cannot have the name of an existing branch"))
1039 _("a bookmark cannot have the name of an existing branch"))
1041
1040
1042 if delete and rename:
1041 if delete and rename:
1043 raise error.Abort(_("--delete and --rename are incompatible"))
1042 raise error.Abort(_("--delete and --rename are incompatible"))
1044 if delete and rev:
1043 if delete and rev:
1045 raise error.Abort(_("--rev is incompatible with --delete"))
1044 raise error.Abort(_("--rev is incompatible with --delete"))
1046 if rename and rev:
1045 if rename and rev:
1047 raise error.Abort(_("--rev is incompatible with --rename"))
1046 raise error.Abort(_("--rev is incompatible with --rename"))
1048 if not names and (delete or rev):
1047 if not names and (delete or rev):
1049 raise error.Abort(_("bookmark name required"))
1048 raise error.Abort(_("bookmark name required"))
1050
1049
1051 if delete or rename or names or inactive:
1050 if delete or rename or names or inactive:
1052 wlock = lock = tr = None
1051 wlock = lock = tr = None
1053 try:
1052 try:
1054 wlock = repo.wlock()
1053 wlock = repo.wlock()
1055 lock = repo.lock()
1054 lock = repo.lock()
1056 cur = repo.changectx('.').node()
1055 cur = repo.changectx('.').node()
1057 marks = repo._bookmarks
1056 marks = repo._bookmarks
1058 if delete:
1057 if delete:
1059 tr = repo.transaction('bookmark')
1058 tr = repo.transaction('bookmark')
1060 for mark in names:
1059 for mark in names:
1061 if mark not in marks:
1060 if mark not in marks:
1062 raise error.Abort(_("bookmark '%s' does not exist") %
1061 raise error.Abort(_("bookmark '%s' does not exist") %
1063 mark)
1062 mark)
1064 if mark == repo._activebookmark:
1063 if mark == repo._activebookmark:
1065 bookmarks.deactivate(repo)
1064 bookmarks.deactivate(repo)
1066 del marks[mark]
1065 del marks[mark]
1067
1066
1068 elif rename:
1067 elif rename:
1069 tr = repo.transaction('bookmark')
1068 tr = repo.transaction('bookmark')
1070 if not names:
1069 if not names:
1071 raise error.Abort(_("new bookmark name required"))
1070 raise error.Abort(_("new bookmark name required"))
1072 elif len(names) > 1:
1071 elif len(names) > 1:
1073 raise error.Abort(_("only one new bookmark name allowed"))
1072 raise error.Abort(_("only one new bookmark name allowed"))
1074 mark = checkformat(names[0])
1073 mark = checkformat(names[0])
1075 if rename not in marks:
1074 if rename not in marks:
1076 raise error.Abort(_("bookmark '%s' does not exist")
1075 raise error.Abort(_("bookmark '%s' does not exist")
1077 % rename)
1076 % rename)
1078 checkconflict(repo, mark, cur, force)
1077 checkconflict(repo, mark, cur, force)
1079 marks[mark] = marks[rename]
1078 marks[mark] = marks[rename]
1080 if repo._activebookmark == rename and not inactive:
1079 if repo._activebookmark == rename and not inactive:
1081 bookmarks.activate(repo, mark)
1080 bookmarks.activate(repo, mark)
1082 del marks[rename]
1081 del marks[rename]
1083 elif names:
1082 elif names:
1084 tr = repo.transaction('bookmark')
1083 tr = repo.transaction('bookmark')
1085 newact = None
1084 newact = None
1086 for mark in names:
1085 for mark in names:
1087 mark = checkformat(mark)
1086 mark = checkformat(mark)
1088 if newact is None:
1087 if newact is None:
1089 newact = mark
1088 newact = mark
1090 if inactive and mark == repo._activebookmark:
1089 if inactive and mark == repo._activebookmark:
1091 bookmarks.deactivate(repo)
1090 bookmarks.deactivate(repo)
1092 return
1091 return
1093 tgt = cur
1092 tgt = cur
1094 if rev:
1093 if rev:
1095 tgt = scmutil.revsingle(repo, rev).node()
1094 tgt = scmutil.revsingle(repo, rev).node()
1096 checkconflict(repo, mark, cur, force, tgt)
1095 checkconflict(repo, mark, cur, force, tgt)
1097 marks[mark] = tgt
1096 marks[mark] = tgt
1098 if not inactive and cur == marks[newact] and not rev:
1097 if not inactive and cur == marks[newact] and not rev:
1099 bookmarks.activate(repo, newact)
1098 bookmarks.activate(repo, newact)
1100 elif cur != tgt and newact == repo._activebookmark:
1099 elif cur != tgt and newact == repo._activebookmark:
1101 bookmarks.deactivate(repo)
1100 bookmarks.deactivate(repo)
1102 elif inactive:
1101 elif inactive:
1103 if len(marks) == 0:
1102 if len(marks) == 0:
1104 ui.status(_("no bookmarks set\n"))
1103 ui.status(_("no bookmarks set\n"))
1105 elif not repo._activebookmark:
1104 elif not repo._activebookmark:
1106 ui.status(_("no active bookmark\n"))
1105 ui.status(_("no active bookmark\n"))
1107 else:
1106 else:
1108 bookmarks.deactivate(repo)
1107 bookmarks.deactivate(repo)
1109 if tr is not None:
1108 if tr is not None:
1110 marks.recordchange(tr)
1109 marks.recordchange(tr)
1111 tr.close()
1110 tr.close()
1112 finally:
1111 finally:
1113 lockmod.release(tr, lock, wlock)
1112 lockmod.release(tr, lock, wlock)
1114 else: # show bookmarks
1113 else: # show bookmarks
1115 fm = ui.formatter('bookmarks', opts)
1114 fm = ui.formatter('bookmarks', opts)
1116 hexfn = fm.hexfunc
1115 hexfn = fm.hexfunc
1117 marks = repo._bookmarks
1116 marks = repo._bookmarks
1118 if len(marks) == 0 and fm.isplain():
1117 if len(marks) == 0 and fm.isplain():
1119 ui.status(_("no bookmarks set\n"))
1118 ui.status(_("no bookmarks set\n"))
1120 for bmark, n in sorted(marks.iteritems()):
1119 for bmark, n in sorted(marks.iteritems()):
1121 active = repo._activebookmark
1120 active = repo._activebookmark
1122 if bmark == active:
1121 if bmark == active:
1123 prefix, label = '*', activebookmarklabel
1122 prefix, label = '*', activebookmarklabel
1124 else:
1123 else:
1125 prefix, label = ' ', ''
1124 prefix, label = ' ', ''
1126
1125
1127 fm.startitem()
1126 fm.startitem()
1128 if not ui.quiet:
1127 if not ui.quiet:
1129 fm.plain(' %s ' % prefix, label=label)
1128 fm.plain(' %s ' % prefix, label=label)
1130 fm.write('bookmark', '%s', bmark, label=label)
1129 fm.write('bookmark', '%s', bmark, label=label)
1131 pad = " " * (25 - encoding.colwidth(bmark))
1130 pad = " " * (25 - encoding.colwidth(bmark))
1132 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1131 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1133 repo.changelog.rev(n), hexfn(n), label=label)
1132 repo.changelog.rev(n), hexfn(n), label=label)
1134 fm.data(active=(bmark == active))
1133 fm.data(active=(bmark == active))
1135 fm.plain('\n')
1134 fm.plain('\n')
1136 fm.end()
1135 fm.end()
1137
1136
1138 @command('branch',
1137 @command('branch',
1139 [('f', 'force', None,
1138 [('f', 'force', None,
1140 _('set branch name even if it shadows an existing branch')),
1139 _('set branch name even if it shadows an existing branch')),
1141 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1140 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1142 _('[-fC] [NAME]'))
1141 _('[-fC] [NAME]'))
1143 def branch(ui, repo, label=None, **opts):
1142 def branch(ui, repo, label=None, **opts):
1144 """set or show the current branch name
1143 """set or show the current branch name
1145
1144
1146 .. note::
1145 .. note::
1147
1146
1148 Branch names are permanent and global. Use :hg:`bookmark` to create a
1147 Branch names are permanent and global. Use :hg:`bookmark` to create a
1149 light-weight bookmark instead. See :hg:`help glossary` for more
1148 light-weight bookmark instead. See :hg:`help glossary` for more
1150 information about named branches and bookmarks.
1149 information about named branches and bookmarks.
1151
1150
1152 With no argument, show the current branch name. With one argument,
1151 With no argument, show the current branch name. With one argument,
1153 set the working directory branch name (the branch will not exist
1152 set the working directory branch name (the branch will not exist
1154 in the repository until the next commit). Standard practice
1153 in the repository until the next commit). Standard practice
1155 recommends that primary development take place on the 'default'
1154 recommends that primary development take place on the 'default'
1156 branch.
1155 branch.
1157
1156
1158 Unless -f/--force is specified, branch will not let you set a
1157 Unless -f/--force is specified, branch will not let you set a
1159 branch name that already exists.
1158 branch name that already exists.
1160
1159
1161 Use -C/--clean to reset the working directory branch to that of
1160 Use -C/--clean to reset the working directory branch to that of
1162 the parent of the working directory, negating a previous branch
1161 the parent of the working directory, negating a previous branch
1163 change.
1162 change.
1164
1163
1165 Use the command :hg:`update` to switch to an existing branch. Use
1164 Use the command :hg:`update` to switch to an existing branch. Use
1166 :hg:`commit --close-branch` to mark this branch head as closed.
1165 :hg:`commit --close-branch` to mark this branch head as closed.
1167 When all heads of a branch are closed, the branch will be
1166 When all heads of a branch are closed, the branch will be
1168 considered closed.
1167 considered closed.
1169
1168
1170 Returns 0 on success.
1169 Returns 0 on success.
1171 """
1170 """
1172 if label:
1171 if label:
1173 label = label.strip()
1172 label = label.strip()
1174
1173
1175 if not opts.get('clean') and not label:
1174 if not opts.get('clean') and not label:
1176 ui.write("%s\n" % repo.dirstate.branch())
1175 ui.write("%s\n" % repo.dirstate.branch())
1177 return
1176 return
1178
1177
1179 with repo.wlock():
1178 with repo.wlock():
1180 if opts.get('clean'):
1179 if opts.get('clean'):
1181 label = repo[None].p1().branch()
1180 label = repo[None].p1().branch()
1182 repo.dirstate.setbranch(label)
1181 repo.dirstate.setbranch(label)
1183 ui.status(_('reset working directory to branch %s\n') % label)
1182 ui.status(_('reset working directory to branch %s\n') % label)
1184 elif label:
1183 elif label:
1185 if not opts.get('force') and label in repo.branchmap():
1184 if not opts.get('force') and label in repo.branchmap():
1186 if label not in [p.branch() for p in repo[None].parents()]:
1185 if label not in [p.branch() for p in repo[None].parents()]:
1187 raise error.Abort(_('a branch of the same name already'
1186 raise error.Abort(_('a branch of the same name already'
1188 ' exists'),
1187 ' exists'),
1189 # i18n: "it" refers to an existing branch
1188 # i18n: "it" refers to an existing branch
1190 hint=_("use 'hg update' to switch to it"))
1189 hint=_("use 'hg update' to switch to it"))
1191 scmutil.checknewlabel(repo, label, 'branch')
1190 scmutil.checknewlabel(repo, label, 'branch')
1192 repo.dirstate.setbranch(label)
1191 repo.dirstate.setbranch(label)
1193 ui.status(_('marked working directory as branch %s\n') % label)
1192 ui.status(_('marked working directory as branch %s\n') % label)
1194
1193
1195 # find any open named branches aside from default
1194 # find any open named branches aside from default
1196 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1195 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1197 if n != "default" and not c]
1196 if n != "default" and not c]
1198 if not others:
1197 if not others:
1199 ui.status(_('(branches are permanent and global, '
1198 ui.status(_('(branches are permanent and global, '
1200 'did you want a bookmark?)\n'))
1199 'did you want a bookmark?)\n'))
1201
1200
1202 @command('branches',
1201 @command('branches',
1203 [('a', 'active', False,
1202 [('a', 'active', False,
1204 _('show only branches that have unmerged heads (DEPRECATED)')),
1203 _('show only branches that have unmerged heads (DEPRECATED)')),
1205 ('c', 'closed', False, _('show normal and closed branches')),
1204 ('c', 'closed', False, _('show normal and closed branches')),
1206 ] + formatteropts,
1205 ] + formatteropts,
1207 _('[-c]'))
1206 _('[-c]'))
1208 def branches(ui, repo, active=False, closed=False, **opts):
1207 def branches(ui, repo, active=False, closed=False, **opts):
1209 """list repository named branches
1208 """list repository named branches
1210
1209
1211 List the repository's named branches, indicating which ones are
1210 List the repository's named branches, indicating which ones are
1212 inactive. If -c/--closed is specified, also list branches which have
1211 inactive. If -c/--closed is specified, also list branches which have
1213 been marked closed (see :hg:`commit --close-branch`).
1212 been marked closed (see :hg:`commit --close-branch`).
1214
1213
1215 Use the command :hg:`update` to switch to an existing branch.
1214 Use the command :hg:`update` to switch to an existing branch.
1216
1215
1217 Returns 0.
1216 Returns 0.
1218 """
1217 """
1219
1218
1220 fm = ui.formatter('branches', opts)
1219 fm = ui.formatter('branches', opts)
1221 hexfunc = fm.hexfunc
1220 hexfunc = fm.hexfunc
1222
1221
1223 allheads = set(repo.heads())
1222 allheads = set(repo.heads())
1224 branches = []
1223 branches = []
1225 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1224 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1226 isactive = not isclosed and bool(set(heads) & allheads)
1225 isactive = not isclosed and bool(set(heads) & allheads)
1227 branches.append((tag, repo[tip], isactive, not isclosed))
1226 branches.append((tag, repo[tip], isactive, not isclosed))
1228 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1227 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1229 reverse=True)
1228 reverse=True)
1230
1229
1231 for tag, ctx, isactive, isopen in branches:
1230 for tag, ctx, isactive, isopen in branches:
1232 if active and not isactive:
1231 if active and not isactive:
1233 continue
1232 continue
1234 if isactive:
1233 if isactive:
1235 label = 'branches.active'
1234 label = 'branches.active'
1236 notice = ''
1235 notice = ''
1237 elif not isopen:
1236 elif not isopen:
1238 if not closed:
1237 if not closed:
1239 continue
1238 continue
1240 label = 'branches.closed'
1239 label = 'branches.closed'
1241 notice = _(' (closed)')
1240 notice = _(' (closed)')
1242 else:
1241 else:
1243 label = 'branches.inactive'
1242 label = 'branches.inactive'
1244 notice = _(' (inactive)')
1243 notice = _(' (inactive)')
1245 current = (tag == repo.dirstate.branch())
1244 current = (tag == repo.dirstate.branch())
1246 if current:
1245 if current:
1247 label = 'branches.current'
1246 label = 'branches.current'
1248
1247
1249 fm.startitem()
1248 fm.startitem()
1250 fm.write('branch', '%s', tag, label=label)
1249 fm.write('branch', '%s', tag, label=label)
1251 rev = ctx.rev()
1250 rev = ctx.rev()
1252 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1251 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1253 fmt = ' ' * padsize + ' %d:%s'
1252 fmt = ' ' * padsize + ' %d:%s'
1254 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1253 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1255 label='log.changeset changeset.%s' % ctx.phasestr())
1254 label='log.changeset changeset.%s' % ctx.phasestr())
1256 fm.data(active=isactive, closed=not isopen, current=current)
1255 fm.data(active=isactive, closed=not isopen, current=current)
1257 if not ui.quiet:
1256 if not ui.quiet:
1258 fm.plain(notice)
1257 fm.plain(notice)
1259 fm.plain('\n')
1258 fm.plain('\n')
1260 fm.end()
1259 fm.end()
1261
1260
1262 @command('bundle',
1261 @command('bundle',
1263 [('f', 'force', None, _('run even when the destination is unrelated')),
1262 [('f', 'force', None, _('run even when the destination is unrelated')),
1264 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1263 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1265 _('REV')),
1264 _('REV')),
1266 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1265 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1267 _('BRANCH')),
1266 _('BRANCH')),
1268 ('', 'base', [],
1267 ('', 'base', [],
1269 _('a base changeset assumed to be available at the destination'),
1268 _('a base changeset assumed to be available at the destination'),
1270 _('REV')),
1269 _('REV')),
1271 ('a', 'all', None, _('bundle all changesets in the repository')),
1270 ('a', 'all', None, _('bundle all changesets in the repository')),
1272 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1271 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1273 ] + remoteopts,
1272 ] + remoteopts,
1274 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1273 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1275 def bundle(ui, repo, fname, dest=None, **opts):
1274 def bundle(ui, repo, fname, dest=None, **opts):
1276 """create a changegroup file
1275 """create a changegroup file
1277
1276
1278 Generate a changegroup file collecting changesets to be added
1277 Generate a changegroup file collecting changesets to be added
1279 to a repository.
1278 to a repository.
1280
1279
1281 To create a bundle containing all changesets, use -a/--all
1280 To create a bundle containing all changesets, use -a/--all
1282 (or --base null). Otherwise, hg assumes the destination will have
1281 (or --base null). Otherwise, hg assumes the destination will have
1283 all the nodes you specify with --base parameters. Otherwise, hg
1282 all the nodes you specify with --base parameters. Otherwise, hg
1284 will assume the repository has all the nodes in destination, or
1283 will assume the repository has all the nodes in destination, or
1285 default-push/default if no destination is specified.
1284 default-push/default if no destination is specified.
1286
1285
1287 You can change bundle format with the -t/--type option. You can
1286 You can change bundle format with the -t/--type option. You can
1288 specify a compression, a bundle version or both using a dash
1287 specify a compression, a bundle version or both using a dash
1289 (comp-version). The available compression methods are: none, bzip2,
1288 (comp-version). The available compression methods are: none, bzip2,
1290 and gzip (by default, bundles are compressed using bzip2). The
1289 and gzip (by default, bundles are compressed using bzip2). The
1291 available formats are: v1, v2 (default to most suitable).
1290 available formats are: v1, v2 (default to most suitable).
1292
1291
1293 The bundle file can then be transferred using conventional means
1292 The bundle file can then be transferred using conventional means
1294 and applied to another repository with the unbundle or pull
1293 and applied to another repository with the unbundle or pull
1295 command. This is useful when direct push and pull are not
1294 command. This is useful when direct push and pull are not
1296 available or when exporting an entire repository is undesirable.
1295 available or when exporting an entire repository is undesirable.
1297
1296
1298 Applying bundles preserves all changeset contents including
1297 Applying bundles preserves all changeset contents including
1299 permissions, copy/rename information, and revision history.
1298 permissions, copy/rename information, and revision history.
1300
1299
1301 Returns 0 on success, 1 if no changes found.
1300 Returns 0 on success, 1 if no changes found.
1302 """
1301 """
1303 revs = None
1302 revs = None
1304 if 'rev' in opts:
1303 if 'rev' in opts:
1305 revstrings = opts['rev']
1304 revstrings = opts['rev']
1306 revs = scmutil.revrange(repo, revstrings)
1305 revs = scmutil.revrange(repo, revstrings)
1307 if revstrings and not revs:
1306 if revstrings and not revs:
1308 raise error.Abort(_('no commits to bundle'))
1307 raise error.Abort(_('no commits to bundle'))
1309
1308
1310 bundletype = opts.get('type', 'bzip2').lower()
1309 bundletype = opts.get('type', 'bzip2').lower()
1311 try:
1310 try:
1312 bcompression, cgversion, params = exchange.parsebundlespec(
1311 bcompression, cgversion, params = exchange.parsebundlespec(
1313 repo, bundletype, strict=False)
1312 repo, bundletype, strict=False)
1314 except error.UnsupportedBundleSpecification as e:
1313 except error.UnsupportedBundleSpecification as e:
1315 raise error.Abort(str(e),
1314 raise error.Abort(str(e),
1316 hint=_("see 'hg help bundle' for supported "
1315 hint=_("see 'hg help bundle' for supported "
1317 "values for --type"))
1316 "values for --type"))
1318
1317
1319 # Packed bundles are a pseudo bundle format for now.
1318 # Packed bundles are a pseudo bundle format for now.
1320 if cgversion == 's1':
1319 if cgversion == 's1':
1321 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1320 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1322 hint=_("use 'hg debugcreatestreamclonebundle'"))
1321 hint=_("use 'hg debugcreatestreamclonebundle'"))
1323
1322
1324 if opts.get('all'):
1323 if opts.get('all'):
1325 if dest:
1324 if dest:
1326 raise error.Abort(_("--all is incompatible with specifying "
1325 raise error.Abort(_("--all is incompatible with specifying "
1327 "a destination"))
1326 "a destination"))
1328 if opts.get('base'):
1327 if opts.get('base'):
1329 ui.warn(_("ignoring --base because --all was specified\n"))
1328 ui.warn(_("ignoring --base because --all was specified\n"))
1330 base = ['null']
1329 base = ['null']
1331 else:
1330 else:
1332 base = scmutil.revrange(repo, opts.get('base'))
1331 base = scmutil.revrange(repo, opts.get('base'))
1333 # TODO: get desired bundlecaps from command line.
1332 # TODO: get desired bundlecaps from command line.
1334 bundlecaps = None
1333 bundlecaps = None
1335 if cgversion not in changegroup.supportedoutgoingversions(repo):
1334 if cgversion not in changegroup.supportedoutgoingversions(repo):
1336 raise error.Abort(_("repository does not support bundle version %s") %
1335 raise error.Abort(_("repository does not support bundle version %s") %
1337 cgversion)
1336 cgversion)
1338
1337
1339 if base:
1338 if base:
1340 if dest:
1339 if dest:
1341 raise error.Abort(_("--base is incompatible with specifying "
1340 raise error.Abort(_("--base is incompatible with specifying "
1342 "a destination"))
1341 "a destination"))
1343 common = [repo.lookup(rev) for rev in base]
1342 common = [repo.lookup(rev) for rev in base]
1344 heads = revs and map(repo.lookup, revs) or None
1343 heads = revs and map(repo.lookup, revs) or None
1345 outgoing = discovery.outgoing(repo, common, heads)
1344 outgoing = discovery.outgoing(repo, common, heads)
1346 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1345 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1347 bundlecaps=bundlecaps,
1346 bundlecaps=bundlecaps,
1348 version=cgversion)
1347 version=cgversion)
1349 outgoing = None
1348 outgoing = None
1350 else:
1349 else:
1351 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1350 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1352 dest, branches = hg.parseurl(dest, opts.get('branch'))
1351 dest, branches = hg.parseurl(dest, opts.get('branch'))
1353 other = hg.peer(repo, opts, dest)
1352 other = hg.peer(repo, opts, dest)
1354 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1353 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1355 heads = revs and map(repo.lookup, revs) or revs
1354 heads = revs and map(repo.lookup, revs) or revs
1356 outgoing = discovery.findcommonoutgoing(repo, other,
1355 outgoing = discovery.findcommonoutgoing(repo, other,
1357 onlyheads=heads,
1356 onlyheads=heads,
1358 force=opts.get('force'),
1357 force=opts.get('force'),
1359 portable=True)
1358 portable=True)
1360 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1359 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1361 bundlecaps, version=cgversion)
1360 bundlecaps, version=cgversion)
1362 if not cg:
1361 if not cg:
1363 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1362 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1364 return 1
1363 return 1
1365
1364
1366 if cgversion == '01': #bundle1
1365 if cgversion == '01': #bundle1
1367 if bcompression is None:
1366 if bcompression is None:
1368 bcompression = 'UN'
1367 bcompression = 'UN'
1369 bversion = 'HG10' + bcompression
1368 bversion = 'HG10' + bcompression
1370 bcompression = None
1369 bcompression = None
1371 else:
1370 else:
1372 assert cgversion == '02'
1371 assert cgversion == '02'
1373 bversion = 'HG20'
1372 bversion = 'HG20'
1374
1373
1375 # TODO compression options should be derived from bundlespec parsing.
1374 # TODO compression options should be derived from bundlespec parsing.
1376 # This is a temporary hack to allow adjusting bundle compression
1375 # This is a temporary hack to allow adjusting bundle compression
1377 # level without a) formalizing the bundlespec changes to declare it
1376 # level without a) formalizing the bundlespec changes to declare it
1378 # b) introducing a command flag.
1377 # b) introducing a command flag.
1379 compopts = {}
1378 compopts = {}
1380 complevel = ui.configint('experimental', 'bundlecomplevel')
1379 complevel = ui.configint('experimental', 'bundlecomplevel')
1381 if complevel is not None:
1380 if complevel is not None:
1382 compopts['level'] = complevel
1381 compopts['level'] = complevel
1383
1382
1384 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1383 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1385 compopts=compopts)
1384 compopts=compopts)
1386
1385
1387 @command('cat',
1386 @command('cat',
1388 [('o', 'output', '',
1387 [('o', 'output', '',
1389 _('print output to file with formatted name'), _('FORMAT')),
1388 _('print output to file with formatted name'), _('FORMAT')),
1390 ('r', 'rev', '', _('print the given revision'), _('REV')),
1389 ('r', 'rev', '', _('print the given revision'), _('REV')),
1391 ('', 'decode', None, _('apply any matching decode filter')),
1390 ('', 'decode', None, _('apply any matching decode filter')),
1392 ] + walkopts,
1391 ] + walkopts,
1393 _('[OPTION]... FILE...'),
1392 _('[OPTION]... FILE...'),
1394 inferrepo=True)
1393 inferrepo=True)
1395 def cat(ui, repo, file1, *pats, **opts):
1394 def cat(ui, repo, file1, *pats, **opts):
1396 """output the current or given revision of files
1395 """output the current or given revision of files
1397
1396
1398 Print the specified files as they were at the given revision. If
1397 Print the specified files as they were at the given revision. If
1399 no revision is given, the parent of the working directory is used.
1398 no revision is given, the parent of the working directory is used.
1400
1399
1401 Output may be to a file, in which case the name of the file is
1400 Output may be to a file, in which case the name of the file is
1402 given using a format string. The formatting rules as follows:
1401 given using a format string. The formatting rules as follows:
1403
1402
1404 :``%%``: literal "%" character
1403 :``%%``: literal "%" character
1405 :``%s``: basename of file being printed
1404 :``%s``: basename of file being printed
1406 :``%d``: dirname of file being printed, or '.' if in repository root
1405 :``%d``: dirname of file being printed, or '.' if in repository root
1407 :``%p``: root-relative path name of file being printed
1406 :``%p``: root-relative path name of file being printed
1408 :``%H``: changeset hash (40 hexadecimal digits)
1407 :``%H``: changeset hash (40 hexadecimal digits)
1409 :``%R``: changeset revision number
1408 :``%R``: changeset revision number
1410 :``%h``: short-form changeset hash (12 hexadecimal digits)
1409 :``%h``: short-form changeset hash (12 hexadecimal digits)
1411 :``%r``: zero-padded changeset revision number
1410 :``%r``: zero-padded changeset revision number
1412 :``%b``: basename of the exporting repository
1411 :``%b``: basename of the exporting repository
1413
1412
1414 Returns 0 on success.
1413 Returns 0 on success.
1415 """
1414 """
1416 ctx = scmutil.revsingle(repo, opts.get('rev'))
1415 ctx = scmutil.revsingle(repo, opts.get('rev'))
1417 m = scmutil.match(ctx, (file1,) + pats, opts)
1416 m = scmutil.match(ctx, (file1,) + pats, opts)
1418
1417
1419 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1418 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1420
1419
1421 @command('^clone',
1420 @command('^clone',
1422 [('U', 'noupdate', None, _('the clone will include an empty working '
1421 [('U', 'noupdate', None, _('the clone will include an empty working '
1423 'directory (only a repository)')),
1422 'directory (only a repository)')),
1424 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1423 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1425 _('REV')),
1424 _('REV')),
1426 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1425 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1427 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1426 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1428 ('', 'pull', None, _('use pull protocol to copy metadata')),
1427 ('', 'pull', None, _('use pull protocol to copy metadata')),
1429 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1428 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1430 ] + remoteopts,
1429 ] + remoteopts,
1431 _('[OPTION]... SOURCE [DEST]'),
1430 _('[OPTION]... SOURCE [DEST]'),
1432 norepo=True)
1431 norepo=True)
1433 def clone(ui, source, dest=None, **opts):
1432 def clone(ui, source, dest=None, **opts):
1434 """make a copy of an existing repository
1433 """make a copy of an existing repository
1435
1434
1436 Create a copy of an existing repository in a new directory.
1435 Create a copy of an existing repository in a new directory.
1437
1436
1438 If no destination directory name is specified, it defaults to the
1437 If no destination directory name is specified, it defaults to the
1439 basename of the source.
1438 basename of the source.
1440
1439
1441 The location of the source is added to the new repository's
1440 The location of the source is added to the new repository's
1442 ``.hg/hgrc`` file, as the default to be used for future pulls.
1441 ``.hg/hgrc`` file, as the default to be used for future pulls.
1443
1442
1444 Only local paths and ``ssh://`` URLs are supported as
1443 Only local paths and ``ssh://`` URLs are supported as
1445 destinations. For ``ssh://`` destinations, no working directory or
1444 destinations. For ``ssh://`` destinations, no working directory or
1446 ``.hg/hgrc`` will be created on the remote side.
1445 ``.hg/hgrc`` will be created on the remote side.
1447
1446
1448 If the source repository has a bookmark called '@' set, that
1447 If the source repository has a bookmark called '@' set, that
1449 revision will be checked out in the new repository by default.
1448 revision will be checked out in the new repository by default.
1450
1449
1451 To check out a particular version, use -u/--update, or
1450 To check out a particular version, use -u/--update, or
1452 -U/--noupdate to create a clone with no working directory.
1451 -U/--noupdate to create a clone with no working directory.
1453
1452
1454 To pull only a subset of changesets, specify one or more revisions
1453 To pull only a subset of changesets, specify one or more revisions
1455 identifiers with -r/--rev or branches with -b/--branch. The
1454 identifiers with -r/--rev or branches with -b/--branch. The
1456 resulting clone will contain only the specified changesets and
1455 resulting clone will contain only the specified changesets and
1457 their ancestors. These options (or 'clone src#rev dest') imply
1456 their ancestors. These options (or 'clone src#rev dest') imply
1458 --pull, even for local source repositories.
1457 --pull, even for local source repositories.
1459
1458
1460 .. note::
1459 .. note::
1461
1460
1462 Specifying a tag will include the tagged changeset but not the
1461 Specifying a tag will include the tagged changeset but not the
1463 changeset containing the tag.
1462 changeset containing the tag.
1464
1463
1465 .. container:: verbose
1464 .. container:: verbose
1466
1465
1467 For efficiency, hardlinks are used for cloning whenever the
1466 For efficiency, hardlinks are used for cloning whenever the
1468 source and destination are on the same filesystem (note this
1467 source and destination are on the same filesystem (note this
1469 applies only to the repository data, not to the working
1468 applies only to the repository data, not to the working
1470 directory). Some filesystems, such as AFS, implement hardlinking
1469 directory). Some filesystems, such as AFS, implement hardlinking
1471 incorrectly, but do not report errors. In these cases, use the
1470 incorrectly, but do not report errors. In these cases, use the
1472 --pull option to avoid hardlinking.
1471 --pull option to avoid hardlinking.
1473
1472
1474 In some cases, you can clone repositories and the working
1473 In some cases, you can clone repositories and the working
1475 directory using full hardlinks with ::
1474 directory using full hardlinks with ::
1476
1475
1477 $ cp -al REPO REPOCLONE
1476 $ cp -al REPO REPOCLONE
1478
1477
1479 This is the fastest way to clone, but it is not always safe. The
1478 This is the fastest way to clone, but it is not always safe. The
1480 operation is not atomic (making sure REPO is not modified during
1479 operation is not atomic (making sure REPO is not modified during
1481 the operation is up to you) and you have to make sure your
1480 the operation is up to you) and you have to make sure your
1482 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1481 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1483 so). Also, this is not compatible with certain extensions that
1482 so). Also, this is not compatible with certain extensions that
1484 place their metadata under the .hg directory, such as mq.
1483 place their metadata under the .hg directory, such as mq.
1485
1484
1486 Mercurial will update the working directory to the first applicable
1485 Mercurial will update the working directory to the first applicable
1487 revision from this list:
1486 revision from this list:
1488
1487
1489 a) null if -U or the source repository has no changesets
1488 a) null if -U or the source repository has no changesets
1490 b) if -u . and the source repository is local, the first parent of
1489 b) if -u . and the source repository is local, the first parent of
1491 the source repository's working directory
1490 the source repository's working directory
1492 c) the changeset specified with -u (if a branch name, this means the
1491 c) the changeset specified with -u (if a branch name, this means the
1493 latest head of that branch)
1492 latest head of that branch)
1494 d) the changeset specified with -r
1493 d) the changeset specified with -r
1495 e) the tipmost head specified with -b
1494 e) the tipmost head specified with -b
1496 f) the tipmost head specified with the url#branch source syntax
1495 f) the tipmost head specified with the url#branch source syntax
1497 g) the revision marked with the '@' bookmark, if present
1496 g) the revision marked with the '@' bookmark, if present
1498 h) the tipmost head of the default branch
1497 h) the tipmost head of the default branch
1499 i) tip
1498 i) tip
1500
1499
1501 When cloning from servers that support it, Mercurial may fetch
1500 When cloning from servers that support it, Mercurial may fetch
1502 pre-generated data from a server-advertised URL. When this is done,
1501 pre-generated data from a server-advertised URL. When this is done,
1503 hooks operating on incoming changesets and changegroups may fire twice,
1502 hooks operating on incoming changesets and changegroups may fire twice,
1504 once for the bundle fetched from the URL and another for any additional
1503 once for the bundle fetched from the URL and another for any additional
1505 data not fetched from this URL. In addition, if an error occurs, the
1504 data not fetched from this URL. In addition, if an error occurs, the
1506 repository may be rolled back to a partial clone. This behavior may
1505 repository may be rolled back to a partial clone. This behavior may
1507 change in future releases. See :hg:`help -e clonebundles` for more.
1506 change in future releases. See :hg:`help -e clonebundles` for more.
1508
1507
1509 Examples:
1508 Examples:
1510
1509
1511 - clone a remote repository to a new directory named hg/::
1510 - clone a remote repository to a new directory named hg/::
1512
1511
1513 hg clone https://www.mercurial-scm.org/repo/hg/
1512 hg clone https://www.mercurial-scm.org/repo/hg/
1514
1513
1515 - create a lightweight local clone::
1514 - create a lightweight local clone::
1516
1515
1517 hg clone project/ project-feature/
1516 hg clone project/ project-feature/
1518
1517
1519 - clone from an absolute path on an ssh server (note double-slash)::
1518 - clone from an absolute path on an ssh server (note double-slash)::
1520
1519
1521 hg clone ssh://user@server//home/projects/alpha/
1520 hg clone ssh://user@server//home/projects/alpha/
1522
1521
1523 - do a high-speed clone over a LAN while checking out a
1522 - do a high-speed clone over a LAN while checking out a
1524 specified version::
1523 specified version::
1525
1524
1526 hg clone --uncompressed http://server/repo -u 1.5
1525 hg clone --uncompressed http://server/repo -u 1.5
1527
1526
1528 - create a repository without changesets after a particular revision::
1527 - create a repository without changesets after a particular revision::
1529
1528
1530 hg clone -r 04e544 experimental/ good/
1529 hg clone -r 04e544 experimental/ good/
1531
1530
1532 - clone (and track) a particular named branch::
1531 - clone (and track) a particular named branch::
1533
1532
1534 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1533 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1535
1534
1536 See :hg:`help urls` for details on specifying URLs.
1535 See :hg:`help urls` for details on specifying URLs.
1537
1536
1538 Returns 0 on success.
1537 Returns 0 on success.
1539 """
1538 """
1540 if opts.get('noupdate') and opts.get('updaterev'):
1539 if opts.get('noupdate') and opts.get('updaterev'):
1541 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1540 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1542
1541
1543 r = hg.clone(ui, opts, source, dest,
1542 r = hg.clone(ui, opts, source, dest,
1544 pull=opts.get('pull'),
1543 pull=opts.get('pull'),
1545 stream=opts.get('uncompressed'),
1544 stream=opts.get('uncompressed'),
1546 rev=opts.get('rev'),
1545 rev=opts.get('rev'),
1547 update=opts.get('updaterev') or not opts.get('noupdate'),
1546 update=opts.get('updaterev') or not opts.get('noupdate'),
1548 branch=opts.get('branch'),
1547 branch=opts.get('branch'),
1549 shareopts=opts.get('shareopts'))
1548 shareopts=opts.get('shareopts'))
1550
1549
1551 return r is None
1550 return r is None
1552
1551
1553 @command('^commit|ci',
1552 @command('^commit|ci',
1554 [('A', 'addremove', None,
1553 [('A', 'addremove', None,
1555 _('mark new/missing files as added/removed before committing')),
1554 _('mark new/missing files as added/removed before committing')),
1556 ('', 'close-branch', None,
1555 ('', 'close-branch', None,
1557 _('mark a branch head as closed')),
1556 _('mark a branch head as closed')),
1558 ('', 'amend', None, _('amend the parent of the working directory')),
1557 ('', 'amend', None, _('amend the parent of the working directory')),
1559 ('s', 'secret', None, _('use the secret phase for committing')),
1558 ('s', 'secret', None, _('use the secret phase for committing')),
1560 ('e', 'edit', None, _('invoke editor on commit messages')),
1559 ('e', 'edit', None, _('invoke editor on commit messages')),
1561 ('i', 'interactive', None, _('use interactive mode')),
1560 ('i', 'interactive', None, _('use interactive mode')),
1562 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1561 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1563 _('[OPTION]... [FILE]...'),
1562 _('[OPTION]... [FILE]...'),
1564 inferrepo=True)
1563 inferrepo=True)
1565 def commit(ui, repo, *pats, **opts):
1564 def commit(ui, repo, *pats, **opts):
1566 """commit the specified files or all outstanding changes
1565 """commit the specified files or all outstanding changes
1567
1566
1568 Commit changes to the given files into the repository. Unlike a
1567 Commit changes to the given files into the repository. Unlike a
1569 centralized SCM, this operation is a local operation. See
1568 centralized SCM, this operation is a local operation. See
1570 :hg:`push` for a way to actively distribute your changes.
1569 :hg:`push` for a way to actively distribute your changes.
1571
1570
1572 If a list of files is omitted, all changes reported by :hg:`status`
1571 If a list of files is omitted, all changes reported by :hg:`status`
1573 will be committed.
1572 will be committed.
1574
1573
1575 If you are committing the result of a merge, do not provide any
1574 If you are committing the result of a merge, do not provide any
1576 filenames or -I/-X filters.
1575 filenames or -I/-X filters.
1577
1576
1578 If no commit message is specified, Mercurial starts your
1577 If no commit message is specified, Mercurial starts your
1579 configured editor where you can enter a message. In case your
1578 configured editor where you can enter a message. In case your
1580 commit fails, you will find a backup of your message in
1579 commit fails, you will find a backup of your message in
1581 ``.hg/last-message.txt``.
1580 ``.hg/last-message.txt``.
1582
1581
1583 The --close-branch flag can be used to mark the current branch
1582 The --close-branch flag can be used to mark the current branch
1584 head closed. When all heads of a branch are closed, the branch
1583 head closed. When all heads of a branch are closed, the branch
1585 will be considered closed and no longer listed.
1584 will be considered closed and no longer listed.
1586
1585
1587 The --amend flag can be used to amend the parent of the
1586 The --amend flag can be used to amend the parent of the
1588 working directory with a new commit that contains the changes
1587 working directory with a new commit that contains the changes
1589 in the parent in addition to those currently reported by :hg:`status`,
1588 in the parent in addition to those currently reported by :hg:`status`,
1590 if there are any. The old commit is stored in a backup bundle in
1589 if there are any. The old commit is stored in a backup bundle in
1591 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1590 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1592 on how to restore it).
1591 on how to restore it).
1593
1592
1594 Message, user and date are taken from the amended commit unless
1593 Message, user and date are taken from the amended commit unless
1595 specified. When a message isn't specified on the command line,
1594 specified. When a message isn't specified on the command line,
1596 the editor will open with the message of the amended commit.
1595 the editor will open with the message of the amended commit.
1597
1596
1598 It is not possible to amend public changesets (see :hg:`help phases`)
1597 It is not possible to amend public changesets (see :hg:`help phases`)
1599 or changesets that have children.
1598 or changesets that have children.
1600
1599
1601 See :hg:`help dates` for a list of formats valid for -d/--date.
1600 See :hg:`help dates` for a list of formats valid for -d/--date.
1602
1601
1603 Returns 0 on success, 1 if nothing changed.
1602 Returns 0 on success, 1 if nothing changed.
1604
1603
1605 .. container:: verbose
1604 .. container:: verbose
1606
1605
1607 Examples:
1606 Examples:
1608
1607
1609 - commit all files ending in .py::
1608 - commit all files ending in .py::
1610
1609
1611 hg commit --include "set:**.py"
1610 hg commit --include "set:**.py"
1612
1611
1613 - commit all non-binary files::
1612 - commit all non-binary files::
1614
1613
1615 hg commit --exclude "set:binary()"
1614 hg commit --exclude "set:binary()"
1616
1615
1617 - amend the current commit and set the date to now::
1616 - amend the current commit and set the date to now::
1618
1617
1619 hg commit --amend --date now
1618 hg commit --amend --date now
1620 """
1619 """
1621 wlock = lock = None
1620 wlock = lock = None
1622 try:
1621 try:
1623 wlock = repo.wlock()
1622 wlock = repo.wlock()
1624 lock = repo.lock()
1623 lock = repo.lock()
1625 return _docommit(ui, repo, *pats, **opts)
1624 return _docommit(ui, repo, *pats, **opts)
1626 finally:
1625 finally:
1627 release(lock, wlock)
1626 release(lock, wlock)
1628
1627
1629 def _docommit(ui, repo, *pats, **opts):
1628 def _docommit(ui, repo, *pats, **opts):
1630 if opts.get('interactive'):
1629 if opts.get('interactive'):
1631 opts.pop('interactive')
1630 opts.pop('interactive')
1632 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1631 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1633 cmdutil.recordfilter, *pats, **opts)
1632 cmdutil.recordfilter, *pats, **opts)
1634 # ret can be 0 (no changes to record) or the value returned by
1633 # ret can be 0 (no changes to record) or the value returned by
1635 # commit(), 1 if nothing changed or None on success.
1634 # commit(), 1 if nothing changed or None on success.
1636 return 1 if ret == 0 else ret
1635 return 1 if ret == 0 else ret
1637
1636
1638 if opts.get('subrepos'):
1637 if opts.get('subrepos'):
1639 if opts.get('amend'):
1638 if opts.get('amend'):
1640 raise error.Abort(_('cannot amend with --subrepos'))
1639 raise error.Abort(_('cannot amend with --subrepos'))
1641 # Let --subrepos on the command line override config setting.
1640 # Let --subrepos on the command line override config setting.
1642 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1641 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1643
1642
1644 cmdutil.checkunfinished(repo, commit=True)
1643 cmdutil.checkunfinished(repo, commit=True)
1645
1644
1646 branch = repo[None].branch()
1645 branch = repo[None].branch()
1647 bheads = repo.branchheads(branch)
1646 bheads = repo.branchheads(branch)
1648
1647
1649 extra = {}
1648 extra = {}
1650 if opts.get('close_branch'):
1649 if opts.get('close_branch'):
1651 extra['close'] = 1
1650 extra['close'] = 1
1652
1651
1653 if not bheads:
1652 if not bheads:
1654 raise error.Abort(_('can only close branch heads'))
1653 raise error.Abort(_('can only close branch heads'))
1655 elif opts.get('amend'):
1654 elif opts.get('amend'):
1656 if repo[None].parents()[0].p1().branch() != branch and \
1655 if repo[None].parents()[0].p1().branch() != branch and \
1657 repo[None].parents()[0].p2().branch() != branch:
1656 repo[None].parents()[0].p2().branch() != branch:
1658 raise error.Abort(_('can only close branch heads'))
1657 raise error.Abort(_('can only close branch heads'))
1659
1658
1660 if opts.get('amend'):
1659 if opts.get('amend'):
1661 if ui.configbool('ui', 'commitsubrepos'):
1660 if ui.configbool('ui', 'commitsubrepos'):
1662 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1661 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1663
1662
1664 old = repo['.']
1663 old = repo['.']
1665 if not old.mutable():
1664 if not old.mutable():
1666 raise error.Abort(_('cannot amend public changesets'))
1665 raise error.Abort(_('cannot amend public changesets'))
1667 if len(repo[None].parents()) > 1:
1666 if len(repo[None].parents()) > 1:
1668 raise error.Abort(_('cannot amend while merging'))
1667 raise error.Abort(_('cannot amend while merging'))
1669 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1668 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1670 if not allowunstable and old.children():
1669 if not allowunstable and old.children():
1671 raise error.Abort(_('cannot amend changeset with children'))
1670 raise error.Abort(_('cannot amend changeset with children'))
1672
1671
1673 # Currently histedit gets confused if an amend happens while histedit
1672 # Currently histedit gets confused if an amend happens while histedit
1674 # is in progress. Since we have a checkunfinished command, we are
1673 # is in progress. Since we have a checkunfinished command, we are
1675 # temporarily honoring it.
1674 # temporarily honoring it.
1676 #
1675 #
1677 # Note: eventually this guard will be removed. Please do not expect
1676 # Note: eventually this guard will be removed. Please do not expect
1678 # this behavior to remain.
1677 # this behavior to remain.
1679 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1678 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1680 cmdutil.checkunfinished(repo)
1679 cmdutil.checkunfinished(repo)
1681
1680
1682 # commitfunc is used only for temporary amend commit by cmdutil.amend
1681 # commitfunc is used only for temporary amend commit by cmdutil.amend
1683 def commitfunc(ui, repo, message, match, opts):
1682 def commitfunc(ui, repo, message, match, opts):
1684 return repo.commit(message,
1683 return repo.commit(message,
1685 opts.get('user') or old.user(),
1684 opts.get('user') or old.user(),
1686 opts.get('date') or old.date(),
1685 opts.get('date') or old.date(),
1687 match,
1686 match,
1688 extra=extra)
1687 extra=extra)
1689
1688
1690 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1689 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1691 if node == old.node():
1690 if node == old.node():
1692 ui.status(_("nothing changed\n"))
1691 ui.status(_("nothing changed\n"))
1693 return 1
1692 return 1
1694 else:
1693 else:
1695 def commitfunc(ui, repo, message, match, opts):
1694 def commitfunc(ui, repo, message, match, opts):
1696 backup = ui.backupconfig('phases', 'new-commit')
1695 backup = ui.backupconfig('phases', 'new-commit')
1697 baseui = repo.baseui
1696 baseui = repo.baseui
1698 basebackup = baseui.backupconfig('phases', 'new-commit')
1697 basebackup = baseui.backupconfig('phases', 'new-commit')
1699 try:
1698 try:
1700 if opts.get('secret'):
1699 if opts.get('secret'):
1701 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1700 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1702 # Propagate to subrepos
1701 # Propagate to subrepos
1703 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1702 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1704
1703
1705 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1704 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1706 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1705 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1707 return repo.commit(message, opts.get('user'), opts.get('date'),
1706 return repo.commit(message, opts.get('user'), opts.get('date'),
1708 match,
1707 match,
1709 editor=editor,
1708 editor=editor,
1710 extra=extra)
1709 extra=extra)
1711 finally:
1710 finally:
1712 ui.restoreconfig(backup)
1711 ui.restoreconfig(backup)
1713 repo.baseui.restoreconfig(basebackup)
1712 repo.baseui.restoreconfig(basebackup)
1714
1713
1715
1714
1716 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1715 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1717
1716
1718 if not node:
1717 if not node:
1719 stat = cmdutil.postcommitstatus(repo, pats, opts)
1718 stat = cmdutil.postcommitstatus(repo, pats, opts)
1720 if stat[3]:
1719 if stat[3]:
1721 ui.status(_("nothing changed (%d missing files, see "
1720 ui.status(_("nothing changed (%d missing files, see "
1722 "'hg status')\n") % len(stat[3]))
1721 "'hg status')\n") % len(stat[3]))
1723 else:
1722 else:
1724 ui.status(_("nothing changed\n"))
1723 ui.status(_("nothing changed\n"))
1725 return 1
1724 return 1
1726
1725
1727 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1726 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1728
1727
1729 @command('config|showconfig|debugconfig',
1728 @command('config|showconfig|debugconfig',
1730 [('u', 'untrusted', None, _('show untrusted configuration options')),
1729 [('u', 'untrusted', None, _('show untrusted configuration options')),
1731 ('e', 'edit', None, _('edit user config')),
1730 ('e', 'edit', None, _('edit user config')),
1732 ('l', 'local', None, _('edit repository config')),
1731 ('l', 'local', None, _('edit repository config')),
1733 ('g', 'global', None, _('edit global config'))] + formatteropts,
1732 ('g', 'global', None, _('edit global config'))] + formatteropts,
1734 _('[-u] [NAME]...'),
1733 _('[-u] [NAME]...'),
1735 optionalrepo=True)
1734 optionalrepo=True)
1736 def config(ui, repo, *values, **opts):
1735 def config(ui, repo, *values, **opts):
1737 """show combined config settings from all hgrc files
1736 """show combined config settings from all hgrc files
1738
1737
1739 With no arguments, print names and values of all config items.
1738 With no arguments, print names and values of all config items.
1740
1739
1741 With one argument of the form section.name, print just the value
1740 With one argument of the form section.name, print just the value
1742 of that config item.
1741 of that config item.
1743
1742
1744 With multiple arguments, print names and values of all config
1743 With multiple arguments, print names and values of all config
1745 items with matching section names.
1744 items with matching section names.
1746
1745
1747 With --edit, start an editor on the user-level config file. With
1746 With --edit, start an editor on the user-level config file. With
1748 --global, edit the system-wide config file. With --local, edit the
1747 --global, edit the system-wide config file. With --local, edit the
1749 repository-level config file.
1748 repository-level config file.
1750
1749
1751 With --debug, the source (filename and line number) is printed
1750 With --debug, the source (filename and line number) is printed
1752 for each config item.
1751 for each config item.
1753
1752
1754 See :hg:`help config` for more information about config files.
1753 See :hg:`help config` for more information about config files.
1755
1754
1756 Returns 0 on success, 1 if NAME does not exist.
1755 Returns 0 on success, 1 if NAME does not exist.
1757
1756
1758 """
1757 """
1759
1758
1760 if opts.get('edit') or opts.get('local') or opts.get('global'):
1759 if opts.get('edit') or opts.get('local') or opts.get('global'):
1761 if opts.get('local') and opts.get('global'):
1760 if opts.get('local') and opts.get('global'):
1762 raise error.Abort(_("can't use --local and --global together"))
1761 raise error.Abort(_("can't use --local and --global together"))
1763
1762
1764 if opts.get('local'):
1763 if opts.get('local'):
1765 if not repo:
1764 if not repo:
1766 raise error.Abort(_("can't use --local outside a repository"))
1765 raise error.Abort(_("can't use --local outside a repository"))
1767 paths = [repo.join('hgrc')]
1766 paths = [repo.join('hgrc')]
1768 elif opts.get('global'):
1767 elif opts.get('global'):
1769 paths = scmutil.systemrcpath()
1768 paths = scmutil.systemrcpath()
1770 else:
1769 else:
1771 paths = scmutil.userrcpath()
1770 paths = scmutil.userrcpath()
1772
1771
1773 for f in paths:
1772 for f in paths:
1774 if os.path.exists(f):
1773 if os.path.exists(f):
1775 break
1774 break
1776 else:
1775 else:
1777 if opts.get('global'):
1776 if opts.get('global'):
1778 samplehgrc = uimod.samplehgrcs['global']
1777 samplehgrc = uimod.samplehgrcs['global']
1779 elif opts.get('local'):
1778 elif opts.get('local'):
1780 samplehgrc = uimod.samplehgrcs['local']
1779 samplehgrc = uimod.samplehgrcs['local']
1781 else:
1780 else:
1782 samplehgrc = uimod.samplehgrcs['user']
1781 samplehgrc = uimod.samplehgrcs['user']
1783
1782
1784 f = paths[0]
1783 f = paths[0]
1785 fp = open(f, "w")
1784 fp = open(f, "w")
1786 fp.write(samplehgrc)
1785 fp.write(samplehgrc)
1787 fp.close()
1786 fp.close()
1788
1787
1789 editor = ui.geteditor()
1788 editor = ui.geteditor()
1790 ui.system("%s \"%s\"" % (editor, f),
1789 ui.system("%s \"%s\"" % (editor, f),
1791 onerr=error.Abort, errprefix=_("edit failed"))
1790 onerr=error.Abort, errprefix=_("edit failed"))
1792 return
1791 return
1793
1792
1794 fm = ui.formatter('config', opts)
1793 fm = ui.formatter('config', opts)
1795 for f in scmutil.rcpath():
1794 for f in scmutil.rcpath():
1796 ui.debug('read config from: %s\n' % f)
1795 ui.debug('read config from: %s\n' % f)
1797 untrusted = bool(opts.get('untrusted'))
1796 untrusted = bool(opts.get('untrusted'))
1798 if values:
1797 if values:
1799 sections = [v for v in values if '.' not in v]
1798 sections = [v for v in values if '.' not in v]
1800 items = [v for v in values if '.' in v]
1799 items = [v for v in values if '.' in v]
1801 if len(items) > 1 or items and sections:
1800 if len(items) > 1 or items and sections:
1802 raise error.Abort(_('only one config item permitted'))
1801 raise error.Abort(_('only one config item permitted'))
1803 matched = False
1802 matched = False
1804 for section, name, value in ui.walkconfig(untrusted=untrusted):
1803 for section, name, value in ui.walkconfig(untrusted=untrusted):
1805 source = ui.configsource(section, name, untrusted)
1804 source = ui.configsource(section, name, untrusted)
1806 value = str(value)
1805 value = str(value)
1807 if fm.isplain():
1806 if fm.isplain():
1808 source = source or 'none'
1807 source = source or 'none'
1809 value = value.replace('\n', '\\n')
1808 value = value.replace('\n', '\\n')
1810 entryname = section + '.' + name
1809 entryname = section + '.' + name
1811 if values:
1810 if values:
1812 for v in values:
1811 for v in values:
1813 if v == section:
1812 if v == section:
1814 fm.startitem()
1813 fm.startitem()
1815 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1814 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1816 fm.write('name value', '%s=%s\n', entryname, value)
1815 fm.write('name value', '%s=%s\n', entryname, value)
1817 matched = True
1816 matched = True
1818 elif v == entryname:
1817 elif v == entryname:
1819 fm.startitem()
1818 fm.startitem()
1820 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1819 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1821 fm.write('value', '%s\n', value)
1820 fm.write('value', '%s\n', value)
1822 fm.data(name=entryname)
1821 fm.data(name=entryname)
1823 matched = True
1822 matched = True
1824 else:
1823 else:
1825 fm.startitem()
1824 fm.startitem()
1826 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1825 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1827 fm.write('name value', '%s=%s\n', entryname, value)
1826 fm.write('name value', '%s=%s\n', entryname, value)
1828 matched = True
1827 matched = True
1829 fm.end()
1828 fm.end()
1830 if matched:
1829 if matched:
1831 return 0
1830 return 0
1832 return 1
1831 return 1
1833
1832
1834 @command('copy|cp',
1833 @command('copy|cp',
1835 [('A', 'after', None, _('record a copy that has already occurred')),
1834 [('A', 'after', None, _('record a copy that has already occurred')),
1836 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1835 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1837 ] + walkopts + dryrunopts,
1836 ] + walkopts + dryrunopts,
1838 _('[OPTION]... [SOURCE]... DEST'))
1837 _('[OPTION]... [SOURCE]... DEST'))
1839 def copy(ui, repo, *pats, **opts):
1838 def copy(ui, repo, *pats, **opts):
1840 """mark files as copied for the next commit
1839 """mark files as copied for the next commit
1841
1840
1842 Mark dest as having copies of source files. If dest is a
1841 Mark dest as having copies of source files. If dest is a
1843 directory, copies are put in that directory. If dest is a file,
1842 directory, copies are put in that directory. If dest is a file,
1844 the source must be a single file.
1843 the source must be a single file.
1845
1844
1846 By default, this command copies the contents of files as they
1845 By default, this command copies the contents of files as they
1847 exist in the working directory. If invoked with -A/--after, the
1846 exist in the working directory. If invoked with -A/--after, the
1848 operation is recorded, but no copying is performed.
1847 operation is recorded, but no copying is performed.
1849
1848
1850 This command takes effect with the next commit. To undo a copy
1849 This command takes effect with the next commit. To undo a copy
1851 before that, see :hg:`revert`.
1850 before that, see :hg:`revert`.
1852
1851
1853 Returns 0 on success, 1 if errors are encountered.
1852 Returns 0 on success, 1 if errors are encountered.
1854 """
1853 """
1855 with repo.wlock(False):
1854 with repo.wlock(False):
1856 return cmdutil.copy(ui, repo, pats, opts)
1855 return cmdutil.copy(ui, repo, pats, opts)
1857
1856
1858 @command('debugdirstate|debugstate',
1859 [('', 'nodates', None, _('do not display the saved mtime')),
1860 ('', 'datesort', None, _('sort by saved mtime'))],
1861 _('[OPTION]...'))
1862 def debugstate(ui, repo, **opts):
1863 """show the contents of the current dirstate"""
1864
1865 nodates = opts.get('nodates')
1866 datesort = opts.get('datesort')
1867
1868 timestr = ""
1869 if datesort:
1870 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1871 else:
1872 keyfunc = None # sort by filename
1873 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1874 if ent[3] == -1:
1875 timestr = 'unset '
1876 elif nodates:
1877 timestr = 'set '
1878 else:
1879 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1880 time.localtime(ent[3]))
1881 if ent[1] & 0o20000:
1882 mode = 'lnk'
1883 else:
1884 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
1885 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1886 for f in repo.dirstate.copies():
1887 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1888
1889 @command('debugsub',
1857 @command('debugsub',
1890 [('r', 'rev', '',
1858 [('r', 'rev', '',
1891 _('revision to check'), _('REV'))],
1859 _('revision to check'), _('REV'))],
1892 _('[-r REV] [REV]'))
1860 _('[-r REV] [REV]'))
1893 def debugsub(ui, repo, rev=None):
1861 def debugsub(ui, repo, rev=None):
1894 ctx = scmutil.revsingle(repo, rev, None)
1862 ctx = scmutil.revsingle(repo, rev, None)
1895 for k, v in sorted(ctx.substate.items()):
1863 for k, v in sorted(ctx.substate.items()):
1896 ui.write(('path %s\n') % k)
1864 ui.write(('path %s\n') % k)
1897 ui.write((' source %s\n') % v[0])
1865 ui.write((' source %s\n') % v[0])
1898 ui.write((' revision %s\n') % v[1])
1866 ui.write((' revision %s\n') % v[1])
1899
1867
1900 @command('debugsuccessorssets',
1868 @command('debugsuccessorssets',
1901 [],
1869 [],
1902 _('[REV]'))
1870 _('[REV]'))
1903 def debugsuccessorssets(ui, repo, *revs):
1871 def debugsuccessorssets(ui, repo, *revs):
1904 """show set of successors for revision
1872 """show set of successors for revision
1905
1873
1906 A successors set of changeset A is a consistent group of revisions that
1874 A successors set of changeset A is a consistent group of revisions that
1907 succeed A. It contains non-obsolete changesets only.
1875 succeed A. It contains non-obsolete changesets only.
1908
1876
1909 In most cases a changeset A has a single successors set containing a single
1877 In most cases a changeset A has a single successors set containing a single
1910 successor (changeset A replaced by A').
1878 successor (changeset A replaced by A').
1911
1879
1912 A changeset that is made obsolete with no successors are called "pruned".
1880 A changeset that is made obsolete with no successors are called "pruned".
1913 Such changesets have no successors sets at all.
1881 Such changesets have no successors sets at all.
1914
1882
1915 A changeset that has been "split" will have a successors set containing
1883 A changeset that has been "split" will have a successors set containing
1916 more than one successor.
1884 more than one successor.
1917
1885
1918 A changeset that has been rewritten in multiple different ways is called
1886 A changeset that has been rewritten in multiple different ways is called
1919 "divergent". Such changesets have multiple successor sets (each of which
1887 "divergent". Such changesets have multiple successor sets (each of which
1920 may also be split, i.e. have multiple successors).
1888 may also be split, i.e. have multiple successors).
1921
1889
1922 Results are displayed as follows::
1890 Results are displayed as follows::
1923
1891
1924 <rev1>
1892 <rev1>
1925 <successors-1A>
1893 <successors-1A>
1926 <rev2>
1894 <rev2>
1927 <successors-2A>
1895 <successors-2A>
1928 <successors-2B1> <successors-2B2> <successors-2B3>
1896 <successors-2B1> <successors-2B2> <successors-2B3>
1929
1897
1930 Here rev2 has two possible (i.e. divergent) successors sets. The first
1898 Here rev2 has two possible (i.e. divergent) successors sets. The first
1931 holds one element, whereas the second holds three (i.e. the changeset has
1899 holds one element, whereas the second holds three (i.e. the changeset has
1932 been split).
1900 been split).
1933 """
1901 """
1934 # passed to successorssets caching computation from one call to another
1902 # passed to successorssets caching computation from one call to another
1935 cache = {}
1903 cache = {}
1936 ctx2str = str
1904 ctx2str = str
1937 node2str = short
1905 node2str = short
1938 if ui.debug():
1906 if ui.debug():
1939 def ctx2str(ctx):
1907 def ctx2str(ctx):
1940 return ctx.hex()
1908 return ctx.hex()
1941 node2str = hex
1909 node2str = hex
1942 for rev in scmutil.revrange(repo, revs):
1910 for rev in scmutil.revrange(repo, revs):
1943 ctx = repo[rev]
1911 ctx = repo[rev]
1944 ui.write('%s\n'% ctx2str(ctx))
1912 ui.write('%s\n'% ctx2str(ctx))
1945 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
1913 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
1946 if succsset:
1914 if succsset:
1947 ui.write(' ')
1915 ui.write(' ')
1948 ui.write(node2str(succsset[0]))
1916 ui.write(node2str(succsset[0]))
1949 for node in succsset[1:]:
1917 for node in succsset[1:]:
1950 ui.write(' ')
1918 ui.write(' ')
1951 ui.write(node2str(node))
1919 ui.write(node2str(node))
1952 ui.write('\n')
1920 ui.write('\n')
1953
1921
1954 @command('debugtemplate',
1922 @command('debugtemplate',
1955 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
1923 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
1956 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
1924 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
1957 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
1925 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
1958 optionalrepo=True)
1926 optionalrepo=True)
1959 def debugtemplate(ui, repo, tmpl, **opts):
1927 def debugtemplate(ui, repo, tmpl, **opts):
1960 """parse and apply a template
1928 """parse and apply a template
1961
1929
1962 If -r/--rev is given, the template is processed as a log template and
1930 If -r/--rev is given, the template is processed as a log template and
1963 applied to the given changesets. Otherwise, it is processed as a generic
1931 applied to the given changesets. Otherwise, it is processed as a generic
1964 template.
1932 template.
1965
1933
1966 Use --verbose to print the parsed tree.
1934 Use --verbose to print the parsed tree.
1967 """
1935 """
1968 revs = None
1936 revs = None
1969 if opts['rev']:
1937 if opts['rev']:
1970 if repo is None:
1938 if repo is None:
1971 raise error.RepoError(_('there is no Mercurial repository here '
1939 raise error.RepoError(_('there is no Mercurial repository here '
1972 '(.hg not found)'))
1940 '(.hg not found)'))
1973 revs = scmutil.revrange(repo, opts['rev'])
1941 revs = scmutil.revrange(repo, opts['rev'])
1974
1942
1975 props = {}
1943 props = {}
1976 for d in opts['define']:
1944 for d in opts['define']:
1977 try:
1945 try:
1978 k, v = (e.strip() for e in d.split('=', 1))
1946 k, v = (e.strip() for e in d.split('=', 1))
1979 if not k:
1947 if not k:
1980 raise ValueError
1948 raise ValueError
1981 props[k] = v
1949 props[k] = v
1982 except ValueError:
1950 except ValueError:
1983 raise error.Abort(_('malformed keyword definition: %s') % d)
1951 raise error.Abort(_('malformed keyword definition: %s') % d)
1984
1952
1985 if ui.verbose:
1953 if ui.verbose:
1986 aliases = ui.configitems('templatealias')
1954 aliases = ui.configitems('templatealias')
1987 tree = templater.parse(tmpl)
1955 tree = templater.parse(tmpl)
1988 ui.note(templater.prettyformat(tree), '\n')
1956 ui.note(templater.prettyformat(tree), '\n')
1989 newtree = templater.expandaliases(tree, aliases)
1957 newtree = templater.expandaliases(tree, aliases)
1990 if newtree != tree:
1958 if newtree != tree:
1991 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
1959 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
1992
1960
1993 mapfile = None
1961 mapfile = None
1994 if revs is None:
1962 if revs is None:
1995 k = 'debugtemplate'
1963 k = 'debugtemplate'
1996 t = formatter.maketemplater(ui, k, tmpl)
1964 t = formatter.maketemplater(ui, k, tmpl)
1997 ui.write(templater.stringify(t(k, **props)))
1965 ui.write(templater.stringify(t(k, **props)))
1998 else:
1966 else:
1999 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
1967 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
2000 mapfile, buffered=False)
1968 mapfile, buffered=False)
2001 for r in revs:
1969 for r in revs:
2002 displayer.show(repo[r], **props)
1970 displayer.show(repo[r], **props)
2003 displayer.close()
1971 displayer.close()
2004
1972
2005 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
1973 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2006 def debugwalk(ui, repo, *pats, **opts):
1974 def debugwalk(ui, repo, *pats, **opts):
2007 """show how files match on given patterns"""
1975 """show how files match on given patterns"""
2008 m = scmutil.match(repo[None], pats, opts)
1976 m = scmutil.match(repo[None], pats, opts)
2009 items = list(repo.walk(m))
1977 items = list(repo.walk(m))
2010 if not items:
1978 if not items:
2011 return
1979 return
2012 f = lambda fn: fn
1980 f = lambda fn: fn
2013 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
1981 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2014 f = lambda fn: util.normpath(fn)
1982 f = lambda fn: util.normpath(fn)
2015 fmt = 'f %%-%ds %%-%ds %%s' % (
1983 fmt = 'f %%-%ds %%-%ds %%s' % (
2016 max([len(abs) for abs in items]),
1984 max([len(abs) for abs in items]),
2017 max([len(m.rel(abs)) for abs in items]))
1985 max([len(m.rel(abs)) for abs in items]))
2018 for abs in items:
1986 for abs in items:
2019 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
1987 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2020 ui.write("%s\n" % line.rstrip())
1988 ui.write("%s\n" % line.rstrip())
2021
1989
2022 @command('debugwireargs',
1990 @command('debugwireargs',
2023 [('', 'three', '', 'three'),
1991 [('', 'three', '', 'three'),
2024 ('', 'four', '', 'four'),
1992 ('', 'four', '', 'four'),
2025 ('', 'five', '', 'five'),
1993 ('', 'five', '', 'five'),
2026 ] + remoteopts,
1994 ] + remoteopts,
2027 _('REPO [OPTIONS]... [ONE [TWO]]'),
1995 _('REPO [OPTIONS]... [ONE [TWO]]'),
2028 norepo=True)
1996 norepo=True)
2029 def debugwireargs(ui, repopath, *vals, **opts):
1997 def debugwireargs(ui, repopath, *vals, **opts):
2030 repo = hg.peer(ui, opts, repopath)
1998 repo = hg.peer(ui, opts, repopath)
2031 for opt in remoteopts:
1999 for opt in remoteopts:
2032 del opts[opt[1]]
2000 del opts[opt[1]]
2033 args = {}
2001 args = {}
2034 for k, v in opts.iteritems():
2002 for k, v in opts.iteritems():
2035 if v:
2003 if v:
2036 args[k] = v
2004 args[k] = v
2037 # run twice to check that we don't mess up the stream for the next command
2005 # run twice to check that we don't mess up the stream for the next command
2038 res1 = repo.debugwireargs(*vals, **args)
2006 res1 = repo.debugwireargs(*vals, **args)
2039 res2 = repo.debugwireargs(*vals, **args)
2007 res2 = repo.debugwireargs(*vals, **args)
2040 ui.write("%s\n" % res1)
2008 ui.write("%s\n" % res1)
2041 if res1 != res2:
2009 if res1 != res2:
2042 ui.warn("%s\n" % res2)
2010 ui.warn("%s\n" % res2)
2043
2011
2044 @command('^diff',
2012 @command('^diff',
2045 [('r', 'rev', [], _('revision'), _('REV')),
2013 [('r', 'rev', [], _('revision'), _('REV')),
2046 ('c', 'change', '', _('change made by revision'), _('REV'))
2014 ('c', 'change', '', _('change made by revision'), _('REV'))
2047 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2015 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2048 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2016 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
2049 inferrepo=True)
2017 inferrepo=True)
2050 def diff(ui, repo, *pats, **opts):
2018 def diff(ui, repo, *pats, **opts):
2051 """diff repository (or selected files)
2019 """diff repository (or selected files)
2052
2020
2053 Show differences between revisions for the specified files.
2021 Show differences between revisions for the specified files.
2054
2022
2055 Differences between files are shown using the unified diff format.
2023 Differences between files are shown using the unified diff format.
2056
2024
2057 .. note::
2025 .. note::
2058
2026
2059 :hg:`diff` may generate unexpected results for merges, as it will
2027 :hg:`diff` may generate unexpected results for merges, as it will
2060 default to comparing against the working directory's first
2028 default to comparing against the working directory's first
2061 parent changeset if no revisions are specified.
2029 parent changeset if no revisions are specified.
2062
2030
2063 When two revision arguments are given, then changes are shown
2031 When two revision arguments are given, then changes are shown
2064 between those revisions. If only one revision is specified then
2032 between those revisions. If only one revision is specified then
2065 that revision is compared to the working directory, and, when no
2033 that revision is compared to the working directory, and, when no
2066 revisions are specified, the working directory files are compared
2034 revisions are specified, the working directory files are compared
2067 to its first parent.
2035 to its first parent.
2068
2036
2069 Alternatively you can specify -c/--change with a revision to see
2037 Alternatively you can specify -c/--change with a revision to see
2070 the changes in that changeset relative to its first parent.
2038 the changes in that changeset relative to its first parent.
2071
2039
2072 Without the -a/--text option, diff will avoid generating diffs of
2040 Without the -a/--text option, diff will avoid generating diffs of
2073 files it detects as binary. With -a, diff will generate a diff
2041 files it detects as binary. With -a, diff will generate a diff
2074 anyway, probably with undesirable results.
2042 anyway, probably with undesirable results.
2075
2043
2076 Use the -g/--git option to generate diffs in the git extended diff
2044 Use the -g/--git option to generate diffs in the git extended diff
2077 format. For more information, read :hg:`help diffs`.
2045 format. For more information, read :hg:`help diffs`.
2078
2046
2079 .. container:: verbose
2047 .. container:: verbose
2080
2048
2081 Examples:
2049 Examples:
2082
2050
2083 - compare a file in the current working directory to its parent::
2051 - compare a file in the current working directory to its parent::
2084
2052
2085 hg diff foo.c
2053 hg diff foo.c
2086
2054
2087 - compare two historical versions of a directory, with rename info::
2055 - compare two historical versions of a directory, with rename info::
2088
2056
2089 hg diff --git -r 1.0:1.2 lib/
2057 hg diff --git -r 1.0:1.2 lib/
2090
2058
2091 - get change stats relative to the last change on some date::
2059 - get change stats relative to the last change on some date::
2092
2060
2093 hg diff --stat -r "date('may 2')"
2061 hg diff --stat -r "date('may 2')"
2094
2062
2095 - diff all newly-added files that contain a keyword::
2063 - diff all newly-added files that contain a keyword::
2096
2064
2097 hg diff "set:added() and grep(GNU)"
2065 hg diff "set:added() and grep(GNU)"
2098
2066
2099 - compare a revision and its parents::
2067 - compare a revision and its parents::
2100
2068
2101 hg diff -c 9353 # compare against first parent
2069 hg diff -c 9353 # compare against first parent
2102 hg diff -r 9353^:9353 # same using revset syntax
2070 hg diff -r 9353^:9353 # same using revset syntax
2103 hg diff -r 9353^2:9353 # compare against the second parent
2071 hg diff -r 9353^2:9353 # compare against the second parent
2104
2072
2105 Returns 0 on success.
2073 Returns 0 on success.
2106 """
2074 """
2107
2075
2108 revs = opts.get('rev')
2076 revs = opts.get('rev')
2109 change = opts.get('change')
2077 change = opts.get('change')
2110 stat = opts.get('stat')
2078 stat = opts.get('stat')
2111 reverse = opts.get('reverse')
2079 reverse = opts.get('reverse')
2112
2080
2113 if revs and change:
2081 if revs and change:
2114 msg = _('cannot specify --rev and --change at the same time')
2082 msg = _('cannot specify --rev and --change at the same time')
2115 raise error.Abort(msg)
2083 raise error.Abort(msg)
2116 elif change:
2084 elif change:
2117 node2 = scmutil.revsingle(repo, change, None).node()
2085 node2 = scmutil.revsingle(repo, change, None).node()
2118 node1 = repo[node2].p1().node()
2086 node1 = repo[node2].p1().node()
2119 else:
2087 else:
2120 node1, node2 = scmutil.revpair(repo, revs)
2088 node1, node2 = scmutil.revpair(repo, revs)
2121
2089
2122 if reverse:
2090 if reverse:
2123 node1, node2 = node2, node1
2091 node1, node2 = node2, node1
2124
2092
2125 diffopts = patch.diffallopts(ui, opts)
2093 diffopts = patch.diffallopts(ui, opts)
2126 m = scmutil.match(repo[node2], pats, opts)
2094 m = scmutil.match(repo[node2], pats, opts)
2127 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2095 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2128 listsubrepos=opts.get('subrepos'),
2096 listsubrepos=opts.get('subrepos'),
2129 root=opts.get('root'))
2097 root=opts.get('root'))
2130
2098
2131 @command('^export',
2099 @command('^export',
2132 [('o', 'output', '',
2100 [('o', 'output', '',
2133 _('print output to file with formatted name'), _('FORMAT')),
2101 _('print output to file with formatted name'), _('FORMAT')),
2134 ('', 'switch-parent', None, _('diff against the second parent')),
2102 ('', 'switch-parent', None, _('diff against the second parent')),
2135 ('r', 'rev', [], _('revisions to export'), _('REV')),
2103 ('r', 'rev', [], _('revisions to export'), _('REV')),
2136 ] + diffopts,
2104 ] + diffopts,
2137 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2105 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2138 def export(ui, repo, *changesets, **opts):
2106 def export(ui, repo, *changesets, **opts):
2139 """dump the header and diffs for one or more changesets
2107 """dump the header and diffs for one or more changesets
2140
2108
2141 Print the changeset header and diffs for one or more revisions.
2109 Print the changeset header and diffs for one or more revisions.
2142 If no revision is given, the parent of the working directory is used.
2110 If no revision is given, the parent of the working directory is used.
2143
2111
2144 The information shown in the changeset header is: author, date,
2112 The information shown in the changeset header is: author, date,
2145 branch name (if non-default), changeset hash, parent(s) and commit
2113 branch name (if non-default), changeset hash, parent(s) and commit
2146 comment.
2114 comment.
2147
2115
2148 .. note::
2116 .. note::
2149
2117
2150 :hg:`export` may generate unexpected diff output for merge
2118 :hg:`export` may generate unexpected diff output for merge
2151 changesets, as it will compare the merge changeset against its
2119 changesets, as it will compare the merge changeset against its
2152 first parent only.
2120 first parent only.
2153
2121
2154 Output may be to a file, in which case the name of the file is
2122 Output may be to a file, in which case the name of the file is
2155 given using a format string. The formatting rules are as follows:
2123 given using a format string. The formatting rules are as follows:
2156
2124
2157 :``%%``: literal "%" character
2125 :``%%``: literal "%" character
2158 :``%H``: changeset hash (40 hexadecimal digits)
2126 :``%H``: changeset hash (40 hexadecimal digits)
2159 :``%N``: number of patches being generated
2127 :``%N``: number of patches being generated
2160 :``%R``: changeset revision number
2128 :``%R``: changeset revision number
2161 :``%b``: basename of the exporting repository
2129 :``%b``: basename of the exporting repository
2162 :``%h``: short-form changeset hash (12 hexadecimal digits)
2130 :``%h``: short-form changeset hash (12 hexadecimal digits)
2163 :``%m``: first line of the commit message (only alphanumeric characters)
2131 :``%m``: first line of the commit message (only alphanumeric characters)
2164 :``%n``: zero-padded sequence number, starting at 1
2132 :``%n``: zero-padded sequence number, starting at 1
2165 :``%r``: zero-padded changeset revision number
2133 :``%r``: zero-padded changeset revision number
2166
2134
2167 Without the -a/--text option, export will avoid generating diffs
2135 Without the -a/--text option, export will avoid generating diffs
2168 of files it detects as binary. With -a, export will generate a
2136 of files it detects as binary. With -a, export will generate a
2169 diff anyway, probably with undesirable results.
2137 diff anyway, probably with undesirable results.
2170
2138
2171 Use the -g/--git option to generate diffs in the git extended diff
2139 Use the -g/--git option to generate diffs in the git extended diff
2172 format. See :hg:`help diffs` for more information.
2140 format. See :hg:`help diffs` for more information.
2173
2141
2174 With the --switch-parent option, the diff will be against the
2142 With the --switch-parent option, the diff will be against the
2175 second parent. It can be useful to review a merge.
2143 second parent. It can be useful to review a merge.
2176
2144
2177 .. container:: verbose
2145 .. container:: verbose
2178
2146
2179 Examples:
2147 Examples:
2180
2148
2181 - use export and import to transplant a bugfix to the current
2149 - use export and import to transplant a bugfix to the current
2182 branch::
2150 branch::
2183
2151
2184 hg export -r 9353 | hg import -
2152 hg export -r 9353 | hg import -
2185
2153
2186 - export all the changesets between two revisions to a file with
2154 - export all the changesets between two revisions to a file with
2187 rename information::
2155 rename information::
2188
2156
2189 hg export --git -r 123:150 > changes.txt
2157 hg export --git -r 123:150 > changes.txt
2190
2158
2191 - split outgoing changes into a series of patches with
2159 - split outgoing changes into a series of patches with
2192 descriptive names::
2160 descriptive names::
2193
2161
2194 hg export -r "outgoing()" -o "%n-%m.patch"
2162 hg export -r "outgoing()" -o "%n-%m.patch"
2195
2163
2196 Returns 0 on success.
2164 Returns 0 on success.
2197 """
2165 """
2198 changesets += tuple(opts.get('rev', []))
2166 changesets += tuple(opts.get('rev', []))
2199 if not changesets:
2167 if not changesets:
2200 changesets = ['.']
2168 changesets = ['.']
2201 revs = scmutil.revrange(repo, changesets)
2169 revs = scmutil.revrange(repo, changesets)
2202 if not revs:
2170 if not revs:
2203 raise error.Abort(_("export requires at least one changeset"))
2171 raise error.Abort(_("export requires at least one changeset"))
2204 if len(revs) > 1:
2172 if len(revs) > 1:
2205 ui.note(_('exporting patches:\n'))
2173 ui.note(_('exporting patches:\n'))
2206 else:
2174 else:
2207 ui.note(_('exporting patch:\n'))
2175 ui.note(_('exporting patch:\n'))
2208 cmdutil.export(repo, revs, template=opts.get('output'),
2176 cmdutil.export(repo, revs, template=opts.get('output'),
2209 switch_parent=opts.get('switch_parent'),
2177 switch_parent=opts.get('switch_parent'),
2210 opts=patch.diffallopts(ui, opts))
2178 opts=patch.diffallopts(ui, opts))
2211
2179
2212 @command('files',
2180 @command('files',
2213 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2181 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2214 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2182 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2215 ] + walkopts + formatteropts + subrepoopts,
2183 ] + walkopts + formatteropts + subrepoopts,
2216 _('[OPTION]... [FILE]...'))
2184 _('[OPTION]... [FILE]...'))
2217 def files(ui, repo, *pats, **opts):
2185 def files(ui, repo, *pats, **opts):
2218 """list tracked files
2186 """list tracked files
2219
2187
2220 Print files under Mercurial control in the working directory or
2188 Print files under Mercurial control in the working directory or
2221 specified revision for given files (excluding removed files).
2189 specified revision for given files (excluding removed files).
2222 Files can be specified as filenames or filesets.
2190 Files can be specified as filenames or filesets.
2223
2191
2224 If no files are given to match, this command prints the names
2192 If no files are given to match, this command prints the names
2225 of all files under Mercurial control.
2193 of all files under Mercurial control.
2226
2194
2227 .. container:: verbose
2195 .. container:: verbose
2228
2196
2229 Examples:
2197 Examples:
2230
2198
2231 - list all files under the current directory::
2199 - list all files under the current directory::
2232
2200
2233 hg files .
2201 hg files .
2234
2202
2235 - shows sizes and flags for current revision::
2203 - shows sizes and flags for current revision::
2236
2204
2237 hg files -vr .
2205 hg files -vr .
2238
2206
2239 - list all files named README::
2207 - list all files named README::
2240
2208
2241 hg files -I "**/README"
2209 hg files -I "**/README"
2242
2210
2243 - list all binary files::
2211 - list all binary files::
2244
2212
2245 hg files "set:binary()"
2213 hg files "set:binary()"
2246
2214
2247 - find files containing a regular expression::
2215 - find files containing a regular expression::
2248
2216
2249 hg files "set:grep('bob')"
2217 hg files "set:grep('bob')"
2250
2218
2251 - search tracked file contents with xargs and grep::
2219 - search tracked file contents with xargs and grep::
2252
2220
2253 hg files -0 | xargs -0 grep foo
2221 hg files -0 | xargs -0 grep foo
2254
2222
2255 See :hg:`help patterns` and :hg:`help filesets` for more information
2223 See :hg:`help patterns` and :hg:`help filesets` for more information
2256 on specifying file patterns.
2224 on specifying file patterns.
2257
2225
2258 Returns 0 if a match is found, 1 otherwise.
2226 Returns 0 if a match is found, 1 otherwise.
2259
2227
2260 """
2228 """
2261 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2229 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2262
2230
2263 end = '\n'
2231 end = '\n'
2264 if opts.get('print0'):
2232 if opts.get('print0'):
2265 end = '\0'
2233 end = '\0'
2266 fmt = '%s' + end
2234 fmt = '%s' + end
2267
2235
2268 m = scmutil.match(ctx, pats, opts)
2236 m = scmutil.match(ctx, pats, opts)
2269 with ui.formatter('files', opts) as fm:
2237 with ui.formatter('files', opts) as fm:
2270 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2238 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2271
2239
2272 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2240 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2273 def forget(ui, repo, *pats, **opts):
2241 def forget(ui, repo, *pats, **opts):
2274 """forget the specified files on the next commit
2242 """forget the specified files on the next commit
2275
2243
2276 Mark the specified files so they will no longer be tracked
2244 Mark the specified files so they will no longer be tracked
2277 after the next commit.
2245 after the next commit.
2278
2246
2279 This only removes files from the current branch, not from the
2247 This only removes files from the current branch, not from the
2280 entire project history, and it does not delete them from the
2248 entire project history, and it does not delete them from the
2281 working directory.
2249 working directory.
2282
2250
2283 To delete the file from the working directory, see :hg:`remove`.
2251 To delete the file from the working directory, see :hg:`remove`.
2284
2252
2285 To undo a forget before the next commit, see :hg:`add`.
2253 To undo a forget before the next commit, see :hg:`add`.
2286
2254
2287 .. container:: verbose
2255 .. container:: verbose
2288
2256
2289 Examples:
2257 Examples:
2290
2258
2291 - forget newly-added binary files::
2259 - forget newly-added binary files::
2292
2260
2293 hg forget "set:added() and binary()"
2261 hg forget "set:added() and binary()"
2294
2262
2295 - forget files that would be excluded by .hgignore::
2263 - forget files that would be excluded by .hgignore::
2296
2264
2297 hg forget "set:hgignore()"
2265 hg forget "set:hgignore()"
2298
2266
2299 Returns 0 on success.
2267 Returns 0 on success.
2300 """
2268 """
2301
2269
2302 if not pats:
2270 if not pats:
2303 raise error.Abort(_('no files specified'))
2271 raise error.Abort(_('no files specified'))
2304
2272
2305 m = scmutil.match(repo[None], pats, opts)
2273 m = scmutil.match(repo[None], pats, opts)
2306 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2274 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2307 return rejected and 1 or 0
2275 return rejected and 1 or 0
2308
2276
2309 @command(
2277 @command(
2310 'graft',
2278 'graft',
2311 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2279 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2312 ('c', 'continue', False, _('resume interrupted graft')),
2280 ('c', 'continue', False, _('resume interrupted graft')),
2313 ('e', 'edit', False, _('invoke editor on commit messages')),
2281 ('e', 'edit', False, _('invoke editor on commit messages')),
2314 ('', 'log', None, _('append graft info to log message')),
2282 ('', 'log', None, _('append graft info to log message')),
2315 ('f', 'force', False, _('force graft')),
2283 ('f', 'force', False, _('force graft')),
2316 ('D', 'currentdate', False,
2284 ('D', 'currentdate', False,
2317 _('record the current date as commit date')),
2285 _('record the current date as commit date')),
2318 ('U', 'currentuser', False,
2286 ('U', 'currentuser', False,
2319 _('record the current user as committer'), _('DATE'))]
2287 _('record the current user as committer'), _('DATE'))]
2320 + commitopts2 + mergetoolopts + dryrunopts,
2288 + commitopts2 + mergetoolopts + dryrunopts,
2321 _('[OPTION]... [-r REV]... REV...'))
2289 _('[OPTION]... [-r REV]... REV...'))
2322 def graft(ui, repo, *revs, **opts):
2290 def graft(ui, repo, *revs, **opts):
2323 '''copy changes from other branches onto the current branch
2291 '''copy changes from other branches onto the current branch
2324
2292
2325 This command uses Mercurial's merge logic to copy individual
2293 This command uses Mercurial's merge logic to copy individual
2326 changes from other branches without merging branches in the
2294 changes from other branches without merging branches in the
2327 history graph. This is sometimes known as 'backporting' or
2295 history graph. This is sometimes known as 'backporting' or
2328 'cherry-picking'. By default, graft will copy user, date, and
2296 'cherry-picking'. By default, graft will copy user, date, and
2329 description from the source changesets.
2297 description from the source changesets.
2330
2298
2331 Changesets that are ancestors of the current revision, that have
2299 Changesets that are ancestors of the current revision, that have
2332 already been grafted, or that are merges will be skipped.
2300 already been grafted, or that are merges will be skipped.
2333
2301
2334 If --log is specified, log messages will have a comment appended
2302 If --log is specified, log messages will have a comment appended
2335 of the form::
2303 of the form::
2336
2304
2337 (grafted from CHANGESETHASH)
2305 (grafted from CHANGESETHASH)
2338
2306
2339 If --force is specified, revisions will be grafted even if they
2307 If --force is specified, revisions will be grafted even if they
2340 are already ancestors of or have been grafted to the destination.
2308 are already ancestors of or have been grafted to the destination.
2341 This is useful when the revisions have since been backed out.
2309 This is useful when the revisions have since been backed out.
2342
2310
2343 If a graft merge results in conflicts, the graft process is
2311 If a graft merge results in conflicts, the graft process is
2344 interrupted so that the current merge can be manually resolved.
2312 interrupted so that the current merge can be manually resolved.
2345 Once all conflicts are addressed, the graft process can be
2313 Once all conflicts are addressed, the graft process can be
2346 continued with the -c/--continue option.
2314 continued with the -c/--continue option.
2347
2315
2348 .. note::
2316 .. note::
2349
2317
2350 The -c/--continue option does not reapply earlier options, except
2318 The -c/--continue option does not reapply earlier options, except
2351 for --force.
2319 for --force.
2352
2320
2353 .. container:: verbose
2321 .. container:: verbose
2354
2322
2355 Examples:
2323 Examples:
2356
2324
2357 - copy a single change to the stable branch and edit its description::
2325 - copy a single change to the stable branch and edit its description::
2358
2326
2359 hg update stable
2327 hg update stable
2360 hg graft --edit 9393
2328 hg graft --edit 9393
2361
2329
2362 - graft a range of changesets with one exception, updating dates::
2330 - graft a range of changesets with one exception, updating dates::
2363
2331
2364 hg graft -D "2085::2093 and not 2091"
2332 hg graft -D "2085::2093 and not 2091"
2365
2333
2366 - continue a graft after resolving conflicts::
2334 - continue a graft after resolving conflicts::
2367
2335
2368 hg graft -c
2336 hg graft -c
2369
2337
2370 - show the source of a grafted changeset::
2338 - show the source of a grafted changeset::
2371
2339
2372 hg log --debug -r .
2340 hg log --debug -r .
2373
2341
2374 - show revisions sorted by date::
2342 - show revisions sorted by date::
2375
2343
2376 hg log -r "sort(all(), date)"
2344 hg log -r "sort(all(), date)"
2377
2345
2378 See :hg:`help revisions` for more about specifying revisions.
2346 See :hg:`help revisions` for more about specifying revisions.
2379
2347
2380 Returns 0 on successful completion.
2348 Returns 0 on successful completion.
2381 '''
2349 '''
2382 with repo.wlock():
2350 with repo.wlock():
2383 return _dograft(ui, repo, *revs, **opts)
2351 return _dograft(ui, repo, *revs, **opts)
2384
2352
2385 def _dograft(ui, repo, *revs, **opts):
2353 def _dograft(ui, repo, *revs, **opts):
2386 if revs and opts.get('rev'):
2354 if revs and opts.get('rev'):
2387 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2355 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2388 'revision ordering!\n'))
2356 'revision ordering!\n'))
2389
2357
2390 revs = list(revs)
2358 revs = list(revs)
2391 revs.extend(opts.get('rev'))
2359 revs.extend(opts.get('rev'))
2392
2360
2393 if not opts.get('user') and opts.get('currentuser'):
2361 if not opts.get('user') and opts.get('currentuser'):
2394 opts['user'] = ui.username()
2362 opts['user'] = ui.username()
2395 if not opts.get('date') and opts.get('currentdate'):
2363 if not opts.get('date') and opts.get('currentdate'):
2396 opts['date'] = "%d %d" % util.makedate()
2364 opts['date'] = "%d %d" % util.makedate()
2397
2365
2398 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2366 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2399
2367
2400 cont = False
2368 cont = False
2401 if opts.get('continue'):
2369 if opts.get('continue'):
2402 cont = True
2370 cont = True
2403 if revs:
2371 if revs:
2404 raise error.Abort(_("can't specify --continue and revisions"))
2372 raise error.Abort(_("can't specify --continue and revisions"))
2405 # read in unfinished revisions
2373 # read in unfinished revisions
2406 try:
2374 try:
2407 nodes = repo.vfs.read('graftstate').splitlines()
2375 nodes = repo.vfs.read('graftstate').splitlines()
2408 revs = [repo[node].rev() for node in nodes]
2376 revs = [repo[node].rev() for node in nodes]
2409 except IOError as inst:
2377 except IOError as inst:
2410 if inst.errno != errno.ENOENT:
2378 if inst.errno != errno.ENOENT:
2411 raise
2379 raise
2412 cmdutil.wrongtooltocontinue(repo, _('graft'))
2380 cmdutil.wrongtooltocontinue(repo, _('graft'))
2413 else:
2381 else:
2414 cmdutil.checkunfinished(repo)
2382 cmdutil.checkunfinished(repo)
2415 cmdutil.bailifchanged(repo)
2383 cmdutil.bailifchanged(repo)
2416 if not revs:
2384 if not revs:
2417 raise error.Abort(_('no revisions specified'))
2385 raise error.Abort(_('no revisions specified'))
2418 revs = scmutil.revrange(repo, revs)
2386 revs = scmutil.revrange(repo, revs)
2419
2387
2420 skipped = set()
2388 skipped = set()
2421 # check for merges
2389 # check for merges
2422 for rev in repo.revs('%ld and merge()', revs):
2390 for rev in repo.revs('%ld and merge()', revs):
2423 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2391 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2424 skipped.add(rev)
2392 skipped.add(rev)
2425 revs = [r for r in revs if r not in skipped]
2393 revs = [r for r in revs if r not in skipped]
2426 if not revs:
2394 if not revs:
2427 return -1
2395 return -1
2428
2396
2429 # Don't check in the --continue case, in effect retaining --force across
2397 # Don't check in the --continue case, in effect retaining --force across
2430 # --continues. That's because without --force, any revisions we decided to
2398 # --continues. That's because without --force, any revisions we decided to
2431 # skip would have been filtered out here, so they wouldn't have made their
2399 # skip would have been filtered out here, so they wouldn't have made their
2432 # way to the graftstate. With --force, any revisions we would have otherwise
2400 # way to the graftstate. With --force, any revisions we would have otherwise
2433 # skipped would not have been filtered out, and if they hadn't been applied
2401 # skipped would not have been filtered out, and if they hadn't been applied
2434 # already, they'd have been in the graftstate.
2402 # already, they'd have been in the graftstate.
2435 if not (cont or opts.get('force')):
2403 if not (cont or opts.get('force')):
2436 # check for ancestors of dest branch
2404 # check for ancestors of dest branch
2437 crev = repo['.'].rev()
2405 crev = repo['.'].rev()
2438 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2406 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2439 # XXX make this lazy in the future
2407 # XXX make this lazy in the future
2440 # don't mutate while iterating, create a copy
2408 # don't mutate while iterating, create a copy
2441 for rev in list(revs):
2409 for rev in list(revs):
2442 if rev in ancestors:
2410 if rev in ancestors:
2443 ui.warn(_('skipping ancestor revision %d:%s\n') %
2411 ui.warn(_('skipping ancestor revision %d:%s\n') %
2444 (rev, repo[rev]))
2412 (rev, repo[rev]))
2445 # XXX remove on list is slow
2413 # XXX remove on list is slow
2446 revs.remove(rev)
2414 revs.remove(rev)
2447 if not revs:
2415 if not revs:
2448 return -1
2416 return -1
2449
2417
2450 # analyze revs for earlier grafts
2418 # analyze revs for earlier grafts
2451 ids = {}
2419 ids = {}
2452 for ctx in repo.set("%ld", revs):
2420 for ctx in repo.set("%ld", revs):
2453 ids[ctx.hex()] = ctx.rev()
2421 ids[ctx.hex()] = ctx.rev()
2454 n = ctx.extra().get('source')
2422 n = ctx.extra().get('source')
2455 if n:
2423 if n:
2456 ids[n] = ctx.rev()
2424 ids[n] = ctx.rev()
2457
2425
2458 # check ancestors for earlier grafts
2426 # check ancestors for earlier grafts
2459 ui.debug('scanning for duplicate grafts\n')
2427 ui.debug('scanning for duplicate grafts\n')
2460
2428
2461 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2429 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2462 ctx = repo[rev]
2430 ctx = repo[rev]
2463 n = ctx.extra().get('source')
2431 n = ctx.extra().get('source')
2464 if n in ids:
2432 if n in ids:
2465 try:
2433 try:
2466 r = repo[n].rev()
2434 r = repo[n].rev()
2467 except error.RepoLookupError:
2435 except error.RepoLookupError:
2468 r = None
2436 r = None
2469 if r in revs:
2437 if r in revs:
2470 ui.warn(_('skipping revision %d:%s '
2438 ui.warn(_('skipping revision %d:%s '
2471 '(already grafted to %d:%s)\n')
2439 '(already grafted to %d:%s)\n')
2472 % (r, repo[r], rev, ctx))
2440 % (r, repo[r], rev, ctx))
2473 revs.remove(r)
2441 revs.remove(r)
2474 elif ids[n] in revs:
2442 elif ids[n] in revs:
2475 if r is None:
2443 if r is None:
2476 ui.warn(_('skipping already grafted revision %d:%s '
2444 ui.warn(_('skipping already grafted revision %d:%s '
2477 '(%d:%s also has unknown origin %s)\n')
2445 '(%d:%s also has unknown origin %s)\n')
2478 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2446 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2479 else:
2447 else:
2480 ui.warn(_('skipping already grafted revision %d:%s '
2448 ui.warn(_('skipping already grafted revision %d:%s '
2481 '(%d:%s also has origin %d:%s)\n')
2449 '(%d:%s also has origin %d:%s)\n')
2482 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2450 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2483 revs.remove(ids[n])
2451 revs.remove(ids[n])
2484 elif ctx.hex() in ids:
2452 elif ctx.hex() in ids:
2485 r = ids[ctx.hex()]
2453 r = ids[ctx.hex()]
2486 ui.warn(_('skipping already grafted revision %d:%s '
2454 ui.warn(_('skipping already grafted revision %d:%s '
2487 '(was grafted from %d:%s)\n') %
2455 '(was grafted from %d:%s)\n') %
2488 (r, repo[r], rev, ctx))
2456 (r, repo[r], rev, ctx))
2489 revs.remove(r)
2457 revs.remove(r)
2490 if not revs:
2458 if not revs:
2491 return -1
2459 return -1
2492
2460
2493 for pos, ctx in enumerate(repo.set("%ld", revs)):
2461 for pos, ctx in enumerate(repo.set("%ld", revs)):
2494 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2462 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2495 ctx.description().split('\n', 1)[0])
2463 ctx.description().split('\n', 1)[0])
2496 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2464 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2497 if names:
2465 if names:
2498 desc += ' (%s)' % ' '.join(names)
2466 desc += ' (%s)' % ' '.join(names)
2499 ui.status(_('grafting %s\n') % desc)
2467 ui.status(_('grafting %s\n') % desc)
2500 if opts.get('dry_run'):
2468 if opts.get('dry_run'):
2501 continue
2469 continue
2502
2470
2503 source = ctx.extra().get('source')
2471 source = ctx.extra().get('source')
2504 extra = {}
2472 extra = {}
2505 if source:
2473 if source:
2506 extra['source'] = source
2474 extra['source'] = source
2507 extra['intermediate-source'] = ctx.hex()
2475 extra['intermediate-source'] = ctx.hex()
2508 else:
2476 else:
2509 extra['source'] = ctx.hex()
2477 extra['source'] = ctx.hex()
2510 user = ctx.user()
2478 user = ctx.user()
2511 if opts.get('user'):
2479 if opts.get('user'):
2512 user = opts['user']
2480 user = opts['user']
2513 date = ctx.date()
2481 date = ctx.date()
2514 if opts.get('date'):
2482 if opts.get('date'):
2515 date = opts['date']
2483 date = opts['date']
2516 message = ctx.description()
2484 message = ctx.description()
2517 if opts.get('log'):
2485 if opts.get('log'):
2518 message += '\n(grafted from %s)' % ctx.hex()
2486 message += '\n(grafted from %s)' % ctx.hex()
2519
2487
2520 # we don't merge the first commit when continuing
2488 # we don't merge the first commit when continuing
2521 if not cont:
2489 if not cont:
2522 # perform the graft merge with p1(rev) as 'ancestor'
2490 # perform the graft merge with p1(rev) as 'ancestor'
2523 try:
2491 try:
2524 # ui.forcemerge is an internal variable, do not document
2492 # ui.forcemerge is an internal variable, do not document
2525 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2493 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2526 'graft')
2494 'graft')
2527 stats = mergemod.graft(repo, ctx, ctx.p1(),
2495 stats = mergemod.graft(repo, ctx, ctx.p1(),
2528 ['local', 'graft'])
2496 ['local', 'graft'])
2529 finally:
2497 finally:
2530 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2498 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2531 # report any conflicts
2499 # report any conflicts
2532 if stats and stats[3] > 0:
2500 if stats and stats[3] > 0:
2533 # write out state for --continue
2501 # write out state for --continue
2534 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2502 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2535 repo.vfs.write('graftstate', ''.join(nodelines))
2503 repo.vfs.write('graftstate', ''.join(nodelines))
2536 extra = ''
2504 extra = ''
2537 if opts.get('user'):
2505 if opts.get('user'):
2538 extra += ' --user %s' % util.shellquote(opts['user'])
2506 extra += ' --user %s' % util.shellquote(opts['user'])
2539 if opts.get('date'):
2507 if opts.get('date'):
2540 extra += ' --date %s' % util.shellquote(opts['date'])
2508 extra += ' --date %s' % util.shellquote(opts['date'])
2541 if opts.get('log'):
2509 if opts.get('log'):
2542 extra += ' --log'
2510 extra += ' --log'
2543 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2511 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2544 raise error.Abort(
2512 raise error.Abort(
2545 _("unresolved conflicts, can't continue"),
2513 _("unresolved conflicts, can't continue"),
2546 hint=hint)
2514 hint=hint)
2547 else:
2515 else:
2548 cont = False
2516 cont = False
2549
2517
2550 # commit
2518 # commit
2551 node = repo.commit(text=message, user=user,
2519 node = repo.commit(text=message, user=user,
2552 date=date, extra=extra, editor=editor)
2520 date=date, extra=extra, editor=editor)
2553 if node is None:
2521 if node is None:
2554 ui.warn(
2522 ui.warn(
2555 _('note: graft of %d:%s created no changes to commit\n') %
2523 _('note: graft of %d:%s created no changes to commit\n') %
2556 (ctx.rev(), ctx))
2524 (ctx.rev(), ctx))
2557
2525
2558 # remove state when we complete successfully
2526 # remove state when we complete successfully
2559 if not opts.get('dry_run'):
2527 if not opts.get('dry_run'):
2560 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2528 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2561
2529
2562 return 0
2530 return 0
2563
2531
2564 @command('grep',
2532 @command('grep',
2565 [('0', 'print0', None, _('end fields with NUL')),
2533 [('0', 'print0', None, _('end fields with NUL')),
2566 ('', 'all', None, _('print all revisions that match')),
2534 ('', 'all', None, _('print all revisions that match')),
2567 ('a', 'text', None, _('treat all files as text')),
2535 ('a', 'text', None, _('treat all files as text')),
2568 ('f', 'follow', None,
2536 ('f', 'follow', None,
2569 _('follow changeset history,'
2537 _('follow changeset history,'
2570 ' or file history across copies and renames')),
2538 ' or file history across copies and renames')),
2571 ('i', 'ignore-case', None, _('ignore case when matching')),
2539 ('i', 'ignore-case', None, _('ignore case when matching')),
2572 ('l', 'files-with-matches', None,
2540 ('l', 'files-with-matches', None,
2573 _('print only filenames and revisions that match')),
2541 _('print only filenames and revisions that match')),
2574 ('n', 'line-number', None, _('print matching line numbers')),
2542 ('n', 'line-number', None, _('print matching line numbers')),
2575 ('r', 'rev', [],
2543 ('r', 'rev', [],
2576 _('only search files changed within revision range'), _('REV')),
2544 _('only search files changed within revision range'), _('REV')),
2577 ('u', 'user', None, _('list the author (long with -v)')),
2545 ('u', 'user', None, _('list the author (long with -v)')),
2578 ('d', 'date', None, _('list the date (short with -q)')),
2546 ('d', 'date', None, _('list the date (short with -q)')),
2579 ] + formatteropts + walkopts,
2547 ] + formatteropts + walkopts,
2580 _('[OPTION]... PATTERN [FILE]...'),
2548 _('[OPTION]... PATTERN [FILE]...'),
2581 inferrepo=True)
2549 inferrepo=True)
2582 def grep(ui, repo, pattern, *pats, **opts):
2550 def grep(ui, repo, pattern, *pats, **opts):
2583 """search revision history for a pattern in specified files
2551 """search revision history for a pattern in specified files
2584
2552
2585 Search revision history for a regular expression in the specified
2553 Search revision history for a regular expression in the specified
2586 files or the entire project.
2554 files or the entire project.
2587
2555
2588 By default, grep prints the most recent revision number for each
2556 By default, grep prints the most recent revision number for each
2589 file in which it finds a match. To get it to print every revision
2557 file in which it finds a match. To get it to print every revision
2590 that contains a change in match status ("-" for a match that becomes
2558 that contains a change in match status ("-" for a match that becomes
2591 a non-match, or "+" for a non-match that becomes a match), use the
2559 a non-match, or "+" for a non-match that becomes a match), use the
2592 --all flag.
2560 --all flag.
2593
2561
2594 PATTERN can be any Python (roughly Perl-compatible) regular
2562 PATTERN can be any Python (roughly Perl-compatible) regular
2595 expression.
2563 expression.
2596
2564
2597 If no FILEs are specified (and -f/--follow isn't set), all files in
2565 If no FILEs are specified (and -f/--follow isn't set), all files in
2598 the repository are searched, including those that don't exist in the
2566 the repository are searched, including those that don't exist in the
2599 current branch or have been deleted in a prior changeset.
2567 current branch or have been deleted in a prior changeset.
2600
2568
2601 Returns 0 if a match is found, 1 otherwise.
2569 Returns 0 if a match is found, 1 otherwise.
2602 """
2570 """
2603 reflags = re.M
2571 reflags = re.M
2604 if opts.get('ignore_case'):
2572 if opts.get('ignore_case'):
2605 reflags |= re.I
2573 reflags |= re.I
2606 try:
2574 try:
2607 regexp = util.re.compile(pattern, reflags)
2575 regexp = util.re.compile(pattern, reflags)
2608 except re.error as inst:
2576 except re.error as inst:
2609 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2577 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2610 return 1
2578 return 1
2611 sep, eol = ':', '\n'
2579 sep, eol = ':', '\n'
2612 if opts.get('print0'):
2580 if opts.get('print0'):
2613 sep = eol = '\0'
2581 sep = eol = '\0'
2614
2582
2615 getfile = util.lrucachefunc(repo.file)
2583 getfile = util.lrucachefunc(repo.file)
2616
2584
2617 def matchlines(body):
2585 def matchlines(body):
2618 begin = 0
2586 begin = 0
2619 linenum = 0
2587 linenum = 0
2620 while begin < len(body):
2588 while begin < len(body):
2621 match = regexp.search(body, begin)
2589 match = regexp.search(body, begin)
2622 if not match:
2590 if not match:
2623 break
2591 break
2624 mstart, mend = match.span()
2592 mstart, mend = match.span()
2625 linenum += body.count('\n', begin, mstart) + 1
2593 linenum += body.count('\n', begin, mstart) + 1
2626 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2594 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2627 begin = body.find('\n', mend) + 1 or len(body) + 1
2595 begin = body.find('\n', mend) + 1 or len(body) + 1
2628 lend = begin - 1
2596 lend = begin - 1
2629 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2597 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2630
2598
2631 class linestate(object):
2599 class linestate(object):
2632 def __init__(self, line, linenum, colstart, colend):
2600 def __init__(self, line, linenum, colstart, colend):
2633 self.line = line
2601 self.line = line
2634 self.linenum = linenum
2602 self.linenum = linenum
2635 self.colstart = colstart
2603 self.colstart = colstart
2636 self.colend = colend
2604 self.colend = colend
2637
2605
2638 def __hash__(self):
2606 def __hash__(self):
2639 return hash((self.linenum, self.line))
2607 return hash((self.linenum, self.line))
2640
2608
2641 def __eq__(self, other):
2609 def __eq__(self, other):
2642 return self.line == other.line
2610 return self.line == other.line
2643
2611
2644 def findpos(self):
2612 def findpos(self):
2645 """Iterate all (start, end) indices of matches"""
2613 """Iterate all (start, end) indices of matches"""
2646 yield self.colstart, self.colend
2614 yield self.colstart, self.colend
2647 p = self.colend
2615 p = self.colend
2648 while p < len(self.line):
2616 while p < len(self.line):
2649 m = regexp.search(self.line, p)
2617 m = regexp.search(self.line, p)
2650 if not m:
2618 if not m:
2651 break
2619 break
2652 yield m.span()
2620 yield m.span()
2653 p = m.end()
2621 p = m.end()
2654
2622
2655 matches = {}
2623 matches = {}
2656 copies = {}
2624 copies = {}
2657 def grepbody(fn, rev, body):
2625 def grepbody(fn, rev, body):
2658 matches[rev].setdefault(fn, [])
2626 matches[rev].setdefault(fn, [])
2659 m = matches[rev][fn]
2627 m = matches[rev][fn]
2660 for lnum, cstart, cend, line in matchlines(body):
2628 for lnum, cstart, cend, line in matchlines(body):
2661 s = linestate(line, lnum, cstart, cend)
2629 s = linestate(line, lnum, cstart, cend)
2662 m.append(s)
2630 m.append(s)
2663
2631
2664 def difflinestates(a, b):
2632 def difflinestates(a, b):
2665 sm = difflib.SequenceMatcher(None, a, b)
2633 sm = difflib.SequenceMatcher(None, a, b)
2666 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2634 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2667 if tag == 'insert':
2635 if tag == 'insert':
2668 for i in xrange(blo, bhi):
2636 for i in xrange(blo, bhi):
2669 yield ('+', b[i])
2637 yield ('+', b[i])
2670 elif tag == 'delete':
2638 elif tag == 'delete':
2671 for i in xrange(alo, ahi):
2639 for i in xrange(alo, ahi):
2672 yield ('-', a[i])
2640 yield ('-', a[i])
2673 elif tag == 'replace':
2641 elif tag == 'replace':
2674 for i in xrange(alo, ahi):
2642 for i in xrange(alo, ahi):
2675 yield ('-', a[i])
2643 yield ('-', a[i])
2676 for i in xrange(blo, bhi):
2644 for i in xrange(blo, bhi):
2677 yield ('+', b[i])
2645 yield ('+', b[i])
2678
2646
2679 def display(fm, fn, ctx, pstates, states):
2647 def display(fm, fn, ctx, pstates, states):
2680 rev = ctx.rev()
2648 rev = ctx.rev()
2681 if fm.isplain():
2649 if fm.isplain():
2682 formatuser = ui.shortuser
2650 formatuser = ui.shortuser
2683 else:
2651 else:
2684 formatuser = str
2652 formatuser = str
2685 if ui.quiet:
2653 if ui.quiet:
2686 datefmt = '%Y-%m-%d'
2654 datefmt = '%Y-%m-%d'
2687 else:
2655 else:
2688 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2656 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2689 found = False
2657 found = False
2690 @util.cachefunc
2658 @util.cachefunc
2691 def binary():
2659 def binary():
2692 flog = getfile(fn)
2660 flog = getfile(fn)
2693 return util.binary(flog.read(ctx.filenode(fn)))
2661 return util.binary(flog.read(ctx.filenode(fn)))
2694
2662
2695 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2663 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2696 if opts.get('all'):
2664 if opts.get('all'):
2697 iter = difflinestates(pstates, states)
2665 iter = difflinestates(pstates, states)
2698 else:
2666 else:
2699 iter = [('', l) for l in states]
2667 iter = [('', l) for l in states]
2700 for change, l in iter:
2668 for change, l in iter:
2701 fm.startitem()
2669 fm.startitem()
2702 fm.data(node=fm.hexfunc(ctx.node()))
2670 fm.data(node=fm.hexfunc(ctx.node()))
2703 cols = [
2671 cols = [
2704 ('filename', fn, True),
2672 ('filename', fn, True),
2705 ('rev', rev, True),
2673 ('rev', rev, True),
2706 ('linenumber', l.linenum, opts.get('line_number')),
2674 ('linenumber', l.linenum, opts.get('line_number')),
2707 ]
2675 ]
2708 if opts.get('all'):
2676 if opts.get('all'):
2709 cols.append(('change', change, True))
2677 cols.append(('change', change, True))
2710 cols.extend([
2678 cols.extend([
2711 ('user', formatuser(ctx.user()), opts.get('user')),
2679 ('user', formatuser(ctx.user()), opts.get('user')),
2712 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2680 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2713 ])
2681 ])
2714 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2682 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2715 for name, data, cond in cols:
2683 for name, data, cond in cols:
2716 field = fieldnamemap.get(name, name)
2684 field = fieldnamemap.get(name, name)
2717 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2685 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2718 if cond and name != lastcol:
2686 if cond and name != lastcol:
2719 fm.plain(sep, label='grep.sep')
2687 fm.plain(sep, label='grep.sep')
2720 if not opts.get('files_with_matches'):
2688 if not opts.get('files_with_matches'):
2721 fm.plain(sep, label='grep.sep')
2689 fm.plain(sep, label='grep.sep')
2722 if not opts.get('text') and binary():
2690 if not opts.get('text') and binary():
2723 fm.plain(_(" Binary file matches"))
2691 fm.plain(_(" Binary file matches"))
2724 else:
2692 else:
2725 displaymatches(fm.nested('texts'), l)
2693 displaymatches(fm.nested('texts'), l)
2726 fm.plain(eol)
2694 fm.plain(eol)
2727 found = True
2695 found = True
2728 if opts.get('files_with_matches'):
2696 if opts.get('files_with_matches'):
2729 break
2697 break
2730 return found
2698 return found
2731
2699
2732 def displaymatches(fm, l):
2700 def displaymatches(fm, l):
2733 p = 0
2701 p = 0
2734 for s, e in l.findpos():
2702 for s, e in l.findpos():
2735 if p < s:
2703 if p < s:
2736 fm.startitem()
2704 fm.startitem()
2737 fm.write('text', '%s', l.line[p:s])
2705 fm.write('text', '%s', l.line[p:s])
2738 fm.data(matched=False)
2706 fm.data(matched=False)
2739 fm.startitem()
2707 fm.startitem()
2740 fm.write('text', '%s', l.line[s:e], label='grep.match')
2708 fm.write('text', '%s', l.line[s:e], label='grep.match')
2741 fm.data(matched=True)
2709 fm.data(matched=True)
2742 p = e
2710 p = e
2743 if p < len(l.line):
2711 if p < len(l.line):
2744 fm.startitem()
2712 fm.startitem()
2745 fm.write('text', '%s', l.line[p:])
2713 fm.write('text', '%s', l.line[p:])
2746 fm.data(matched=False)
2714 fm.data(matched=False)
2747 fm.end()
2715 fm.end()
2748
2716
2749 skip = {}
2717 skip = {}
2750 revfiles = {}
2718 revfiles = {}
2751 matchfn = scmutil.match(repo[None], pats, opts)
2719 matchfn = scmutil.match(repo[None], pats, opts)
2752 found = False
2720 found = False
2753 follow = opts.get('follow')
2721 follow = opts.get('follow')
2754
2722
2755 def prep(ctx, fns):
2723 def prep(ctx, fns):
2756 rev = ctx.rev()
2724 rev = ctx.rev()
2757 pctx = ctx.p1()
2725 pctx = ctx.p1()
2758 parent = pctx.rev()
2726 parent = pctx.rev()
2759 matches.setdefault(rev, {})
2727 matches.setdefault(rev, {})
2760 matches.setdefault(parent, {})
2728 matches.setdefault(parent, {})
2761 files = revfiles.setdefault(rev, [])
2729 files = revfiles.setdefault(rev, [])
2762 for fn in fns:
2730 for fn in fns:
2763 flog = getfile(fn)
2731 flog = getfile(fn)
2764 try:
2732 try:
2765 fnode = ctx.filenode(fn)
2733 fnode = ctx.filenode(fn)
2766 except error.LookupError:
2734 except error.LookupError:
2767 continue
2735 continue
2768
2736
2769 copied = flog.renamed(fnode)
2737 copied = flog.renamed(fnode)
2770 copy = follow and copied and copied[0]
2738 copy = follow and copied and copied[0]
2771 if copy:
2739 if copy:
2772 copies.setdefault(rev, {})[fn] = copy
2740 copies.setdefault(rev, {})[fn] = copy
2773 if fn in skip:
2741 if fn in skip:
2774 if copy:
2742 if copy:
2775 skip[copy] = True
2743 skip[copy] = True
2776 continue
2744 continue
2777 files.append(fn)
2745 files.append(fn)
2778
2746
2779 if fn not in matches[rev]:
2747 if fn not in matches[rev]:
2780 grepbody(fn, rev, flog.read(fnode))
2748 grepbody(fn, rev, flog.read(fnode))
2781
2749
2782 pfn = copy or fn
2750 pfn = copy or fn
2783 if pfn not in matches[parent]:
2751 if pfn not in matches[parent]:
2784 try:
2752 try:
2785 fnode = pctx.filenode(pfn)
2753 fnode = pctx.filenode(pfn)
2786 grepbody(pfn, parent, flog.read(fnode))
2754 grepbody(pfn, parent, flog.read(fnode))
2787 except error.LookupError:
2755 except error.LookupError:
2788 pass
2756 pass
2789
2757
2790 fm = ui.formatter('grep', opts)
2758 fm = ui.formatter('grep', opts)
2791 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2759 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2792 rev = ctx.rev()
2760 rev = ctx.rev()
2793 parent = ctx.p1().rev()
2761 parent = ctx.p1().rev()
2794 for fn in sorted(revfiles.get(rev, [])):
2762 for fn in sorted(revfiles.get(rev, [])):
2795 states = matches[rev][fn]
2763 states = matches[rev][fn]
2796 copy = copies.get(rev, {}).get(fn)
2764 copy = copies.get(rev, {}).get(fn)
2797 if fn in skip:
2765 if fn in skip:
2798 if copy:
2766 if copy:
2799 skip[copy] = True
2767 skip[copy] = True
2800 continue
2768 continue
2801 pstates = matches.get(parent, {}).get(copy or fn, [])
2769 pstates = matches.get(parent, {}).get(copy or fn, [])
2802 if pstates or states:
2770 if pstates or states:
2803 r = display(fm, fn, ctx, pstates, states)
2771 r = display(fm, fn, ctx, pstates, states)
2804 found = found or r
2772 found = found or r
2805 if r and not opts.get('all'):
2773 if r and not opts.get('all'):
2806 skip[fn] = True
2774 skip[fn] = True
2807 if copy:
2775 if copy:
2808 skip[copy] = True
2776 skip[copy] = True
2809 del matches[rev]
2777 del matches[rev]
2810 del revfiles[rev]
2778 del revfiles[rev]
2811 fm.end()
2779 fm.end()
2812
2780
2813 return not found
2781 return not found
2814
2782
2815 @command('heads',
2783 @command('heads',
2816 [('r', 'rev', '',
2784 [('r', 'rev', '',
2817 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2785 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2818 ('t', 'topo', False, _('show topological heads only')),
2786 ('t', 'topo', False, _('show topological heads only')),
2819 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2787 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2820 ('c', 'closed', False, _('show normal and closed branch heads')),
2788 ('c', 'closed', False, _('show normal and closed branch heads')),
2821 ] + templateopts,
2789 ] + templateopts,
2822 _('[-ct] [-r STARTREV] [REV]...'))
2790 _('[-ct] [-r STARTREV] [REV]...'))
2823 def heads(ui, repo, *branchrevs, **opts):
2791 def heads(ui, repo, *branchrevs, **opts):
2824 """show branch heads
2792 """show branch heads
2825
2793
2826 With no arguments, show all open branch heads in the repository.
2794 With no arguments, show all open branch heads in the repository.
2827 Branch heads are changesets that have no descendants on the
2795 Branch heads are changesets that have no descendants on the
2828 same branch. They are where development generally takes place and
2796 same branch. They are where development generally takes place and
2829 are the usual targets for update and merge operations.
2797 are the usual targets for update and merge operations.
2830
2798
2831 If one or more REVs are given, only open branch heads on the
2799 If one or more REVs are given, only open branch heads on the
2832 branches associated with the specified changesets are shown. This
2800 branches associated with the specified changesets are shown. This
2833 means that you can use :hg:`heads .` to see the heads on the
2801 means that you can use :hg:`heads .` to see the heads on the
2834 currently checked-out branch.
2802 currently checked-out branch.
2835
2803
2836 If -c/--closed is specified, also show branch heads marked closed
2804 If -c/--closed is specified, also show branch heads marked closed
2837 (see :hg:`commit --close-branch`).
2805 (see :hg:`commit --close-branch`).
2838
2806
2839 If STARTREV is specified, only those heads that are descendants of
2807 If STARTREV is specified, only those heads that are descendants of
2840 STARTREV will be displayed.
2808 STARTREV will be displayed.
2841
2809
2842 If -t/--topo is specified, named branch mechanics will be ignored and only
2810 If -t/--topo is specified, named branch mechanics will be ignored and only
2843 topological heads (changesets with no children) will be shown.
2811 topological heads (changesets with no children) will be shown.
2844
2812
2845 Returns 0 if matching heads are found, 1 if not.
2813 Returns 0 if matching heads are found, 1 if not.
2846 """
2814 """
2847
2815
2848 start = None
2816 start = None
2849 if 'rev' in opts:
2817 if 'rev' in opts:
2850 start = scmutil.revsingle(repo, opts['rev'], None).node()
2818 start = scmutil.revsingle(repo, opts['rev'], None).node()
2851
2819
2852 if opts.get('topo'):
2820 if opts.get('topo'):
2853 heads = [repo[h] for h in repo.heads(start)]
2821 heads = [repo[h] for h in repo.heads(start)]
2854 else:
2822 else:
2855 heads = []
2823 heads = []
2856 for branch in repo.branchmap():
2824 for branch in repo.branchmap():
2857 heads += repo.branchheads(branch, start, opts.get('closed'))
2825 heads += repo.branchheads(branch, start, opts.get('closed'))
2858 heads = [repo[h] for h in heads]
2826 heads = [repo[h] for h in heads]
2859
2827
2860 if branchrevs:
2828 if branchrevs:
2861 branches = set(repo[br].branch() for br in branchrevs)
2829 branches = set(repo[br].branch() for br in branchrevs)
2862 heads = [h for h in heads if h.branch() in branches]
2830 heads = [h for h in heads if h.branch() in branches]
2863
2831
2864 if opts.get('active') and branchrevs:
2832 if opts.get('active') and branchrevs:
2865 dagheads = repo.heads(start)
2833 dagheads = repo.heads(start)
2866 heads = [h for h in heads if h.node() in dagheads]
2834 heads = [h for h in heads if h.node() in dagheads]
2867
2835
2868 if branchrevs:
2836 if branchrevs:
2869 haveheads = set(h.branch() for h in heads)
2837 haveheads = set(h.branch() for h in heads)
2870 if branches - haveheads:
2838 if branches - haveheads:
2871 headless = ', '.join(b for b in branches - haveheads)
2839 headless = ', '.join(b for b in branches - haveheads)
2872 msg = _('no open branch heads found on branches %s')
2840 msg = _('no open branch heads found on branches %s')
2873 if opts.get('rev'):
2841 if opts.get('rev'):
2874 msg += _(' (started at %s)') % opts['rev']
2842 msg += _(' (started at %s)') % opts['rev']
2875 ui.warn((msg + '\n') % headless)
2843 ui.warn((msg + '\n') % headless)
2876
2844
2877 if not heads:
2845 if not heads:
2878 return 1
2846 return 1
2879
2847
2880 heads = sorted(heads, key=lambda x: -x.rev())
2848 heads = sorted(heads, key=lambda x: -x.rev())
2881 displayer = cmdutil.show_changeset(ui, repo, opts)
2849 displayer = cmdutil.show_changeset(ui, repo, opts)
2882 for ctx in heads:
2850 for ctx in heads:
2883 displayer.show(ctx)
2851 displayer.show(ctx)
2884 displayer.close()
2852 displayer.close()
2885
2853
2886 @command('help',
2854 @command('help',
2887 [('e', 'extension', None, _('show only help for extensions')),
2855 [('e', 'extension', None, _('show only help for extensions')),
2888 ('c', 'command', None, _('show only help for commands')),
2856 ('c', 'command', None, _('show only help for commands')),
2889 ('k', 'keyword', None, _('show topics matching keyword')),
2857 ('k', 'keyword', None, _('show topics matching keyword')),
2890 ('s', 'system', [], _('show help for specific platform(s)')),
2858 ('s', 'system', [], _('show help for specific platform(s)')),
2891 ],
2859 ],
2892 _('[-ecks] [TOPIC]'),
2860 _('[-ecks] [TOPIC]'),
2893 norepo=True)
2861 norepo=True)
2894 def help_(ui, name=None, **opts):
2862 def help_(ui, name=None, **opts):
2895 """show help for a given topic or a help overview
2863 """show help for a given topic or a help overview
2896
2864
2897 With no arguments, print a list of commands with short help messages.
2865 With no arguments, print a list of commands with short help messages.
2898
2866
2899 Given a topic, extension, or command name, print help for that
2867 Given a topic, extension, or command name, print help for that
2900 topic.
2868 topic.
2901
2869
2902 Returns 0 if successful.
2870 Returns 0 if successful.
2903 """
2871 """
2904
2872
2905 textwidth = ui.configint('ui', 'textwidth', 78)
2873 textwidth = ui.configint('ui', 'textwidth', 78)
2906 termwidth = ui.termwidth() - 2
2874 termwidth = ui.termwidth() - 2
2907 if textwidth <= 0 or termwidth < textwidth:
2875 if textwidth <= 0 or termwidth < textwidth:
2908 textwidth = termwidth
2876 textwidth = termwidth
2909
2877
2910 keep = opts.get('system') or []
2878 keep = opts.get('system') or []
2911 if len(keep) == 0:
2879 if len(keep) == 0:
2912 if pycompat.sysplatform.startswith('win'):
2880 if pycompat.sysplatform.startswith('win'):
2913 keep.append('windows')
2881 keep.append('windows')
2914 elif pycompat.sysplatform == 'OpenVMS':
2882 elif pycompat.sysplatform == 'OpenVMS':
2915 keep.append('vms')
2883 keep.append('vms')
2916 elif pycompat.sysplatform == 'plan9':
2884 elif pycompat.sysplatform == 'plan9':
2917 keep.append('plan9')
2885 keep.append('plan9')
2918 else:
2886 else:
2919 keep.append('unix')
2887 keep.append('unix')
2920 keep.append(pycompat.sysplatform.lower())
2888 keep.append(pycompat.sysplatform.lower())
2921 if ui.verbose:
2889 if ui.verbose:
2922 keep.append('verbose')
2890 keep.append('verbose')
2923
2891
2924 fullname = name
2892 fullname = name
2925 section = None
2893 section = None
2926 subtopic = None
2894 subtopic = None
2927 if name and '.' in name:
2895 if name and '.' in name:
2928 name, remaining = name.split('.', 1)
2896 name, remaining = name.split('.', 1)
2929 remaining = encoding.lower(remaining)
2897 remaining = encoding.lower(remaining)
2930 if '.' in remaining:
2898 if '.' in remaining:
2931 subtopic, section = remaining.split('.', 1)
2899 subtopic, section = remaining.split('.', 1)
2932 else:
2900 else:
2933 if name in help.subtopics:
2901 if name in help.subtopics:
2934 subtopic = remaining
2902 subtopic = remaining
2935 else:
2903 else:
2936 section = remaining
2904 section = remaining
2937
2905
2938 text = help.help_(ui, name, subtopic=subtopic, **opts)
2906 text = help.help_(ui, name, subtopic=subtopic, **opts)
2939
2907
2940 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2908 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2941 section=section)
2909 section=section)
2942
2910
2943 # We could have been given a weird ".foo" section without a name
2911 # We could have been given a weird ".foo" section without a name
2944 # to look for, or we could have simply failed to found "foo.bar"
2912 # to look for, or we could have simply failed to found "foo.bar"
2945 # because bar isn't a section of foo
2913 # because bar isn't a section of foo
2946 if section and not (formatted and name):
2914 if section and not (formatted and name):
2947 raise error.Abort(_("help section not found: %s") % fullname)
2915 raise error.Abort(_("help section not found: %s") % fullname)
2948
2916
2949 if 'verbose' in pruned:
2917 if 'verbose' in pruned:
2950 keep.append('omitted')
2918 keep.append('omitted')
2951 else:
2919 else:
2952 keep.append('notomitted')
2920 keep.append('notomitted')
2953 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2921 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2954 section=section)
2922 section=section)
2955 ui.write(formatted)
2923 ui.write(formatted)
2956
2924
2957
2925
2958 @command('identify|id',
2926 @command('identify|id',
2959 [('r', 'rev', '',
2927 [('r', 'rev', '',
2960 _('identify the specified revision'), _('REV')),
2928 _('identify the specified revision'), _('REV')),
2961 ('n', 'num', None, _('show local revision number')),
2929 ('n', 'num', None, _('show local revision number')),
2962 ('i', 'id', None, _('show global revision id')),
2930 ('i', 'id', None, _('show global revision id')),
2963 ('b', 'branch', None, _('show branch')),
2931 ('b', 'branch', None, _('show branch')),
2964 ('t', 'tags', None, _('show tags')),
2932 ('t', 'tags', None, _('show tags')),
2965 ('B', 'bookmarks', None, _('show bookmarks')),
2933 ('B', 'bookmarks', None, _('show bookmarks')),
2966 ] + remoteopts,
2934 ] + remoteopts,
2967 _('[-nibtB] [-r REV] [SOURCE]'),
2935 _('[-nibtB] [-r REV] [SOURCE]'),
2968 optionalrepo=True)
2936 optionalrepo=True)
2969 def identify(ui, repo, source=None, rev=None,
2937 def identify(ui, repo, source=None, rev=None,
2970 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2938 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2971 """identify the working directory or specified revision
2939 """identify the working directory or specified revision
2972
2940
2973 Print a summary identifying the repository state at REV using one or
2941 Print a summary identifying the repository state at REV using one or
2974 two parent hash identifiers, followed by a "+" if the working
2942 two parent hash identifiers, followed by a "+" if the working
2975 directory has uncommitted changes, the branch name (if not default),
2943 directory has uncommitted changes, the branch name (if not default),
2976 a list of tags, and a list of bookmarks.
2944 a list of tags, and a list of bookmarks.
2977
2945
2978 When REV is not given, print a summary of the current state of the
2946 When REV is not given, print a summary of the current state of the
2979 repository.
2947 repository.
2980
2948
2981 Specifying a path to a repository root or Mercurial bundle will
2949 Specifying a path to a repository root or Mercurial bundle will
2982 cause lookup to operate on that repository/bundle.
2950 cause lookup to operate on that repository/bundle.
2983
2951
2984 .. container:: verbose
2952 .. container:: verbose
2985
2953
2986 Examples:
2954 Examples:
2987
2955
2988 - generate a build identifier for the working directory::
2956 - generate a build identifier for the working directory::
2989
2957
2990 hg id --id > build-id.dat
2958 hg id --id > build-id.dat
2991
2959
2992 - find the revision corresponding to a tag::
2960 - find the revision corresponding to a tag::
2993
2961
2994 hg id -n -r 1.3
2962 hg id -n -r 1.3
2995
2963
2996 - check the most recent revision of a remote repository::
2964 - check the most recent revision of a remote repository::
2997
2965
2998 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2966 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2999
2967
3000 See :hg:`log` for generating more information about specific revisions,
2968 See :hg:`log` for generating more information about specific revisions,
3001 including full hash identifiers.
2969 including full hash identifiers.
3002
2970
3003 Returns 0 if successful.
2971 Returns 0 if successful.
3004 """
2972 """
3005
2973
3006 if not repo and not source:
2974 if not repo and not source:
3007 raise error.Abort(_("there is no Mercurial repository here "
2975 raise error.Abort(_("there is no Mercurial repository here "
3008 "(.hg not found)"))
2976 "(.hg not found)"))
3009
2977
3010 if ui.debugflag:
2978 if ui.debugflag:
3011 hexfunc = hex
2979 hexfunc = hex
3012 else:
2980 else:
3013 hexfunc = short
2981 hexfunc = short
3014 default = not (num or id or branch or tags or bookmarks)
2982 default = not (num or id or branch or tags or bookmarks)
3015 output = []
2983 output = []
3016 revs = []
2984 revs = []
3017
2985
3018 if source:
2986 if source:
3019 source, branches = hg.parseurl(ui.expandpath(source))
2987 source, branches = hg.parseurl(ui.expandpath(source))
3020 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2988 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3021 repo = peer.local()
2989 repo = peer.local()
3022 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2990 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3023
2991
3024 if not repo:
2992 if not repo:
3025 if num or branch or tags:
2993 if num or branch or tags:
3026 raise error.Abort(
2994 raise error.Abort(
3027 _("can't query remote revision number, branch, or tags"))
2995 _("can't query remote revision number, branch, or tags"))
3028 if not rev and revs:
2996 if not rev and revs:
3029 rev = revs[0]
2997 rev = revs[0]
3030 if not rev:
2998 if not rev:
3031 rev = "tip"
2999 rev = "tip"
3032
3000
3033 remoterev = peer.lookup(rev)
3001 remoterev = peer.lookup(rev)
3034 if default or id:
3002 if default or id:
3035 output = [hexfunc(remoterev)]
3003 output = [hexfunc(remoterev)]
3036
3004
3037 def getbms():
3005 def getbms():
3038 bms = []
3006 bms = []
3039
3007
3040 if 'bookmarks' in peer.listkeys('namespaces'):
3008 if 'bookmarks' in peer.listkeys('namespaces'):
3041 hexremoterev = hex(remoterev)
3009 hexremoterev = hex(remoterev)
3042 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3010 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3043 if bmr == hexremoterev]
3011 if bmr == hexremoterev]
3044
3012
3045 return sorted(bms)
3013 return sorted(bms)
3046
3014
3047 if bookmarks:
3015 if bookmarks:
3048 output.extend(getbms())
3016 output.extend(getbms())
3049 elif default and not ui.quiet:
3017 elif default and not ui.quiet:
3050 # multiple bookmarks for a single parent separated by '/'
3018 # multiple bookmarks for a single parent separated by '/'
3051 bm = '/'.join(getbms())
3019 bm = '/'.join(getbms())
3052 if bm:
3020 if bm:
3053 output.append(bm)
3021 output.append(bm)
3054 else:
3022 else:
3055 ctx = scmutil.revsingle(repo, rev, None)
3023 ctx = scmutil.revsingle(repo, rev, None)
3056
3024
3057 if ctx.rev() is None:
3025 if ctx.rev() is None:
3058 ctx = repo[None]
3026 ctx = repo[None]
3059 parents = ctx.parents()
3027 parents = ctx.parents()
3060 taglist = []
3028 taglist = []
3061 for p in parents:
3029 for p in parents:
3062 taglist.extend(p.tags())
3030 taglist.extend(p.tags())
3063
3031
3064 changed = ""
3032 changed = ""
3065 if default or id or num:
3033 if default or id or num:
3066 if (any(repo.status())
3034 if (any(repo.status())
3067 or any(ctx.sub(s).dirty() for s in ctx.substate)):
3035 or any(ctx.sub(s).dirty() for s in ctx.substate)):
3068 changed = '+'
3036 changed = '+'
3069 if default or id:
3037 if default or id:
3070 output = ["%s%s" %
3038 output = ["%s%s" %
3071 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3039 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3072 if num:
3040 if num:
3073 output.append("%s%s" %
3041 output.append("%s%s" %
3074 ('+'.join([str(p.rev()) for p in parents]), changed))
3042 ('+'.join([str(p.rev()) for p in parents]), changed))
3075 else:
3043 else:
3076 if default or id:
3044 if default or id:
3077 output = [hexfunc(ctx.node())]
3045 output = [hexfunc(ctx.node())]
3078 if num:
3046 if num:
3079 output.append(str(ctx.rev()))
3047 output.append(str(ctx.rev()))
3080 taglist = ctx.tags()
3048 taglist = ctx.tags()
3081
3049
3082 if default and not ui.quiet:
3050 if default and not ui.quiet:
3083 b = ctx.branch()
3051 b = ctx.branch()
3084 if b != 'default':
3052 if b != 'default':
3085 output.append("(%s)" % b)
3053 output.append("(%s)" % b)
3086
3054
3087 # multiple tags for a single parent separated by '/'
3055 # multiple tags for a single parent separated by '/'
3088 t = '/'.join(taglist)
3056 t = '/'.join(taglist)
3089 if t:
3057 if t:
3090 output.append(t)
3058 output.append(t)
3091
3059
3092 # multiple bookmarks for a single parent separated by '/'
3060 # multiple bookmarks for a single parent separated by '/'
3093 bm = '/'.join(ctx.bookmarks())
3061 bm = '/'.join(ctx.bookmarks())
3094 if bm:
3062 if bm:
3095 output.append(bm)
3063 output.append(bm)
3096 else:
3064 else:
3097 if branch:
3065 if branch:
3098 output.append(ctx.branch())
3066 output.append(ctx.branch())
3099
3067
3100 if tags:
3068 if tags:
3101 output.extend(taglist)
3069 output.extend(taglist)
3102
3070
3103 if bookmarks:
3071 if bookmarks:
3104 output.extend(ctx.bookmarks())
3072 output.extend(ctx.bookmarks())
3105
3073
3106 ui.write("%s\n" % ' '.join(output))
3074 ui.write("%s\n" % ' '.join(output))
3107
3075
3108 @command('import|patch',
3076 @command('import|patch',
3109 [('p', 'strip', 1,
3077 [('p', 'strip', 1,
3110 _('directory strip option for patch. This has the same '
3078 _('directory strip option for patch. This has the same '
3111 'meaning as the corresponding patch option'), _('NUM')),
3079 'meaning as the corresponding patch option'), _('NUM')),
3112 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3080 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3113 ('e', 'edit', False, _('invoke editor on commit messages')),
3081 ('e', 'edit', False, _('invoke editor on commit messages')),
3114 ('f', 'force', None,
3082 ('f', 'force', None,
3115 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3083 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3116 ('', 'no-commit', None,
3084 ('', 'no-commit', None,
3117 _("don't commit, just update the working directory")),
3085 _("don't commit, just update the working directory")),
3118 ('', 'bypass', None,
3086 ('', 'bypass', None,
3119 _("apply patch without touching the working directory")),
3087 _("apply patch without touching the working directory")),
3120 ('', 'partial', None,
3088 ('', 'partial', None,
3121 _('commit even if some hunks fail')),
3089 _('commit even if some hunks fail')),
3122 ('', 'exact', None,
3090 ('', 'exact', None,
3123 _('abort if patch would apply lossily')),
3091 _('abort if patch would apply lossily')),
3124 ('', 'prefix', '',
3092 ('', 'prefix', '',
3125 _('apply patch to subdirectory'), _('DIR')),
3093 _('apply patch to subdirectory'), _('DIR')),
3126 ('', 'import-branch', None,
3094 ('', 'import-branch', None,
3127 _('use any branch information in patch (implied by --exact)'))] +
3095 _('use any branch information in patch (implied by --exact)'))] +
3128 commitopts + commitopts2 + similarityopts,
3096 commitopts + commitopts2 + similarityopts,
3129 _('[OPTION]... PATCH...'))
3097 _('[OPTION]... PATCH...'))
3130 def import_(ui, repo, patch1=None, *patches, **opts):
3098 def import_(ui, repo, patch1=None, *patches, **opts):
3131 """import an ordered set of patches
3099 """import an ordered set of patches
3132
3100
3133 Import a list of patches and commit them individually (unless
3101 Import a list of patches and commit them individually (unless
3134 --no-commit is specified).
3102 --no-commit is specified).
3135
3103
3136 To read a patch from standard input (stdin), use "-" as the patch
3104 To read a patch from standard input (stdin), use "-" as the patch
3137 name. If a URL is specified, the patch will be downloaded from
3105 name. If a URL is specified, the patch will be downloaded from
3138 there.
3106 there.
3139
3107
3140 Import first applies changes to the working directory (unless
3108 Import first applies changes to the working directory (unless
3141 --bypass is specified), import will abort if there are outstanding
3109 --bypass is specified), import will abort if there are outstanding
3142 changes.
3110 changes.
3143
3111
3144 Use --bypass to apply and commit patches directly to the
3112 Use --bypass to apply and commit patches directly to the
3145 repository, without affecting the working directory. Without
3113 repository, without affecting the working directory. Without
3146 --exact, patches will be applied on top of the working directory
3114 --exact, patches will be applied on top of the working directory
3147 parent revision.
3115 parent revision.
3148
3116
3149 You can import a patch straight from a mail message. Even patches
3117 You can import a patch straight from a mail message. Even patches
3150 as attachments work (to use the body part, it must have type
3118 as attachments work (to use the body part, it must have type
3151 text/plain or text/x-patch). From and Subject headers of email
3119 text/plain or text/x-patch). From and Subject headers of email
3152 message are used as default committer and commit message. All
3120 message are used as default committer and commit message. All
3153 text/plain body parts before first diff are added to the commit
3121 text/plain body parts before first diff are added to the commit
3154 message.
3122 message.
3155
3123
3156 If the imported patch was generated by :hg:`export`, user and
3124 If the imported patch was generated by :hg:`export`, user and
3157 description from patch override values from message headers and
3125 description from patch override values from message headers and
3158 body. Values given on command line with -m/--message and -u/--user
3126 body. Values given on command line with -m/--message and -u/--user
3159 override these.
3127 override these.
3160
3128
3161 If --exact is specified, import will set the working directory to
3129 If --exact is specified, import will set the working directory to
3162 the parent of each patch before applying it, and will abort if the
3130 the parent of each patch before applying it, and will abort if the
3163 resulting changeset has a different ID than the one recorded in
3131 resulting changeset has a different ID than the one recorded in
3164 the patch. This will guard against various ways that portable
3132 the patch. This will guard against various ways that portable
3165 patch formats and mail systems might fail to transfer Mercurial
3133 patch formats and mail systems might fail to transfer Mercurial
3166 data or metadata. See :hg:`bundle` for lossless transmission.
3134 data or metadata. See :hg:`bundle` for lossless transmission.
3167
3135
3168 Use --partial to ensure a changeset will be created from the patch
3136 Use --partial to ensure a changeset will be created from the patch
3169 even if some hunks fail to apply. Hunks that fail to apply will be
3137 even if some hunks fail to apply. Hunks that fail to apply will be
3170 written to a <target-file>.rej file. Conflicts can then be resolved
3138 written to a <target-file>.rej file. Conflicts can then be resolved
3171 by hand before :hg:`commit --amend` is run to update the created
3139 by hand before :hg:`commit --amend` is run to update the created
3172 changeset. This flag exists to let people import patches that
3140 changeset. This flag exists to let people import patches that
3173 partially apply without losing the associated metadata (author,
3141 partially apply without losing the associated metadata (author,
3174 date, description, ...).
3142 date, description, ...).
3175
3143
3176 .. note::
3144 .. note::
3177
3145
3178 When no hunks apply cleanly, :hg:`import --partial` will create
3146 When no hunks apply cleanly, :hg:`import --partial` will create
3179 an empty changeset, importing only the patch metadata.
3147 an empty changeset, importing only the patch metadata.
3180
3148
3181 With -s/--similarity, hg will attempt to discover renames and
3149 With -s/--similarity, hg will attempt to discover renames and
3182 copies in the patch in the same way as :hg:`addremove`.
3150 copies in the patch in the same way as :hg:`addremove`.
3183
3151
3184 It is possible to use external patch programs to perform the patch
3152 It is possible to use external patch programs to perform the patch
3185 by setting the ``ui.patch`` configuration option. For the default
3153 by setting the ``ui.patch`` configuration option. For the default
3186 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3154 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3187 See :hg:`help config` for more information about configuration
3155 See :hg:`help config` for more information about configuration
3188 files and how to use these options.
3156 files and how to use these options.
3189
3157
3190 See :hg:`help dates` for a list of formats valid for -d/--date.
3158 See :hg:`help dates` for a list of formats valid for -d/--date.
3191
3159
3192 .. container:: verbose
3160 .. container:: verbose
3193
3161
3194 Examples:
3162 Examples:
3195
3163
3196 - import a traditional patch from a website and detect renames::
3164 - import a traditional patch from a website and detect renames::
3197
3165
3198 hg import -s 80 http://example.com/bugfix.patch
3166 hg import -s 80 http://example.com/bugfix.patch
3199
3167
3200 - import a changeset from an hgweb server::
3168 - import a changeset from an hgweb server::
3201
3169
3202 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3170 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3203
3171
3204 - import all the patches in an Unix-style mbox::
3172 - import all the patches in an Unix-style mbox::
3205
3173
3206 hg import incoming-patches.mbox
3174 hg import incoming-patches.mbox
3207
3175
3208 - import patches from stdin::
3176 - import patches from stdin::
3209
3177
3210 hg import -
3178 hg import -
3211
3179
3212 - attempt to exactly restore an exported changeset (not always
3180 - attempt to exactly restore an exported changeset (not always
3213 possible)::
3181 possible)::
3214
3182
3215 hg import --exact proposed-fix.patch
3183 hg import --exact proposed-fix.patch
3216
3184
3217 - use an external tool to apply a patch which is too fuzzy for
3185 - use an external tool to apply a patch which is too fuzzy for
3218 the default internal tool.
3186 the default internal tool.
3219
3187
3220 hg import --config ui.patch="patch --merge" fuzzy.patch
3188 hg import --config ui.patch="patch --merge" fuzzy.patch
3221
3189
3222 - change the default fuzzing from 2 to a less strict 7
3190 - change the default fuzzing from 2 to a less strict 7
3223
3191
3224 hg import --config ui.fuzz=7 fuzz.patch
3192 hg import --config ui.fuzz=7 fuzz.patch
3225
3193
3226 Returns 0 on success, 1 on partial success (see --partial).
3194 Returns 0 on success, 1 on partial success (see --partial).
3227 """
3195 """
3228
3196
3229 if not patch1:
3197 if not patch1:
3230 raise error.Abort(_('need at least one patch to import'))
3198 raise error.Abort(_('need at least one patch to import'))
3231
3199
3232 patches = (patch1,) + patches
3200 patches = (patch1,) + patches
3233
3201
3234 date = opts.get('date')
3202 date = opts.get('date')
3235 if date:
3203 if date:
3236 opts['date'] = util.parsedate(date)
3204 opts['date'] = util.parsedate(date)
3237
3205
3238 exact = opts.get('exact')
3206 exact = opts.get('exact')
3239 update = not opts.get('bypass')
3207 update = not opts.get('bypass')
3240 if not update and opts.get('no_commit'):
3208 if not update and opts.get('no_commit'):
3241 raise error.Abort(_('cannot use --no-commit with --bypass'))
3209 raise error.Abort(_('cannot use --no-commit with --bypass'))
3242 try:
3210 try:
3243 sim = float(opts.get('similarity') or 0)
3211 sim = float(opts.get('similarity') or 0)
3244 except ValueError:
3212 except ValueError:
3245 raise error.Abort(_('similarity must be a number'))
3213 raise error.Abort(_('similarity must be a number'))
3246 if sim < 0 or sim > 100:
3214 if sim < 0 or sim > 100:
3247 raise error.Abort(_('similarity must be between 0 and 100'))
3215 raise error.Abort(_('similarity must be between 0 and 100'))
3248 if sim and not update:
3216 if sim and not update:
3249 raise error.Abort(_('cannot use --similarity with --bypass'))
3217 raise error.Abort(_('cannot use --similarity with --bypass'))
3250 if exact:
3218 if exact:
3251 if opts.get('edit'):
3219 if opts.get('edit'):
3252 raise error.Abort(_('cannot use --exact with --edit'))
3220 raise error.Abort(_('cannot use --exact with --edit'))
3253 if opts.get('prefix'):
3221 if opts.get('prefix'):
3254 raise error.Abort(_('cannot use --exact with --prefix'))
3222 raise error.Abort(_('cannot use --exact with --prefix'))
3255
3223
3256 base = opts["base"]
3224 base = opts["base"]
3257 wlock = dsguard = lock = tr = None
3225 wlock = dsguard = lock = tr = None
3258 msgs = []
3226 msgs = []
3259 ret = 0
3227 ret = 0
3260
3228
3261
3229
3262 try:
3230 try:
3263 wlock = repo.wlock()
3231 wlock = repo.wlock()
3264
3232
3265 if update:
3233 if update:
3266 cmdutil.checkunfinished(repo)
3234 cmdutil.checkunfinished(repo)
3267 if (exact or not opts.get('force')):
3235 if (exact or not opts.get('force')):
3268 cmdutil.bailifchanged(repo)
3236 cmdutil.bailifchanged(repo)
3269
3237
3270 if not opts.get('no_commit'):
3238 if not opts.get('no_commit'):
3271 lock = repo.lock()
3239 lock = repo.lock()
3272 tr = repo.transaction('import')
3240 tr = repo.transaction('import')
3273 else:
3241 else:
3274 dsguard = dirstateguard.dirstateguard(repo, 'import')
3242 dsguard = dirstateguard.dirstateguard(repo, 'import')
3275 parents = repo[None].parents()
3243 parents = repo[None].parents()
3276 for patchurl in patches:
3244 for patchurl in patches:
3277 if patchurl == '-':
3245 if patchurl == '-':
3278 ui.status(_('applying patch from stdin\n'))
3246 ui.status(_('applying patch from stdin\n'))
3279 patchfile = ui.fin
3247 patchfile = ui.fin
3280 patchurl = 'stdin' # for error message
3248 patchurl = 'stdin' # for error message
3281 else:
3249 else:
3282 patchurl = os.path.join(base, patchurl)
3250 patchurl = os.path.join(base, patchurl)
3283 ui.status(_('applying %s\n') % patchurl)
3251 ui.status(_('applying %s\n') % patchurl)
3284 patchfile = hg.openpath(ui, patchurl)
3252 patchfile = hg.openpath(ui, patchurl)
3285
3253
3286 haspatch = False
3254 haspatch = False
3287 for hunk in patch.split(patchfile):
3255 for hunk in patch.split(patchfile):
3288 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3256 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3289 parents, opts,
3257 parents, opts,
3290 msgs, hg.clean)
3258 msgs, hg.clean)
3291 if msg:
3259 if msg:
3292 haspatch = True
3260 haspatch = True
3293 ui.note(msg + '\n')
3261 ui.note(msg + '\n')
3294 if update or exact:
3262 if update or exact:
3295 parents = repo[None].parents()
3263 parents = repo[None].parents()
3296 else:
3264 else:
3297 parents = [repo[node]]
3265 parents = [repo[node]]
3298 if rej:
3266 if rej:
3299 ui.write_err(_("patch applied partially\n"))
3267 ui.write_err(_("patch applied partially\n"))
3300 ui.write_err(_("(fix the .rej files and run "
3268 ui.write_err(_("(fix the .rej files and run "
3301 "`hg commit --amend`)\n"))
3269 "`hg commit --amend`)\n"))
3302 ret = 1
3270 ret = 1
3303 break
3271 break
3304
3272
3305 if not haspatch:
3273 if not haspatch:
3306 raise error.Abort(_('%s: no diffs found') % patchurl)
3274 raise error.Abort(_('%s: no diffs found') % patchurl)
3307
3275
3308 if tr:
3276 if tr:
3309 tr.close()
3277 tr.close()
3310 if msgs:
3278 if msgs:
3311 repo.savecommitmessage('\n* * *\n'.join(msgs))
3279 repo.savecommitmessage('\n* * *\n'.join(msgs))
3312 if dsguard:
3280 if dsguard:
3313 dsguard.close()
3281 dsguard.close()
3314 return ret
3282 return ret
3315 finally:
3283 finally:
3316 if tr:
3284 if tr:
3317 tr.release()
3285 tr.release()
3318 release(lock, dsguard, wlock)
3286 release(lock, dsguard, wlock)
3319
3287
3320 @command('incoming|in',
3288 @command('incoming|in',
3321 [('f', 'force', None,
3289 [('f', 'force', None,
3322 _('run even if remote repository is unrelated')),
3290 _('run even if remote repository is unrelated')),
3323 ('n', 'newest-first', None, _('show newest record first')),
3291 ('n', 'newest-first', None, _('show newest record first')),
3324 ('', 'bundle', '',
3292 ('', 'bundle', '',
3325 _('file to store the bundles into'), _('FILE')),
3293 _('file to store the bundles into'), _('FILE')),
3326 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3294 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3327 ('B', 'bookmarks', False, _("compare bookmarks")),
3295 ('B', 'bookmarks', False, _("compare bookmarks")),
3328 ('b', 'branch', [],
3296 ('b', 'branch', [],
3329 _('a specific branch you would like to pull'), _('BRANCH')),
3297 _('a specific branch you would like to pull'), _('BRANCH')),
3330 ] + logopts + remoteopts + subrepoopts,
3298 ] + logopts + remoteopts + subrepoopts,
3331 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3299 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3332 def incoming(ui, repo, source="default", **opts):
3300 def incoming(ui, repo, source="default", **opts):
3333 """show new changesets found in source
3301 """show new changesets found in source
3334
3302
3335 Show new changesets found in the specified path/URL or the default
3303 Show new changesets found in the specified path/URL or the default
3336 pull location. These are the changesets that would have been pulled
3304 pull location. These are the changesets that would have been pulled
3337 if a pull at the time you issued this command.
3305 if a pull at the time you issued this command.
3338
3306
3339 See pull for valid source format details.
3307 See pull for valid source format details.
3340
3308
3341 .. container:: verbose
3309 .. container:: verbose
3342
3310
3343 With -B/--bookmarks, the result of bookmark comparison between
3311 With -B/--bookmarks, the result of bookmark comparison between
3344 local and remote repositories is displayed. With -v/--verbose,
3312 local and remote repositories is displayed. With -v/--verbose,
3345 status is also displayed for each bookmark like below::
3313 status is also displayed for each bookmark like below::
3346
3314
3347 BM1 01234567890a added
3315 BM1 01234567890a added
3348 BM2 1234567890ab advanced
3316 BM2 1234567890ab advanced
3349 BM3 234567890abc diverged
3317 BM3 234567890abc diverged
3350 BM4 34567890abcd changed
3318 BM4 34567890abcd changed
3351
3319
3352 The action taken locally when pulling depends on the
3320 The action taken locally when pulling depends on the
3353 status of each bookmark:
3321 status of each bookmark:
3354
3322
3355 :``added``: pull will create it
3323 :``added``: pull will create it
3356 :``advanced``: pull will update it
3324 :``advanced``: pull will update it
3357 :``diverged``: pull will create a divergent bookmark
3325 :``diverged``: pull will create a divergent bookmark
3358 :``changed``: result depends on remote changesets
3326 :``changed``: result depends on remote changesets
3359
3327
3360 From the point of view of pulling behavior, bookmark
3328 From the point of view of pulling behavior, bookmark
3361 existing only in the remote repository are treated as ``added``,
3329 existing only in the remote repository are treated as ``added``,
3362 even if it is in fact locally deleted.
3330 even if it is in fact locally deleted.
3363
3331
3364 .. container:: verbose
3332 .. container:: verbose
3365
3333
3366 For remote repository, using --bundle avoids downloading the
3334 For remote repository, using --bundle avoids downloading the
3367 changesets twice if the incoming is followed by a pull.
3335 changesets twice if the incoming is followed by a pull.
3368
3336
3369 Examples:
3337 Examples:
3370
3338
3371 - show incoming changes with patches and full description::
3339 - show incoming changes with patches and full description::
3372
3340
3373 hg incoming -vp
3341 hg incoming -vp
3374
3342
3375 - show incoming changes excluding merges, store a bundle::
3343 - show incoming changes excluding merges, store a bundle::
3376
3344
3377 hg in -vpM --bundle incoming.hg
3345 hg in -vpM --bundle incoming.hg
3378 hg pull incoming.hg
3346 hg pull incoming.hg
3379
3347
3380 - briefly list changes inside a bundle::
3348 - briefly list changes inside a bundle::
3381
3349
3382 hg in changes.hg -T "{desc|firstline}\\n"
3350 hg in changes.hg -T "{desc|firstline}\\n"
3383
3351
3384 Returns 0 if there are incoming changes, 1 otherwise.
3352 Returns 0 if there are incoming changes, 1 otherwise.
3385 """
3353 """
3386 if opts.get('graph'):
3354 if opts.get('graph'):
3387 cmdutil.checkunsupportedgraphflags([], opts)
3355 cmdutil.checkunsupportedgraphflags([], opts)
3388 def display(other, chlist, displayer):
3356 def display(other, chlist, displayer):
3389 revdag = cmdutil.graphrevs(other, chlist, opts)
3357 revdag = cmdutil.graphrevs(other, chlist, opts)
3390 cmdutil.displaygraph(ui, repo, revdag, displayer,
3358 cmdutil.displaygraph(ui, repo, revdag, displayer,
3391 graphmod.asciiedges)
3359 graphmod.asciiedges)
3392
3360
3393 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3361 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3394 return 0
3362 return 0
3395
3363
3396 if opts.get('bundle') and opts.get('subrepos'):
3364 if opts.get('bundle') and opts.get('subrepos'):
3397 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3365 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3398
3366
3399 if opts.get('bookmarks'):
3367 if opts.get('bookmarks'):
3400 source, branches = hg.parseurl(ui.expandpath(source),
3368 source, branches = hg.parseurl(ui.expandpath(source),
3401 opts.get('branch'))
3369 opts.get('branch'))
3402 other = hg.peer(repo, opts, source)
3370 other = hg.peer(repo, opts, source)
3403 if 'bookmarks' not in other.listkeys('namespaces'):
3371 if 'bookmarks' not in other.listkeys('namespaces'):
3404 ui.warn(_("remote doesn't support bookmarks\n"))
3372 ui.warn(_("remote doesn't support bookmarks\n"))
3405 return 0
3373 return 0
3406 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3374 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3407 return bookmarks.incoming(ui, repo, other)
3375 return bookmarks.incoming(ui, repo, other)
3408
3376
3409 repo._subtoppath = ui.expandpath(source)
3377 repo._subtoppath = ui.expandpath(source)
3410 try:
3378 try:
3411 return hg.incoming(ui, repo, source, opts)
3379 return hg.incoming(ui, repo, source, opts)
3412 finally:
3380 finally:
3413 del repo._subtoppath
3381 del repo._subtoppath
3414
3382
3415
3383
3416 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3384 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3417 norepo=True)
3385 norepo=True)
3418 def init(ui, dest=".", **opts):
3386 def init(ui, dest=".", **opts):
3419 """create a new repository in the given directory
3387 """create a new repository in the given directory
3420
3388
3421 Initialize a new repository in the given directory. If the given
3389 Initialize a new repository in the given directory. If the given
3422 directory does not exist, it will be created.
3390 directory does not exist, it will be created.
3423
3391
3424 If no directory is given, the current directory is used.
3392 If no directory is given, the current directory is used.
3425
3393
3426 It is possible to specify an ``ssh://`` URL as the destination.
3394 It is possible to specify an ``ssh://`` URL as the destination.
3427 See :hg:`help urls` for more information.
3395 See :hg:`help urls` for more information.
3428
3396
3429 Returns 0 on success.
3397 Returns 0 on success.
3430 """
3398 """
3431 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3399 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3432
3400
3433 @command('locate',
3401 @command('locate',
3434 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3402 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3435 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3403 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3436 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3404 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3437 ] + walkopts,
3405 ] + walkopts,
3438 _('[OPTION]... [PATTERN]...'))
3406 _('[OPTION]... [PATTERN]...'))
3439 def locate(ui, repo, *pats, **opts):
3407 def locate(ui, repo, *pats, **opts):
3440 """locate files matching specific patterns (DEPRECATED)
3408 """locate files matching specific patterns (DEPRECATED)
3441
3409
3442 Print files under Mercurial control in the working directory whose
3410 Print files under Mercurial control in the working directory whose
3443 names match the given patterns.
3411 names match the given patterns.
3444
3412
3445 By default, this command searches all directories in the working
3413 By default, this command searches all directories in the working
3446 directory. To search just the current directory and its
3414 directory. To search just the current directory and its
3447 subdirectories, use "--include .".
3415 subdirectories, use "--include .".
3448
3416
3449 If no patterns are given to match, this command prints the names
3417 If no patterns are given to match, this command prints the names
3450 of all files under Mercurial control in the working directory.
3418 of all files under Mercurial control in the working directory.
3451
3419
3452 If you want to feed the output of this command into the "xargs"
3420 If you want to feed the output of this command into the "xargs"
3453 command, use the -0 option to both this command and "xargs". This
3421 command, use the -0 option to both this command and "xargs". This
3454 will avoid the problem of "xargs" treating single filenames that
3422 will avoid the problem of "xargs" treating single filenames that
3455 contain whitespace as multiple filenames.
3423 contain whitespace as multiple filenames.
3456
3424
3457 See :hg:`help files` for a more versatile command.
3425 See :hg:`help files` for a more versatile command.
3458
3426
3459 Returns 0 if a match is found, 1 otherwise.
3427 Returns 0 if a match is found, 1 otherwise.
3460 """
3428 """
3461 if opts.get('print0'):
3429 if opts.get('print0'):
3462 end = '\0'
3430 end = '\0'
3463 else:
3431 else:
3464 end = '\n'
3432 end = '\n'
3465 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3433 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3466
3434
3467 ret = 1
3435 ret = 1
3468 ctx = repo[rev]
3436 ctx = repo[rev]
3469 m = scmutil.match(ctx, pats, opts, default='relglob',
3437 m = scmutil.match(ctx, pats, opts, default='relglob',
3470 badfn=lambda x, y: False)
3438 badfn=lambda x, y: False)
3471
3439
3472 for abs in ctx.matches(m):
3440 for abs in ctx.matches(m):
3473 if opts.get('fullpath'):
3441 if opts.get('fullpath'):
3474 ui.write(repo.wjoin(abs), end)
3442 ui.write(repo.wjoin(abs), end)
3475 else:
3443 else:
3476 ui.write(((pats and m.rel(abs)) or abs), end)
3444 ui.write(((pats and m.rel(abs)) or abs), end)
3477 ret = 0
3445 ret = 0
3478
3446
3479 return ret
3447 return ret
3480
3448
3481 @command('^log|history',
3449 @command('^log|history',
3482 [('f', 'follow', None,
3450 [('f', 'follow', None,
3483 _('follow changeset history, or file history across copies and renames')),
3451 _('follow changeset history, or file history across copies and renames')),
3484 ('', 'follow-first', None,
3452 ('', 'follow-first', None,
3485 _('only follow the first parent of merge changesets (DEPRECATED)')),
3453 _('only follow the first parent of merge changesets (DEPRECATED)')),
3486 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3454 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3487 ('C', 'copies', None, _('show copied files')),
3455 ('C', 'copies', None, _('show copied files')),
3488 ('k', 'keyword', [],
3456 ('k', 'keyword', [],
3489 _('do case-insensitive search for a given text'), _('TEXT')),
3457 _('do case-insensitive search for a given text'), _('TEXT')),
3490 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3458 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3491 ('', 'removed', None, _('include revisions where files were removed')),
3459 ('', 'removed', None, _('include revisions where files were removed')),
3492 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3460 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3493 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3461 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3494 ('', 'only-branch', [],
3462 ('', 'only-branch', [],
3495 _('show only changesets within the given named branch (DEPRECATED)'),
3463 _('show only changesets within the given named branch (DEPRECATED)'),
3496 _('BRANCH')),
3464 _('BRANCH')),
3497 ('b', 'branch', [],
3465 ('b', 'branch', [],
3498 _('show changesets within the given named branch'), _('BRANCH')),
3466 _('show changesets within the given named branch'), _('BRANCH')),
3499 ('P', 'prune', [],
3467 ('P', 'prune', [],
3500 _('do not display revision or any of its ancestors'), _('REV')),
3468 _('do not display revision or any of its ancestors'), _('REV')),
3501 ] + logopts + walkopts,
3469 ] + logopts + walkopts,
3502 _('[OPTION]... [FILE]'),
3470 _('[OPTION]... [FILE]'),
3503 inferrepo=True)
3471 inferrepo=True)
3504 def log(ui, repo, *pats, **opts):
3472 def log(ui, repo, *pats, **opts):
3505 """show revision history of entire repository or files
3473 """show revision history of entire repository or files
3506
3474
3507 Print the revision history of the specified files or the entire
3475 Print the revision history of the specified files or the entire
3508 project.
3476 project.
3509
3477
3510 If no revision range is specified, the default is ``tip:0`` unless
3478 If no revision range is specified, the default is ``tip:0`` unless
3511 --follow is set, in which case the working directory parent is
3479 --follow is set, in which case the working directory parent is
3512 used as the starting revision.
3480 used as the starting revision.
3513
3481
3514 File history is shown without following rename or copy history of
3482 File history is shown without following rename or copy history of
3515 files. Use -f/--follow with a filename to follow history across
3483 files. Use -f/--follow with a filename to follow history across
3516 renames and copies. --follow without a filename will only show
3484 renames and copies. --follow without a filename will only show
3517 ancestors or descendants of the starting revision.
3485 ancestors or descendants of the starting revision.
3518
3486
3519 By default this command prints revision number and changeset id,
3487 By default this command prints revision number and changeset id,
3520 tags, non-trivial parents, user, date and time, and a summary for
3488 tags, non-trivial parents, user, date and time, and a summary for
3521 each commit. When the -v/--verbose switch is used, the list of
3489 each commit. When the -v/--verbose switch is used, the list of
3522 changed files and full commit message are shown.
3490 changed files and full commit message are shown.
3523
3491
3524 With --graph the revisions are shown as an ASCII art DAG with the most
3492 With --graph the revisions are shown as an ASCII art DAG with the most
3525 recent changeset at the top.
3493 recent changeset at the top.
3526 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3494 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3527 and '+' represents a fork where the changeset from the lines below is a
3495 and '+' represents a fork where the changeset from the lines below is a
3528 parent of the 'o' merge on the same line.
3496 parent of the 'o' merge on the same line.
3529
3497
3530 .. note::
3498 .. note::
3531
3499
3532 :hg:`log --patch` may generate unexpected diff output for merge
3500 :hg:`log --patch` may generate unexpected diff output for merge
3533 changesets, as it will only compare the merge changeset against
3501 changesets, as it will only compare the merge changeset against
3534 its first parent. Also, only files different from BOTH parents
3502 its first parent. Also, only files different from BOTH parents
3535 will appear in files:.
3503 will appear in files:.
3536
3504
3537 .. note::
3505 .. note::
3538
3506
3539 For performance reasons, :hg:`log FILE` may omit duplicate changes
3507 For performance reasons, :hg:`log FILE` may omit duplicate changes
3540 made on branches and will not show removals or mode changes. To
3508 made on branches and will not show removals or mode changes. To
3541 see all such changes, use the --removed switch.
3509 see all such changes, use the --removed switch.
3542
3510
3543 .. container:: verbose
3511 .. container:: verbose
3544
3512
3545 Some examples:
3513 Some examples:
3546
3514
3547 - changesets with full descriptions and file lists::
3515 - changesets with full descriptions and file lists::
3548
3516
3549 hg log -v
3517 hg log -v
3550
3518
3551 - changesets ancestral to the working directory::
3519 - changesets ancestral to the working directory::
3552
3520
3553 hg log -f
3521 hg log -f
3554
3522
3555 - last 10 commits on the current branch::
3523 - last 10 commits on the current branch::
3556
3524
3557 hg log -l 10 -b .
3525 hg log -l 10 -b .
3558
3526
3559 - changesets showing all modifications of a file, including removals::
3527 - changesets showing all modifications of a file, including removals::
3560
3528
3561 hg log --removed file.c
3529 hg log --removed file.c
3562
3530
3563 - all changesets that touch a directory, with diffs, excluding merges::
3531 - all changesets that touch a directory, with diffs, excluding merges::
3564
3532
3565 hg log -Mp lib/
3533 hg log -Mp lib/
3566
3534
3567 - all revision numbers that match a keyword::
3535 - all revision numbers that match a keyword::
3568
3536
3569 hg log -k bug --template "{rev}\\n"
3537 hg log -k bug --template "{rev}\\n"
3570
3538
3571 - the full hash identifier of the working directory parent::
3539 - the full hash identifier of the working directory parent::
3572
3540
3573 hg log -r . --template "{node}\\n"
3541 hg log -r . --template "{node}\\n"
3574
3542
3575 - list available log templates::
3543 - list available log templates::
3576
3544
3577 hg log -T list
3545 hg log -T list
3578
3546
3579 - check if a given changeset is included in a tagged release::
3547 - check if a given changeset is included in a tagged release::
3580
3548
3581 hg log -r "a21ccf and ancestor(1.9)"
3549 hg log -r "a21ccf and ancestor(1.9)"
3582
3550
3583 - find all changesets by some user in a date range::
3551 - find all changesets by some user in a date range::
3584
3552
3585 hg log -k alice -d "may 2008 to jul 2008"
3553 hg log -k alice -d "may 2008 to jul 2008"
3586
3554
3587 - summary of all changesets after the last tag::
3555 - summary of all changesets after the last tag::
3588
3556
3589 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3557 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3590
3558
3591 See :hg:`help dates` for a list of formats valid for -d/--date.
3559 See :hg:`help dates` for a list of formats valid for -d/--date.
3592
3560
3593 See :hg:`help revisions` for more about specifying and ordering
3561 See :hg:`help revisions` for more about specifying and ordering
3594 revisions.
3562 revisions.
3595
3563
3596 See :hg:`help templates` for more about pre-packaged styles and
3564 See :hg:`help templates` for more about pre-packaged styles and
3597 specifying custom templates.
3565 specifying custom templates.
3598
3566
3599 Returns 0 on success.
3567 Returns 0 on success.
3600
3568
3601 """
3569 """
3602 if opts.get('follow') and opts.get('rev'):
3570 if opts.get('follow') and opts.get('rev'):
3603 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
3571 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
3604 del opts['follow']
3572 del opts['follow']
3605
3573
3606 if opts.get('graph'):
3574 if opts.get('graph'):
3607 return cmdutil.graphlog(ui, repo, *pats, **opts)
3575 return cmdutil.graphlog(ui, repo, *pats, **opts)
3608
3576
3609 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3577 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3610 limit = cmdutil.loglimit(opts)
3578 limit = cmdutil.loglimit(opts)
3611 count = 0
3579 count = 0
3612
3580
3613 getrenamed = None
3581 getrenamed = None
3614 if opts.get('copies'):
3582 if opts.get('copies'):
3615 endrev = None
3583 endrev = None
3616 if opts.get('rev'):
3584 if opts.get('rev'):
3617 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3585 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3618 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3586 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3619
3587
3620 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3588 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3621 for rev in revs:
3589 for rev in revs:
3622 if count == limit:
3590 if count == limit:
3623 break
3591 break
3624 ctx = repo[rev]
3592 ctx = repo[rev]
3625 copies = None
3593 copies = None
3626 if getrenamed is not None and rev:
3594 if getrenamed is not None and rev:
3627 copies = []
3595 copies = []
3628 for fn in ctx.files():
3596 for fn in ctx.files():
3629 rename = getrenamed(fn, rev)
3597 rename = getrenamed(fn, rev)
3630 if rename:
3598 if rename:
3631 copies.append((fn, rename[0]))
3599 copies.append((fn, rename[0]))
3632 if filematcher:
3600 if filematcher:
3633 revmatchfn = filematcher(ctx.rev())
3601 revmatchfn = filematcher(ctx.rev())
3634 else:
3602 else:
3635 revmatchfn = None
3603 revmatchfn = None
3636 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3604 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3637 if displayer.flush(ctx):
3605 if displayer.flush(ctx):
3638 count += 1
3606 count += 1
3639
3607
3640 displayer.close()
3608 displayer.close()
3641
3609
3642 @command('manifest',
3610 @command('manifest',
3643 [('r', 'rev', '', _('revision to display'), _('REV')),
3611 [('r', 'rev', '', _('revision to display'), _('REV')),
3644 ('', 'all', False, _("list files from all revisions"))]
3612 ('', 'all', False, _("list files from all revisions"))]
3645 + formatteropts,
3613 + formatteropts,
3646 _('[-r REV]'))
3614 _('[-r REV]'))
3647 def manifest(ui, repo, node=None, rev=None, **opts):
3615 def manifest(ui, repo, node=None, rev=None, **opts):
3648 """output the current or given revision of the project manifest
3616 """output the current or given revision of the project manifest
3649
3617
3650 Print a list of version controlled files for the given revision.
3618 Print a list of version controlled files for the given revision.
3651 If no revision is given, the first parent of the working directory
3619 If no revision is given, the first parent of the working directory
3652 is used, or the null revision if no revision is checked out.
3620 is used, or the null revision if no revision is checked out.
3653
3621
3654 With -v, print file permissions, symlink and executable bits.
3622 With -v, print file permissions, symlink and executable bits.
3655 With --debug, print file revision hashes.
3623 With --debug, print file revision hashes.
3656
3624
3657 If option --all is specified, the list of all files from all revisions
3625 If option --all is specified, the list of all files from all revisions
3658 is printed. This includes deleted and renamed files.
3626 is printed. This includes deleted and renamed files.
3659
3627
3660 Returns 0 on success.
3628 Returns 0 on success.
3661 """
3629 """
3662
3630
3663 fm = ui.formatter('manifest', opts)
3631 fm = ui.formatter('manifest', opts)
3664
3632
3665 if opts.get('all'):
3633 if opts.get('all'):
3666 if rev or node:
3634 if rev or node:
3667 raise error.Abort(_("can't specify a revision with --all"))
3635 raise error.Abort(_("can't specify a revision with --all"))
3668
3636
3669 res = []
3637 res = []
3670 prefix = "data/"
3638 prefix = "data/"
3671 suffix = ".i"
3639 suffix = ".i"
3672 plen = len(prefix)
3640 plen = len(prefix)
3673 slen = len(suffix)
3641 slen = len(suffix)
3674 with repo.lock():
3642 with repo.lock():
3675 for fn, b, size in repo.store.datafiles():
3643 for fn, b, size in repo.store.datafiles():
3676 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3644 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3677 res.append(fn[plen:-slen])
3645 res.append(fn[plen:-slen])
3678 for f in res:
3646 for f in res:
3679 fm.startitem()
3647 fm.startitem()
3680 fm.write("path", '%s\n', f)
3648 fm.write("path", '%s\n', f)
3681 fm.end()
3649 fm.end()
3682 return
3650 return
3683
3651
3684 if rev and node:
3652 if rev and node:
3685 raise error.Abort(_("please specify just one revision"))
3653 raise error.Abort(_("please specify just one revision"))
3686
3654
3687 if not node:
3655 if not node:
3688 node = rev
3656 node = rev
3689
3657
3690 char = {'l': '@', 'x': '*', '': ''}
3658 char = {'l': '@', 'x': '*', '': ''}
3691 mode = {'l': '644', 'x': '755', '': '644'}
3659 mode = {'l': '644', 'x': '755', '': '644'}
3692 ctx = scmutil.revsingle(repo, node)
3660 ctx = scmutil.revsingle(repo, node)
3693 mf = ctx.manifest()
3661 mf = ctx.manifest()
3694 for f in ctx:
3662 for f in ctx:
3695 fm.startitem()
3663 fm.startitem()
3696 fl = ctx[f].flags()
3664 fl = ctx[f].flags()
3697 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3665 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3698 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3666 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3699 fm.write('path', '%s\n', f)
3667 fm.write('path', '%s\n', f)
3700 fm.end()
3668 fm.end()
3701
3669
3702 @command('^merge',
3670 @command('^merge',
3703 [('f', 'force', None,
3671 [('f', 'force', None,
3704 _('force a merge including outstanding changes (DEPRECATED)')),
3672 _('force a merge including outstanding changes (DEPRECATED)')),
3705 ('r', 'rev', '', _('revision to merge'), _('REV')),
3673 ('r', 'rev', '', _('revision to merge'), _('REV')),
3706 ('P', 'preview', None,
3674 ('P', 'preview', None,
3707 _('review revisions to merge (no merge is performed)'))
3675 _('review revisions to merge (no merge is performed)'))
3708 ] + mergetoolopts,
3676 ] + mergetoolopts,
3709 _('[-P] [[-r] REV]'))
3677 _('[-P] [[-r] REV]'))
3710 def merge(ui, repo, node=None, **opts):
3678 def merge(ui, repo, node=None, **opts):
3711 """merge another revision into working directory
3679 """merge another revision into working directory
3712
3680
3713 The current working directory is updated with all changes made in
3681 The current working directory is updated with all changes made in
3714 the requested revision since the last common predecessor revision.
3682 the requested revision since the last common predecessor revision.
3715
3683
3716 Files that changed between either parent are marked as changed for
3684 Files that changed between either parent are marked as changed for
3717 the next commit and a commit must be performed before any further
3685 the next commit and a commit must be performed before any further
3718 updates to the repository are allowed. The next commit will have
3686 updates to the repository are allowed. The next commit will have
3719 two parents.
3687 two parents.
3720
3688
3721 ``--tool`` can be used to specify the merge tool used for file
3689 ``--tool`` can be used to specify the merge tool used for file
3722 merges. It overrides the HGMERGE environment variable and your
3690 merges. It overrides the HGMERGE environment variable and your
3723 configuration files. See :hg:`help merge-tools` for options.
3691 configuration files. See :hg:`help merge-tools` for options.
3724
3692
3725 If no revision is specified, the working directory's parent is a
3693 If no revision is specified, the working directory's parent is a
3726 head revision, and the current branch contains exactly one other
3694 head revision, and the current branch contains exactly one other
3727 head, the other head is merged with by default. Otherwise, an
3695 head, the other head is merged with by default. Otherwise, an
3728 explicit revision with which to merge with must be provided.
3696 explicit revision with which to merge with must be provided.
3729
3697
3730 See :hg:`help resolve` for information on handling file conflicts.
3698 See :hg:`help resolve` for information on handling file conflicts.
3731
3699
3732 To undo an uncommitted merge, use :hg:`update --clean .` which
3700 To undo an uncommitted merge, use :hg:`update --clean .` which
3733 will check out a clean copy of the original merge parent, losing
3701 will check out a clean copy of the original merge parent, losing
3734 all changes.
3702 all changes.
3735
3703
3736 Returns 0 on success, 1 if there are unresolved files.
3704 Returns 0 on success, 1 if there are unresolved files.
3737 """
3705 """
3738
3706
3739 if opts.get('rev') and node:
3707 if opts.get('rev') and node:
3740 raise error.Abort(_("please specify just one revision"))
3708 raise error.Abort(_("please specify just one revision"))
3741 if not node:
3709 if not node:
3742 node = opts.get('rev')
3710 node = opts.get('rev')
3743
3711
3744 if node:
3712 if node:
3745 node = scmutil.revsingle(repo, node).node()
3713 node = scmutil.revsingle(repo, node).node()
3746
3714
3747 if not node:
3715 if not node:
3748 node = repo[destutil.destmerge(repo)].node()
3716 node = repo[destutil.destmerge(repo)].node()
3749
3717
3750 if opts.get('preview'):
3718 if opts.get('preview'):
3751 # find nodes that are ancestors of p2 but not of p1
3719 # find nodes that are ancestors of p2 but not of p1
3752 p1 = repo.lookup('.')
3720 p1 = repo.lookup('.')
3753 p2 = repo.lookup(node)
3721 p2 = repo.lookup(node)
3754 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3722 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3755
3723
3756 displayer = cmdutil.show_changeset(ui, repo, opts)
3724 displayer = cmdutil.show_changeset(ui, repo, opts)
3757 for node in nodes:
3725 for node in nodes:
3758 displayer.show(repo[node])
3726 displayer.show(repo[node])
3759 displayer.close()
3727 displayer.close()
3760 return 0
3728 return 0
3761
3729
3762 try:
3730 try:
3763 # ui.forcemerge is an internal variable, do not document
3731 # ui.forcemerge is an internal variable, do not document
3764 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3732 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3765 force = opts.get('force')
3733 force = opts.get('force')
3766 labels = ['working copy', 'merge rev']
3734 labels = ['working copy', 'merge rev']
3767 return hg.merge(repo, node, force=force, mergeforce=force,
3735 return hg.merge(repo, node, force=force, mergeforce=force,
3768 labels=labels)
3736 labels=labels)
3769 finally:
3737 finally:
3770 ui.setconfig('ui', 'forcemerge', '', 'merge')
3738 ui.setconfig('ui', 'forcemerge', '', 'merge')
3771
3739
3772 @command('outgoing|out',
3740 @command('outgoing|out',
3773 [('f', 'force', None, _('run even when the destination is unrelated')),
3741 [('f', 'force', None, _('run even when the destination is unrelated')),
3774 ('r', 'rev', [],
3742 ('r', 'rev', [],
3775 _('a changeset intended to be included in the destination'), _('REV')),
3743 _('a changeset intended to be included in the destination'), _('REV')),
3776 ('n', 'newest-first', None, _('show newest record first')),
3744 ('n', 'newest-first', None, _('show newest record first')),
3777 ('B', 'bookmarks', False, _('compare bookmarks')),
3745 ('B', 'bookmarks', False, _('compare bookmarks')),
3778 ('b', 'branch', [], _('a specific branch you would like to push'),
3746 ('b', 'branch', [], _('a specific branch you would like to push'),
3779 _('BRANCH')),
3747 _('BRANCH')),
3780 ] + logopts + remoteopts + subrepoopts,
3748 ] + logopts + remoteopts + subrepoopts,
3781 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3749 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3782 def outgoing(ui, repo, dest=None, **opts):
3750 def outgoing(ui, repo, dest=None, **opts):
3783 """show changesets not found in the destination
3751 """show changesets not found in the destination
3784
3752
3785 Show changesets not found in the specified destination repository
3753 Show changesets not found in the specified destination repository
3786 or the default push location. These are the changesets that would
3754 or the default push location. These are the changesets that would
3787 be pushed if a push was requested.
3755 be pushed if a push was requested.
3788
3756
3789 See pull for details of valid destination formats.
3757 See pull for details of valid destination formats.
3790
3758
3791 .. container:: verbose
3759 .. container:: verbose
3792
3760
3793 With -B/--bookmarks, the result of bookmark comparison between
3761 With -B/--bookmarks, the result of bookmark comparison between
3794 local and remote repositories is displayed. With -v/--verbose,
3762 local and remote repositories is displayed. With -v/--verbose,
3795 status is also displayed for each bookmark like below::
3763 status is also displayed for each bookmark like below::
3796
3764
3797 BM1 01234567890a added
3765 BM1 01234567890a added
3798 BM2 deleted
3766 BM2 deleted
3799 BM3 234567890abc advanced
3767 BM3 234567890abc advanced
3800 BM4 34567890abcd diverged
3768 BM4 34567890abcd diverged
3801 BM5 4567890abcde changed
3769 BM5 4567890abcde changed
3802
3770
3803 The action taken when pushing depends on the
3771 The action taken when pushing depends on the
3804 status of each bookmark:
3772 status of each bookmark:
3805
3773
3806 :``added``: push with ``-B`` will create it
3774 :``added``: push with ``-B`` will create it
3807 :``deleted``: push with ``-B`` will delete it
3775 :``deleted``: push with ``-B`` will delete it
3808 :``advanced``: push will update it
3776 :``advanced``: push will update it
3809 :``diverged``: push with ``-B`` will update it
3777 :``diverged``: push with ``-B`` will update it
3810 :``changed``: push with ``-B`` will update it
3778 :``changed``: push with ``-B`` will update it
3811
3779
3812 From the point of view of pushing behavior, bookmarks
3780 From the point of view of pushing behavior, bookmarks
3813 existing only in the remote repository are treated as
3781 existing only in the remote repository are treated as
3814 ``deleted``, even if it is in fact added remotely.
3782 ``deleted``, even if it is in fact added remotely.
3815
3783
3816 Returns 0 if there are outgoing changes, 1 otherwise.
3784 Returns 0 if there are outgoing changes, 1 otherwise.
3817 """
3785 """
3818 if opts.get('graph'):
3786 if opts.get('graph'):
3819 cmdutil.checkunsupportedgraphflags([], opts)
3787 cmdutil.checkunsupportedgraphflags([], opts)
3820 o, other = hg._outgoing(ui, repo, dest, opts)
3788 o, other = hg._outgoing(ui, repo, dest, opts)
3821 if not o:
3789 if not o:
3822 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3790 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3823 return
3791 return
3824
3792
3825 revdag = cmdutil.graphrevs(repo, o, opts)
3793 revdag = cmdutil.graphrevs(repo, o, opts)
3826 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3794 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3827 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3795 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3828 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3796 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3829 return 0
3797 return 0
3830
3798
3831 if opts.get('bookmarks'):
3799 if opts.get('bookmarks'):
3832 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3800 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3833 dest, branches = hg.parseurl(dest, opts.get('branch'))
3801 dest, branches = hg.parseurl(dest, opts.get('branch'))
3834 other = hg.peer(repo, opts, dest)
3802 other = hg.peer(repo, opts, dest)
3835 if 'bookmarks' not in other.listkeys('namespaces'):
3803 if 'bookmarks' not in other.listkeys('namespaces'):
3836 ui.warn(_("remote doesn't support bookmarks\n"))
3804 ui.warn(_("remote doesn't support bookmarks\n"))
3837 return 0
3805 return 0
3838 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3806 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3839 return bookmarks.outgoing(ui, repo, other)
3807 return bookmarks.outgoing(ui, repo, other)
3840
3808
3841 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3809 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3842 try:
3810 try:
3843 return hg.outgoing(ui, repo, dest, opts)
3811 return hg.outgoing(ui, repo, dest, opts)
3844 finally:
3812 finally:
3845 del repo._subtoppath
3813 del repo._subtoppath
3846
3814
3847 @command('parents',
3815 @command('parents',
3848 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3816 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3849 ] + templateopts,
3817 ] + templateopts,
3850 _('[-r REV] [FILE]'),
3818 _('[-r REV] [FILE]'),
3851 inferrepo=True)
3819 inferrepo=True)
3852 def parents(ui, repo, file_=None, **opts):
3820 def parents(ui, repo, file_=None, **opts):
3853 """show the parents of the working directory or revision (DEPRECATED)
3821 """show the parents of the working directory or revision (DEPRECATED)
3854
3822
3855 Print the working directory's parent revisions. If a revision is
3823 Print the working directory's parent revisions. If a revision is
3856 given via -r/--rev, the parent of that revision will be printed.
3824 given via -r/--rev, the parent of that revision will be printed.
3857 If a file argument is given, the revision in which the file was
3825 If a file argument is given, the revision in which the file was
3858 last changed (before the working directory revision or the
3826 last changed (before the working directory revision or the
3859 argument to --rev if given) is printed.
3827 argument to --rev if given) is printed.
3860
3828
3861 This command is equivalent to::
3829 This command is equivalent to::
3862
3830
3863 hg log -r "p1()+p2()" or
3831 hg log -r "p1()+p2()" or
3864 hg log -r "p1(REV)+p2(REV)" or
3832 hg log -r "p1(REV)+p2(REV)" or
3865 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3833 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3866 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3834 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3867
3835
3868 See :hg:`summary` and :hg:`help revsets` for related information.
3836 See :hg:`summary` and :hg:`help revsets` for related information.
3869
3837
3870 Returns 0 on success.
3838 Returns 0 on success.
3871 """
3839 """
3872
3840
3873 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3841 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3874
3842
3875 if file_:
3843 if file_:
3876 m = scmutil.match(ctx, (file_,), opts)
3844 m = scmutil.match(ctx, (file_,), opts)
3877 if m.anypats() or len(m.files()) != 1:
3845 if m.anypats() or len(m.files()) != 1:
3878 raise error.Abort(_('can only specify an explicit filename'))
3846 raise error.Abort(_('can only specify an explicit filename'))
3879 file_ = m.files()[0]
3847 file_ = m.files()[0]
3880 filenodes = []
3848 filenodes = []
3881 for cp in ctx.parents():
3849 for cp in ctx.parents():
3882 if not cp:
3850 if not cp:
3883 continue
3851 continue
3884 try:
3852 try:
3885 filenodes.append(cp.filenode(file_))
3853 filenodes.append(cp.filenode(file_))
3886 except error.LookupError:
3854 except error.LookupError:
3887 pass
3855 pass
3888 if not filenodes:
3856 if not filenodes:
3889 raise error.Abort(_("'%s' not found in manifest!") % file_)
3857 raise error.Abort(_("'%s' not found in manifest!") % file_)
3890 p = []
3858 p = []
3891 for fn in filenodes:
3859 for fn in filenodes:
3892 fctx = repo.filectx(file_, fileid=fn)
3860 fctx = repo.filectx(file_, fileid=fn)
3893 p.append(fctx.node())
3861 p.append(fctx.node())
3894 else:
3862 else:
3895 p = [cp.node() for cp in ctx.parents()]
3863 p = [cp.node() for cp in ctx.parents()]
3896
3864
3897 displayer = cmdutil.show_changeset(ui, repo, opts)
3865 displayer = cmdutil.show_changeset(ui, repo, opts)
3898 for n in p:
3866 for n in p:
3899 if n != nullid:
3867 if n != nullid:
3900 displayer.show(repo[n])
3868 displayer.show(repo[n])
3901 displayer.close()
3869 displayer.close()
3902
3870
3903 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3871 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3904 def paths(ui, repo, search=None, **opts):
3872 def paths(ui, repo, search=None, **opts):
3905 """show aliases for remote repositories
3873 """show aliases for remote repositories
3906
3874
3907 Show definition of symbolic path name NAME. If no name is given,
3875 Show definition of symbolic path name NAME. If no name is given,
3908 show definition of all available names.
3876 show definition of all available names.
3909
3877
3910 Option -q/--quiet suppresses all output when searching for NAME
3878 Option -q/--quiet suppresses all output when searching for NAME
3911 and shows only the path names when listing all definitions.
3879 and shows only the path names when listing all definitions.
3912
3880
3913 Path names are defined in the [paths] section of your
3881 Path names are defined in the [paths] section of your
3914 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3882 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3915 repository, ``.hg/hgrc`` is used, too.
3883 repository, ``.hg/hgrc`` is used, too.
3916
3884
3917 The path names ``default`` and ``default-push`` have a special
3885 The path names ``default`` and ``default-push`` have a special
3918 meaning. When performing a push or pull operation, they are used
3886 meaning. When performing a push or pull operation, they are used
3919 as fallbacks if no location is specified on the command-line.
3887 as fallbacks if no location is specified on the command-line.
3920 When ``default-push`` is set, it will be used for push and
3888 When ``default-push`` is set, it will be used for push and
3921 ``default`` will be used for pull; otherwise ``default`` is used
3889 ``default`` will be used for pull; otherwise ``default`` is used
3922 as the fallback for both. When cloning a repository, the clone
3890 as the fallback for both. When cloning a repository, the clone
3923 source is written as ``default`` in ``.hg/hgrc``.
3891 source is written as ``default`` in ``.hg/hgrc``.
3924
3892
3925 .. note::
3893 .. note::
3926
3894
3927 ``default`` and ``default-push`` apply to all inbound (e.g.
3895 ``default`` and ``default-push`` apply to all inbound (e.g.
3928 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3896 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3929 and :hg:`bundle`) operations.
3897 and :hg:`bundle`) operations.
3930
3898
3931 See :hg:`help urls` for more information.
3899 See :hg:`help urls` for more information.
3932
3900
3933 Returns 0 on success.
3901 Returns 0 on success.
3934 """
3902 """
3935 if search:
3903 if search:
3936 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3904 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3937 if name == search]
3905 if name == search]
3938 else:
3906 else:
3939 pathitems = sorted(ui.paths.iteritems())
3907 pathitems = sorted(ui.paths.iteritems())
3940
3908
3941 fm = ui.formatter('paths', opts)
3909 fm = ui.formatter('paths', opts)
3942 if fm.isplain():
3910 if fm.isplain():
3943 hidepassword = util.hidepassword
3911 hidepassword = util.hidepassword
3944 else:
3912 else:
3945 hidepassword = str
3913 hidepassword = str
3946 if ui.quiet:
3914 if ui.quiet:
3947 namefmt = '%s\n'
3915 namefmt = '%s\n'
3948 else:
3916 else:
3949 namefmt = '%s = '
3917 namefmt = '%s = '
3950 showsubopts = not search and not ui.quiet
3918 showsubopts = not search and not ui.quiet
3951
3919
3952 for name, path in pathitems:
3920 for name, path in pathitems:
3953 fm.startitem()
3921 fm.startitem()
3954 fm.condwrite(not search, 'name', namefmt, name)
3922 fm.condwrite(not search, 'name', namefmt, name)
3955 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3923 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3956 for subopt, value in sorted(path.suboptions.items()):
3924 for subopt, value in sorted(path.suboptions.items()):
3957 assert subopt not in ('name', 'url')
3925 assert subopt not in ('name', 'url')
3958 if showsubopts:
3926 if showsubopts:
3959 fm.plain('%s:%s = ' % (name, subopt))
3927 fm.plain('%s:%s = ' % (name, subopt))
3960 fm.condwrite(showsubopts, subopt, '%s\n', value)
3928 fm.condwrite(showsubopts, subopt, '%s\n', value)
3961
3929
3962 fm.end()
3930 fm.end()
3963
3931
3964 if search and not pathitems:
3932 if search and not pathitems:
3965 if not ui.quiet:
3933 if not ui.quiet:
3966 ui.warn(_("not found!\n"))
3934 ui.warn(_("not found!\n"))
3967 return 1
3935 return 1
3968 else:
3936 else:
3969 return 0
3937 return 0
3970
3938
3971 @command('phase',
3939 @command('phase',
3972 [('p', 'public', False, _('set changeset phase to public')),
3940 [('p', 'public', False, _('set changeset phase to public')),
3973 ('d', 'draft', False, _('set changeset phase to draft')),
3941 ('d', 'draft', False, _('set changeset phase to draft')),
3974 ('s', 'secret', False, _('set changeset phase to secret')),
3942 ('s', 'secret', False, _('set changeset phase to secret')),
3975 ('f', 'force', False, _('allow to move boundary backward')),
3943 ('f', 'force', False, _('allow to move boundary backward')),
3976 ('r', 'rev', [], _('target revision'), _('REV')),
3944 ('r', 'rev', [], _('target revision'), _('REV')),
3977 ],
3945 ],
3978 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3946 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3979 def phase(ui, repo, *revs, **opts):
3947 def phase(ui, repo, *revs, **opts):
3980 """set or show the current phase name
3948 """set or show the current phase name
3981
3949
3982 With no argument, show the phase name of the current revision(s).
3950 With no argument, show the phase name of the current revision(s).
3983
3951
3984 With one of -p/--public, -d/--draft or -s/--secret, change the
3952 With one of -p/--public, -d/--draft or -s/--secret, change the
3985 phase value of the specified revisions.
3953 phase value of the specified revisions.
3986
3954
3987 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3955 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3988 lower phase to an higher phase. Phases are ordered as follows::
3956 lower phase to an higher phase. Phases are ordered as follows::
3989
3957
3990 public < draft < secret
3958 public < draft < secret
3991
3959
3992 Returns 0 on success, 1 if some phases could not be changed.
3960 Returns 0 on success, 1 if some phases could not be changed.
3993
3961
3994 (For more information about the phases concept, see :hg:`help phases`.)
3962 (For more information about the phases concept, see :hg:`help phases`.)
3995 """
3963 """
3996 # search for a unique phase argument
3964 # search for a unique phase argument
3997 targetphase = None
3965 targetphase = None
3998 for idx, name in enumerate(phases.phasenames):
3966 for idx, name in enumerate(phases.phasenames):
3999 if opts[name]:
3967 if opts[name]:
4000 if targetphase is not None:
3968 if targetphase is not None:
4001 raise error.Abort(_('only one phase can be specified'))
3969 raise error.Abort(_('only one phase can be specified'))
4002 targetphase = idx
3970 targetphase = idx
4003
3971
4004 # look for specified revision
3972 # look for specified revision
4005 revs = list(revs)
3973 revs = list(revs)
4006 revs.extend(opts['rev'])
3974 revs.extend(opts['rev'])
4007 if not revs:
3975 if not revs:
4008 # display both parents as the second parent phase can influence
3976 # display both parents as the second parent phase can influence
4009 # the phase of a merge commit
3977 # the phase of a merge commit
4010 revs = [c.rev() for c in repo[None].parents()]
3978 revs = [c.rev() for c in repo[None].parents()]
4011
3979
4012 revs = scmutil.revrange(repo, revs)
3980 revs = scmutil.revrange(repo, revs)
4013
3981
4014 lock = None
3982 lock = None
4015 ret = 0
3983 ret = 0
4016 if targetphase is None:
3984 if targetphase is None:
4017 # display
3985 # display
4018 for r in revs:
3986 for r in revs:
4019 ctx = repo[r]
3987 ctx = repo[r]
4020 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3988 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4021 else:
3989 else:
4022 tr = None
3990 tr = None
4023 lock = repo.lock()
3991 lock = repo.lock()
4024 try:
3992 try:
4025 tr = repo.transaction("phase")
3993 tr = repo.transaction("phase")
4026 # set phase
3994 # set phase
4027 if not revs:
3995 if not revs:
4028 raise error.Abort(_('empty revision set'))
3996 raise error.Abort(_('empty revision set'))
4029 nodes = [repo[r].node() for r in revs]
3997 nodes = [repo[r].node() for r in revs]
4030 # moving revision from public to draft may hide them
3998 # moving revision from public to draft may hide them
4031 # We have to check result on an unfiltered repository
3999 # We have to check result on an unfiltered repository
4032 unfi = repo.unfiltered()
4000 unfi = repo.unfiltered()
4033 getphase = unfi._phasecache.phase
4001 getphase = unfi._phasecache.phase
4034 olddata = [getphase(unfi, r) for r in unfi]
4002 olddata = [getphase(unfi, r) for r in unfi]
4035 phases.advanceboundary(repo, tr, targetphase, nodes)
4003 phases.advanceboundary(repo, tr, targetphase, nodes)
4036 if opts['force']:
4004 if opts['force']:
4037 phases.retractboundary(repo, tr, targetphase, nodes)
4005 phases.retractboundary(repo, tr, targetphase, nodes)
4038 tr.close()
4006 tr.close()
4039 finally:
4007 finally:
4040 if tr is not None:
4008 if tr is not None:
4041 tr.release()
4009 tr.release()
4042 lock.release()
4010 lock.release()
4043 getphase = unfi._phasecache.phase
4011 getphase = unfi._phasecache.phase
4044 newdata = [getphase(unfi, r) for r in unfi]
4012 newdata = [getphase(unfi, r) for r in unfi]
4045 changes = sum(newdata[r] != olddata[r] for r in unfi)
4013 changes = sum(newdata[r] != olddata[r] for r in unfi)
4046 cl = unfi.changelog
4014 cl = unfi.changelog
4047 rejected = [n for n in nodes
4015 rejected = [n for n in nodes
4048 if newdata[cl.rev(n)] < targetphase]
4016 if newdata[cl.rev(n)] < targetphase]
4049 if rejected:
4017 if rejected:
4050 ui.warn(_('cannot move %i changesets to a higher '
4018 ui.warn(_('cannot move %i changesets to a higher '
4051 'phase, use --force\n') % len(rejected))
4019 'phase, use --force\n') % len(rejected))
4052 ret = 1
4020 ret = 1
4053 if changes:
4021 if changes:
4054 msg = _('phase changed for %i changesets\n') % changes
4022 msg = _('phase changed for %i changesets\n') % changes
4055 if ret:
4023 if ret:
4056 ui.status(msg)
4024 ui.status(msg)
4057 else:
4025 else:
4058 ui.note(msg)
4026 ui.note(msg)
4059 else:
4027 else:
4060 ui.warn(_('no phases changed\n'))
4028 ui.warn(_('no phases changed\n'))
4061 return ret
4029 return ret
4062
4030
4063 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4031 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
4064 """Run after a changegroup has been added via pull/unbundle
4032 """Run after a changegroup has been added via pull/unbundle
4065
4033
4066 This takes arguments below:
4034 This takes arguments below:
4067
4035
4068 :modheads: change of heads by pull/unbundle
4036 :modheads: change of heads by pull/unbundle
4069 :optupdate: updating working directory is needed or not
4037 :optupdate: updating working directory is needed or not
4070 :checkout: update destination revision (or None to default destination)
4038 :checkout: update destination revision (or None to default destination)
4071 :brev: a name, which might be a bookmark to be activated after updating
4039 :brev: a name, which might be a bookmark to be activated after updating
4072 """
4040 """
4073 if modheads == 0:
4041 if modheads == 0:
4074 return
4042 return
4075 if optupdate:
4043 if optupdate:
4076 try:
4044 try:
4077 return hg.updatetotally(ui, repo, checkout, brev)
4045 return hg.updatetotally(ui, repo, checkout, brev)
4078 except error.UpdateAbort as inst:
4046 except error.UpdateAbort as inst:
4079 msg = _("not updating: %s") % str(inst)
4047 msg = _("not updating: %s") % str(inst)
4080 hint = inst.hint
4048 hint = inst.hint
4081 raise error.UpdateAbort(msg, hint=hint)
4049 raise error.UpdateAbort(msg, hint=hint)
4082 if modheads > 1:
4050 if modheads > 1:
4083 currentbranchheads = len(repo.branchheads())
4051 currentbranchheads = len(repo.branchheads())
4084 if currentbranchheads == modheads:
4052 if currentbranchheads == modheads:
4085 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4053 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4086 elif currentbranchheads > 1:
4054 elif currentbranchheads > 1:
4087 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4055 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4088 "merge)\n"))
4056 "merge)\n"))
4089 else:
4057 else:
4090 ui.status(_("(run 'hg heads' to see heads)\n"))
4058 ui.status(_("(run 'hg heads' to see heads)\n"))
4091 else:
4059 else:
4092 ui.status(_("(run 'hg update' to get a working copy)\n"))
4060 ui.status(_("(run 'hg update' to get a working copy)\n"))
4093
4061
4094 @command('^pull',
4062 @command('^pull',
4095 [('u', 'update', None,
4063 [('u', 'update', None,
4096 _('update to new branch head if changesets were pulled')),
4064 _('update to new branch head if changesets were pulled')),
4097 ('f', 'force', None, _('run even when remote repository is unrelated')),
4065 ('f', 'force', None, _('run even when remote repository is unrelated')),
4098 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4066 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4099 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4067 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4100 ('b', 'branch', [], _('a specific branch you would like to pull'),
4068 ('b', 'branch', [], _('a specific branch you would like to pull'),
4101 _('BRANCH')),
4069 _('BRANCH')),
4102 ] + remoteopts,
4070 ] + remoteopts,
4103 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4071 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4104 def pull(ui, repo, source="default", **opts):
4072 def pull(ui, repo, source="default", **opts):
4105 """pull changes from the specified source
4073 """pull changes from the specified source
4106
4074
4107 Pull changes from a remote repository to a local one.
4075 Pull changes from a remote repository to a local one.
4108
4076
4109 This finds all changes from the repository at the specified path
4077 This finds all changes from the repository at the specified path
4110 or URL and adds them to a local repository (the current one unless
4078 or URL and adds them to a local repository (the current one unless
4111 -R is specified). By default, this does not update the copy of the
4079 -R is specified). By default, this does not update the copy of the
4112 project in the working directory.
4080 project in the working directory.
4113
4081
4114 Use :hg:`incoming` if you want to see what would have been added
4082 Use :hg:`incoming` if you want to see what would have been added
4115 by a pull at the time you issued this command. If you then decide
4083 by a pull at the time you issued this command. If you then decide
4116 to add those changes to the repository, you should use :hg:`pull
4084 to add those changes to the repository, you should use :hg:`pull
4117 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4085 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4118
4086
4119 If SOURCE is omitted, the 'default' path will be used.
4087 If SOURCE is omitted, the 'default' path will be used.
4120 See :hg:`help urls` for more information.
4088 See :hg:`help urls` for more information.
4121
4089
4122 Specifying bookmark as ``.`` is equivalent to specifying the active
4090 Specifying bookmark as ``.`` is equivalent to specifying the active
4123 bookmark's name.
4091 bookmark's name.
4124
4092
4125 Returns 0 on success, 1 if an update had unresolved files.
4093 Returns 0 on success, 1 if an update had unresolved files.
4126 """
4094 """
4127 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4095 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4128 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4096 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4129 other = hg.peer(repo, opts, source)
4097 other = hg.peer(repo, opts, source)
4130 try:
4098 try:
4131 revs, checkout = hg.addbranchrevs(repo, other, branches,
4099 revs, checkout = hg.addbranchrevs(repo, other, branches,
4132 opts.get('rev'))
4100 opts.get('rev'))
4133
4101
4134
4102
4135 pullopargs = {}
4103 pullopargs = {}
4136 if opts.get('bookmark'):
4104 if opts.get('bookmark'):
4137 if not revs:
4105 if not revs:
4138 revs = []
4106 revs = []
4139 # The list of bookmark used here is not the one used to actually
4107 # The list of bookmark used here is not the one used to actually
4140 # update the bookmark name. This can result in the revision pulled
4108 # update the bookmark name. This can result in the revision pulled
4141 # not ending up with the name of the bookmark because of a race
4109 # not ending up with the name of the bookmark because of a race
4142 # condition on the server. (See issue 4689 for details)
4110 # condition on the server. (See issue 4689 for details)
4143 remotebookmarks = other.listkeys('bookmarks')
4111 remotebookmarks = other.listkeys('bookmarks')
4144 pullopargs['remotebookmarks'] = remotebookmarks
4112 pullopargs['remotebookmarks'] = remotebookmarks
4145 for b in opts['bookmark']:
4113 for b in opts['bookmark']:
4146 b = repo._bookmarks.expandname(b)
4114 b = repo._bookmarks.expandname(b)
4147 if b not in remotebookmarks:
4115 if b not in remotebookmarks:
4148 raise error.Abort(_('remote bookmark %s not found!') % b)
4116 raise error.Abort(_('remote bookmark %s not found!') % b)
4149 revs.append(remotebookmarks[b])
4117 revs.append(remotebookmarks[b])
4150
4118
4151 if revs:
4119 if revs:
4152 try:
4120 try:
4153 # When 'rev' is a bookmark name, we cannot guarantee that it
4121 # When 'rev' is a bookmark name, we cannot guarantee that it
4154 # will be updated with that name because of a race condition
4122 # will be updated with that name because of a race condition
4155 # server side. (See issue 4689 for details)
4123 # server side. (See issue 4689 for details)
4156 oldrevs = revs
4124 oldrevs = revs
4157 revs = [] # actually, nodes
4125 revs = [] # actually, nodes
4158 for r in oldrevs:
4126 for r in oldrevs:
4159 node = other.lookup(r)
4127 node = other.lookup(r)
4160 revs.append(node)
4128 revs.append(node)
4161 if r == checkout:
4129 if r == checkout:
4162 checkout = node
4130 checkout = node
4163 except error.CapabilityError:
4131 except error.CapabilityError:
4164 err = _("other repository doesn't support revision lookup, "
4132 err = _("other repository doesn't support revision lookup, "
4165 "so a rev cannot be specified.")
4133 "so a rev cannot be specified.")
4166 raise error.Abort(err)
4134 raise error.Abort(err)
4167
4135
4168 pullopargs.update(opts.get('opargs', {}))
4136 pullopargs.update(opts.get('opargs', {}))
4169 modheads = exchange.pull(repo, other, heads=revs,
4137 modheads = exchange.pull(repo, other, heads=revs,
4170 force=opts.get('force'),
4138 force=opts.get('force'),
4171 bookmarks=opts.get('bookmark', ()),
4139 bookmarks=opts.get('bookmark', ()),
4172 opargs=pullopargs).cgresult
4140 opargs=pullopargs).cgresult
4173
4141
4174 # brev is a name, which might be a bookmark to be activated at
4142 # brev is a name, which might be a bookmark to be activated at
4175 # the end of the update. In other words, it is an explicit
4143 # the end of the update. In other words, it is an explicit
4176 # destination of the update
4144 # destination of the update
4177 brev = None
4145 brev = None
4178
4146
4179 if checkout:
4147 if checkout:
4180 checkout = str(repo.changelog.rev(checkout))
4148 checkout = str(repo.changelog.rev(checkout))
4181
4149
4182 # order below depends on implementation of
4150 # order below depends on implementation of
4183 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4151 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4184 # because 'checkout' is determined without it.
4152 # because 'checkout' is determined without it.
4185 if opts.get('rev'):
4153 if opts.get('rev'):
4186 brev = opts['rev'][0]
4154 brev = opts['rev'][0]
4187 elif opts.get('branch'):
4155 elif opts.get('branch'):
4188 brev = opts['branch'][0]
4156 brev = opts['branch'][0]
4189 else:
4157 else:
4190 brev = branches[0]
4158 brev = branches[0]
4191 repo._subtoppath = source
4159 repo._subtoppath = source
4192 try:
4160 try:
4193 ret = postincoming(ui, repo, modheads, opts.get('update'),
4161 ret = postincoming(ui, repo, modheads, opts.get('update'),
4194 checkout, brev)
4162 checkout, brev)
4195
4163
4196 finally:
4164 finally:
4197 del repo._subtoppath
4165 del repo._subtoppath
4198
4166
4199 finally:
4167 finally:
4200 other.close()
4168 other.close()
4201 return ret
4169 return ret
4202
4170
4203 @command('^push',
4171 @command('^push',
4204 [('f', 'force', None, _('force push')),
4172 [('f', 'force', None, _('force push')),
4205 ('r', 'rev', [],
4173 ('r', 'rev', [],
4206 _('a changeset intended to be included in the destination'),
4174 _('a changeset intended to be included in the destination'),
4207 _('REV')),
4175 _('REV')),
4208 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4176 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4209 ('b', 'branch', [],
4177 ('b', 'branch', [],
4210 _('a specific branch you would like to push'), _('BRANCH')),
4178 _('a specific branch you would like to push'), _('BRANCH')),
4211 ('', 'new-branch', False, _('allow pushing a new branch')),
4179 ('', 'new-branch', False, _('allow pushing a new branch')),
4212 ] + remoteopts,
4180 ] + remoteopts,
4213 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4181 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4214 def push(ui, repo, dest=None, **opts):
4182 def push(ui, repo, dest=None, **opts):
4215 """push changes to the specified destination
4183 """push changes to the specified destination
4216
4184
4217 Push changesets from the local repository to the specified
4185 Push changesets from the local repository to the specified
4218 destination.
4186 destination.
4219
4187
4220 This operation is symmetrical to pull: it is identical to a pull
4188 This operation is symmetrical to pull: it is identical to a pull
4221 in the destination repository from the current one.
4189 in the destination repository from the current one.
4222
4190
4223 By default, push will not allow creation of new heads at the
4191 By default, push will not allow creation of new heads at the
4224 destination, since multiple heads would make it unclear which head
4192 destination, since multiple heads would make it unclear which head
4225 to use. In this situation, it is recommended to pull and merge
4193 to use. In this situation, it is recommended to pull and merge
4226 before pushing.
4194 before pushing.
4227
4195
4228 Use --new-branch if you want to allow push to create a new named
4196 Use --new-branch if you want to allow push to create a new named
4229 branch that is not present at the destination. This allows you to
4197 branch that is not present at the destination. This allows you to
4230 only create a new branch without forcing other changes.
4198 only create a new branch without forcing other changes.
4231
4199
4232 .. note::
4200 .. note::
4233
4201
4234 Extra care should be taken with the -f/--force option,
4202 Extra care should be taken with the -f/--force option,
4235 which will push all new heads on all branches, an action which will
4203 which will push all new heads on all branches, an action which will
4236 almost always cause confusion for collaborators.
4204 almost always cause confusion for collaborators.
4237
4205
4238 If -r/--rev is used, the specified revision and all its ancestors
4206 If -r/--rev is used, the specified revision and all its ancestors
4239 will be pushed to the remote repository.
4207 will be pushed to the remote repository.
4240
4208
4241 If -B/--bookmark is used, the specified bookmarked revision, its
4209 If -B/--bookmark is used, the specified bookmarked revision, its
4242 ancestors, and the bookmark will be pushed to the remote
4210 ancestors, and the bookmark will be pushed to the remote
4243 repository. Specifying ``.`` is equivalent to specifying the active
4211 repository. Specifying ``.`` is equivalent to specifying the active
4244 bookmark's name.
4212 bookmark's name.
4245
4213
4246 Please see :hg:`help urls` for important details about ``ssh://``
4214 Please see :hg:`help urls` for important details about ``ssh://``
4247 URLs. If DESTINATION is omitted, a default path will be used.
4215 URLs. If DESTINATION is omitted, a default path will be used.
4248
4216
4249 Returns 0 if push was successful, 1 if nothing to push.
4217 Returns 0 if push was successful, 1 if nothing to push.
4250 """
4218 """
4251
4219
4252 if opts.get('bookmark'):
4220 if opts.get('bookmark'):
4253 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4221 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4254 for b in opts['bookmark']:
4222 for b in opts['bookmark']:
4255 # translate -B options to -r so changesets get pushed
4223 # translate -B options to -r so changesets get pushed
4256 b = repo._bookmarks.expandname(b)
4224 b = repo._bookmarks.expandname(b)
4257 if b in repo._bookmarks:
4225 if b in repo._bookmarks:
4258 opts.setdefault('rev', []).append(b)
4226 opts.setdefault('rev', []).append(b)
4259 else:
4227 else:
4260 # if we try to push a deleted bookmark, translate it to null
4228 # if we try to push a deleted bookmark, translate it to null
4261 # this lets simultaneous -r, -b options continue working
4229 # this lets simultaneous -r, -b options continue working
4262 opts.setdefault('rev', []).append("null")
4230 opts.setdefault('rev', []).append("null")
4263
4231
4264 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4232 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4265 if not path:
4233 if not path:
4266 raise error.Abort(_('default repository not configured!'),
4234 raise error.Abort(_('default repository not configured!'),
4267 hint=_("see 'hg help config.paths'"))
4235 hint=_("see 'hg help config.paths'"))
4268 dest = path.pushloc or path.loc
4236 dest = path.pushloc or path.loc
4269 branches = (path.branch, opts.get('branch') or [])
4237 branches = (path.branch, opts.get('branch') or [])
4270 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4238 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4271 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4239 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4272 other = hg.peer(repo, opts, dest)
4240 other = hg.peer(repo, opts, dest)
4273
4241
4274 if revs:
4242 if revs:
4275 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4243 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4276 if not revs:
4244 if not revs:
4277 raise error.Abort(_("specified revisions evaluate to an empty set"),
4245 raise error.Abort(_("specified revisions evaluate to an empty set"),
4278 hint=_("use different revision arguments"))
4246 hint=_("use different revision arguments"))
4279 elif path.pushrev:
4247 elif path.pushrev:
4280 # It doesn't make any sense to specify ancestor revisions. So limit
4248 # It doesn't make any sense to specify ancestor revisions. So limit
4281 # to DAG heads to make discovery simpler.
4249 # to DAG heads to make discovery simpler.
4282 expr = revset.formatspec('heads(%r)', path.pushrev)
4250 expr = revset.formatspec('heads(%r)', path.pushrev)
4283 revs = scmutil.revrange(repo, [expr])
4251 revs = scmutil.revrange(repo, [expr])
4284 revs = [repo[rev].node() for rev in revs]
4252 revs = [repo[rev].node() for rev in revs]
4285 if not revs:
4253 if not revs:
4286 raise error.Abort(_('default push revset for path evaluates to an '
4254 raise error.Abort(_('default push revset for path evaluates to an '
4287 'empty set'))
4255 'empty set'))
4288
4256
4289 repo._subtoppath = dest
4257 repo._subtoppath = dest
4290 try:
4258 try:
4291 # push subrepos depth-first for coherent ordering
4259 # push subrepos depth-first for coherent ordering
4292 c = repo['']
4260 c = repo['']
4293 subs = c.substate # only repos that are committed
4261 subs = c.substate # only repos that are committed
4294 for s in sorted(subs):
4262 for s in sorted(subs):
4295 result = c.sub(s).push(opts)
4263 result = c.sub(s).push(opts)
4296 if result == 0:
4264 if result == 0:
4297 return not result
4265 return not result
4298 finally:
4266 finally:
4299 del repo._subtoppath
4267 del repo._subtoppath
4300 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4268 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4301 newbranch=opts.get('new_branch'),
4269 newbranch=opts.get('new_branch'),
4302 bookmarks=opts.get('bookmark', ()),
4270 bookmarks=opts.get('bookmark', ()),
4303 opargs=opts.get('opargs'))
4271 opargs=opts.get('opargs'))
4304
4272
4305 result = not pushop.cgresult
4273 result = not pushop.cgresult
4306
4274
4307 if pushop.bkresult is not None:
4275 if pushop.bkresult is not None:
4308 if pushop.bkresult == 2:
4276 if pushop.bkresult == 2:
4309 result = 2
4277 result = 2
4310 elif not result and pushop.bkresult:
4278 elif not result and pushop.bkresult:
4311 result = 2
4279 result = 2
4312
4280
4313 return result
4281 return result
4314
4282
4315 @command('recover', [])
4283 @command('recover', [])
4316 def recover(ui, repo):
4284 def recover(ui, repo):
4317 """roll back an interrupted transaction
4285 """roll back an interrupted transaction
4318
4286
4319 Recover from an interrupted commit or pull.
4287 Recover from an interrupted commit or pull.
4320
4288
4321 This command tries to fix the repository status after an
4289 This command tries to fix the repository status after an
4322 interrupted operation. It should only be necessary when Mercurial
4290 interrupted operation. It should only be necessary when Mercurial
4323 suggests it.
4291 suggests it.
4324
4292
4325 Returns 0 if successful, 1 if nothing to recover or verify fails.
4293 Returns 0 if successful, 1 if nothing to recover or verify fails.
4326 """
4294 """
4327 if repo.recover():
4295 if repo.recover():
4328 return hg.verify(repo)
4296 return hg.verify(repo)
4329 return 1
4297 return 1
4330
4298
4331 @command('^remove|rm',
4299 @command('^remove|rm',
4332 [('A', 'after', None, _('record delete for missing files')),
4300 [('A', 'after', None, _('record delete for missing files')),
4333 ('f', 'force', None,
4301 ('f', 'force', None,
4334 _('forget added files, delete modified files')),
4302 _('forget added files, delete modified files')),
4335 ] + subrepoopts + walkopts,
4303 ] + subrepoopts + walkopts,
4336 _('[OPTION]... FILE...'),
4304 _('[OPTION]... FILE...'),
4337 inferrepo=True)
4305 inferrepo=True)
4338 def remove(ui, repo, *pats, **opts):
4306 def remove(ui, repo, *pats, **opts):
4339 """remove the specified files on the next commit
4307 """remove the specified files on the next commit
4340
4308
4341 Schedule the indicated files for removal from the current branch.
4309 Schedule the indicated files for removal from the current branch.
4342
4310
4343 This command schedules the files to be removed at the next commit.
4311 This command schedules the files to be removed at the next commit.
4344 To undo a remove before that, see :hg:`revert`. To undo added
4312 To undo a remove before that, see :hg:`revert`. To undo added
4345 files, see :hg:`forget`.
4313 files, see :hg:`forget`.
4346
4314
4347 .. container:: verbose
4315 .. container:: verbose
4348
4316
4349 -A/--after can be used to remove only files that have already
4317 -A/--after can be used to remove only files that have already
4350 been deleted, -f/--force can be used to force deletion, and -Af
4318 been deleted, -f/--force can be used to force deletion, and -Af
4351 can be used to remove files from the next revision without
4319 can be used to remove files from the next revision without
4352 deleting them from the working directory.
4320 deleting them from the working directory.
4353
4321
4354 The following table details the behavior of remove for different
4322 The following table details the behavior of remove for different
4355 file states (columns) and option combinations (rows). The file
4323 file states (columns) and option combinations (rows). The file
4356 states are Added [A], Clean [C], Modified [M] and Missing [!]
4324 states are Added [A], Clean [C], Modified [M] and Missing [!]
4357 (as reported by :hg:`status`). The actions are Warn, Remove
4325 (as reported by :hg:`status`). The actions are Warn, Remove
4358 (from branch) and Delete (from disk):
4326 (from branch) and Delete (from disk):
4359
4327
4360 ========= == == == ==
4328 ========= == == == ==
4361 opt/state A C M !
4329 opt/state A C M !
4362 ========= == == == ==
4330 ========= == == == ==
4363 none W RD W R
4331 none W RD W R
4364 -f R RD RD R
4332 -f R RD RD R
4365 -A W W W R
4333 -A W W W R
4366 -Af R R R R
4334 -Af R R R R
4367 ========= == == == ==
4335 ========= == == == ==
4368
4336
4369 .. note::
4337 .. note::
4370
4338
4371 :hg:`remove` never deletes files in Added [A] state from the
4339 :hg:`remove` never deletes files in Added [A] state from the
4372 working directory, not even if ``--force`` is specified.
4340 working directory, not even if ``--force`` is specified.
4373
4341
4374 Returns 0 on success, 1 if any warnings encountered.
4342 Returns 0 on success, 1 if any warnings encountered.
4375 """
4343 """
4376
4344
4377 after, force = opts.get('after'), opts.get('force')
4345 after, force = opts.get('after'), opts.get('force')
4378 if not pats and not after:
4346 if not pats and not after:
4379 raise error.Abort(_('no files specified'))
4347 raise error.Abort(_('no files specified'))
4380
4348
4381 m = scmutil.match(repo[None], pats, opts)
4349 m = scmutil.match(repo[None], pats, opts)
4382 subrepos = opts.get('subrepos')
4350 subrepos = opts.get('subrepos')
4383 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4351 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4384
4352
4385 @command('rename|move|mv',
4353 @command('rename|move|mv',
4386 [('A', 'after', None, _('record a rename that has already occurred')),
4354 [('A', 'after', None, _('record a rename that has already occurred')),
4387 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4355 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4388 ] + walkopts + dryrunopts,
4356 ] + walkopts + dryrunopts,
4389 _('[OPTION]... SOURCE... DEST'))
4357 _('[OPTION]... SOURCE... DEST'))
4390 def rename(ui, repo, *pats, **opts):
4358 def rename(ui, repo, *pats, **opts):
4391 """rename files; equivalent of copy + remove
4359 """rename files; equivalent of copy + remove
4392
4360
4393 Mark dest as copies of sources; mark sources for deletion. If dest
4361 Mark dest as copies of sources; mark sources for deletion. If dest
4394 is a directory, copies are put in that directory. If dest is a
4362 is a directory, copies are put in that directory. If dest is a
4395 file, there can only be one source.
4363 file, there can only be one source.
4396
4364
4397 By default, this command copies the contents of files as they
4365 By default, this command copies the contents of files as they
4398 exist in the working directory. If invoked with -A/--after, the
4366 exist in the working directory. If invoked with -A/--after, the
4399 operation is recorded, but no copying is performed.
4367 operation is recorded, but no copying is performed.
4400
4368
4401 This command takes effect at the next commit. To undo a rename
4369 This command takes effect at the next commit. To undo a rename
4402 before that, see :hg:`revert`.
4370 before that, see :hg:`revert`.
4403
4371
4404 Returns 0 on success, 1 if errors are encountered.
4372 Returns 0 on success, 1 if errors are encountered.
4405 """
4373 """
4406 with repo.wlock(False):
4374 with repo.wlock(False):
4407 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4375 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4408
4376
4409 @command('resolve',
4377 @command('resolve',
4410 [('a', 'all', None, _('select all unresolved files')),
4378 [('a', 'all', None, _('select all unresolved files')),
4411 ('l', 'list', None, _('list state of files needing merge')),
4379 ('l', 'list', None, _('list state of files needing merge')),
4412 ('m', 'mark', None, _('mark files as resolved')),
4380 ('m', 'mark', None, _('mark files as resolved')),
4413 ('u', 'unmark', None, _('mark files as unresolved')),
4381 ('u', 'unmark', None, _('mark files as unresolved')),
4414 ('n', 'no-status', None, _('hide status prefix'))]
4382 ('n', 'no-status', None, _('hide status prefix'))]
4415 + mergetoolopts + walkopts + formatteropts,
4383 + mergetoolopts + walkopts + formatteropts,
4416 _('[OPTION]... [FILE]...'),
4384 _('[OPTION]... [FILE]...'),
4417 inferrepo=True)
4385 inferrepo=True)
4418 def resolve(ui, repo, *pats, **opts):
4386 def resolve(ui, repo, *pats, **opts):
4419 """redo merges or set/view the merge status of files
4387 """redo merges or set/view the merge status of files
4420
4388
4421 Merges with unresolved conflicts are often the result of
4389 Merges with unresolved conflicts are often the result of
4422 non-interactive merging using the ``internal:merge`` configuration
4390 non-interactive merging using the ``internal:merge`` configuration
4423 setting, or a command-line merge tool like ``diff3``. The resolve
4391 setting, or a command-line merge tool like ``diff3``. The resolve
4424 command is used to manage the files involved in a merge, after
4392 command is used to manage the files involved in a merge, after
4425 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4393 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4426 working directory must have two parents). See :hg:`help
4394 working directory must have two parents). See :hg:`help
4427 merge-tools` for information on configuring merge tools.
4395 merge-tools` for information on configuring merge tools.
4428
4396
4429 The resolve command can be used in the following ways:
4397 The resolve command can be used in the following ways:
4430
4398
4431 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4399 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4432 files, discarding any previous merge attempts. Re-merging is not
4400 files, discarding any previous merge attempts. Re-merging is not
4433 performed for files already marked as resolved. Use ``--all/-a``
4401 performed for files already marked as resolved. Use ``--all/-a``
4434 to select all unresolved files. ``--tool`` can be used to specify
4402 to select all unresolved files. ``--tool`` can be used to specify
4435 the merge tool used for the given files. It overrides the HGMERGE
4403 the merge tool used for the given files. It overrides the HGMERGE
4436 environment variable and your configuration files. Previous file
4404 environment variable and your configuration files. Previous file
4437 contents are saved with a ``.orig`` suffix.
4405 contents are saved with a ``.orig`` suffix.
4438
4406
4439 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4407 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4440 (e.g. after having manually fixed-up the files). The default is
4408 (e.g. after having manually fixed-up the files). The default is
4441 to mark all unresolved files.
4409 to mark all unresolved files.
4442
4410
4443 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4411 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4444 default is to mark all resolved files.
4412 default is to mark all resolved files.
4445
4413
4446 - :hg:`resolve -l`: list files which had or still have conflicts.
4414 - :hg:`resolve -l`: list files which had or still have conflicts.
4447 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4415 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4448
4416
4449 .. note::
4417 .. note::
4450
4418
4451 Mercurial will not let you commit files with unresolved merge
4419 Mercurial will not let you commit files with unresolved merge
4452 conflicts. You must use :hg:`resolve -m ...` before you can
4420 conflicts. You must use :hg:`resolve -m ...` before you can
4453 commit after a conflicting merge.
4421 commit after a conflicting merge.
4454
4422
4455 Returns 0 on success, 1 if any files fail a resolve attempt.
4423 Returns 0 on success, 1 if any files fail a resolve attempt.
4456 """
4424 """
4457
4425
4458 flaglist = 'all mark unmark list no_status'.split()
4426 flaglist = 'all mark unmark list no_status'.split()
4459 all, mark, unmark, show, nostatus = \
4427 all, mark, unmark, show, nostatus = \
4460 [opts.get(o) for o in flaglist]
4428 [opts.get(o) for o in flaglist]
4461
4429
4462 if (show and (mark or unmark)) or (mark and unmark):
4430 if (show and (mark or unmark)) or (mark and unmark):
4463 raise error.Abort(_("too many options specified"))
4431 raise error.Abort(_("too many options specified"))
4464 if pats and all:
4432 if pats and all:
4465 raise error.Abort(_("can't specify --all and patterns"))
4433 raise error.Abort(_("can't specify --all and patterns"))
4466 if not (all or pats or show or mark or unmark):
4434 if not (all or pats or show or mark or unmark):
4467 raise error.Abort(_('no files or directories specified'),
4435 raise error.Abort(_('no files or directories specified'),
4468 hint=('use --all to re-merge all unresolved files'))
4436 hint=('use --all to re-merge all unresolved files'))
4469
4437
4470 if show:
4438 if show:
4471 fm = ui.formatter('resolve', opts)
4439 fm = ui.formatter('resolve', opts)
4472 ms = mergemod.mergestate.read(repo)
4440 ms = mergemod.mergestate.read(repo)
4473 m = scmutil.match(repo[None], pats, opts)
4441 m = scmutil.match(repo[None], pats, opts)
4474 for f in ms:
4442 for f in ms:
4475 if not m(f):
4443 if not m(f):
4476 continue
4444 continue
4477 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4445 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4478 'd': 'driverresolved'}[ms[f]]
4446 'd': 'driverresolved'}[ms[f]]
4479 fm.startitem()
4447 fm.startitem()
4480 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4448 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4481 fm.write('path', '%s\n', f, label=l)
4449 fm.write('path', '%s\n', f, label=l)
4482 fm.end()
4450 fm.end()
4483 return 0
4451 return 0
4484
4452
4485 with repo.wlock():
4453 with repo.wlock():
4486 ms = mergemod.mergestate.read(repo)
4454 ms = mergemod.mergestate.read(repo)
4487
4455
4488 if not (ms.active() or repo.dirstate.p2() != nullid):
4456 if not (ms.active() or repo.dirstate.p2() != nullid):
4489 raise error.Abort(
4457 raise error.Abort(
4490 _('resolve command not applicable when not merging'))
4458 _('resolve command not applicable when not merging'))
4491
4459
4492 wctx = repo[None]
4460 wctx = repo[None]
4493
4461
4494 if ms.mergedriver and ms.mdstate() == 'u':
4462 if ms.mergedriver and ms.mdstate() == 'u':
4495 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4463 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4496 ms.commit()
4464 ms.commit()
4497 # allow mark and unmark to go through
4465 # allow mark and unmark to go through
4498 if not mark and not unmark and not proceed:
4466 if not mark and not unmark and not proceed:
4499 return 1
4467 return 1
4500
4468
4501 m = scmutil.match(wctx, pats, opts)
4469 m = scmutil.match(wctx, pats, opts)
4502 ret = 0
4470 ret = 0
4503 didwork = False
4471 didwork = False
4504 runconclude = False
4472 runconclude = False
4505
4473
4506 tocomplete = []
4474 tocomplete = []
4507 for f in ms:
4475 for f in ms:
4508 if not m(f):
4476 if not m(f):
4509 continue
4477 continue
4510
4478
4511 didwork = True
4479 didwork = True
4512
4480
4513 # don't let driver-resolved files be marked, and run the conclude
4481 # don't let driver-resolved files be marked, and run the conclude
4514 # step if asked to resolve
4482 # step if asked to resolve
4515 if ms[f] == "d":
4483 if ms[f] == "d":
4516 exact = m.exact(f)
4484 exact = m.exact(f)
4517 if mark:
4485 if mark:
4518 if exact:
4486 if exact:
4519 ui.warn(_('not marking %s as it is driver-resolved\n')
4487 ui.warn(_('not marking %s as it is driver-resolved\n')
4520 % f)
4488 % f)
4521 elif unmark:
4489 elif unmark:
4522 if exact:
4490 if exact:
4523 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4491 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4524 % f)
4492 % f)
4525 else:
4493 else:
4526 runconclude = True
4494 runconclude = True
4527 continue
4495 continue
4528
4496
4529 if mark:
4497 if mark:
4530 ms.mark(f, "r")
4498 ms.mark(f, "r")
4531 elif unmark:
4499 elif unmark:
4532 ms.mark(f, "u")
4500 ms.mark(f, "u")
4533 else:
4501 else:
4534 # backup pre-resolve (merge uses .orig for its own purposes)
4502 # backup pre-resolve (merge uses .orig for its own purposes)
4535 a = repo.wjoin(f)
4503 a = repo.wjoin(f)
4536 try:
4504 try:
4537 util.copyfile(a, a + ".resolve")
4505 util.copyfile(a, a + ".resolve")
4538 except (IOError, OSError) as inst:
4506 except (IOError, OSError) as inst:
4539 if inst.errno != errno.ENOENT:
4507 if inst.errno != errno.ENOENT:
4540 raise
4508 raise
4541
4509
4542 try:
4510 try:
4543 # preresolve file
4511 # preresolve file
4544 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4512 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4545 'resolve')
4513 'resolve')
4546 complete, r = ms.preresolve(f, wctx)
4514 complete, r = ms.preresolve(f, wctx)
4547 if not complete:
4515 if not complete:
4548 tocomplete.append(f)
4516 tocomplete.append(f)
4549 elif r:
4517 elif r:
4550 ret = 1
4518 ret = 1
4551 finally:
4519 finally:
4552 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4520 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4553 ms.commit()
4521 ms.commit()
4554
4522
4555 # replace filemerge's .orig file with our resolve file, but only
4523 # replace filemerge's .orig file with our resolve file, but only
4556 # for merges that are complete
4524 # for merges that are complete
4557 if complete:
4525 if complete:
4558 try:
4526 try:
4559 util.rename(a + ".resolve",
4527 util.rename(a + ".resolve",
4560 scmutil.origpath(ui, repo, a))
4528 scmutil.origpath(ui, repo, a))
4561 except OSError as inst:
4529 except OSError as inst:
4562 if inst.errno != errno.ENOENT:
4530 if inst.errno != errno.ENOENT:
4563 raise
4531 raise
4564
4532
4565 for f in tocomplete:
4533 for f in tocomplete:
4566 try:
4534 try:
4567 # resolve file
4535 # resolve file
4568 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4536 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4569 'resolve')
4537 'resolve')
4570 r = ms.resolve(f, wctx)
4538 r = ms.resolve(f, wctx)
4571 if r:
4539 if r:
4572 ret = 1
4540 ret = 1
4573 finally:
4541 finally:
4574 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4542 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4575 ms.commit()
4543 ms.commit()
4576
4544
4577 # replace filemerge's .orig file with our resolve file
4545 # replace filemerge's .orig file with our resolve file
4578 a = repo.wjoin(f)
4546 a = repo.wjoin(f)
4579 try:
4547 try:
4580 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4548 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4581 except OSError as inst:
4549 except OSError as inst:
4582 if inst.errno != errno.ENOENT:
4550 if inst.errno != errno.ENOENT:
4583 raise
4551 raise
4584
4552
4585 ms.commit()
4553 ms.commit()
4586 ms.recordactions()
4554 ms.recordactions()
4587
4555
4588 if not didwork and pats:
4556 if not didwork and pats:
4589 hint = None
4557 hint = None
4590 if not any([p for p in pats if p.find(':') >= 0]):
4558 if not any([p for p in pats if p.find(':') >= 0]):
4591 pats = ['path:%s' % p for p in pats]
4559 pats = ['path:%s' % p for p in pats]
4592 m = scmutil.match(wctx, pats, opts)
4560 m = scmutil.match(wctx, pats, opts)
4593 for f in ms:
4561 for f in ms:
4594 if not m(f):
4562 if not m(f):
4595 continue
4563 continue
4596 flags = ''.join(['-%s ' % o[0] for o in flaglist
4564 flags = ''.join(['-%s ' % o[0] for o in flaglist
4597 if opts.get(o)])
4565 if opts.get(o)])
4598 hint = _("(try: hg resolve %s%s)\n") % (
4566 hint = _("(try: hg resolve %s%s)\n") % (
4599 flags,
4567 flags,
4600 ' '.join(pats))
4568 ' '.join(pats))
4601 break
4569 break
4602 ui.warn(_("arguments do not match paths that need resolving\n"))
4570 ui.warn(_("arguments do not match paths that need resolving\n"))
4603 if hint:
4571 if hint:
4604 ui.warn(hint)
4572 ui.warn(hint)
4605 elif ms.mergedriver and ms.mdstate() != 's':
4573 elif ms.mergedriver and ms.mdstate() != 's':
4606 # run conclude step when either a driver-resolved file is requested
4574 # run conclude step when either a driver-resolved file is requested
4607 # or there are no driver-resolved files
4575 # or there are no driver-resolved files
4608 # we can't use 'ret' to determine whether any files are unresolved
4576 # we can't use 'ret' to determine whether any files are unresolved
4609 # because we might not have tried to resolve some
4577 # because we might not have tried to resolve some
4610 if ((runconclude or not list(ms.driverresolved()))
4578 if ((runconclude or not list(ms.driverresolved()))
4611 and not list(ms.unresolved())):
4579 and not list(ms.unresolved())):
4612 proceed = mergemod.driverconclude(repo, ms, wctx)
4580 proceed = mergemod.driverconclude(repo, ms, wctx)
4613 ms.commit()
4581 ms.commit()
4614 if not proceed:
4582 if not proceed:
4615 return 1
4583 return 1
4616
4584
4617 # Nudge users into finishing an unfinished operation
4585 # Nudge users into finishing an unfinished operation
4618 unresolvedf = list(ms.unresolved())
4586 unresolvedf = list(ms.unresolved())
4619 driverresolvedf = list(ms.driverresolved())
4587 driverresolvedf = list(ms.driverresolved())
4620 if not unresolvedf and not driverresolvedf:
4588 if not unresolvedf and not driverresolvedf:
4621 ui.status(_('(no more unresolved files)\n'))
4589 ui.status(_('(no more unresolved files)\n'))
4622 cmdutil.checkafterresolved(repo)
4590 cmdutil.checkafterresolved(repo)
4623 elif not unresolvedf:
4591 elif not unresolvedf:
4624 ui.status(_('(no more unresolved files -- '
4592 ui.status(_('(no more unresolved files -- '
4625 'run "hg resolve --all" to conclude)\n'))
4593 'run "hg resolve --all" to conclude)\n'))
4626
4594
4627 return ret
4595 return ret
4628
4596
4629 @command('revert',
4597 @command('revert',
4630 [('a', 'all', None, _('revert all changes when no arguments given')),
4598 [('a', 'all', None, _('revert all changes when no arguments given')),
4631 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4599 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4632 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4600 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4633 ('C', 'no-backup', None, _('do not save backup copies of files')),
4601 ('C', 'no-backup', None, _('do not save backup copies of files')),
4634 ('i', 'interactive', None,
4602 ('i', 'interactive', None,
4635 _('interactively select the changes (EXPERIMENTAL)')),
4603 _('interactively select the changes (EXPERIMENTAL)')),
4636 ] + walkopts + dryrunopts,
4604 ] + walkopts + dryrunopts,
4637 _('[OPTION]... [-r REV] [NAME]...'))
4605 _('[OPTION]... [-r REV] [NAME]...'))
4638 def revert(ui, repo, *pats, **opts):
4606 def revert(ui, repo, *pats, **opts):
4639 """restore files to their checkout state
4607 """restore files to their checkout state
4640
4608
4641 .. note::
4609 .. note::
4642
4610
4643 To check out earlier revisions, you should use :hg:`update REV`.
4611 To check out earlier revisions, you should use :hg:`update REV`.
4644 To cancel an uncommitted merge (and lose your changes),
4612 To cancel an uncommitted merge (and lose your changes),
4645 use :hg:`update --clean .`.
4613 use :hg:`update --clean .`.
4646
4614
4647 With no revision specified, revert the specified files or directories
4615 With no revision specified, revert the specified files or directories
4648 to the contents they had in the parent of the working directory.
4616 to the contents they had in the parent of the working directory.
4649 This restores the contents of files to an unmodified
4617 This restores the contents of files to an unmodified
4650 state and unschedules adds, removes, copies, and renames. If the
4618 state and unschedules adds, removes, copies, and renames. If the
4651 working directory has two parents, you must explicitly specify a
4619 working directory has two parents, you must explicitly specify a
4652 revision.
4620 revision.
4653
4621
4654 Using the -r/--rev or -d/--date options, revert the given files or
4622 Using the -r/--rev or -d/--date options, revert the given files or
4655 directories to their states as of a specific revision. Because
4623 directories to their states as of a specific revision. Because
4656 revert does not change the working directory parents, this will
4624 revert does not change the working directory parents, this will
4657 cause these files to appear modified. This can be helpful to "back
4625 cause these files to appear modified. This can be helpful to "back
4658 out" some or all of an earlier change. See :hg:`backout` for a
4626 out" some or all of an earlier change. See :hg:`backout` for a
4659 related method.
4627 related method.
4660
4628
4661 Modified files are saved with a .orig suffix before reverting.
4629 Modified files are saved with a .orig suffix before reverting.
4662 To disable these backups, use --no-backup. It is possible to store
4630 To disable these backups, use --no-backup. It is possible to store
4663 the backup files in a custom directory relative to the root of the
4631 the backup files in a custom directory relative to the root of the
4664 repository by setting the ``ui.origbackuppath`` configuration
4632 repository by setting the ``ui.origbackuppath`` configuration
4665 option.
4633 option.
4666
4634
4667 See :hg:`help dates` for a list of formats valid for -d/--date.
4635 See :hg:`help dates` for a list of formats valid for -d/--date.
4668
4636
4669 See :hg:`help backout` for a way to reverse the effect of an
4637 See :hg:`help backout` for a way to reverse the effect of an
4670 earlier changeset.
4638 earlier changeset.
4671
4639
4672 Returns 0 on success.
4640 Returns 0 on success.
4673 """
4641 """
4674
4642
4675 if opts.get("date"):
4643 if opts.get("date"):
4676 if opts.get("rev"):
4644 if opts.get("rev"):
4677 raise error.Abort(_("you can't specify a revision and a date"))
4645 raise error.Abort(_("you can't specify a revision and a date"))
4678 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4646 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4679
4647
4680 parent, p2 = repo.dirstate.parents()
4648 parent, p2 = repo.dirstate.parents()
4681 if not opts.get('rev') and p2 != nullid:
4649 if not opts.get('rev') and p2 != nullid:
4682 # revert after merge is a trap for new users (issue2915)
4650 # revert after merge is a trap for new users (issue2915)
4683 raise error.Abort(_('uncommitted merge with no revision specified'),
4651 raise error.Abort(_('uncommitted merge with no revision specified'),
4684 hint=_("use 'hg update' or see 'hg help revert'"))
4652 hint=_("use 'hg update' or see 'hg help revert'"))
4685
4653
4686 ctx = scmutil.revsingle(repo, opts.get('rev'))
4654 ctx = scmutil.revsingle(repo, opts.get('rev'))
4687
4655
4688 if (not (pats or opts.get('include') or opts.get('exclude') or
4656 if (not (pats or opts.get('include') or opts.get('exclude') or
4689 opts.get('all') or opts.get('interactive'))):
4657 opts.get('all') or opts.get('interactive'))):
4690 msg = _("no files or directories specified")
4658 msg = _("no files or directories specified")
4691 if p2 != nullid:
4659 if p2 != nullid:
4692 hint = _("uncommitted merge, use --all to discard all changes,"
4660 hint = _("uncommitted merge, use --all to discard all changes,"
4693 " or 'hg update -C .' to abort the merge")
4661 " or 'hg update -C .' to abort the merge")
4694 raise error.Abort(msg, hint=hint)
4662 raise error.Abort(msg, hint=hint)
4695 dirty = any(repo.status())
4663 dirty = any(repo.status())
4696 node = ctx.node()
4664 node = ctx.node()
4697 if node != parent:
4665 if node != parent:
4698 if dirty:
4666 if dirty:
4699 hint = _("uncommitted changes, use --all to discard all"
4667 hint = _("uncommitted changes, use --all to discard all"
4700 " changes, or 'hg update %s' to update") % ctx.rev()
4668 " changes, or 'hg update %s' to update") % ctx.rev()
4701 else:
4669 else:
4702 hint = _("use --all to revert all files,"
4670 hint = _("use --all to revert all files,"
4703 " or 'hg update %s' to update") % ctx.rev()
4671 " or 'hg update %s' to update") % ctx.rev()
4704 elif dirty:
4672 elif dirty:
4705 hint = _("uncommitted changes, use --all to discard all changes")
4673 hint = _("uncommitted changes, use --all to discard all changes")
4706 else:
4674 else:
4707 hint = _("use --all to revert all files")
4675 hint = _("use --all to revert all files")
4708 raise error.Abort(msg, hint=hint)
4676 raise error.Abort(msg, hint=hint)
4709
4677
4710 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4678 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4711
4679
4712 @command('rollback', dryrunopts +
4680 @command('rollback', dryrunopts +
4713 [('f', 'force', False, _('ignore safety measures'))])
4681 [('f', 'force', False, _('ignore safety measures'))])
4714 def rollback(ui, repo, **opts):
4682 def rollback(ui, repo, **opts):
4715 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4683 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4716
4684
4717 Please use :hg:`commit --amend` instead of rollback to correct
4685 Please use :hg:`commit --amend` instead of rollback to correct
4718 mistakes in the last commit.
4686 mistakes in the last commit.
4719
4687
4720 This command should be used with care. There is only one level of
4688 This command should be used with care. There is only one level of
4721 rollback, and there is no way to undo a rollback. It will also
4689 rollback, and there is no way to undo a rollback. It will also
4722 restore the dirstate at the time of the last transaction, losing
4690 restore the dirstate at the time of the last transaction, losing
4723 any dirstate changes since that time. This command does not alter
4691 any dirstate changes since that time. This command does not alter
4724 the working directory.
4692 the working directory.
4725
4693
4726 Transactions are used to encapsulate the effects of all commands
4694 Transactions are used to encapsulate the effects of all commands
4727 that create new changesets or propagate existing changesets into a
4695 that create new changesets or propagate existing changesets into a
4728 repository.
4696 repository.
4729
4697
4730 .. container:: verbose
4698 .. container:: verbose
4731
4699
4732 For example, the following commands are transactional, and their
4700 For example, the following commands are transactional, and their
4733 effects can be rolled back:
4701 effects can be rolled back:
4734
4702
4735 - commit
4703 - commit
4736 - import
4704 - import
4737 - pull
4705 - pull
4738 - push (with this repository as the destination)
4706 - push (with this repository as the destination)
4739 - unbundle
4707 - unbundle
4740
4708
4741 To avoid permanent data loss, rollback will refuse to rollback a
4709 To avoid permanent data loss, rollback will refuse to rollback a
4742 commit transaction if it isn't checked out. Use --force to
4710 commit transaction if it isn't checked out. Use --force to
4743 override this protection.
4711 override this protection.
4744
4712
4745 The rollback command can be entirely disabled by setting the
4713 The rollback command can be entirely disabled by setting the
4746 ``ui.rollback`` configuration setting to false. If you're here
4714 ``ui.rollback`` configuration setting to false. If you're here
4747 because you want to use rollback and it's disabled, you can
4715 because you want to use rollback and it's disabled, you can
4748 re-enable the command by setting ``ui.rollback`` to true.
4716 re-enable the command by setting ``ui.rollback`` to true.
4749
4717
4750 This command is not intended for use on public repositories. Once
4718 This command is not intended for use on public repositories. Once
4751 changes are visible for pull by other users, rolling a transaction
4719 changes are visible for pull by other users, rolling a transaction
4752 back locally is ineffective (someone else may already have pulled
4720 back locally is ineffective (someone else may already have pulled
4753 the changes). Furthermore, a race is possible with readers of the
4721 the changes). Furthermore, a race is possible with readers of the
4754 repository; for example an in-progress pull from the repository
4722 repository; for example an in-progress pull from the repository
4755 may fail if a rollback is performed.
4723 may fail if a rollback is performed.
4756
4724
4757 Returns 0 on success, 1 if no rollback data is available.
4725 Returns 0 on success, 1 if no rollback data is available.
4758 """
4726 """
4759 if not ui.configbool('ui', 'rollback', True):
4727 if not ui.configbool('ui', 'rollback', True):
4760 raise error.Abort(_('rollback is disabled because it is unsafe'),
4728 raise error.Abort(_('rollback is disabled because it is unsafe'),
4761 hint=('see `hg help -v rollback` for information'))
4729 hint=('see `hg help -v rollback` for information'))
4762 return repo.rollback(dryrun=opts.get('dry_run'),
4730 return repo.rollback(dryrun=opts.get('dry_run'),
4763 force=opts.get('force'))
4731 force=opts.get('force'))
4764
4732
4765 @command('root', [])
4733 @command('root', [])
4766 def root(ui, repo):
4734 def root(ui, repo):
4767 """print the root (top) of the current working directory
4735 """print the root (top) of the current working directory
4768
4736
4769 Print the root directory of the current repository.
4737 Print the root directory of the current repository.
4770
4738
4771 Returns 0 on success.
4739 Returns 0 on success.
4772 """
4740 """
4773 ui.write(repo.root + "\n")
4741 ui.write(repo.root + "\n")
4774
4742
4775 @command('^serve',
4743 @command('^serve',
4776 [('A', 'accesslog', '', _('name of access log file to write to'),
4744 [('A', 'accesslog', '', _('name of access log file to write to'),
4777 _('FILE')),
4745 _('FILE')),
4778 ('d', 'daemon', None, _('run server in background')),
4746 ('d', 'daemon', None, _('run server in background')),
4779 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4747 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4780 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4748 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4781 # use string type, then we can check if something was passed
4749 # use string type, then we can check if something was passed
4782 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4750 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4783 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4751 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4784 _('ADDR')),
4752 _('ADDR')),
4785 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4753 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4786 _('PREFIX')),
4754 _('PREFIX')),
4787 ('n', 'name', '',
4755 ('n', 'name', '',
4788 _('name to show in web pages (default: working directory)'), _('NAME')),
4756 _('name to show in web pages (default: working directory)'), _('NAME')),
4789 ('', 'web-conf', '',
4757 ('', 'web-conf', '',
4790 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4758 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4791 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4759 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4792 _('FILE')),
4760 _('FILE')),
4793 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4761 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4794 ('', 'stdio', None, _('for remote clients')),
4762 ('', 'stdio', None, _('for remote clients')),
4795 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4763 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4796 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4764 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4797 ('', 'style', '', _('template style to use'), _('STYLE')),
4765 ('', 'style', '', _('template style to use'), _('STYLE')),
4798 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4766 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4799 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4767 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4800 _('[OPTION]...'),
4768 _('[OPTION]...'),
4801 optionalrepo=True)
4769 optionalrepo=True)
4802 def serve(ui, repo, **opts):
4770 def serve(ui, repo, **opts):
4803 """start stand-alone webserver
4771 """start stand-alone webserver
4804
4772
4805 Start a local HTTP repository browser and pull server. You can use
4773 Start a local HTTP repository browser and pull server. You can use
4806 this for ad-hoc sharing and browsing of repositories. It is
4774 this for ad-hoc sharing and browsing of repositories. It is
4807 recommended to use a real web server to serve a repository for
4775 recommended to use a real web server to serve a repository for
4808 longer periods of time.
4776 longer periods of time.
4809
4777
4810 Please note that the server does not implement access control.
4778 Please note that the server does not implement access control.
4811 This means that, by default, anybody can read from the server and
4779 This means that, by default, anybody can read from the server and
4812 nobody can write to it by default. Set the ``web.allow_push``
4780 nobody can write to it by default. Set the ``web.allow_push``
4813 option to ``*`` to allow everybody to push to the server. You
4781 option to ``*`` to allow everybody to push to the server. You
4814 should use a real web server if you need to authenticate users.
4782 should use a real web server if you need to authenticate users.
4815
4783
4816 By default, the server logs accesses to stdout and errors to
4784 By default, the server logs accesses to stdout and errors to
4817 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4785 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4818 files.
4786 files.
4819
4787
4820 To have the server choose a free port number to listen on, specify
4788 To have the server choose a free port number to listen on, specify
4821 a port number of 0; in this case, the server will print the port
4789 a port number of 0; in this case, the server will print the port
4822 number it uses.
4790 number it uses.
4823
4791
4824 Returns 0 on success.
4792 Returns 0 on success.
4825 """
4793 """
4826
4794
4827 if opts["stdio"] and opts["cmdserver"]:
4795 if opts["stdio"] and opts["cmdserver"]:
4828 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4796 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4829
4797
4830 if opts["stdio"]:
4798 if opts["stdio"]:
4831 if repo is None:
4799 if repo is None:
4832 raise error.RepoError(_("there is no Mercurial repository here"
4800 raise error.RepoError(_("there is no Mercurial repository here"
4833 " (.hg not found)"))
4801 " (.hg not found)"))
4834 s = sshserver.sshserver(ui, repo)
4802 s = sshserver.sshserver(ui, repo)
4835 s.serve_forever()
4803 s.serve_forever()
4836
4804
4837 service = server.createservice(ui, repo, opts)
4805 service = server.createservice(ui, repo, opts)
4838 return server.runservice(opts, initfn=service.init, runfn=service.run)
4806 return server.runservice(opts, initfn=service.init, runfn=service.run)
4839
4807
4840 @command('^status|st',
4808 @command('^status|st',
4841 [('A', 'all', None, _('show status of all files')),
4809 [('A', 'all', None, _('show status of all files')),
4842 ('m', 'modified', None, _('show only modified files')),
4810 ('m', 'modified', None, _('show only modified files')),
4843 ('a', 'added', None, _('show only added files')),
4811 ('a', 'added', None, _('show only added files')),
4844 ('r', 'removed', None, _('show only removed files')),
4812 ('r', 'removed', None, _('show only removed files')),
4845 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4813 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4846 ('c', 'clean', None, _('show only files without changes')),
4814 ('c', 'clean', None, _('show only files without changes')),
4847 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4815 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4848 ('i', 'ignored', None, _('show only ignored files')),
4816 ('i', 'ignored', None, _('show only ignored files')),
4849 ('n', 'no-status', None, _('hide status prefix')),
4817 ('n', 'no-status', None, _('hide status prefix')),
4850 ('C', 'copies', None, _('show source of copied files')),
4818 ('C', 'copies', None, _('show source of copied files')),
4851 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4819 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4852 ('', 'rev', [], _('show difference from revision'), _('REV')),
4820 ('', 'rev', [], _('show difference from revision'), _('REV')),
4853 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4821 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4854 ] + walkopts + subrepoopts + formatteropts,
4822 ] + walkopts + subrepoopts + formatteropts,
4855 _('[OPTION]... [FILE]...'),
4823 _('[OPTION]... [FILE]...'),
4856 inferrepo=True)
4824 inferrepo=True)
4857 def status(ui, repo, *pats, **opts):
4825 def status(ui, repo, *pats, **opts):
4858 """show changed files in the working directory
4826 """show changed files in the working directory
4859
4827
4860 Show status of files in the repository. If names are given, only
4828 Show status of files in the repository. If names are given, only
4861 files that match are shown. Files that are clean or ignored or
4829 files that match are shown. Files that are clean or ignored or
4862 the source of a copy/move operation, are not listed unless
4830 the source of a copy/move operation, are not listed unless
4863 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4831 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4864 Unless options described with "show only ..." are given, the
4832 Unless options described with "show only ..." are given, the
4865 options -mardu are used.
4833 options -mardu are used.
4866
4834
4867 Option -q/--quiet hides untracked (unknown and ignored) files
4835 Option -q/--quiet hides untracked (unknown and ignored) files
4868 unless explicitly requested with -u/--unknown or -i/--ignored.
4836 unless explicitly requested with -u/--unknown or -i/--ignored.
4869
4837
4870 .. note::
4838 .. note::
4871
4839
4872 :hg:`status` may appear to disagree with diff if permissions have
4840 :hg:`status` may appear to disagree with diff if permissions have
4873 changed or a merge has occurred. The standard diff format does
4841 changed or a merge has occurred. The standard diff format does
4874 not report permission changes and diff only reports changes
4842 not report permission changes and diff only reports changes
4875 relative to one merge parent.
4843 relative to one merge parent.
4876
4844
4877 If one revision is given, it is used as the base revision.
4845 If one revision is given, it is used as the base revision.
4878 If two revisions are given, the differences between them are
4846 If two revisions are given, the differences between them are
4879 shown. The --change option can also be used as a shortcut to list
4847 shown. The --change option can also be used as a shortcut to list
4880 the changed files of a revision from its first parent.
4848 the changed files of a revision from its first parent.
4881
4849
4882 The codes used to show the status of files are::
4850 The codes used to show the status of files are::
4883
4851
4884 M = modified
4852 M = modified
4885 A = added
4853 A = added
4886 R = removed
4854 R = removed
4887 C = clean
4855 C = clean
4888 ! = missing (deleted by non-hg command, but still tracked)
4856 ! = missing (deleted by non-hg command, but still tracked)
4889 ? = not tracked
4857 ? = not tracked
4890 I = ignored
4858 I = ignored
4891 = origin of the previous file (with --copies)
4859 = origin of the previous file (with --copies)
4892
4860
4893 .. container:: verbose
4861 .. container:: verbose
4894
4862
4895 Examples:
4863 Examples:
4896
4864
4897 - show changes in the working directory relative to a
4865 - show changes in the working directory relative to a
4898 changeset::
4866 changeset::
4899
4867
4900 hg status --rev 9353
4868 hg status --rev 9353
4901
4869
4902 - show changes in the working directory relative to the
4870 - show changes in the working directory relative to the
4903 current directory (see :hg:`help patterns` for more information)::
4871 current directory (see :hg:`help patterns` for more information)::
4904
4872
4905 hg status re:
4873 hg status re:
4906
4874
4907 - show all changes including copies in an existing changeset::
4875 - show all changes including copies in an existing changeset::
4908
4876
4909 hg status --copies --change 9353
4877 hg status --copies --change 9353
4910
4878
4911 - get a NUL separated list of added files, suitable for xargs::
4879 - get a NUL separated list of added files, suitable for xargs::
4912
4880
4913 hg status -an0
4881 hg status -an0
4914
4882
4915 Returns 0 on success.
4883 Returns 0 on success.
4916 """
4884 """
4917
4885
4918 revs = opts.get('rev')
4886 revs = opts.get('rev')
4919 change = opts.get('change')
4887 change = opts.get('change')
4920
4888
4921 if revs and change:
4889 if revs and change:
4922 msg = _('cannot specify --rev and --change at the same time')
4890 msg = _('cannot specify --rev and --change at the same time')
4923 raise error.Abort(msg)
4891 raise error.Abort(msg)
4924 elif change:
4892 elif change:
4925 node2 = scmutil.revsingle(repo, change, None).node()
4893 node2 = scmutil.revsingle(repo, change, None).node()
4926 node1 = repo[node2].p1().node()
4894 node1 = repo[node2].p1().node()
4927 else:
4895 else:
4928 node1, node2 = scmutil.revpair(repo, revs)
4896 node1, node2 = scmutil.revpair(repo, revs)
4929
4897
4930 if pats:
4898 if pats:
4931 cwd = repo.getcwd()
4899 cwd = repo.getcwd()
4932 else:
4900 else:
4933 cwd = ''
4901 cwd = ''
4934
4902
4935 if opts.get('print0'):
4903 if opts.get('print0'):
4936 end = '\0'
4904 end = '\0'
4937 else:
4905 else:
4938 end = '\n'
4906 end = '\n'
4939 copy = {}
4907 copy = {}
4940 states = 'modified added removed deleted unknown ignored clean'.split()
4908 states = 'modified added removed deleted unknown ignored clean'.split()
4941 show = [k for k in states if opts.get(k)]
4909 show = [k for k in states if opts.get(k)]
4942 if opts.get('all'):
4910 if opts.get('all'):
4943 show += ui.quiet and (states[:4] + ['clean']) or states
4911 show += ui.quiet and (states[:4] + ['clean']) or states
4944 if not show:
4912 if not show:
4945 if ui.quiet:
4913 if ui.quiet:
4946 show = states[:4]
4914 show = states[:4]
4947 else:
4915 else:
4948 show = states[:5]
4916 show = states[:5]
4949
4917
4950 m = scmutil.match(repo[node2], pats, opts)
4918 m = scmutil.match(repo[node2], pats, opts)
4951 stat = repo.status(node1, node2, m,
4919 stat = repo.status(node1, node2, m,
4952 'ignored' in show, 'clean' in show, 'unknown' in show,
4920 'ignored' in show, 'clean' in show, 'unknown' in show,
4953 opts.get('subrepos'))
4921 opts.get('subrepos'))
4954 changestates = zip(states, 'MAR!?IC', stat)
4922 changestates = zip(states, 'MAR!?IC', stat)
4955
4923
4956 if (opts.get('all') or opts.get('copies')
4924 if (opts.get('all') or opts.get('copies')
4957 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4925 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4958 copy = copies.pathcopies(repo[node1], repo[node2], m)
4926 copy = copies.pathcopies(repo[node1], repo[node2], m)
4959
4927
4960 fm = ui.formatter('status', opts)
4928 fm = ui.formatter('status', opts)
4961 fmt = '%s' + end
4929 fmt = '%s' + end
4962 showchar = not opts.get('no_status')
4930 showchar = not opts.get('no_status')
4963
4931
4964 for state, char, files in changestates:
4932 for state, char, files in changestates:
4965 if state in show:
4933 if state in show:
4966 label = 'status.' + state
4934 label = 'status.' + state
4967 for f in files:
4935 for f in files:
4968 fm.startitem()
4936 fm.startitem()
4969 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4937 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4970 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4938 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4971 if f in copy:
4939 if f in copy:
4972 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4940 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4973 label='status.copied')
4941 label='status.copied')
4974 fm.end()
4942 fm.end()
4975
4943
4976 @command('^summary|sum',
4944 @command('^summary|sum',
4977 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4945 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4978 def summary(ui, repo, **opts):
4946 def summary(ui, repo, **opts):
4979 """summarize working directory state
4947 """summarize working directory state
4980
4948
4981 This generates a brief summary of the working directory state,
4949 This generates a brief summary of the working directory state,
4982 including parents, branch, commit status, phase and available updates.
4950 including parents, branch, commit status, phase and available updates.
4983
4951
4984 With the --remote option, this will check the default paths for
4952 With the --remote option, this will check the default paths for
4985 incoming and outgoing changes. This can be time-consuming.
4953 incoming and outgoing changes. This can be time-consuming.
4986
4954
4987 Returns 0 on success.
4955 Returns 0 on success.
4988 """
4956 """
4989
4957
4990 ctx = repo[None]
4958 ctx = repo[None]
4991 parents = ctx.parents()
4959 parents = ctx.parents()
4992 pnode = parents[0].node()
4960 pnode = parents[0].node()
4993 marks = []
4961 marks = []
4994
4962
4995 ms = None
4963 ms = None
4996 try:
4964 try:
4997 ms = mergemod.mergestate.read(repo)
4965 ms = mergemod.mergestate.read(repo)
4998 except error.UnsupportedMergeRecords as e:
4966 except error.UnsupportedMergeRecords as e:
4999 s = ' '.join(e.recordtypes)
4967 s = ' '.join(e.recordtypes)
5000 ui.warn(
4968 ui.warn(
5001 _('warning: merge state has unsupported record types: %s\n') % s)
4969 _('warning: merge state has unsupported record types: %s\n') % s)
5002 unresolved = 0
4970 unresolved = 0
5003 else:
4971 else:
5004 unresolved = [f for f in ms if ms[f] == 'u']
4972 unresolved = [f for f in ms if ms[f] == 'u']
5005
4973
5006 for p in parents:
4974 for p in parents:
5007 # label with log.changeset (instead of log.parent) since this
4975 # label with log.changeset (instead of log.parent) since this
5008 # shows a working directory parent *changeset*:
4976 # shows a working directory parent *changeset*:
5009 # i18n: column positioning for "hg summary"
4977 # i18n: column positioning for "hg summary"
5010 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4978 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5011 label=cmdutil._changesetlabels(p))
4979 label=cmdutil._changesetlabels(p))
5012 ui.write(' '.join(p.tags()), label='log.tag')
4980 ui.write(' '.join(p.tags()), label='log.tag')
5013 if p.bookmarks():
4981 if p.bookmarks():
5014 marks.extend(p.bookmarks())
4982 marks.extend(p.bookmarks())
5015 if p.rev() == -1:
4983 if p.rev() == -1:
5016 if not len(repo):
4984 if not len(repo):
5017 ui.write(_(' (empty repository)'))
4985 ui.write(_(' (empty repository)'))
5018 else:
4986 else:
5019 ui.write(_(' (no revision checked out)'))
4987 ui.write(_(' (no revision checked out)'))
5020 if p.troubled():
4988 if p.troubled():
5021 ui.write(' ('
4989 ui.write(' ('
5022 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4990 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
5023 for trouble in p.troubles())
4991 for trouble in p.troubles())
5024 + ')')
4992 + ')')
5025 ui.write('\n')
4993 ui.write('\n')
5026 if p.description():
4994 if p.description():
5027 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4995 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5028 label='log.summary')
4996 label='log.summary')
5029
4997
5030 branch = ctx.branch()
4998 branch = ctx.branch()
5031 bheads = repo.branchheads(branch)
4999 bheads = repo.branchheads(branch)
5032 # i18n: column positioning for "hg summary"
5000 # i18n: column positioning for "hg summary"
5033 m = _('branch: %s\n') % branch
5001 m = _('branch: %s\n') % branch
5034 if branch != 'default':
5002 if branch != 'default':
5035 ui.write(m, label='log.branch')
5003 ui.write(m, label='log.branch')
5036 else:
5004 else:
5037 ui.status(m, label='log.branch')
5005 ui.status(m, label='log.branch')
5038
5006
5039 if marks:
5007 if marks:
5040 active = repo._activebookmark
5008 active = repo._activebookmark
5041 # i18n: column positioning for "hg summary"
5009 # i18n: column positioning for "hg summary"
5042 ui.write(_('bookmarks:'), label='log.bookmark')
5010 ui.write(_('bookmarks:'), label='log.bookmark')
5043 if active is not None:
5011 if active is not None:
5044 if active in marks:
5012 if active in marks:
5045 ui.write(' *' + active, label=activebookmarklabel)
5013 ui.write(' *' + active, label=activebookmarklabel)
5046 marks.remove(active)
5014 marks.remove(active)
5047 else:
5015 else:
5048 ui.write(' [%s]' % active, label=activebookmarklabel)
5016 ui.write(' [%s]' % active, label=activebookmarklabel)
5049 for m in marks:
5017 for m in marks:
5050 ui.write(' ' + m, label='log.bookmark')
5018 ui.write(' ' + m, label='log.bookmark')
5051 ui.write('\n', label='log.bookmark')
5019 ui.write('\n', label='log.bookmark')
5052
5020
5053 status = repo.status(unknown=True)
5021 status = repo.status(unknown=True)
5054
5022
5055 c = repo.dirstate.copies()
5023 c = repo.dirstate.copies()
5056 copied, renamed = [], []
5024 copied, renamed = [], []
5057 for d, s in c.iteritems():
5025 for d, s in c.iteritems():
5058 if s in status.removed:
5026 if s in status.removed:
5059 status.removed.remove(s)
5027 status.removed.remove(s)
5060 renamed.append(d)
5028 renamed.append(d)
5061 else:
5029 else:
5062 copied.append(d)
5030 copied.append(d)
5063 if d in status.added:
5031 if d in status.added:
5064 status.added.remove(d)
5032 status.added.remove(d)
5065
5033
5066 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5034 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5067
5035
5068 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5036 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5069 (ui.label(_('%d added'), 'status.added'), status.added),
5037 (ui.label(_('%d added'), 'status.added'), status.added),
5070 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5038 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5071 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5039 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5072 (ui.label(_('%d copied'), 'status.copied'), copied),
5040 (ui.label(_('%d copied'), 'status.copied'), copied),
5073 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5041 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5074 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5042 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5075 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5043 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5076 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5044 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5077 t = []
5045 t = []
5078 for l, s in labels:
5046 for l, s in labels:
5079 if s:
5047 if s:
5080 t.append(l % len(s))
5048 t.append(l % len(s))
5081
5049
5082 t = ', '.join(t)
5050 t = ', '.join(t)
5083 cleanworkdir = False
5051 cleanworkdir = False
5084
5052
5085 if repo.vfs.exists('graftstate'):
5053 if repo.vfs.exists('graftstate'):
5086 t += _(' (graft in progress)')
5054 t += _(' (graft in progress)')
5087 if repo.vfs.exists('updatestate'):
5055 if repo.vfs.exists('updatestate'):
5088 t += _(' (interrupted update)')
5056 t += _(' (interrupted update)')
5089 elif len(parents) > 1:
5057 elif len(parents) > 1:
5090 t += _(' (merge)')
5058 t += _(' (merge)')
5091 elif branch != parents[0].branch():
5059 elif branch != parents[0].branch():
5092 t += _(' (new branch)')
5060 t += _(' (new branch)')
5093 elif (parents[0].closesbranch() and
5061 elif (parents[0].closesbranch() and
5094 pnode in repo.branchheads(branch, closed=True)):
5062 pnode in repo.branchheads(branch, closed=True)):
5095 t += _(' (head closed)')
5063 t += _(' (head closed)')
5096 elif not (status.modified or status.added or status.removed or renamed or
5064 elif not (status.modified or status.added or status.removed or renamed or
5097 copied or subs):
5065 copied or subs):
5098 t += _(' (clean)')
5066 t += _(' (clean)')
5099 cleanworkdir = True
5067 cleanworkdir = True
5100 elif pnode not in bheads:
5068 elif pnode not in bheads:
5101 t += _(' (new branch head)')
5069 t += _(' (new branch head)')
5102
5070
5103 if parents:
5071 if parents:
5104 pendingphase = max(p.phase() for p in parents)
5072 pendingphase = max(p.phase() for p in parents)
5105 else:
5073 else:
5106 pendingphase = phases.public
5074 pendingphase = phases.public
5107
5075
5108 if pendingphase > phases.newcommitphase(ui):
5076 if pendingphase > phases.newcommitphase(ui):
5109 t += ' (%s)' % phases.phasenames[pendingphase]
5077 t += ' (%s)' % phases.phasenames[pendingphase]
5110
5078
5111 if cleanworkdir:
5079 if cleanworkdir:
5112 # i18n: column positioning for "hg summary"
5080 # i18n: column positioning for "hg summary"
5113 ui.status(_('commit: %s\n') % t.strip())
5081 ui.status(_('commit: %s\n') % t.strip())
5114 else:
5082 else:
5115 # i18n: column positioning for "hg summary"
5083 # i18n: column positioning for "hg summary"
5116 ui.write(_('commit: %s\n') % t.strip())
5084 ui.write(_('commit: %s\n') % t.strip())
5117
5085
5118 # all ancestors of branch heads - all ancestors of parent = new csets
5086 # all ancestors of branch heads - all ancestors of parent = new csets
5119 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5087 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5120 bheads))
5088 bheads))
5121
5089
5122 if new == 0:
5090 if new == 0:
5123 # i18n: column positioning for "hg summary"
5091 # i18n: column positioning for "hg summary"
5124 ui.status(_('update: (current)\n'))
5092 ui.status(_('update: (current)\n'))
5125 elif pnode not in bheads:
5093 elif pnode not in bheads:
5126 # i18n: column positioning for "hg summary"
5094 # i18n: column positioning for "hg summary"
5127 ui.write(_('update: %d new changesets (update)\n') % new)
5095 ui.write(_('update: %d new changesets (update)\n') % new)
5128 else:
5096 else:
5129 # i18n: column positioning for "hg summary"
5097 # i18n: column positioning for "hg summary"
5130 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5098 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5131 (new, len(bheads)))
5099 (new, len(bheads)))
5132
5100
5133 t = []
5101 t = []
5134 draft = len(repo.revs('draft()'))
5102 draft = len(repo.revs('draft()'))
5135 if draft:
5103 if draft:
5136 t.append(_('%d draft') % draft)
5104 t.append(_('%d draft') % draft)
5137 secret = len(repo.revs('secret()'))
5105 secret = len(repo.revs('secret()'))
5138 if secret:
5106 if secret:
5139 t.append(_('%d secret') % secret)
5107 t.append(_('%d secret') % secret)
5140
5108
5141 if draft or secret:
5109 if draft or secret:
5142 ui.status(_('phases: %s\n') % ', '.join(t))
5110 ui.status(_('phases: %s\n') % ', '.join(t))
5143
5111
5144 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5112 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5145 for trouble in ("unstable", "divergent", "bumped"):
5113 for trouble in ("unstable", "divergent", "bumped"):
5146 numtrouble = len(repo.revs(trouble + "()"))
5114 numtrouble = len(repo.revs(trouble + "()"))
5147 # We write all the possibilities to ease translation
5115 # We write all the possibilities to ease translation
5148 troublemsg = {
5116 troublemsg = {
5149 "unstable": _("unstable: %d changesets"),
5117 "unstable": _("unstable: %d changesets"),
5150 "divergent": _("divergent: %d changesets"),
5118 "divergent": _("divergent: %d changesets"),
5151 "bumped": _("bumped: %d changesets"),
5119 "bumped": _("bumped: %d changesets"),
5152 }
5120 }
5153 if numtrouble > 0:
5121 if numtrouble > 0:
5154 ui.status(troublemsg[trouble] % numtrouble + "\n")
5122 ui.status(troublemsg[trouble] % numtrouble + "\n")
5155
5123
5156 cmdutil.summaryhooks(ui, repo)
5124 cmdutil.summaryhooks(ui, repo)
5157
5125
5158 if opts.get('remote'):
5126 if opts.get('remote'):
5159 needsincoming, needsoutgoing = True, True
5127 needsincoming, needsoutgoing = True, True
5160 else:
5128 else:
5161 needsincoming, needsoutgoing = False, False
5129 needsincoming, needsoutgoing = False, False
5162 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5130 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5163 if i:
5131 if i:
5164 needsincoming = True
5132 needsincoming = True
5165 if o:
5133 if o:
5166 needsoutgoing = True
5134 needsoutgoing = True
5167 if not needsincoming and not needsoutgoing:
5135 if not needsincoming and not needsoutgoing:
5168 return
5136 return
5169
5137
5170 def getincoming():
5138 def getincoming():
5171 source, branches = hg.parseurl(ui.expandpath('default'))
5139 source, branches = hg.parseurl(ui.expandpath('default'))
5172 sbranch = branches[0]
5140 sbranch = branches[0]
5173 try:
5141 try:
5174 other = hg.peer(repo, {}, source)
5142 other = hg.peer(repo, {}, source)
5175 except error.RepoError:
5143 except error.RepoError:
5176 if opts.get('remote'):
5144 if opts.get('remote'):
5177 raise
5145 raise
5178 return source, sbranch, None, None, None
5146 return source, sbranch, None, None, None
5179 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5147 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5180 if revs:
5148 if revs:
5181 revs = [other.lookup(rev) for rev in revs]
5149 revs = [other.lookup(rev) for rev in revs]
5182 ui.debug('comparing with %s\n' % util.hidepassword(source))
5150 ui.debug('comparing with %s\n' % util.hidepassword(source))
5183 repo.ui.pushbuffer()
5151 repo.ui.pushbuffer()
5184 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5152 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5185 repo.ui.popbuffer()
5153 repo.ui.popbuffer()
5186 return source, sbranch, other, commoninc, commoninc[1]
5154 return source, sbranch, other, commoninc, commoninc[1]
5187
5155
5188 if needsincoming:
5156 if needsincoming:
5189 source, sbranch, sother, commoninc, incoming = getincoming()
5157 source, sbranch, sother, commoninc, incoming = getincoming()
5190 else:
5158 else:
5191 source = sbranch = sother = commoninc = incoming = None
5159 source = sbranch = sother = commoninc = incoming = None
5192
5160
5193 def getoutgoing():
5161 def getoutgoing():
5194 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5162 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5195 dbranch = branches[0]
5163 dbranch = branches[0]
5196 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5164 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5197 if source != dest:
5165 if source != dest:
5198 try:
5166 try:
5199 dother = hg.peer(repo, {}, dest)
5167 dother = hg.peer(repo, {}, dest)
5200 except error.RepoError:
5168 except error.RepoError:
5201 if opts.get('remote'):
5169 if opts.get('remote'):
5202 raise
5170 raise
5203 return dest, dbranch, None, None
5171 return dest, dbranch, None, None
5204 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5172 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5205 elif sother is None:
5173 elif sother is None:
5206 # there is no explicit destination peer, but source one is invalid
5174 # there is no explicit destination peer, but source one is invalid
5207 return dest, dbranch, None, None
5175 return dest, dbranch, None, None
5208 else:
5176 else:
5209 dother = sother
5177 dother = sother
5210 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5178 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5211 common = None
5179 common = None
5212 else:
5180 else:
5213 common = commoninc
5181 common = commoninc
5214 if revs:
5182 if revs:
5215 revs = [repo.lookup(rev) for rev in revs]
5183 revs = [repo.lookup(rev) for rev in revs]
5216 repo.ui.pushbuffer()
5184 repo.ui.pushbuffer()
5217 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5185 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5218 commoninc=common)
5186 commoninc=common)
5219 repo.ui.popbuffer()
5187 repo.ui.popbuffer()
5220 return dest, dbranch, dother, outgoing
5188 return dest, dbranch, dother, outgoing
5221
5189
5222 if needsoutgoing:
5190 if needsoutgoing:
5223 dest, dbranch, dother, outgoing = getoutgoing()
5191 dest, dbranch, dother, outgoing = getoutgoing()
5224 else:
5192 else:
5225 dest = dbranch = dother = outgoing = None
5193 dest = dbranch = dother = outgoing = None
5226
5194
5227 if opts.get('remote'):
5195 if opts.get('remote'):
5228 t = []
5196 t = []
5229 if incoming:
5197 if incoming:
5230 t.append(_('1 or more incoming'))
5198 t.append(_('1 or more incoming'))
5231 o = outgoing.missing
5199 o = outgoing.missing
5232 if o:
5200 if o:
5233 t.append(_('%d outgoing') % len(o))
5201 t.append(_('%d outgoing') % len(o))
5234 other = dother or sother
5202 other = dother or sother
5235 if 'bookmarks' in other.listkeys('namespaces'):
5203 if 'bookmarks' in other.listkeys('namespaces'):
5236 counts = bookmarks.summary(repo, other)
5204 counts = bookmarks.summary(repo, other)
5237 if counts[0] > 0:
5205 if counts[0] > 0:
5238 t.append(_('%d incoming bookmarks') % counts[0])
5206 t.append(_('%d incoming bookmarks') % counts[0])
5239 if counts[1] > 0:
5207 if counts[1] > 0:
5240 t.append(_('%d outgoing bookmarks') % counts[1])
5208 t.append(_('%d outgoing bookmarks') % counts[1])
5241
5209
5242 if t:
5210 if t:
5243 # i18n: column positioning for "hg summary"
5211 # i18n: column positioning for "hg summary"
5244 ui.write(_('remote: %s\n') % (', '.join(t)))
5212 ui.write(_('remote: %s\n') % (', '.join(t)))
5245 else:
5213 else:
5246 # i18n: column positioning for "hg summary"
5214 # i18n: column positioning for "hg summary"
5247 ui.status(_('remote: (synced)\n'))
5215 ui.status(_('remote: (synced)\n'))
5248
5216
5249 cmdutil.summaryremotehooks(ui, repo, opts,
5217 cmdutil.summaryremotehooks(ui, repo, opts,
5250 ((source, sbranch, sother, commoninc),
5218 ((source, sbranch, sother, commoninc),
5251 (dest, dbranch, dother, outgoing)))
5219 (dest, dbranch, dother, outgoing)))
5252
5220
5253 @command('tag',
5221 @command('tag',
5254 [('f', 'force', None, _('force tag')),
5222 [('f', 'force', None, _('force tag')),
5255 ('l', 'local', None, _('make the tag local')),
5223 ('l', 'local', None, _('make the tag local')),
5256 ('r', 'rev', '', _('revision to tag'), _('REV')),
5224 ('r', 'rev', '', _('revision to tag'), _('REV')),
5257 ('', 'remove', None, _('remove a tag')),
5225 ('', 'remove', None, _('remove a tag')),
5258 # -l/--local is already there, commitopts cannot be used
5226 # -l/--local is already there, commitopts cannot be used
5259 ('e', 'edit', None, _('invoke editor on commit messages')),
5227 ('e', 'edit', None, _('invoke editor on commit messages')),
5260 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5228 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5261 ] + commitopts2,
5229 ] + commitopts2,
5262 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5230 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5263 def tag(ui, repo, name1, *names, **opts):
5231 def tag(ui, repo, name1, *names, **opts):
5264 """add one or more tags for the current or given revision
5232 """add one or more tags for the current or given revision
5265
5233
5266 Name a particular revision using <name>.
5234 Name a particular revision using <name>.
5267
5235
5268 Tags are used to name particular revisions of the repository and are
5236 Tags are used to name particular revisions of the repository and are
5269 very useful to compare different revisions, to go back to significant
5237 very useful to compare different revisions, to go back to significant
5270 earlier versions or to mark branch points as releases, etc. Changing
5238 earlier versions or to mark branch points as releases, etc. Changing
5271 an existing tag is normally disallowed; use -f/--force to override.
5239 an existing tag is normally disallowed; use -f/--force to override.
5272
5240
5273 If no revision is given, the parent of the working directory is
5241 If no revision is given, the parent of the working directory is
5274 used.
5242 used.
5275
5243
5276 To facilitate version control, distribution, and merging of tags,
5244 To facilitate version control, distribution, and merging of tags,
5277 they are stored as a file named ".hgtags" which is managed similarly
5245 they are stored as a file named ".hgtags" which is managed similarly
5278 to other project files and can be hand-edited if necessary. This
5246 to other project files and can be hand-edited if necessary. This
5279 also means that tagging creates a new commit. The file
5247 also means that tagging creates a new commit. The file
5280 ".hg/localtags" is used for local tags (not shared among
5248 ".hg/localtags" is used for local tags (not shared among
5281 repositories).
5249 repositories).
5282
5250
5283 Tag commits are usually made at the head of a branch. If the parent
5251 Tag commits are usually made at the head of a branch. If the parent
5284 of the working directory is not a branch head, :hg:`tag` aborts; use
5252 of the working directory is not a branch head, :hg:`tag` aborts; use
5285 -f/--force to force the tag commit to be based on a non-head
5253 -f/--force to force the tag commit to be based on a non-head
5286 changeset.
5254 changeset.
5287
5255
5288 See :hg:`help dates` for a list of formats valid for -d/--date.
5256 See :hg:`help dates` for a list of formats valid for -d/--date.
5289
5257
5290 Since tag names have priority over branch names during revision
5258 Since tag names have priority over branch names during revision
5291 lookup, using an existing branch name as a tag name is discouraged.
5259 lookup, using an existing branch name as a tag name is discouraged.
5292
5260
5293 Returns 0 on success.
5261 Returns 0 on success.
5294 """
5262 """
5295 wlock = lock = None
5263 wlock = lock = None
5296 try:
5264 try:
5297 wlock = repo.wlock()
5265 wlock = repo.wlock()
5298 lock = repo.lock()
5266 lock = repo.lock()
5299 rev_ = "."
5267 rev_ = "."
5300 names = [t.strip() for t in (name1,) + names]
5268 names = [t.strip() for t in (name1,) + names]
5301 if len(names) != len(set(names)):
5269 if len(names) != len(set(names)):
5302 raise error.Abort(_('tag names must be unique'))
5270 raise error.Abort(_('tag names must be unique'))
5303 for n in names:
5271 for n in names:
5304 scmutil.checknewlabel(repo, n, 'tag')
5272 scmutil.checknewlabel(repo, n, 'tag')
5305 if not n:
5273 if not n:
5306 raise error.Abort(_('tag names cannot consist entirely of '
5274 raise error.Abort(_('tag names cannot consist entirely of '
5307 'whitespace'))
5275 'whitespace'))
5308 if opts.get('rev') and opts.get('remove'):
5276 if opts.get('rev') and opts.get('remove'):
5309 raise error.Abort(_("--rev and --remove are incompatible"))
5277 raise error.Abort(_("--rev and --remove are incompatible"))
5310 if opts.get('rev'):
5278 if opts.get('rev'):
5311 rev_ = opts['rev']
5279 rev_ = opts['rev']
5312 message = opts.get('message')
5280 message = opts.get('message')
5313 if opts.get('remove'):
5281 if opts.get('remove'):
5314 if opts.get('local'):
5282 if opts.get('local'):
5315 expectedtype = 'local'
5283 expectedtype = 'local'
5316 else:
5284 else:
5317 expectedtype = 'global'
5285 expectedtype = 'global'
5318
5286
5319 for n in names:
5287 for n in names:
5320 if not repo.tagtype(n):
5288 if not repo.tagtype(n):
5321 raise error.Abort(_("tag '%s' does not exist") % n)
5289 raise error.Abort(_("tag '%s' does not exist") % n)
5322 if repo.tagtype(n) != expectedtype:
5290 if repo.tagtype(n) != expectedtype:
5323 if expectedtype == 'global':
5291 if expectedtype == 'global':
5324 raise error.Abort(_("tag '%s' is not a global tag") % n)
5292 raise error.Abort(_("tag '%s' is not a global tag") % n)
5325 else:
5293 else:
5326 raise error.Abort(_("tag '%s' is not a local tag") % n)
5294 raise error.Abort(_("tag '%s' is not a local tag") % n)
5327 rev_ = 'null'
5295 rev_ = 'null'
5328 if not message:
5296 if not message:
5329 # we don't translate commit messages
5297 # we don't translate commit messages
5330 message = 'Removed tag %s' % ', '.join(names)
5298 message = 'Removed tag %s' % ', '.join(names)
5331 elif not opts.get('force'):
5299 elif not opts.get('force'):
5332 for n in names:
5300 for n in names:
5333 if n in repo.tags():
5301 if n in repo.tags():
5334 raise error.Abort(_("tag '%s' already exists "
5302 raise error.Abort(_("tag '%s' already exists "
5335 "(use -f to force)") % n)
5303 "(use -f to force)") % n)
5336 if not opts.get('local'):
5304 if not opts.get('local'):
5337 p1, p2 = repo.dirstate.parents()
5305 p1, p2 = repo.dirstate.parents()
5338 if p2 != nullid:
5306 if p2 != nullid:
5339 raise error.Abort(_('uncommitted merge'))
5307 raise error.Abort(_('uncommitted merge'))
5340 bheads = repo.branchheads()
5308 bheads = repo.branchheads()
5341 if not opts.get('force') and bheads and p1 not in bheads:
5309 if not opts.get('force') and bheads and p1 not in bheads:
5342 raise error.Abort(_('working directory is not at a branch head '
5310 raise error.Abort(_('working directory is not at a branch head '
5343 '(use -f to force)'))
5311 '(use -f to force)'))
5344 r = scmutil.revsingle(repo, rev_).node()
5312 r = scmutil.revsingle(repo, rev_).node()
5345
5313
5346 if not message:
5314 if not message:
5347 # we don't translate commit messages
5315 # we don't translate commit messages
5348 message = ('Added tag %s for changeset %s' %
5316 message = ('Added tag %s for changeset %s' %
5349 (', '.join(names), short(r)))
5317 (', '.join(names), short(r)))
5350
5318
5351 date = opts.get('date')
5319 date = opts.get('date')
5352 if date:
5320 if date:
5353 date = util.parsedate(date)
5321 date = util.parsedate(date)
5354
5322
5355 if opts.get('remove'):
5323 if opts.get('remove'):
5356 editform = 'tag.remove'
5324 editform = 'tag.remove'
5357 else:
5325 else:
5358 editform = 'tag.add'
5326 editform = 'tag.add'
5359 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5327 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5360
5328
5361 # don't allow tagging the null rev
5329 # don't allow tagging the null rev
5362 if (not opts.get('remove') and
5330 if (not opts.get('remove') and
5363 scmutil.revsingle(repo, rev_).rev() == nullrev):
5331 scmutil.revsingle(repo, rev_).rev() == nullrev):
5364 raise error.Abort(_("cannot tag null revision"))
5332 raise error.Abort(_("cannot tag null revision"))
5365
5333
5366 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5334 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5367 editor=editor)
5335 editor=editor)
5368 finally:
5336 finally:
5369 release(lock, wlock)
5337 release(lock, wlock)
5370
5338
5371 @command('tags', formatteropts, '')
5339 @command('tags', formatteropts, '')
5372 def tags(ui, repo, **opts):
5340 def tags(ui, repo, **opts):
5373 """list repository tags
5341 """list repository tags
5374
5342
5375 This lists both regular and local tags. When the -v/--verbose
5343 This lists both regular and local tags. When the -v/--verbose
5376 switch is used, a third column "local" is printed for local tags.
5344 switch is used, a third column "local" is printed for local tags.
5377 When the -q/--quiet switch is used, only the tag name is printed.
5345 When the -q/--quiet switch is used, only the tag name is printed.
5378
5346
5379 Returns 0 on success.
5347 Returns 0 on success.
5380 """
5348 """
5381
5349
5382 fm = ui.formatter('tags', opts)
5350 fm = ui.formatter('tags', opts)
5383 hexfunc = fm.hexfunc
5351 hexfunc = fm.hexfunc
5384 tagtype = ""
5352 tagtype = ""
5385
5353
5386 for t, n in reversed(repo.tagslist()):
5354 for t, n in reversed(repo.tagslist()):
5387 hn = hexfunc(n)
5355 hn = hexfunc(n)
5388 label = 'tags.normal'
5356 label = 'tags.normal'
5389 tagtype = ''
5357 tagtype = ''
5390 if repo.tagtype(t) == 'local':
5358 if repo.tagtype(t) == 'local':
5391 label = 'tags.local'
5359 label = 'tags.local'
5392 tagtype = 'local'
5360 tagtype = 'local'
5393
5361
5394 fm.startitem()
5362 fm.startitem()
5395 fm.write('tag', '%s', t, label=label)
5363 fm.write('tag', '%s', t, label=label)
5396 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5364 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5397 fm.condwrite(not ui.quiet, 'rev node', fmt,
5365 fm.condwrite(not ui.quiet, 'rev node', fmt,
5398 repo.changelog.rev(n), hn, label=label)
5366 repo.changelog.rev(n), hn, label=label)
5399 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5367 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5400 tagtype, label=label)
5368 tagtype, label=label)
5401 fm.plain('\n')
5369 fm.plain('\n')
5402 fm.end()
5370 fm.end()
5403
5371
5404 @command('tip',
5372 @command('tip',
5405 [('p', 'patch', None, _('show patch')),
5373 [('p', 'patch', None, _('show patch')),
5406 ('g', 'git', None, _('use git extended diff format')),
5374 ('g', 'git', None, _('use git extended diff format')),
5407 ] + templateopts,
5375 ] + templateopts,
5408 _('[-p] [-g]'))
5376 _('[-p] [-g]'))
5409 def tip(ui, repo, **opts):
5377 def tip(ui, repo, **opts):
5410 """show the tip revision (DEPRECATED)
5378 """show the tip revision (DEPRECATED)
5411
5379
5412 The tip revision (usually just called the tip) is the changeset
5380 The tip revision (usually just called the tip) is the changeset
5413 most recently added to the repository (and therefore the most
5381 most recently added to the repository (and therefore the most
5414 recently changed head).
5382 recently changed head).
5415
5383
5416 If you have just made a commit, that commit will be the tip. If
5384 If you have just made a commit, that commit will be the tip. If
5417 you have just pulled changes from another repository, the tip of
5385 you have just pulled changes from another repository, the tip of
5418 that repository becomes the current tip. The "tip" tag is special
5386 that repository becomes the current tip. The "tip" tag is special
5419 and cannot be renamed or assigned to a different changeset.
5387 and cannot be renamed or assigned to a different changeset.
5420
5388
5421 This command is deprecated, please use :hg:`heads` instead.
5389 This command is deprecated, please use :hg:`heads` instead.
5422
5390
5423 Returns 0 on success.
5391 Returns 0 on success.
5424 """
5392 """
5425 displayer = cmdutil.show_changeset(ui, repo, opts)
5393 displayer = cmdutil.show_changeset(ui, repo, opts)
5426 displayer.show(repo['tip'])
5394 displayer.show(repo['tip'])
5427 displayer.close()
5395 displayer.close()
5428
5396
5429 @command('unbundle',
5397 @command('unbundle',
5430 [('u', 'update', None,
5398 [('u', 'update', None,
5431 _('update to new branch head if changesets were unbundled'))],
5399 _('update to new branch head if changesets were unbundled'))],
5432 _('[-u] FILE...'))
5400 _('[-u] FILE...'))
5433 def unbundle(ui, repo, fname1, *fnames, **opts):
5401 def unbundle(ui, repo, fname1, *fnames, **opts):
5434 """apply one or more changegroup files
5402 """apply one or more changegroup files
5435
5403
5436 Apply one or more compressed changegroup files generated by the
5404 Apply one or more compressed changegroup files generated by the
5437 bundle command.
5405 bundle command.
5438
5406
5439 Returns 0 on success, 1 if an update has unresolved files.
5407 Returns 0 on success, 1 if an update has unresolved files.
5440 """
5408 """
5441 fnames = (fname1,) + fnames
5409 fnames = (fname1,) + fnames
5442
5410
5443 with repo.lock():
5411 with repo.lock():
5444 for fname in fnames:
5412 for fname in fnames:
5445 f = hg.openpath(ui, fname)
5413 f = hg.openpath(ui, fname)
5446 gen = exchange.readbundle(ui, f, fname)
5414 gen = exchange.readbundle(ui, f, fname)
5447 if isinstance(gen, bundle2.unbundle20):
5415 if isinstance(gen, bundle2.unbundle20):
5448 tr = repo.transaction('unbundle')
5416 tr = repo.transaction('unbundle')
5449 try:
5417 try:
5450 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5418 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5451 url='bundle:' + fname)
5419 url='bundle:' + fname)
5452 tr.close()
5420 tr.close()
5453 except error.BundleUnknownFeatureError as exc:
5421 except error.BundleUnknownFeatureError as exc:
5454 raise error.Abort(_('%s: unknown bundle feature, %s')
5422 raise error.Abort(_('%s: unknown bundle feature, %s')
5455 % (fname, exc),
5423 % (fname, exc),
5456 hint=_("see https://mercurial-scm.org/"
5424 hint=_("see https://mercurial-scm.org/"
5457 "wiki/BundleFeature for more "
5425 "wiki/BundleFeature for more "
5458 "information"))
5426 "information"))
5459 finally:
5427 finally:
5460 if tr:
5428 if tr:
5461 tr.release()
5429 tr.release()
5462 changes = [r.get('return', 0)
5430 changes = [r.get('return', 0)
5463 for r in op.records['changegroup']]
5431 for r in op.records['changegroup']]
5464 modheads = changegroup.combineresults(changes)
5432 modheads = changegroup.combineresults(changes)
5465 elif isinstance(gen, streamclone.streamcloneapplier):
5433 elif isinstance(gen, streamclone.streamcloneapplier):
5466 raise error.Abort(
5434 raise error.Abort(
5467 _('packed bundles cannot be applied with '
5435 _('packed bundles cannot be applied with '
5468 '"hg unbundle"'),
5436 '"hg unbundle"'),
5469 hint=_('use "hg debugapplystreamclonebundle"'))
5437 hint=_('use "hg debugapplystreamclonebundle"'))
5470 else:
5438 else:
5471 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5439 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5472
5440
5473 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5441 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5474
5442
5475 @command('^update|up|checkout|co',
5443 @command('^update|up|checkout|co',
5476 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5444 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5477 ('c', 'check', None, _('require clean working directory')),
5445 ('c', 'check', None, _('require clean working directory')),
5478 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5446 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5479 ('r', 'rev', '', _('revision'), _('REV'))
5447 ('r', 'rev', '', _('revision'), _('REV'))
5480 ] + mergetoolopts,
5448 ] + mergetoolopts,
5481 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5449 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5482 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5450 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5483 tool=None):
5451 tool=None):
5484 """update working directory (or switch revisions)
5452 """update working directory (or switch revisions)
5485
5453
5486 Update the repository's working directory to the specified
5454 Update the repository's working directory to the specified
5487 changeset. If no changeset is specified, update to the tip of the
5455 changeset. If no changeset is specified, update to the tip of the
5488 current named branch and move the active bookmark (see :hg:`help
5456 current named branch and move the active bookmark (see :hg:`help
5489 bookmarks`).
5457 bookmarks`).
5490
5458
5491 Update sets the working directory's parent revision to the specified
5459 Update sets the working directory's parent revision to the specified
5492 changeset (see :hg:`help parents`).
5460 changeset (see :hg:`help parents`).
5493
5461
5494 If the changeset is not a descendant or ancestor of the working
5462 If the changeset is not a descendant or ancestor of the working
5495 directory's parent and there are uncommitted changes, the update is
5463 directory's parent and there are uncommitted changes, the update is
5496 aborted. With the -c/--check option, the working directory is checked
5464 aborted. With the -c/--check option, the working directory is checked
5497 for uncommitted changes; if none are found, the working directory is
5465 for uncommitted changes; if none are found, the working directory is
5498 updated to the specified changeset.
5466 updated to the specified changeset.
5499
5467
5500 .. container:: verbose
5468 .. container:: verbose
5501
5469
5502 The following rules apply when the working directory contains
5470 The following rules apply when the working directory contains
5503 uncommitted changes:
5471 uncommitted changes:
5504
5472
5505 1. If neither -c/--check nor -C/--clean is specified, and if
5473 1. If neither -c/--check nor -C/--clean is specified, and if
5506 the requested changeset is an ancestor or descendant of
5474 the requested changeset is an ancestor or descendant of
5507 the working directory's parent, the uncommitted changes
5475 the working directory's parent, the uncommitted changes
5508 are merged into the requested changeset and the merged
5476 are merged into the requested changeset and the merged
5509 result is left uncommitted. If the requested changeset is
5477 result is left uncommitted. If the requested changeset is
5510 not an ancestor or descendant (that is, it is on another
5478 not an ancestor or descendant (that is, it is on another
5511 branch), the update is aborted and the uncommitted changes
5479 branch), the update is aborted and the uncommitted changes
5512 are preserved.
5480 are preserved.
5513
5481
5514 2. With the -c/--check option, the update is aborted and the
5482 2. With the -c/--check option, the update is aborted and the
5515 uncommitted changes are preserved.
5483 uncommitted changes are preserved.
5516
5484
5517 3. With the -C/--clean option, uncommitted changes are discarded and
5485 3. With the -C/--clean option, uncommitted changes are discarded and
5518 the working directory is updated to the requested changeset.
5486 the working directory is updated to the requested changeset.
5519
5487
5520 To cancel an uncommitted merge (and lose your changes), use
5488 To cancel an uncommitted merge (and lose your changes), use
5521 :hg:`update --clean .`.
5489 :hg:`update --clean .`.
5522
5490
5523 Use null as the changeset to remove the working directory (like
5491 Use null as the changeset to remove the working directory (like
5524 :hg:`clone -U`).
5492 :hg:`clone -U`).
5525
5493
5526 If you want to revert just one file to an older revision, use
5494 If you want to revert just one file to an older revision, use
5527 :hg:`revert [-r REV] NAME`.
5495 :hg:`revert [-r REV] NAME`.
5528
5496
5529 See :hg:`help dates` for a list of formats valid for -d/--date.
5497 See :hg:`help dates` for a list of formats valid for -d/--date.
5530
5498
5531 Returns 0 on success, 1 if there are unresolved files.
5499 Returns 0 on success, 1 if there are unresolved files.
5532 """
5500 """
5533 if rev and node:
5501 if rev and node:
5534 raise error.Abort(_("please specify just one revision"))
5502 raise error.Abort(_("please specify just one revision"))
5535
5503
5536 if rev is None or rev == '':
5504 if rev is None or rev == '':
5537 rev = node
5505 rev = node
5538
5506
5539 if date and rev is not None:
5507 if date and rev is not None:
5540 raise error.Abort(_("you can't specify a revision and a date"))
5508 raise error.Abort(_("you can't specify a revision and a date"))
5541
5509
5542 if check and clean:
5510 if check and clean:
5543 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
5511 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
5544
5512
5545 with repo.wlock():
5513 with repo.wlock():
5546 cmdutil.clearunfinished(repo)
5514 cmdutil.clearunfinished(repo)
5547
5515
5548 if date:
5516 if date:
5549 rev = cmdutil.finddate(ui, repo, date)
5517 rev = cmdutil.finddate(ui, repo, date)
5550
5518
5551 # if we defined a bookmark, we have to remember the original name
5519 # if we defined a bookmark, we have to remember the original name
5552 brev = rev
5520 brev = rev
5553 rev = scmutil.revsingle(repo, rev, rev).rev()
5521 rev = scmutil.revsingle(repo, rev, rev).rev()
5554
5522
5555 if check:
5523 if check:
5556 cmdutil.bailifchanged(repo, merge=False)
5524 cmdutil.bailifchanged(repo, merge=False)
5557
5525
5558 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5526 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5559
5527
5560 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
5528 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
5561
5529
5562 @command('verify', [])
5530 @command('verify', [])
5563 def verify(ui, repo):
5531 def verify(ui, repo):
5564 """verify the integrity of the repository
5532 """verify the integrity of the repository
5565
5533
5566 Verify the integrity of the current repository.
5534 Verify the integrity of the current repository.
5567
5535
5568 This will perform an extensive check of the repository's
5536 This will perform an extensive check of the repository's
5569 integrity, validating the hashes and checksums of each entry in
5537 integrity, validating the hashes and checksums of each entry in
5570 the changelog, manifest, and tracked files, as well as the
5538 the changelog, manifest, and tracked files, as well as the
5571 integrity of their crosslinks and indices.
5539 integrity of their crosslinks and indices.
5572
5540
5573 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5541 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5574 for more information about recovery from corruption of the
5542 for more information about recovery from corruption of the
5575 repository.
5543 repository.
5576
5544
5577 Returns 0 on success, 1 if errors are encountered.
5545 Returns 0 on success, 1 if errors are encountered.
5578 """
5546 """
5579 return hg.verify(repo)
5547 return hg.verify(repo)
5580
5548
5581 @command('version', [] + formatteropts, norepo=True)
5549 @command('version', [] + formatteropts, norepo=True)
5582 def version_(ui, **opts):
5550 def version_(ui, **opts):
5583 """output version and copyright information"""
5551 """output version and copyright information"""
5584 fm = ui.formatter("version", opts)
5552 fm = ui.formatter("version", opts)
5585 fm.startitem()
5553 fm.startitem()
5586 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5554 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5587 util.version())
5555 util.version())
5588 license = _(
5556 license = _(
5589 "(see https://mercurial-scm.org for more information)\n"
5557 "(see https://mercurial-scm.org for more information)\n"
5590 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5558 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5591 "This is free software; see the source for copying conditions. "
5559 "This is free software; see the source for copying conditions. "
5592 "There is NO\nwarranty; "
5560 "There is NO\nwarranty; "
5593 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5561 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5594 )
5562 )
5595 if not ui.quiet:
5563 if not ui.quiet:
5596 fm.plain(license)
5564 fm.plain(license)
5597
5565
5598 if ui.verbose:
5566 if ui.verbose:
5599 fm.plain(_("\nEnabled extensions:\n\n"))
5567 fm.plain(_("\nEnabled extensions:\n\n"))
5600 # format names and versions into columns
5568 # format names and versions into columns
5601 names = []
5569 names = []
5602 vers = []
5570 vers = []
5603 isinternals = []
5571 isinternals = []
5604 for name, module in extensions.extensions():
5572 for name, module in extensions.extensions():
5605 names.append(name)
5573 names.append(name)
5606 vers.append(extensions.moduleversion(module) or None)
5574 vers.append(extensions.moduleversion(module) or None)
5607 isinternals.append(extensions.ismoduleinternal(module))
5575 isinternals.append(extensions.ismoduleinternal(module))
5608 fn = fm.nested("extensions")
5576 fn = fm.nested("extensions")
5609 if names:
5577 if names:
5610 namefmt = " %%-%ds " % max(len(n) for n in names)
5578 namefmt = " %%-%ds " % max(len(n) for n in names)
5611 places = [_("external"), _("internal")]
5579 places = [_("external"), _("internal")]
5612 for n, v, p in zip(names, vers, isinternals):
5580 for n, v, p in zip(names, vers, isinternals):
5613 fn.startitem()
5581 fn.startitem()
5614 fn.condwrite(ui.verbose, "name", namefmt, n)
5582 fn.condwrite(ui.verbose, "name", namefmt, n)
5615 if ui.verbose:
5583 if ui.verbose:
5616 fn.plain("%s " % places[p])
5584 fn.plain("%s " % places[p])
5617 fn.data(bundled=p)
5585 fn.data(bundled=p)
5618 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5586 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5619 if ui.verbose:
5587 if ui.verbose:
5620 fn.plain("\n")
5588 fn.plain("\n")
5621 fn.end()
5589 fn.end()
5622 fm.end()
5590 fm.end()
5623
5591
5624 def loadcmdtable(ui, name, cmdtable):
5592 def loadcmdtable(ui, name, cmdtable):
5625 """Load command functions from specified cmdtable
5593 """Load command functions from specified cmdtable
5626 """
5594 """
5627 overrides = [cmd for cmd in cmdtable if cmd in table]
5595 overrides = [cmd for cmd in cmdtable if cmd in table]
5628 if overrides:
5596 if overrides:
5629 ui.warn(_("extension '%s' overrides commands: %s\n")
5597 ui.warn(_("extension '%s' overrides commands: %s\n")
5630 % (name, " ".join(overrides)))
5598 % (name, " ".join(overrides)))
5631 table.update(cmdtable)
5599 table.update(cmdtable)
@@ -1,1879 +1,1910
1 # debugcommands.py - command processing for debug* commands
1 # debugcommands.py - command processing for debug* commands
2 #
2 #
3 # Copyright 2005-2016 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2016 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 socket
15 import socket
16 import string
16 import string
17 import sys
17 import sys
18 import tempfile
18 import tempfile
19 import time
19 import time
20
20
21 from .i18n import _
21 from .i18n import _
22 from .node import (
22 from .node import (
23 bin,
23 bin,
24 hex,
24 hex,
25 nullhex,
25 nullhex,
26 nullid,
26 nullid,
27 nullrev,
27 nullrev,
28 short,
28 short,
29 )
29 )
30 from . import (
30 from . import (
31 bundle2,
31 bundle2,
32 changegroup,
32 changegroup,
33 cmdutil,
33 cmdutil,
34 commands,
34 commands,
35 context,
35 context,
36 dagparser,
36 dagparser,
37 dagutil,
37 dagutil,
38 encoding,
38 encoding,
39 error,
39 error,
40 exchange,
40 exchange,
41 extensions,
41 extensions,
42 fileset,
42 fileset,
43 hg,
43 hg,
44 localrepo,
44 localrepo,
45 lock as lockmod,
45 lock as lockmod,
46 merge as mergemod,
46 merge as mergemod,
47 obsolete,
47 obsolete,
48 policy,
48 policy,
49 pvec,
49 pvec,
50 pycompat,
50 pycompat,
51 repair,
51 repair,
52 revlog,
52 revlog,
53 revset,
53 revset,
54 scmutil,
54 scmutil,
55 setdiscovery,
55 setdiscovery,
56 simplemerge,
56 simplemerge,
57 smartset,
57 smartset,
58 sslutil,
58 sslutil,
59 streamclone,
59 streamclone,
60 templater,
60 templater,
61 treediscovery,
61 treediscovery,
62 util,
62 util,
63 )
63 )
64
64
65 release = lockmod.release
65 release = lockmod.release
66
66
67 # We reuse the command table from commands because it is easier than
67 # We reuse the command table from commands because it is easier than
68 # teaching dispatch about multiple tables.
68 # teaching dispatch about multiple tables.
69 command = cmdutil.command(commands.table)
69 command = cmdutil.command(commands.table)
70
70
71 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
71 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
72 def debugancestor(ui, repo, *args):
72 def debugancestor(ui, repo, *args):
73 """find the ancestor revision of two revisions in a given index"""
73 """find the ancestor revision of two revisions in a given index"""
74 if len(args) == 3:
74 if len(args) == 3:
75 index, rev1, rev2 = args
75 index, rev1, rev2 = args
76 r = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False), index)
76 r = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False), index)
77 lookup = r.lookup
77 lookup = r.lookup
78 elif len(args) == 2:
78 elif len(args) == 2:
79 if not repo:
79 if not repo:
80 raise error.Abort(_('there is no Mercurial repository here '
80 raise error.Abort(_('there is no Mercurial repository here '
81 '(.hg not found)'))
81 '(.hg not found)'))
82 rev1, rev2 = args
82 rev1, rev2 = args
83 r = repo.changelog
83 r = repo.changelog
84 lookup = repo.lookup
84 lookup = repo.lookup
85 else:
85 else:
86 raise error.Abort(_('either two or three arguments required'))
86 raise error.Abort(_('either two or three arguments required'))
87 a = r.ancestor(lookup(rev1), lookup(rev2))
87 a = r.ancestor(lookup(rev1), lookup(rev2))
88 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
88 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
89
89
90 @command('debugapplystreamclonebundle', [], 'FILE')
90 @command('debugapplystreamclonebundle', [], 'FILE')
91 def debugapplystreamclonebundle(ui, repo, fname):
91 def debugapplystreamclonebundle(ui, repo, fname):
92 """apply a stream clone bundle file"""
92 """apply a stream clone bundle file"""
93 f = hg.openpath(ui, fname)
93 f = hg.openpath(ui, fname)
94 gen = exchange.readbundle(ui, f, fname)
94 gen = exchange.readbundle(ui, f, fname)
95 gen.apply(repo)
95 gen.apply(repo)
96
96
97 @command('debugbuilddag',
97 @command('debugbuilddag',
98 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
98 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
99 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
99 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
100 ('n', 'new-file', None, _('add new file at each rev'))],
100 ('n', 'new-file', None, _('add new file at each rev'))],
101 _('[OPTION]... [TEXT]'))
101 _('[OPTION]... [TEXT]'))
102 def debugbuilddag(ui, repo, text=None,
102 def debugbuilddag(ui, repo, text=None,
103 mergeable_file=False,
103 mergeable_file=False,
104 overwritten_file=False,
104 overwritten_file=False,
105 new_file=False):
105 new_file=False):
106 """builds a repo with a given DAG from scratch in the current empty repo
106 """builds a repo with a given DAG from scratch in the current empty repo
107
107
108 The description of the DAG is read from stdin if not given on the
108 The description of the DAG is read from stdin if not given on the
109 command line.
109 command line.
110
110
111 Elements:
111 Elements:
112
112
113 - "+n" is a linear run of n nodes based on the current default parent
113 - "+n" is a linear run of n nodes based on the current default parent
114 - "." is a single node based on the current default parent
114 - "." is a single node based on the current default parent
115 - "$" resets the default parent to null (implied at the start);
115 - "$" resets the default parent to null (implied at the start);
116 otherwise the default parent is always the last node created
116 otherwise the default parent is always the last node created
117 - "<p" sets the default parent to the backref p
117 - "<p" sets the default parent to the backref p
118 - "*p" is a fork at parent p, which is a backref
118 - "*p" is a fork at parent p, which is a backref
119 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
119 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
120 - "/p2" is a merge of the preceding node and p2
120 - "/p2" is a merge of the preceding node and p2
121 - ":tag" defines a local tag for the preceding node
121 - ":tag" defines a local tag for the preceding node
122 - "@branch" sets the named branch for subsequent nodes
122 - "@branch" sets the named branch for subsequent nodes
123 - "#...\\n" is a comment up to the end of the line
123 - "#...\\n" is a comment up to the end of the line
124
124
125 Whitespace between the above elements is ignored.
125 Whitespace between the above elements is ignored.
126
126
127 A backref is either
127 A backref is either
128
128
129 - a number n, which references the node curr-n, where curr is the current
129 - a number n, which references the node curr-n, where curr is the current
130 node, or
130 node, or
131 - the name of a local tag you placed earlier using ":tag", or
131 - the name of a local tag you placed earlier using ":tag", or
132 - empty to denote the default parent.
132 - empty to denote the default parent.
133
133
134 All string valued-elements are either strictly alphanumeric, or must
134 All string valued-elements are either strictly alphanumeric, or must
135 be enclosed in double quotes ("..."), with "\\" as escape character.
135 be enclosed in double quotes ("..."), with "\\" as escape character.
136 """
136 """
137
137
138 if text is None:
138 if text is None:
139 ui.status(_("reading DAG from stdin\n"))
139 ui.status(_("reading DAG from stdin\n"))
140 text = ui.fin.read()
140 text = ui.fin.read()
141
141
142 cl = repo.changelog
142 cl = repo.changelog
143 if len(cl) > 0:
143 if len(cl) > 0:
144 raise error.Abort(_('repository is not empty'))
144 raise error.Abort(_('repository is not empty'))
145
145
146 # determine number of revs in DAG
146 # determine number of revs in DAG
147 total = 0
147 total = 0
148 for type, data in dagparser.parsedag(text):
148 for type, data in dagparser.parsedag(text):
149 if type == 'n':
149 if type == 'n':
150 total += 1
150 total += 1
151
151
152 if mergeable_file:
152 if mergeable_file:
153 linesperrev = 2
153 linesperrev = 2
154 # make a file with k lines per rev
154 # make a file with k lines per rev
155 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
155 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
156 initialmergedlines.append("")
156 initialmergedlines.append("")
157
157
158 tags = []
158 tags = []
159
159
160 wlock = lock = tr = None
160 wlock = lock = tr = None
161 try:
161 try:
162 wlock = repo.wlock()
162 wlock = repo.wlock()
163 lock = repo.lock()
163 lock = repo.lock()
164 tr = repo.transaction("builddag")
164 tr = repo.transaction("builddag")
165
165
166 at = -1
166 at = -1
167 atbranch = 'default'
167 atbranch = 'default'
168 nodeids = []
168 nodeids = []
169 id = 0
169 id = 0
170 ui.progress(_('building'), id, unit=_('revisions'), total=total)
170 ui.progress(_('building'), id, unit=_('revisions'), total=total)
171 for type, data in dagparser.parsedag(text):
171 for type, data in dagparser.parsedag(text):
172 if type == 'n':
172 if type == 'n':
173 ui.note(('node %s\n' % str(data)))
173 ui.note(('node %s\n' % str(data)))
174 id, ps = data
174 id, ps = data
175
175
176 files = []
176 files = []
177 fctxs = {}
177 fctxs = {}
178
178
179 p2 = None
179 p2 = None
180 if mergeable_file:
180 if mergeable_file:
181 fn = "mf"
181 fn = "mf"
182 p1 = repo[ps[0]]
182 p1 = repo[ps[0]]
183 if len(ps) > 1:
183 if len(ps) > 1:
184 p2 = repo[ps[1]]
184 p2 = repo[ps[1]]
185 pa = p1.ancestor(p2)
185 pa = p1.ancestor(p2)
186 base, local, other = [x[fn].data() for x in (pa, p1,
186 base, local, other = [x[fn].data() for x in (pa, p1,
187 p2)]
187 p2)]
188 m3 = simplemerge.Merge3Text(base, local, other)
188 m3 = simplemerge.Merge3Text(base, local, other)
189 ml = [l.strip() for l in m3.merge_lines()]
189 ml = [l.strip() for l in m3.merge_lines()]
190 ml.append("")
190 ml.append("")
191 elif at > 0:
191 elif at > 0:
192 ml = p1[fn].data().split("\n")
192 ml = p1[fn].data().split("\n")
193 else:
193 else:
194 ml = initialmergedlines
194 ml = initialmergedlines
195 ml[id * linesperrev] += " r%i" % id
195 ml[id * linesperrev] += " r%i" % id
196 mergedtext = "\n".join(ml)
196 mergedtext = "\n".join(ml)
197 files.append(fn)
197 files.append(fn)
198 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
198 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
199
199
200 if overwritten_file:
200 if overwritten_file:
201 fn = "of"
201 fn = "of"
202 files.append(fn)
202 files.append(fn)
203 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
203 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
204
204
205 if new_file:
205 if new_file:
206 fn = "nf%i" % id
206 fn = "nf%i" % id
207 files.append(fn)
207 files.append(fn)
208 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
208 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
209 if len(ps) > 1:
209 if len(ps) > 1:
210 if not p2:
210 if not p2:
211 p2 = repo[ps[1]]
211 p2 = repo[ps[1]]
212 for fn in p2:
212 for fn in p2:
213 if fn.startswith("nf"):
213 if fn.startswith("nf"):
214 files.append(fn)
214 files.append(fn)
215 fctxs[fn] = p2[fn]
215 fctxs[fn] = p2[fn]
216
216
217 def fctxfn(repo, cx, path):
217 def fctxfn(repo, cx, path):
218 return fctxs.get(path)
218 return fctxs.get(path)
219
219
220 if len(ps) == 0 or ps[0] < 0:
220 if len(ps) == 0 or ps[0] < 0:
221 pars = [None, None]
221 pars = [None, None]
222 elif len(ps) == 1:
222 elif len(ps) == 1:
223 pars = [nodeids[ps[0]], None]
223 pars = [nodeids[ps[0]], None]
224 else:
224 else:
225 pars = [nodeids[p] for p in ps]
225 pars = [nodeids[p] for p in ps]
226 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
226 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
227 date=(id, 0),
227 date=(id, 0),
228 user="debugbuilddag",
228 user="debugbuilddag",
229 extra={'branch': atbranch})
229 extra={'branch': atbranch})
230 nodeid = repo.commitctx(cx)
230 nodeid = repo.commitctx(cx)
231 nodeids.append(nodeid)
231 nodeids.append(nodeid)
232 at = id
232 at = id
233 elif type == 'l':
233 elif type == 'l':
234 id, name = data
234 id, name = data
235 ui.note(('tag %s\n' % name))
235 ui.note(('tag %s\n' % name))
236 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
236 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
237 elif type == 'a':
237 elif type == 'a':
238 ui.note(('branch %s\n' % data))
238 ui.note(('branch %s\n' % data))
239 atbranch = data
239 atbranch = data
240 ui.progress(_('building'), id, unit=_('revisions'), total=total)
240 ui.progress(_('building'), id, unit=_('revisions'), total=total)
241 tr.close()
241 tr.close()
242
242
243 if tags:
243 if tags:
244 repo.vfs.write("localtags", "".join(tags))
244 repo.vfs.write("localtags", "".join(tags))
245 finally:
245 finally:
246 ui.progress(_('building'), None)
246 ui.progress(_('building'), None)
247 release(tr, lock, wlock)
247 release(tr, lock, wlock)
248
248
249 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
249 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
250 indent_string = ' ' * indent
250 indent_string = ' ' * indent
251 if all:
251 if all:
252 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
252 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
253 % indent_string)
253 % indent_string)
254
254
255 def showchunks(named):
255 def showchunks(named):
256 ui.write("\n%s%s\n" % (indent_string, named))
256 ui.write("\n%s%s\n" % (indent_string, named))
257 chain = None
257 chain = None
258 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
258 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
259 node = chunkdata['node']
259 node = chunkdata['node']
260 p1 = chunkdata['p1']
260 p1 = chunkdata['p1']
261 p2 = chunkdata['p2']
261 p2 = chunkdata['p2']
262 cs = chunkdata['cs']
262 cs = chunkdata['cs']
263 deltabase = chunkdata['deltabase']
263 deltabase = chunkdata['deltabase']
264 delta = chunkdata['delta']
264 delta = chunkdata['delta']
265 ui.write("%s%s %s %s %s %s %s\n" %
265 ui.write("%s%s %s %s %s %s %s\n" %
266 (indent_string, hex(node), hex(p1), hex(p2),
266 (indent_string, hex(node), hex(p1), hex(p2),
267 hex(cs), hex(deltabase), len(delta)))
267 hex(cs), hex(deltabase), len(delta)))
268 chain = node
268 chain = node
269
269
270 chunkdata = gen.changelogheader()
270 chunkdata = gen.changelogheader()
271 showchunks("changelog")
271 showchunks("changelog")
272 chunkdata = gen.manifestheader()
272 chunkdata = gen.manifestheader()
273 showchunks("manifest")
273 showchunks("manifest")
274 for chunkdata in iter(gen.filelogheader, {}):
274 for chunkdata in iter(gen.filelogheader, {}):
275 fname = chunkdata['filename']
275 fname = chunkdata['filename']
276 showchunks(fname)
276 showchunks(fname)
277 else:
277 else:
278 if isinstance(gen, bundle2.unbundle20):
278 if isinstance(gen, bundle2.unbundle20):
279 raise error.Abort(_('use debugbundle2 for this file'))
279 raise error.Abort(_('use debugbundle2 for this file'))
280 chunkdata = gen.changelogheader()
280 chunkdata = gen.changelogheader()
281 chain = None
281 chain = None
282 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
282 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
283 node = chunkdata['node']
283 node = chunkdata['node']
284 ui.write("%s%s\n" % (indent_string, hex(node)))
284 ui.write("%s%s\n" % (indent_string, hex(node)))
285 chain = node
285 chain = node
286
286
287 def _debugbundle2(ui, gen, all=None, **opts):
287 def _debugbundle2(ui, gen, all=None, **opts):
288 """lists the contents of a bundle2"""
288 """lists the contents of a bundle2"""
289 if not isinstance(gen, bundle2.unbundle20):
289 if not isinstance(gen, bundle2.unbundle20):
290 raise error.Abort(_('not a bundle2 file'))
290 raise error.Abort(_('not a bundle2 file'))
291 ui.write(('Stream params: %s\n' % repr(gen.params)))
291 ui.write(('Stream params: %s\n' % repr(gen.params)))
292 for part in gen.iterparts():
292 for part in gen.iterparts():
293 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
293 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
294 if part.type == 'changegroup':
294 if part.type == 'changegroup':
295 version = part.params.get('version', '01')
295 version = part.params.get('version', '01')
296 cg = changegroup.getunbundler(version, part, 'UN')
296 cg = changegroup.getunbundler(version, part, 'UN')
297 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
297 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
298
298
299 @command('debugbundle',
299 @command('debugbundle',
300 [('a', 'all', None, _('show all details')),
300 [('a', 'all', None, _('show all details')),
301 ('', 'spec', None, _('print the bundlespec of the bundle'))],
301 ('', 'spec', None, _('print the bundlespec of the bundle'))],
302 _('FILE'),
302 _('FILE'),
303 norepo=True)
303 norepo=True)
304 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
304 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
305 """lists the contents of a bundle"""
305 """lists the contents of a bundle"""
306 with hg.openpath(ui, bundlepath) as f:
306 with hg.openpath(ui, bundlepath) as f:
307 if spec:
307 if spec:
308 spec = exchange.getbundlespec(ui, f)
308 spec = exchange.getbundlespec(ui, f)
309 ui.write('%s\n' % spec)
309 ui.write('%s\n' % spec)
310 return
310 return
311
311
312 gen = exchange.readbundle(ui, f, bundlepath)
312 gen = exchange.readbundle(ui, f, bundlepath)
313 if isinstance(gen, bundle2.unbundle20):
313 if isinstance(gen, bundle2.unbundle20):
314 return _debugbundle2(ui, gen, all=all, **opts)
314 return _debugbundle2(ui, gen, all=all, **opts)
315 _debugchangegroup(ui, gen, all=all, **opts)
315 _debugchangegroup(ui, gen, all=all, **opts)
316
316
317 @command('debugcheckstate', [], '')
317 @command('debugcheckstate', [], '')
318 def debugcheckstate(ui, repo):
318 def debugcheckstate(ui, repo):
319 """validate the correctness of the current dirstate"""
319 """validate the correctness of the current dirstate"""
320 parent1, parent2 = repo.dirstate.parents()
320 parent1, parent2 = repo.dirstate.parents()
321 m1 = repo[parent1].manifest()
321 m1 = repo[parent1].manifest()
322 m2 = repo[parent2].manifest()
322 m2 = repo[parent2].manifest()
323 errors = 0
323 errors = 0
324 for f in repo.dirstate:
324 for f in repo.dirstate:
325 state = repo.dirstate[f]
325 state = repo.dirstate[f]
326 if state in "nr" and f not in m1:
326 if state in "nr" and f not in m1:
327 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
327 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
328 errors += 1
328 errors += 1
329 if state in "a" and f in m1:
329 if state in "a" and f in m1:
330 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
330 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
331 errors += 1
331 errors += 1
332 if state in "m" and f not in m1 and f not in m2:
332 if state in "m" and f not in m1 and f not in m2:
333 ui.warn(_("%s in state %s, but not in either manifest\n") %
333 ui.warn(_("%s in state %s, but not in either manifest\n") %
334 (f, state))
334 (f, state))
335 errors += 1
335 errors += 1
336 for f in m1:
336 for f in m1:
337 state = repo.dirstate[f]
337 state = repo.dirstate[f]
338 if state not in "nrm":
338 if state not in "nrm":
339 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
339 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
340 errors += 1
340 errors += 1
341 if errors:
341 if errors:
342 error = _(".hg/dirstate inconsistent with current parent's manifest")
342 error = _(".hg/dirstate inconsistent with current parent's manifest")
343 raise error.Abort(error)
343 raise error.Abort(error)
344
344
345 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
345 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
346 def debugcommands(ui, cmd='', *args):
346 def debugcommands(ui, cmd='', *args):
347 """list all available commands and options"""
347 """list all available commands and options"""
348 for cmd, vals in sorted(commands.table.iteritems()):
348 for cmd, vals in sorted(commands.table.iteritems()):
349 cmd = cmd.split('|')[0].strip('^')
349 cmd = cmd.split('|')[0].strip('^')
350 opts = ', '.join([i[1] for i in vals[1]])
350 opts = ', '.join([i[1] for i in vals[1]])
351 ui.write('%s: %s\n' % (cmd, opts))
351 ui.write('%s: %s\n' % (cmd, opts))
352
352
353 @command('debugcomplete',
353 @command('debugcomplete',
354 [('o', 'options', None, _('show the command options'))],
354 [('o', 'options', None, _('show the command options'))],
355 _('[-o] CMD'),
355 _('[-o] CMD'),
356 norepo=True)
356 norepo=True)
357 def debugcomplete(ui, cmd='', **opts):
357 def debugcomplete(ui, cmd='', **opts):
358 """returns the completion list associated with the given command"""
358 """returns the completion list associated with the given command"""
359
359
360 if opts.get('options'):
360 if opts.get('options'):
361 options = []
361 options = []
362 otables = [commands.globalopts]
362 otables = [commands.globalopts]
363 if cmd:
363 if cmd:
364 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
364 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
365 otables.append(entry[1])
365 otables.append(entry[1])
366 for t in otables:
366 for t in otables:
367 for o in t:
367 for o in t:
368 if "(DEPRECATED)" in o[3]:
368 if "(DEPRECATED)" in o[3]:
369 continue
369 continue
370 if o[0]:
370 if o[0]:
371 options.append('-%s' % o[0])
371 options.append('-%s' % o[0])
372 options.append('--%s' % o[1])
372 options.append('--%s' % o[1])
373 ui.write("%s\n" % "\n".join(options))
373 ui.write("%s\n" % "\n".join(options))
374 return
374 return
375
375
376 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, commands.table)
376 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, commands.table)
377 if ui.verbose:
377 if ui.verbose:
378 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
378 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
379 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
379 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
380
380
381 @command('debugcreatestreamclonebundle', [], 'FILE')
381 @command('debugcreatestreamclonebundle', [], 'FILE')
382 def debugcreatestreamclonebundle(ui, repo, fname):
382 def debugcreatestreamclonebundle(ui, repo, fname):
383 """create a stream clone bundle file
383 """create a stream clone bundle file
384
384
385 Stream bundles are special bundles that are essentially archives of
385 Stream bundles are special bundles that are essentially archives of
386 revlog files. They are commonly used for cloning very quickly.
386 revlog files. They are commonly used for cloning very quickly.
387 """
387 """
388 requirements, gen = streamclone.generatebundlev1(repo)
388 requirements, gen = streamclone.generatebundlev1(repo)
389 changegroup.writechunks(ui, gen, fname)
389 changegroup.writechunks(ui, gen, fname)
390
390
391 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
391 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
392
392
393 @command('debugdag',
393 @command('debugdag',
394 [('t', 'tags', None, _('use tags as labels')),
394 [('t', 'tags', None, _('use tags as labels')),
395 ('b', 'branches', None, _('annotate with branch names')),
395 ('b', 'branches', None, _('annotate with branch names')),
396 ('', 'dots', None, _('use dots for runs')),
396 ('', 'dots', None, _('use dots for runs')),
397 ('s', 'spaces', None, _('separate elements by spaces'))],
397 ('s', 'spaces', None, _('separate elements by spaces'))],
398 _('[OPTION]... [FILE [REV]...]'),
398 _('[OPTION]... [FILE [REV]...]'),
399 optionalrepo=True)
399 optionalrepo=True)
400 def debugdag(ui, repo, file_=None, *revs, **opts):
400 def debugdag(ui, repo, file_=None, *revs, **opts):
401 """format the changelog or an index DAG as a concise textual description
401 """format the changelog or an index DAG as a concise textual description
402
402
403 If you pass a revlog index, the revlog's DAG is emitted. If you list
403 If you pass a revlog index, the revlog's DAG is emitted. If you list
404 revision numbers, they get labeled in the output as rN.
404 revision numbers, they get labeled in the output as rN.
405
405
406 Otherwise, the changelog DAG of the current repo is emitted.
406 Otherwise, the changelog DAG of the current repo is emitted.
407 """
407 """
408 spaces = opts.get('spaces')
408 spaces = opts.get('spaces')
409 dots = opts.get('dots')
409 dots = opts.get('dots')
410 if file_:
410 if file_:
411 rlog = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False),
411 rlog = revlog.revlog(scmutil.opener(pycompat.getcwd(), audit=False),
412 file_)
412 file_)
413 revs = set((int(r) for r in revs))
413 revs = set((int(r) for r in revs))
414 def events():
414 def events():
415 for r in rlog:
415 for r in rlog:
416 yield 'n', (r, list(p for p in rlog.parentrevs(r)
416 yield 'n', (r, list(p for p in rlog.parentrevs(r)
417 if p != -1))
417 if p != -1))
418 if r in revs:
418 if r in revs:
419 yield 'l', (r, "r%i" % r)
419 yield 'l', (r, "r%i" % r)
420 elif repo:
420 elif repo:
421 cl = repo.changelog
421 cl = repo.changelog
422 tags = opts.get('tags')
422 tags = opts.get('tags')
423 branches = opts.get('branches')
423 branches = opts.get('branches')
424 if tags:
424 if tags:
425 labels = {}
425 labels = {}
426 for l, n in repo.tags().items():
426 for l, n in repo.tags().items():
427 labels.setdefault(cl.rev(n), []).append(l)
427 labels.setdefault(cl.rev(n), []).append(l)
428 def events():
428 def events():
429 b = "default"
429 b = "default"
430 for r in cl:
430 for r in cl:
431 if branches:
431 if branches:
432 newb = cl.read(cl.node(r))[5]['branch']
432 newb = cl.read(cl.node(r))[5]['branch']
433 if newb != b:
433 if newb != b:
434 yield 'a', newb
434 yield 'a', newb
435 b = newb
435 b = newb
436 yield 'n', (r, list(p for p in cl.parentrevs(r)
436 yield 'n', (r, list(p for p in cl.parentrevs(r)
437 if p != -1))
437 if p != -1))
438 if tags:
438 if tags:
439 ls = labels.get(r)
439 ls = labels.get(r)
440 if ls:
440 if ls:
441 for l in ls:
441 for l in ls:
442 yield 'l', (r, l)
442 yield 'l', (r, l)
443 else:
443 else:
444 raise error.Abort(_('need repo for changelog dag'))
444 raise error.Abort(_('need repo for changelog dag'))
445
445
446 for line in dagparser.dagtextlines(events(),
446 for line in dagparser.dagtextlines(events(),
447 addspaces=spaces,
447 addspaces=spaces,
448 wraplabels=True,
448 wraplabels=True,
449 wrapannotations=True,
449 wrapannotations=True,
450 wrapnonlinear=dots,
450 wrapnonlinear=dots,
451 usedots=dots,
451 usedots=dots,
452 maxlinewidth=70):
452 maxlinewidth=70):
453 ui.write(line)
453 ui.write(line)
454 ui.write("\n")
454 ui.write("\n")
455
455
456 @command('debugdata', commands.debugrevlogopts, _('-c|-m|FILE REV'))
456 @command('debugdata', commands.debugrevlogopts, _('-c|-m|FILE REV'))
457 def debugdata(ui, repo, file_, rev=None, **opts):
457 def debugdata(ui, repo, file_, rev=None, **opts):
458 """dump the contents of a data file revision"""
458 """dump the contents of a data file revision"""
459 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
459 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
460 if rev is not None:
460 if rev is not None:
461 raise error.CommandError('debugdata', _('invalid arguments'))
461 raise error.CommandError('debugdata', _('invalid arguments'))
462 file_, rev = None, file_
462 file_, rev = None, file_
463 elif rev is None:
463 elif rev is None:
464 raise error.CommandError('debugdata', _('invalid arguments'))
464 raise error.CommandError('debugdata', _('invalid arguments'))
465 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
465 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
466 try:
466 try:
467 ui.write(r.revision(r.lookup(rev), raw=True))
467 ui.write(r.revision(r.lookup(rev), raw=True))
468 except KeyError:
468 except KeyError:
469 raise error.Abort(_('invalid revision identifier %s') % rev)
469 raise error.Abort(_('invalid revision identifier %s') % rev)
470
470
471 @command('debugdate',
471 @command('debugdate',
472 [('e', 'extended', None, _('try extended date formats'))],
472 [('e', 'extended', None, _('try extended date formats'))],
473 _('[-e] DATE [RANGE]'),
473 _('[-e] DATE [RANGE]'),
474 norepo=True, optionalrepo=True)
474 norepo=True, optionalrepo=True)
475 def debugdate(ui, date, range=None, **opts):
475 def debugdate(ui, date, range=None, **opts):
476 """parse and display a date"""
476 """parse and display a date"""
477 if opts["extended"]:
477 if opts["extended"]:
478 d = util.parsedate(date, util.extendeddateformats)
478 d = util.parsedate(date, util.extendeddateformats)
479 else:
479 else:
480 d = util.parsedate(date)
480 d = util.parsedate(date)
481 ui.write(("internal: %s %s\n") % d)
481 ui.write(("internal: %s %s\n") % d)
482 ui.write(("standard: %s\n") % util.datestr(d))
482 ui.write(("standard: %s\n") % util.datestr(d))
483 if range:
483 if range:
484 m = util.matchdate(range)
484 m = util.matchdate(range)
485 ui.write(("match: %s\n") % m(d[0]))
485 ui.write(("match: %s\n") % m(d[0]))
486
486
487 @command('debugdeltachain',
487 @command('debugdeltachain',
488 commands.debugrevlogopts + commands.formatteropts,
488 commands.debugrevlogopts + commands.formatteropts,
489 _('-c|-m|FILE'),
489 _('-c|-m|FILE'),
490 optionalrepo=True)
490 optionalrepo=True)
491 def debugdeltachain(ui, repo, file_=None, **opts):
491 def debugdeltachain(ui, repo, file_=None, **opts):
492 """dump information about delta chains in a revlog
492 """dump information about delta chains in a revlog
493
493
494 Output can be templatized. Available template keywords are:
494 Output can be templatized. Available template keywords are:
495
495
496 :``rev``: revision number
496 :``rev``: revision number
497 :``chainid``: delta chain identifier (numbered by unique base)
497 :``chainid``: delta chain identifier (numbered by unique base)
498 :``chainlen``: delta chain length to this revision
498 :``chainlen``: delta chain length to this revision
499 :``prevrev``: previous revision in delta chain
499 :``prevrev``: previous revision in delta chain
500 :``deltatype``: role of delta / how it was computed
500 :``deltatype``: role of delta / how it was computed
501 :``compsize``: compressed size of revision
501 :``compsize``: compressed size of revision
502 :``uncompsize``: uncompressed size of revision
502 :``uncompsize``: uncompressed size of revision
503 :``chainsize``: total size of compressed revisions in chain
503 :``chainsize``: total size of compressed revisions in chain
504 :``chainratio``: total chain size divided by uncompressed revision size
504 :``chainratio``: total chain size divided by uncompressed revision size
505 (new delta chains typically start at ratio 2.00)
505 (new delta chains typically start at ratio 2.00)
506 :``lindist``: linear distance from base revision in delta chain to end
506 :``lindist``: linear distance from base revision in delta chain to end
507 of this revision
507 of this revision
508 :``extradist``: total size of revisions not part of this delta chain from
508 :``extradist``: total size of revisions not part of this delta chain from
509 base of delta chain to end of this revision; a measurement
509 base of delta chain to end of this revision; a measurement
510 of how much extra data we need to read/seek across to read
510 of how much extra data we need to read/seek across to read
511 the delta chain for this revision
511 the delta chain for this revision
512 :``extraratio``: extradist divided by chainsize; another representation of
512 :``extraratio``: extradist divided by chainsize; another representation of
513 how much unrelated data is needed to load this delta chain
513 how much unrelated data is needed to load this delta chain
514 """
514 """
515 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
515 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
516 index = r.index
516 index = r.index
517 generaldelta = r.version & revlog.REVLOGGENERALDELTA
517 generaldelta = r.version & revlog.REVLOGGENERALDELTA
518
518
519 def revinfo(rev):
519 def revinfo(rev):
520 e = index[rev]
520 e = index[rev]
521 compsize = e[1]
521 compsize = e[1]
522 uncompsize = e[2]
522 uncompsize = e[2]
523 chainsize = 0
523 chainsize = 0
524
524
525 if generaldelta:
525 if generaldelta:
526 if e[3] == e[5]:
526 if e[3] == e[5]:
527 deltatype = 'p1'
527 deltatype = 'p1'
528 elif e[3] == e[6]:
528 elif e[3] == e[6]:
529 deltatype = 'p2'
529 deltatype = 'p2'
530 elif e[3] == rev - 1:
530 elif e[3] == rev - 1:
531 deltatype = 'prev'
531 deltatype = 'prev'
532 elif e[3] == rev:
532 elif e[3] == rev:
533 deltatype = 'base'
533 deltatype = 'base'
534 else:
534 else:
535 deltatype = 'other'
535 deltatype = 'other'
536 else:
536 else:
537 if e[3] == rev:
537 if e[3] == rev:
538 deltatype = 'base'
538 deltatype = 'base'
539 else:
539 else:
540 deltatype = 'prev'
540 deltatype = 'prev'
541
541
542 chain = r._deltachain(rev)[0]
542 chain = r._deltachain(rev)[0]
543 for iterrev in chain:
543 for iterrev in chain:
544 e = index[iterrev]
544 e = index[iterrev]
545 chainsize += e[1]
545 chainsize += e[1]
546
546
547 return compsize, uncompsize, deltatype, chain, chainsize
547 return compsize, uncompsize, deltatype, chain, chainsize
548
548
549 fm = ui.formatter('debugdeltachain', opts)
549 fm = ui.formatter('debugdeltachain', opts)
550
550
551 fm.plain(' rev chain# chainlen prev delta '
551 fm.plain(' rev chain# chainlen prev delta '
552 'size rawsize chainsize ratio lindist extradist '
552 'size rawsize chainsize ratio lindist extradist '
553 'extraratio\n')
553 'extraratio\n')
554
554
555 chainbases = {}
555 chainbases = {}
556 for rev in r:
556 for rev in r:
557 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
557 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
558 chainbase = chain[0]
558 chainbase = chain[0]
559 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
559 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
560 basestart = r.start(chainbase)
560 basestart = r.start(chainbase)
561 revstart = r.start(rev)
561 revstart = r.start(rev)
562 lineardist = revstart + comp - basestart
562 lineardist = revstart + comp - basestart
563 extradist = lineardist - chainsize
563 extradist = lineardist - chainsize
564 try:
564 try:
565 prevrev = chain[-2]
565 prevrev = chain[-2]
566 except IndexError:
566 except IndexError:
567 prevrev = -1
567 prevrev = -1
568
568
569 chainratio = float(chainsize) / float(uncomp)
569 chainratio = float(chainsize) / float(uncomp)
570 extraratio = float(extradist) / float(chainsize)
570 extraratio = float(extradist) / float(chainsize)
571
571
572 fm.startitem()
572 fm.startitem()
573 fm.write('rev chainid chainlen prevrev deltatype compsize '
573 fm.write('rev chainid chainlen prevrev deltatype compsize '
574 'uncompsize chainsize chainratio lindist extradist '
574 'uncompsize chainsize chainratio lindist extradist '
575 'extraratio',
575 'extraratio',
576 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
576 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
577 rev, chainid, len(chain), prevrev, deltatype, comp,
577 rev, chainid, len(chain), prevrev, deltatype, comp,
578 uncomp, chainsize, chainratio, lineardist, extradist,
578 uncomp, chainsize, chainratio, lineardist, extradist,
579 extraratio,
579 extraratio,
580 rev=rev, chainid=chainid, chainlen=len(chain),
580 rev=rev, chainid=chainid, chainlen=len(chain),
581 prevrev=prevrev, deltatype=deltatype, compsize=comp,
581 prevrev=prevrev, deltatype=deltatype, compsize=comp,
582 uncompsize=uncomp, chainsize=chainsize,
582 uncompsize=uncomp, chainsize=chainsize,
583 chainratio=chainratio, lindist=lineardist,
583 chainratio=chainratio, lindist=lineardist,
584 extradist=extradist, extraratio=extraratio)
584 extradist=extradist, extraratio=extraratio)
585
585
586 fm.end()
586 fm.end()
587
587
588 @command('debugdirstate|debugstate',
589 [('', 'nodates', None, _('do not display the saved mtime')),
590 ('', 'datesort', None, _('sort by saved mtime'))],
591 _('[OPTION]...'))
592 def debugstate(ui, repo, **opts):
593 """show the contents of the current dirstate"""
594
595 nodates = opts.get('nodates')
596 datesort = opts.get('datesort')
597
598 timestr = ""
599 if datesort:
600 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
601 else:
602 keyfunc = None # sort by filename
603 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
604 if ent[3] == -1:
605 timestr = 'unset '
606 elif nodates:
607 timestr = 'set '
608 else:
609 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
610 time.localtime(ent[3]))
611 if ent[1] & 0o20000:
612 mode = 'lnk'
613 else:
614 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
615 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
616 for f in repo.dirstate.copies():
617 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
618
588 @command('debugdiscovery',
619 @command('debugdiscovery',
589 [('', 'old', None, _('use old-style discovery')),
620 [('', 'old', None, _('use old-style discovery')),
590 ('', 'nonheads', None,
621 ('', 'nonheads', None,
591 _('use old-style discovery with non-heads included')),
622 _('use old-style discovery with non-heads included')),
592 ] + commands.remoteopts,
623 ] + commands.remoteopts,
593 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
624 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
594 def debugdiscovery(ui, repo, remoteurl="default", **opts):
625 def debugdiscovery(ui, repo, remoteurl="default", **opts):
595 """runs the changeset discovery protocol in isolation"""
626 """runs the changeset discovery protocol in isolation"""
596 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
627 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
597 opts.get('branch'))
628 opts.get('branch'))
598 remote = hg.peer(repo, opts, remoteurl)
629 remote = hg.peer(repo, opts, remoteurl)
599 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
630 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
600
631
601 # make sure tests are repeatable
632 # make sure tests are repeatable
602 random.seed(12323)
633 random.seed(12323)
603
634
604 def doit(localheads, remoteheads, remote=remote):
635 def doit(localheads, remoteheads, remote=remote):
605 if opts.get('old'):
636 if opts.get('old'):
606 if localheads:
637 if localheads:
607 raise error.Abort('cannot use localheads with old style '
638 raise error.Abort('cannot use localheads with old style '
608 'discovery')
639 'discovery')
609 if not util.safehasattr(remote, 'branches'):
640 if not util.safehasattr(remote, 'branches'):
610 # enable in-client legacy support
641 # enable in-client legacy support
611 remote = localrepo.locallegacypeer(remote.local())
642 remote = localrepo.locallegacypeer(remote.local())
612 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
643 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
613 force=True)
644 force=True)
614 common = set(common)
645 common = set(common)
615 if not opts.get('nonheads'):
646 if not opts.get('nonheads'):
616 ui.write(("unpruned common: %s\n") %
647 ui.write(("unpruned common: %s\n") %
617 " ".join(sorted(short(n) for n in common)))
648 " ".join(sorted(short(n) for n in common)))
618 dag = dagutil.revlogdag(repo.changelog)
649 dag = dagutil.revlogdag(repo.changelog)
619 all = dag.ancestorset(dag.internalizeall(common))
650 all = dag.ancestorset(dag.internalizeall(common))
620 common = dag.externalizeall(dag.headsetofconnecteds(all))
651 common = dag.externalizeall(dag.headsetofconnecteds(all))
621 else:
652 else:
622 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
653 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
623 common = set(common)
654 common = set(common)
624 rheads = set(hds)
655 rheads = set(hds)
625 lheads = set(repo.heads())
656 lheads = set(repo.heads())
626 ui.write(("common heads: %s\n") %
657 ui.write(("common heads: %s\n") %
627 " ".join(sorted(short(n) for n in common)))
658 " ".join(sorted(short(n) for n in common)))
628 if lheads <= common:
659 if lheads <= common:
629 ui.write(("local is subset\n"))
660 ui.write(("local is subset\n"))
630 elif rheads <= common:
661 elif rheads <= common:
631 ui.write(("remote is subset\n"))
662 ui.write(("remote is subset\n"))
632
663
633 serverlogs = opts.get('serverlog')
664 serverlogs = opts.get('serverlog')
634 if serverlogs:
665 if serverlogs:
635 for filename in serverlogs:
666 for filename in serverlogs:
636 with open(filename, 'r') as logfile:
667 with open(filename, 'r') as logfile:
637 line = logfile.readline()
668 line = logfile.readline()
638 while line:
669 while line:
639 parts = line.strip().split(';')
670 parts = line.strip().split(';')
640 op = parts[1]
671 op = parts[1]
641 if op == 'cg':
672 if op == 'cg':
642 pass
673 pass
643 elif op == 'cgss':
674 elif op == 'cgss':
644 doit(parts[2].split(' '), parts[3].split(' '))
675 doit(parts[2].split(' '), parts[3].split(' '))
645 elif op == 'unb':
676 elif op == 'unb':
646 doit(parts[3].split(' '), parts[2].split(' '))
677 doit(parts[3].split(' '), parts[2].split(' '))
647 line = logfile.readline()
678 line = logfile.readline()
648 else:
679 else:
649 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
680 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
650 opts.get('remote_head'))
681 opts.get('remote_head'))
651 localrevs = opts.get('local_head')
682 localrevs = opts.get('local_head')
652 doit(localrevs, remoterevs)
683 doit(localrevs, remoterevs)
653
684
654 @command('debugextensions', commands.formatteropts, [], norepo=True)
685 @command('debugextensions', commands.formatteropts, [], norepo=True)
655 def debugextensions(ui, **opts):
686 def debugextensions(ui, **opts):
656 '''show information about active extensions'''
687 '''show information about active extensions'''
657 exts = extensions.extensions(ui)
688 exts = extensions.extensions(ui)
658 hgver = util.version()
689 hgver = util.version()
659 fm = ui.formatter('debugextensions', opts)
690 fm = ui.formatter('debugextensions', opts)
660 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
691 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
661 isinternal = extensions.ismoduleinternal(extmod)
692 isinternal = extensions.ismoduleinternal(extmod)
662 extsource = extmod.__file__
693 extsource = extmod.__file__
663 if isinternal:
694 if isinternal:
664 exttestedwith = [] # never expose magic string to users
695 exttestedwith = [] # never expose magic string to users
665 else:
696 else:
666 exttestedwith = getattr(extmod, 'testedwith', '').split()
697 exttestedwith = getattr(extmod, 'testedwith', '').split()
667 extbuglink = getattr(extmod, 'buglink', None)
698 extbuglink = getattr(extmod, 'buglink', None)
668
699
669 fm.startitem()
700 fm.startitem()
670
701
671 if ui.quiet or ui.verbose:
702 if ui.quiet or ui.verbose:
672 fm.write('name', '%s\n', extname)
703 fm.write('name', '%s\n', extname)
673 else:
704 else:
674 fm.write('name', '%s', extname)
705 fm.write('name', '%s', extname)
675 if isinternal or hgver in exttestedwith:
706 if isinternal or hgver in exttestedwith:
676 fm.plain('\n')
707 fm.plain('\n')
677 elif not exttestedwith:
708 elif not exttestedwith:
678 fm.plain(_(' (untested!)\n'))
709 fm.plain(_(' (untested!)\n'))
679 else:
710 else:
680 lasttestedversion = exttestedwith[-1]
711 lasttestedversion = exttestedwith[-1]
681 fm.plain(' (%s!)\n' % lasttestedversion)
712 fm.plain(' (%s!)\n' % lasttestedversion)
682
713
683 fm.condwrite(ui.verbose and extsource, 'source',
714 fm.condwrite(ui.verbose and extsource, 'source',
684 _(' location: %s\n'), extsource or "")
715 _(' location: %s\n'), extsource or "")
685
716
686 if ui.verbose:
717 if ui.verbose:
687 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
718 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
688 fm.data(bundled=isinternal)
719 fm.data(bundled=isinternal)
689
720
690 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
721 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
691 _(' tested with: %s\n'),
722 _(' tested with: %s\n'),
692 fm.formatlist(exttestedwith, name='ver'))
723 fm.formatlist(exttestedwith, name='ver'))
693
724
694 fm.condwrite(ui.verbose and extbuglink, 'buglink',
725 fm.condwrite(ui.verbose and extbuglink, 'buglink',
695 _(' bug reporting: %s\n'), extbuglink or "")
726 _(' bug reporting: %s\n'), extbuglink or "")
696
727
697 fm.end()
728 fm.end()
698
729
699 @command('debugfileset',
730 @command('debugfileset',
700 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
731 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
701 _('[-r REV] FILESPEC'))
732 _('[-r REV] FILESPEC'))
702 def debugfileset(ui, repo, expr, **opts):
733 def debugfileset(ui, repo, expr, **opts):
703 '''parse and apply a fileset specification'''
734 '''parse and apply a fileset specification'''
704 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
735 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
705 if ui.verbose:
736 if ui.verbose:
706 tree = fileset.parse(expr)
737 tree = fileset.parse(expr)
707 ui.note(fileset.prettyformat(tree), "\n")
738 ui.note(fileset.prettyformat(tree), "\n")
708
739
709 for f in ctx.getfileset(expr):
740 for f in ctx.getfileset(expr):
710 ui.write("%s\n" % f)
741 ui.write("%s\n" % f)
711
742
712 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
743 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
713 def debugfsinfo(ui, path="."):
744 def debugfsinfo(ui, path="."):
714 """show information detected about current filesystem"""
745 """show information detected about current filesystem"""
715 util.writefile('.debugfsinfo', '')
746 util.writefile('.debugfsinfo', '')
716 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
747 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
717 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
748 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
718 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
749 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
719 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
750 ui.write(('case-sensitive: %s\n') % (util.fscasesensitive('.debugfsinfo')
720 and 'yes' or 'no'))
751 and 'yes' or 'no'))
721 os.unlink('.debugfsinfo')
752 os.unlink('.debugfsinfo')
722
753
723 @command('debuggetbundle',
754 @command('debuggetbundle',
724 [('H', 'head', [], _('id of head node'), _('ID')),
755 [('H', 'head', [], _('id of head node'), _('ID')),
725 ('C', 'common', [], _('id of common node'), _('ID')),
756 ('C', 'common', [], _('id of common node'), _('ID')),
726 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
757 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
727 _('REPO FILE [-H|-C ID]...'),
758 _('REPO FILE [-H|-C ID]...'),
728 norepo=True)
759 norepo=True)
729 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
760 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
730 """retrieves a bundle from a repo
761 """retrieves a bundle from a repo
731
762
732 Every ID must be a full-length hex node id string. Saves the bundle to the
763 Every ID must be a full-length hex node id string. Saves the bundle to the
733 given file.
764 given file.
734 """
765 """
735 repo = hg.peer(ui, opts, repopath)
766 repo = hg.peer(ui, opts, repopath)
736 if not repo.capable('getbundle'):
767 if not repo.capable('getbundle'):
737 raise error.Abort("getbundle() not supported by target repository")
768 raise error.Abort("getbundle() not supported by target repository")
738 args = {}
769 args = {}
739 if common:
770 if common:
740 args['common'] = [bin(s) for s in common]
771 args['common'] = [bin(s) for s in common]
741 if head:
772 if head:
742 args['heads'] = [bin(s) for s in head]
773 args['heads'] = [bin(s) for s in head]
743 # TODO: get desired bundlecaps from command line.
774 # TODO: get desired bundlecaps from command line.
744 args['bundlecaps'] = None
775 args['bundlecaps'] = None
745 bundle = repo.getbundle('debug', **args)
776 bundle = repo.getbundle('debug', **args)
746
777
747 bundletype = opts.get('type', 'bzip2').lower()
778 bundletype = opts.get('type', 'bzip2').lower()
748 btypes = {'none': 'HG10UN',
779 btypes = {'none': 'HG10UN',
749 'bzip2': 'HG10BZ',
780 'bzip2': 'HG10BZ',
750 'gzip': 'HG10GZ',
781 'gzip': 'HG10GZ',
751 'bundle2': 'HG20'}
782 'bundle2': 'HG20'}
752 bundletype = btypes.get(bundletype)
783 bundletype = btypes.get(bundletype)
753 if bundletype not in bundle2.bundletypes:
784 if bundletype not in bundle2.bundletypes:
754 raise error.Abort(_('unknown bundle type specified with --type'))
785 raise error.Abort(_('unknown bundle type specified with --type'))
755 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
786 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
756
787
757 @command('debugignore', [], '[FILE]')
788 @command('debugignore', [], '[FILE]')
758 def debugignore(ui, repo, *files, **opts):
789 def debugignore(ui, repo, *files, **opts):
759 """display the combined ignore pattern and information about ignored files
790 """display the combined ignore pattern and information about ignored files
760
791
761 With no argument display the combined ignore pattern.
792 With no argument display the combined ignore pattern.
762
793
763 Given space separated file names, shows if the given file is ignored and
794 Given space separated file names, shows if the given file is ignored and
764 if so, show the ignore rule (file and line number) that matched it.
795 if so, show the ignore rule (file and line number) that matched it.
765 """
796 """
766 ignore = repo.dirstate._ignore
797 ignore = repo.dirstate._ignore
767 if not files:
798 if not files:
768 # Show all the patterns
799 # Show all the patterns
769 includepat = getattr(ignore, 'includepat', None)
800 includepat = getattr(ignore, 'includepat', None)
770 if includepat is not None:
801 if includepat is not None:
771 ui.write("%s\n" % includepat)
802 ui.write("%s\n" % includepat)
772 else:
803 else:
773 raise error.Abort(_("no ignore patterns found"))
804 raise error.Abort(_("no ignore patterns found"))
774 else:
805 else:
775 for f in files:
806 for f in files:
776 nf = util.normpath(f)
807 nf = util.normpath(f)
777 ignored = None
808 ignored = None
778 ignoredata = None
809 ignoredata = None
779 if nf != '.':
810 if nf != '.':
780 if ignore(nf):
811 if ignore(nf):
781 ignored = nf
812 ignored = nf
782 ignoredata = repo.dirstate._ignorefileandline(nf)
813 ignoredata = repo.dirstate._ignorefileandline(nf)
783 else:
814 else:
784 for p in util.finddirs(nf):
815 for p in util.finddirs(nf):
785 if ignore(p):
816 if ignore(p):
786 ignored = p
817 ignored = p
787 ignoredata = repo.dirstate._ignorefileandline(p)
818 ignoredata = repo.dirstate._ignorefileandline(p)
788 break
819 break
789 if ignored:
820 if ignored:
790 if ignored == nf:
821 if ignored == nf:
791 ui.write(_("%s is ignored\n") % f)
822 ui.write(_("%s is ignored\n") % f)
792 else:
823 else:
793 ui.write(_("%s is ignored because of "
824 ui.write(_("%s is ignored because of "
794 "containing folder %s\n")
825 "containing folder %s\n")
795 % (f, ignored))
826 % (f, ignored))
796 ignorefile, lineno, line = ignoredata
827 ignorefile, lineno, line = ignoredata
797 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
828 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
798 % (ignorefile, lineno, line))
829 % (ignorefile, lineno, line))
799 else:
830 else:
800 ui.write(_("%s is not ignored\n") % f)
831 ui.write(_("%s is not ignored\n") % f)
801
832
802 @command('debugindex', commands.debugrevlogopts +
833 @command('debugindex', commands.debugrevlogopts +
803 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
834 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
804 _('[-f FORMAT] -c|-m|FILE'),
835 _('[-f FORMAT] -c|-m|FILE'),
805 optionalrepo=True)
836 optionalrepo=True)
806 def debugindex(ui, repo, file_=None, **opts):
837 def debugindex(ui, repo, file_=None, **opts):
807 """dump the contents of an index file"""
838 """dump the contents of an index file"""
808 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
839 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
809 format = opts.get('format', 0)
840 format = opts.get('format', 0)
810 if format not in (0, 1):
841 if format not in (0, 1):
811 raise error.Abort(_("unknown format %d") % format)
842 raise error.Abort(_("unknown format %d") % format)
812
843
813 generaldelta = r.version & revlog.REVLOGGENERALDELTA
844 generaldelta = r.version & revlog.REVLOGGENERALDELTA
814 if generaldelta:
845 if generaldelta:
815 basehdr = ' delta'
846 basehdr = ' delta'
816 else:
847 else:
817 basehdr = ' base'
848 basehdr = ' base'
818
849
819 if ui.debugflag:
850 if ui.debugflag:
820 shortfn = hex
851 shortfn = hex
821 else:
852 else:
822 shortfn = short
853 shortfn = short
823
854
824 # There might not be anything in r, so have a sane default
855 # There might not be anything in r, so have a sane default
825 idlen = 12
856 idlen = 12
826 for i in r:
857 for i in r:
827 idlen = len(shortfn(r.node(i)))
858 idlen = len(shortfn(r.node(i)))
828 break
859 break
829
860
830 if format == 0:
861 if format == 0:
831 ui.write((" rev offset length " + basehdr + " linkrev"
862 ui.write((" rev offset length " + basehdr + " linkrev"
832 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
863 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
833 elif format == 1:
864 elif format == 1:
834 ui.write((" rev flag offset length"
865 ui.write((" rev flag offset length"
835 " size " + basehdr + " link p1 p2"
866 " size " + basehdr + " link p1 p2"
836 " %s\n") % "nodeid".rjust(idlen))
867 " %s\n") % "nodeid".rjust(idlen))
837
868
838 for i in r:
869 for i in r:
839 node = r.node(i)
870 node = r.node(i)
840 if generaldelta:
871 if generaldelta:
841 base = r.deltaparent(i)
872 base = r.deltaparent(i)
842 else:
873 else:
843 base = r.chainbase(i)
874 base = r.chainbase(i)
844 if format == 0:
875 if format == 0:
845 try:
876 try:
846 pp = r.parents(node)
877 pp = r.parents(node)
847 except Exception:
878 except Exception:
848 pp = [nullid, nullid]
879 pp = [nullid, nullid]
849 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
880 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
850 i, r.start(i), r.length(i), base, r.linkrev(i),
881 i, r.start(i), r.length(i), base, r.linkrev(i),
851 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
882 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
852 elif format == 1:
883 elif format == 1:
853 pr = r.parentrevs(i)
884 pr = r.parentrevs(i)
854 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
885 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
855 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
886 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
856 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
887 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
857
888
858 @command('debugindexdot', commands.debugrevlogopts,
889 @command('debugindexdot', commands.debugrevlogopts,
859 _('-c|-m|FILE'), optionalrepo=True)
890 _('-c|-m|FILE'), optionalrepo=True)
860 def debugindexdot(ui, repo, file_=None, **opts):
891 def debugindexdot(ui, repo, file_=None, **opts):
861 """dump an index DAG as a graphviz dot file"""
892 """dump an index DAG as a graphviz dot file"""
862 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
893 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
863 ui.write(("digraph G {\n"))
894 ui.write(("digraph G {\n"))
864 for i in r:
895 for i in r:
865 node = r.node(i)
896 node = r.node(i)
866 pp = r.parents(node)
897 pp = r.parents(node)
867 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
898 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
868 if pp[1] != nullid:
899 if pp[1] != nullid:
869 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
900 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
870 ui.write("}\n")
901 ui.write("}\n")
871
902
872 @command('debuginstall', [] + commands.formatteropts, '', norepo=True)
903 @command('debuginstall', [] + commands.formatteropts, '', norepo=True)
873 def debuginstall(ui, **opts):
904 def debuginstall(ui, **opts):
874 '''test Mercurial installation
905 '''test Mercurial installation
875
906
876 Returns 0 on success.
907 Returns 0 on success.
877 '''
908 '''
878
909
879 def writetemp(contents):
910 def writetemp(contents):
880 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
911 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
881 f = os.fdopen(fd, "wb")
912 f = os.fdopen(fd, "wb")
882 f.write(contents)
913 f.write(contents)
883 f.close()
914 f.close()
884 return name
915 return name
885
916
886 problems = 0
917 problems = 0
887
918
888 fm = ui.formatter('debuginstall', opts)
919 fm = ui.formatter('debuginstall', opts)
889 fm.startitem()
920 fm.startitem()
890
921
891 # encoding
922 # encoding
892 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
923 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
893 err = None
924 err = None
894 try:
925 try:
895 encoding.fromlocal("test")
926 encoding.fromlocal("test")
896 except error.Abort as inst:
927 except error.Abort as inst:
897 err = inst
928 err = inst
898 problems += 1
929 problems += 1
899 fm.condwrite(err, 'encodingerror', _(" %s\n"
930 fm.condwrite(err, 'encodingerror', _(" %s\n"
900 " (check that your locale is properly set)\n"), err)
931 " (check that your locale is properly set)\n"), err)
901
932
902 # Python
933 # Python
903 fm.write('pythonexe', _("checking Python executable (%s)\n"),
934 fm.write('pythonexe', _("checking Python executable (%s)\n"),
904 pycompat.sysexecutable)
935 pycompat.sysexecutable)
905 fm.write('pythonver', _("checking Python version (%s)\n"),
936 fm.write('pythonver', _("checking Python version (%s)\n"),
906 ("%d.%d.%d" % sys.version_info[:3]))
937 ("%d.%d.%d" % sys.version_info[:3]))
907 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
938 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
908 os.path.dirname(pycompat.fsencode(os.__file__)))
939 os.path.dirname(pycompat.fsencode(os.__file__)))
909
940
910 security = set(sslutil.supportedprotocols)
941 security = set(sslutil.supportedprotocols)
911 if sslutil.hassni:
942 if sslutil.hassni:
912 security.add('sni')
943 security.add('sni')
913
944
914 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
945 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
915 fm.formatlist(sorted(security), name='protocol',
946 fm.formatlist(sorted(security), name='protocol',
916 fmt='%s', sep=','))
947 fmt='%s', sep=','))
917
948
918 # These are warnings, not errors. So don't increment problem count. This
949 # These are warnings, not errors. So don't increment problem count. This
919 # may change in the future.
950 # may change in the future.
920 if 'tls1.2' not in security:
951 if 'tls1.2' not in security:
921 fm.plain(_(' TLS 1.2 not supported by Python install; '
952 fm.plain(_(' TLS 1.2 not supported by Python install; '
922 'network connections lack modern security\n'))
953 'network connections lack modern security\n'))
923 if 'sni' not in security:
954 if 'sni' not in security:
924 fm.plain(_(' SNI not supported by Python install; may have '
955 fm.plain(_(' SNI not supported by Python install; may have '
925 'connectivity issues with some servers\n'))
956 'connectivity issues with some servers\n'))
926
957
927 # TODO print CA cert info
958 # TODO print CA cert info
928
959
929 # hg version
960 # hg version
930 hgver = util.version()
961 hgver = util.version()
931 fm.write('hgver', _("checking Mercurial version (%s)\n"),
962 fm.write('hgver', _("checking Mercurial version (%s)\n"),
932 hgver.split('+')[0])
963 hgver.split('+')[0])
933 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
964 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
934 '+'.join(hgver.split('+')[1:]))
965 '+'.join(hgver.split('+')[1:]))
935
966
936 # compiled modules
967 # compiled modules
937 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
968 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
938 policy.policy)
969 policy.policy)
939 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
970 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
940 os.path.dirname(__file__))
971 os.path.dirname(__file__))
941
972
942 err = None
973 err = None
943 try:
974 try:
944 from . import (
975 from . import (
945 base85,
976 base85,
946 bdiff,
977 bdiff,
947 mpatch,
978 mpatch,
948 osutil,
979 osutil,
949 )
980 )
950 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
981 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
951 except Exception as inst:
982 except Exception as inst:
952 err = inst
983 err = inst
953 problems += 1
984 problems += 1
954 fm.condwrite(err, 'extensionserror', " %s\n", err)
985 fm.condwrite(err, 'extensionserror', " %s\n", err)
955
986
956 compengines = util.compengines._engines.values()
987 compengines = util.compengines._engines.values()
957 fm.write('compengines', _('checking registered compression engines (%s)\n'),
988 fm.write('compengines', _('checking registered compression engines (%s)\n'),
958 fm.formatlist(sorted(e.name() for e in compengines),
989 fm.formatlist(sorted(e.name() for e in compengines),
959 name='compengine', fmt='%s', sep=', '))
990 name='compengine', fmt='%s', sep=', '))
960 fm.write('compenginesavail', _('checking available compression engines '
991 fm.write('compenginesavail', _('checking available compression engines '
961 '(%s)\n'),
992 '(%s)\n'),
962 fm.formatlist(sorted(e.name() for e in compengines
993 fm.formatlist(sorted(e.name() for e in compengines
963 if e.available()),
994 if e.available()),
964 name='compengine', fmt='%s', sep=', '))
995 name='compengine', fmt='%s', sep=', '))
965 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
996 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
966 fm.write('compenginesserver', _('checking available compression engines '
997 fm.write('compenginesserver', _('checking available compression engines '
967 'for wire protocol (%s)\n'),
998 'for wire protocol (%s)\n'),
968 fm.formatlist([e.name() for e in wirecompengines
999 fm.formatlist([e.name() for e in wirecompengines
969 if e.wireprotosupport()],
1000 if e.wireprotosupport()],
970 name='compengine', fmt='%s', sep=', '))
1001 name='compengine', fmt='%s', sep=', '))
971
1002
972 # templates
1003 # templates
973 p = templater.templatepaths()
1004 p = templater.templatepaths()
974 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
1005 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
975 fm.condwrite(not p, '', _(" no template directories found\n"))
1006 fm.condwrite(not p, '', _(" no template directories found\n"))
976 if p:
1007 if p:
977 m = templater.templatepath("map-cmdline.default")
1008 m = templater.templatepath("map-cmdline.default")
978 if m:
1009 if m:
979 # template found, check if it is working
1010 # template found, check if it is working
980 err = None
1011 err = None
981 try:
1012 try:
982 templater.templater.frommapfile(m)
1013 templater.templater.frommapfile(m)
983 except Exception as inst:
1014 except Exception as inst:
984 err = inst
1015 err = inst
985 p = None
1016 p = None
986 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
1017 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
987 else:
1018 else:
988 p = None
1019 p = None
989 fm.condwrite(p, 'defaulttemplate',
1020 fm.condwrite(p, 'defaulttemplate',
990 _("checking default template (%s)\n"), m)
1021 _("checking default template (%s)\n"), m)
991 fm.condwrite(not m, 'defaulttemplatenotfound',
1022 fm.condwrite(not m, 'defaulttemplatenotfound',
992 _(" template '%s' not found\n"), "default")
1023 _(" template '%s' not found\n"), "default")
993 if not p:
1024 if not p:
994 problems += 1
1025 problems += 1
995 fm.condwrite(not p, '',
1026 fm.condwrite(not p, '',
996 _(" (templates seem to have been installed incorrectly)\n"))
1027 _(" (templates seem to have been installed incorrectly)\n"))
997
1028
998 # editor
1029 # editor
999 editor = ui.geteditor()
1030 editor = ui.geteditor()
1000 editor = util.expandpath(editor)
1031 editor = util.expandpath(editor)
1001 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
1032 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
1002 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
1033 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
1003 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1034 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1004 _(" No commit editor set and can't find %s in PATH\n"
1035 _(" No commit editor set and can't find %s in PATH\n"
1005 " (specify a commit editor in your configuration"
1036 " (specify a commit editor in your configuration"
1006 " file)\n"), not cmdpath and editor == 'vi' and editor)
1037 " file)\n"), not cmdpath and editor == 'vi' and editor)
1007 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1038 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1008 _(" Can't find editor '%s' in PATH\n"
1039 _(" Can't find editor '%s' in PATH\n"
1009 " (specify a commit editor in your configuration"
1040 " (specify a commit editor in your configuration"
1010 " file)\n"), not cmdpath and editor)
1041 " file)\n"), not cmdpath and editor)
1011 if not cmdpath and editor != 'vi':
1042 if not cmdpath and editor != 'vi':
1012 problems += 1
1043 problems += 1
1013
1044
1014 # check username
1045 # check username
1015 username = None
1046 username = None
1016 err = None
1047 err = None
1017 try:
1048 try:
1018 username = ui.username()
1049 username = ui.username()
1019 except error.Abort as e:
1050 except error.Abort as e:
1020 err = e
1051 err = e
1021 problems += 1
1052 problems += 1
1022
1053
1023 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1054 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1024 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1055 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1025 " (specify a username in your configuration file)\n"), err)
1056 " (specify a username in your configuration file)\n"), err)
1026
1057
1027 fm.condwrite(not problems, '',
1058 fm.condwrite(not problems, '',
1028 _("no problems detected\n"))
1059 _("no problems detected\n"))
1029 if not problems:
1060 if not problems:
1030 fm.data(problems=problems)
1061 fm.data(problems=problems)
1031 fm.condwrite(problems, 'problems',
1062 fm.condwrite(problems, 'problems',
1032 _("%d problems detected,"
1063 _("%d problems detected,"
1033 " please check your install!\n"), problems)
1064 " please check your install!\n"), problems)
1034 fm.end()
1065 fm.end()
1035
1066
1036 return problems
1067 return problems
1037
1068
1038 @command('debugknown', [], _('REPO ID...'), norepo=True)
1069 @command('debugknown', [], _('REPO ID...'), norepo=True)
1039 def debugknown(ui, repopath, *ids, **opts):
1070 def debugknown(ui, repopath, *ids, **opts):
1040 """test whether node ids are known to a repo
1071 """test whether node ids are known to a repo
1041
1072
1042 Every ID must be a full-length hex node id string. Returns a list of 0s
1073 Every ID must be a full-length hex node id string. Returns a list of 0s
1043 and 1s indicating unknown/known.
1074 and 1s indicating unknown/known.
1044 """
1075 """
1045 repo = hg.peer(ui, opts, repopath)
1076 repo = hg.peer(ui, opts, repopath)
1046 if not repo.capable('known'):
1077 if not repo.capable('known'):
1047 raise error.Abort("known() not supported by target repository")
1078 raise error.Abort("known() not supported by target repository")
1048 flags = repo.known([bin(s) for s in ids])
1079 flags = repo.known([bin(s) for s in ids])
1049 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1080 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1050
1081
1051 @command('debuglabelcomplete', [], _('LABEL...'))
1082 @command('debuglabelcomplete', [], _('LABEL...'))
1052 def debuglabelcomplete(ui, repo, *args):
1083 def debuglabelcomplete(ui, repo, *args):
1053 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1084 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1054 commands.debugnamecomplete(ui, repo, *args)
1085 commands.debugnamecomplete(ui, repo, *args)
1055
1086
1056 @command('debuglocks',
1087 @command('debuglocks',
1057 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1088 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1058 ('W', 'force-wlock', None,
1089 ('W', 'force-wlock', None,
1059 _('free the working state lock (DANGEROUS)'))],
1090 _('free the working state lock (DANGEROUS)'))],
1060 _('[OPTION]...'))
1091 _('[OPTION]...'))
1061 def debuglocks(ui, repo, **opts):
1092 def debuglocks(ui, repo, **opts):
1062 """show or modify state of locks
1093 """show or modify state of locks
1063
1094
1064 By default, this command will show which locks are held. This
1095 By default, this command will show which locks are held. This
1065 includes the user and process holding the lock, the amount of time
1096 includes the user and process holding the lock, the amount of time
1066 the lock has been held, and the machine name where the process is
1097 the lock has been held, and the machine name where the process is
1067 running if it's not local.
1098 running if it's not local.
1068
1099
1069 Locks protect the integrity of Mercurial's data, so should be
1100 Locks protect the integrity of Mercurial's data, so should be
1070 treated with care. System crashes or other interruptions may cause
1101 treated with care. System crashes or other interruptions may cause
1071 locks to not be properly released, though Mercurial will usually
1102 locks to not be properly released, though Mercurial will usually
1072 detect and remove such stale locks automatically.
1103 detect and remove such stale locks automatically.
1073
1104
1074 However, detecting stale locks may not always be possible (for
1105 However, detecting stale locks may not always be possible (for
1075 instance, on a shared filesystem). Removing locks may also be
1106 instance, on a shared filesystem). Removing locks may also be
1076 blocked by filesystem permissions.
1107 blocked by filesystem permissions.
1077
1108
1078 Returns 0 if no locks are held.
1109 Returns 0 if no locks are held.
1079
1110
1080 """
1111 """
1081
1112
1082 if opts.get('force_lock'):
1113 if opts.get('force_lock'):
1083 repo.svfs.unlink('lock')
1114 repo.svfs.unlink('lock')
1084 if opts.get('force_wlock'):
1115 if opts.get('force_wlock'):
1085 repo.vfs.unlink('wlock')
1116 repo.vfs.unlink('wlock')
1086 if opts.get('force_lock') or opts.get('force_lock'):
1117 if opts.get('force_lock') or opts.get('force_lock'):
1087 return 0
1118 return 0
1088
1119
1089 now = time.time()
1120 now = time.time()
1090 held = 0
1121 held = 0
1091
1122
1092 def report(vfs, name, method):
1123 def report(vfs, name, method):
1093 # this causes stale locks to get reaped for more accurate reporting
1124 # this causes stale locks to get reaped for more accurate reporting
1094 try:
1125 try:
1095 l = method(False)
1126 l = method(False)
1096 except error.LockHeld:
1127 except error.LockHeld:
1097 l = None
1128 l = None
1098
1129
1099 if l:
1130 if l:
1100 l.release()
1131 l.release()
1101 else:
1132 else:
1102 try:
1133 try:
1103 stat = vfs.lstat(name)
1134 stat = vfs.lstat(name)
1104 age = now - stat.st_mtime
1135 age = now - stat.st_mtime
1105 user = util.username(stat.st_uid)
1136 user = util.username(stat.st_uid)
1106 locker = vfs.readlock(name)
1137 locker = vfs.readlock(name)
1107 if ":" in locker:
1138 if ":" in locker:
1108 host, pid = locker.split(':')
1139 host, pid = locker.split(':')
1109 if host == socket.gethostname():
1140 if host == socket.gethostname():
1110 locker = 'user %s, process %s' % (user, pid)
1141 locker = 'user %s, process %s' % (user, pid)
1111 else:
1142 else:
1112 locker = 'user %s, process %s, host %s' \
1143 locker = 'user %s, process %s, host %s' \
1113 % (user, pid, host)
1144 % (user, pid, host)
1114 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1145 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1115 return 1
1146 return 1
1116 except OSError as e:
1147 except OSError as e:
1117 if e.errno != errno.ENOENT:
1148 if e.errno != errno.ENOENT:
1118 raise
1149 raise
1119
1150
1120 ui.write(("%-6s free\n") % (name + ":"))
1151 ui.write(("%-6s free\n") % (name + ":"))
1121 return 0
1152 return 0
1122
1153
1123 held += report(repo.svfs, "lock", repo.lock)
1154 held += report(repo.svfs, "lock", repo.lock)
1124 held += report(repo.vfs, "wlock", repo.wlock)
1155 held += report(repo.vfs, "wlock", repo.wlock)
1125
1156
1126 return held
1157 return held
1127
1158
1128 @command('debugmergestate', [], '')
1159 @command('debugmergestate', [], '')
1129 def debugmergestate(ui, repo, *args):
1160 def debugmergestate(ui, repo, *args):
1130 """print merge state
1161 """print merge state
1131
1162
1132 Use --verbose to print out information about whether v1 or v2 merge state
1163 Use --verbose to print out information about whether v1 or v2 merge state
1133 was chosen."""
1164 was chosen."""
1134 def _hashornull(h):
1165 def _hashornull(h):
1135 if h == nullhex:
1166 if h == nullhex:
1136 return 'null'
1167 return 'null'
1137 else:
1168 else:
1138 return h
1169 return h
1139
1170
1140 def printrecords(version):
1171 def printrecords(version):
1141 ui.write(('* version %s records\n') % version)
1172 ui.write(('* version %s records\n') % version)
1142 if version == 1:
1173 if version == 1:
1143 records = v1records
1174 records = v1records
1144 else:
1175 else:
1145 records = v2records
1176 records = v2records
1146
1177
1147 for rtype, record in records:
1178 for rtype, record in records:
1148 # pretty print some record types
1179 # pretty print some record types
1149 if rtype == 'L':
1180 if rtype == 'L':
1150 ui.write(('local: %s\n') % record)
1181 ui.write(('local: %s\n') % record)
1151 elif rtype == 'O':
1182 elif rtype == 'O':
1152 ui.write(('other: %s\n') % record)
1183 ui.write(('other: %s\n') % record)
1153 elif rtype == 'm':
1184 elif rtype == 'm':
1154 driver, mdstate = record.split('\0', 1)
1185 driver, mdstate = record.split('\0', 1)
1155 ui.write(('merge driver: %s (state "%s")\n')
1186 ui.write(('merge driver: %s (state "%s")\n')
1156 % (driver, mdstate))
1187 % (driver, mdstate))
1157 elif rtype in 'FDC':
1188 elif rtype in 'FDC':
1158 r = record.split('\0')
1189 r = record.split('\0')
1159 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1190 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1160 if version == 1:
1191 if version == 1:
1161 onode = 'not stored in v1 format'
1192 onode = 'not stored in v1 format'
1162 flags = r[7]
1193 flags = r[7]
1163 else:
1194 else:
1164 onode, flags = r[7:9]
1195 onode, flags = r[7:9]
1165 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1196 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1166 % (f, rtype, state, _hashornull(hash)))
1197 % (f, rtype, state, _hashornull(hash)))
1167 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1198 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1168 ui.write((' ancestor path: %s (node %s)\n')
1199 ui.write((' ancestor path: %s (node %s)\n')
1169 % (afile, _hashornull(anode)))
1200 % (afile, _hashornull(anode)))
1170 ui.write((' other path: %s (node %s)\n')
1201 ui.write((' other path: %s (node %s)\n')
1171 % (ofile, _hashornull(onode)))
1202 % (ofile, _hashornull(onode)))
1172 elif rtype == 'f':
1203 elif rtype == 'f':
1173 filename, rawextras = record.split('\0', 1)
1204 filename, rawextras = record.split('\0', 1)
1174 extras = rawextras.split('\0')
1205 extras = rawextras.split('\0')
1175 i = 0
1206 i = 0
1176 extrastrings = []
1207 extrastrings = []
1177 while i < len(extras):
1208 while i < len(extras):
1178 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1209 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1179 i += 2
1210 i += 2
1180
1211
1181 ui.write(('file extras: %s (%s)\n')
1212 ui.write(('file extras: %s (%s)\n')
1182 % (filename, ', '.join(extrastrings)))
1213 % (filename, ', '.join(extrastrings)))
1183 elif rtype == 'l':
1214 elif rtype == 'l':
1184 labels = record.split('\0', 2)
1215 labels = record.split('\0', 2)
1185 labels = [l for l in labels if len(l) > 0]
1216 labels = [l for l in labels if len(l) > 0]
1186 ui.write(('labels:\n'))
1217 ui.write(('labels:\n'))
1187 ui.write((' local: %s\n' % labels[0]))
1218 ui.write((' local: %s\n' % labels[0]))
1188 ui.write((' other: %s\n' % labels[1]))
1219 ui.write((' other: %s\n' % labels[1]))
1189 if len(labels) > 2:
1220 if len(labels) > 2:
1190 ui.write((' base: %s\n' % labels[2]))
1221 ui.write((' base: %s\n' % labels[2]))
1191 else:
1222 else:
1192 ui.write(('unrecognized entry: %s\t%s\n')
1223 ui.write(('unrecognized entry: %s\t%s\n')
1193 % (rtype, record.replace('\0', '\t')))
1224 % (rtype, record.replace('\0', '\t')))
1194
1225
1195 # Avoid mergestate.read() since it may raise an exception for unsupported
1226 # Avoid mergestate.read() since it may raise an exception for unsupported
1196 # merge state records. We shouldn't be doing this, but this is OK since this
1227 # merge state records. We shouldn't be doing this, but this is OK since this
1197 # command is pretty low-level.
1228 # command is pretty low-level.
1198 ms = mergemod.mergestate(repo)
1229 ms = mergemod.mergestate(repo)
1199
1230
1200 # sort so that reasonable information is on top
1231 # sort so that reasonable information is on top
1201 v1records = ms._readrecordsv1()
1232 v1records = ms._readrecordsv1()
1202 v2records = ms._readrecordsv2()
1233 v2records = ms._readrecordsv2()
1203 order = 'LOml'
1234 order = 'LOml'
1204 def key(r):
1235 def key(r):
1205 idx = order.find(r[0])
1236 idx = order.find(r[0])
1206 if idx == -1:
1237 if idx == -1:
1207 return (1, r[1])
1238 return (1, r[1])
1208 else:
1239 else:
1209 return (0, idx)
1240 return (0, idx)
1210 v1records.sort(key=key)
1241 v1records.sort(key=key)
1211 v2records.sort(key=key)
1242 v2records.sort(key=key)
1212
1243
1213 if not v1records and not v2records:
1244 if not v1records and not v2records:
1214 ui.write(('no merge state found\n'))
1245 ui.write(('no merge state found\n'))
1215 elif not v2records:
1246 elif not v2records:
1216 ui.note(('no version 2 merge state\n'))
1247 ui.note(('no version 2 merge state\n'))
1217 printrecords(1)
1248 printrecords(1)
1218 elif ms._v1v2match(v1records, v2records):
1249 elif ms._v1v2match(v1records, v2records):
1219 ui.note(('v1 and v2 states match: using v2\n'))
1250 ui.note(('v1 and v2 states match: using v2\n'))
1220 printrecords(2)
1251 printrecords(2)
1221 else:
1252 else:
1222 ui.note(('v1 and v2 states mismatch: using v1\n'))
1253 ui.note(('v1 and v2 states mismatch: using v1\n'))
1223 printrecords(1)
1254 printrecords(1)
1224 if ui.verbose:
1255 if ui.verbose:
1225 printrecords(2)
1256 printrecords(2)
1226
1257
1227 @command('debugnamecomplete', [], _('NAME...'))
1258 @command('debugnamecomplete', [], _('NAME...'))
1228 def debugnamecomplete(ui, repo, *args):
1259 def debugnamecomplete(ui, repo, *args):
1229 '''complete "names" - tags, open branch names, bookmark names'''
1260 '''complete "names" - tags, open branch names, bookmark names'''
1230
1261
1231 names = set()
1262 names = set()
1232 # since we previously only listed open branches, we will handle that
1263 # since we previously only listed open branches, we will handle that
1233 # specially (after this for loop)
1264 # specially (after this for loop)
1234 for name, ns in repo.names.iteritems():
1265 for name, ns in repo.names.iteritems():
1235 if name != 'branches':
1266 if name != 'branches':
1236 names.update(ns.listnames(repo))
1267 names.update(ns.listnames(repo))
1237 names.update(tag for (tag, heads, tip, closed)
1268 names.update(tag for (tag, heads, tip, closed)
1238 in repo.branchmap().iterbranches() if not closed)
1269 in repo.branchmap().iterbranches() if not closed)
1239 completions = set()
1270 completions = set()
1240 if not args:
1271 if not args:
1241 args = ['']
1272 args = ['']
1242 for a in args:
1273 for a in args:
1243 completions.update(n for n in names if n.startswith(a))
1274 completions.update(n for n in names if n.startswith(a))
1244 ui.write('\n'.join(sorted(completions)))
1275 ui.write('\n'.join(sorted(completions)))
1245 ui.write('\n')
1276 ui.write('\n')
1246
1277
1247 @command('debugobsolete',
1278 @command('debugobsolete',
1248 [('', 'flags', 0, _('markers flag')),
1279 [('', 'flags', 0, _('markers flag')),
1249 ('', 'record-parents', False,
1280 ('', 'record-parents', False,
1250 _('record parent information for the precursor')),
1281 _('record parent information for the precursor')),
1251 ('r', 'rev', [], _('display markers relevant to REV')),
1282 ('r', 'rev', [], _('display markers relevant to REV')),
1252 ('', 'index', False, _('display index of the marker')),
1283 ('', 'index', False, _('display index of the marker')),
1253 ('', 'delete', [], _('delete markers specified by indices')),
1284 ('', 'delete', [], _('delete markers specified by indices')),
1254 ] + commands.commitopts2 + commands.formatteropts,
1285 ] + commands.commitopts2 + commands.formatteropts,
1255 _('[OBSOLETED [REPLACEMENT ...]]'))
1286 _('[OBSOLETED [REPLACEMENT ...]]'))
1256 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1287 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1257 """create arbitrary obsolete marker
1288 """create arbitrary obsolete marker
1258
1289
1259 With no arguments, displays the list of obsolescence markers."""
1290 With no arguments, displays the list of obsolescence markers."""
1260
1291
1261 def parsenodeid(s):
1292 def parsenodeid(s):
1262 try:
1293 try:
1263 # We do not use revsingle/revrange functions here to accept
1294 # We do not use revsingle/revrange functions here to accept
1264 # arbitrary node identifiers, possibly not present in the
1295 # arbitrary node identifiers, possibly not present in the
1265 # local repository.
1296 # local repository.
1266 n = bin(s)
1297 n = bin(s)
1267 if len(n) != len(nullid):
1298 if len(n) != len(nullid):
1268 raise TypeError()
1299 raise TypeError()
1269 return n
1300 return n
1270 except TypeError:
1301 except TypeError:
1271 raise error.Abort('changeset references must be full hexadecimal '
1302 raise error.Abort('changeset references must be full hexadecimal '
1272 'node identifiers')
1303 'node identifiers')
1273
1304
1274 if opts.get('delete'):
1305 if opts.get('delete'):
1275 indices = []
1306 indices = []
1276 for v in opts.get('delete'):
1307 for v in opts.get('delete'):
1277 try:
1308 try:
1278 indices.append(int(v))
1309 indices.append(int(v))
1279 except ValueError:
1310 except ValueError:
1280 raise error.Abort(_('invalid index value: %r') % v,
1311 raise error.Abort(_('invalid index value: %r') % v,
1281 hint=_('use integers for indices'))
1312 hint=_('use integers for indices'))
1282
1313
1283 if repo.currenttransaction():
1314 if repo.currenttransaction():
1284 raise error.Abort(_('cannot delete obsmarkers in the middle '
1315 raise error.Abort(_('cannot delete obsmarkers in the middle '
1285 'of transaction.'))
1316 'of transaction.'))
1286
1317
1287 with repo.lock():
1318 with repo.lock():
1288 n = repair.deleteobsmarkers(repo.obsstore, indices)
1319 n = repair.deleteobsmarkers(repo.obsstore, indices)
1289 ui.write(_('deleted %i obsolescence markers\n') % n)
1320 ui.write(_('deleted %i obsolescence markers\n') % n)
1290
1321
1291 return
1322 return
1292
1323
1293 if precursor is not None:
1324 if precursor is not None:
1294 if opts['rev']:
1325 if opts['rev']:
1295 raise error.Abort('cannot select revision when creating marker')
1326 raise error.Abort('cannot select revision when creating marker')
1296 metadata = {}
1327 metadata = {}
1297 metadata['user'] = opts['user'] or ui.username()
1328 metadata['user'] = opts['user'] or ui.username()
1298 succs = tuple(parsenodeid(succ) for succ in successors)
1329 succs = tuple(parsenodeid(succ) for succ in successors)
1299 l = repo.lock()
1330 l = repo.lock()
1300 try:
1331 try:
1301 tr = repo.transaction('debugobsolete')
1332 tr = repo.transaction('debugobsolete')
1302 try:
1333 try:
1303 date = opts.get('date')
1334 date = opts.get('date')
1304 if date:
1335 if date:
1305 date = util.parsedate(date)
1336 date = util.parsedate(date)
1306 else:
1337 else:
1307 date = None
1338 date = None
1308 prec = parsenodeid(precursor)
1339 prec = parsenodeid(precursor)
1309 parents = None
1340 parents = None
1310 if opts['record_parents']:
1341 if opts['record_parents']:
1311 if prec not in repo.unfiltered():
1342 if prec not in repo.unfiltered():
1312 raise error.Abort('cannot used --record-parents on '
1343 raise error.Abort('cannot used --record-parents on '
1313 'unknown changesets')
1344 'unknown changesets')
1314 parents = repo.unfiltered()[prec].parents()
1345 parents = repo.unfiltered()[prec].parents()
1315 parents = tuple(p.node() for p in parents)
1346 parents = tuple(p.node() for p in parents)
1316 repo.obsstore.create(tr, prec, succs, opts['flags'],
1347 repo.obsstore.create(tr, prec, succs, opts['flags'],
1317 parents=parents, date=date,
1348 parents=parents, date=date,
1318 metadata=metadata)
1349 metadata=metadata)
1319 tr.close()
1350 tr.close()
1320 except ValueError as exc:
1351 except ValueError as exc:
1321 raise error.Abort(_('bad obsmarker input: %s') % exc)
1352 raise error.Abort(_('bad obsmarker input: %s') % exc)
1322 finally:
1353 finally:
1323 tr.release()
1354 tr.release()
1324 finally:
1355 finally:
1325 l.release()
1356 l.release()
1326 else:
1357 else:
1327 if opts['rev']:
1358 if opts['rev']:
1328 revs = scmutil.revrange(repo, opts['rev'])
1359 revs = scmutil.revrange(repo, opts['rev'])
1329 nodes = [repo[r].node() for r in revs]
1360 nodes = [repo[r].node() for r in revs]
1330 markers = list(obsolete.getmarkers(repo, nodes=nodes))
1361 markers = list(obsolete.getmarkers(repo, nodes=nodes))
1331 markers.sort(key=lambda x: x._data)
1362 markers.sort(key=lambda x: x._data)
1332 else:
1363 else:
1333 markers = obsolete.getmarkers(repo)
1364 markers = obsolete.getmarkers(repo)
1334
1365
1335 markerstoiter = markers
1366 markerstoiter = markers
1336 isrelevant = lambda m: True
1367 isrelevant = lambda m: True
1337 if opts.get('rev') and opts.get('index'):
1368 if opts.get('rev') and opts.get('index'):
1338 markerstoiter = obsolete.getmarkers(repo)
1369 markerstoiter = obsolete.getmarkers(repo)
1339 markerset = set(markers)
1370 markerset = set(markers)
1340 isrelevant = lambda m: m in markerset
1371 isrelevant = lambda m: m in markerset
1341
1372
1342 fm = ui.formatter('debugobsolete', opts)
1373 fm = ui.formatter('debugobsolete', opts)
1343 for i, m in enumerate(markerstoiter):
1374 for i, m in enumerate(markerstoiter):
1344 if not isrelevant(m):
1375 if not isrelevant(m):
1345 # marker can be irrelevant when we're iterating over a set
1376 # marker can be irrelevant when we're iterating over a set
1346 # of markers (markerstoiter) which is bigger than the set
1377 # of markers (markerstoiter) which is bigger than the set
1347 # of markers we want to display (markers)
1378 # of markers we want to display (markers)
1348 # this can happen if both --index and --rev options are
1379 # this can happen if both --index and --rev options are
1349 # provided and thus we need to iterate over all of the markers
1380 # provided and thus we need to iterate over all of the markers
1350 # to get the correct indices, but only display the ones that
1381 # to get the correct indices, but only display the ones that
1351 # are relevant to --rev value
1382 # are relevant to --rev value
1352 continue
1383 continue
1353 fm.startitem()
1384 fm.startitem()
1354 ind = i if opts.get('index') else None
1385 ind = i if opts.get('index') else None
1355 cmdutil.showmarker(fm, m, index=ind)
1386 cmdutil.showmarker(fm, m, index=ind)
1356 fm.end()
1387 fm.end()
1357
1388
1358 @command('debugpathcomplete',
1389 @command('debugpathcomplete',
1359 [('f', 'full', None, _('complete an entire path')),
1390 [('f', 'full', None, _('complete an entire path')),
1360 ('n', 'normal', None, _('show only normal files')),
1391 ('n', 'normal', None, _('show only normal files')),
1361 ('a', 'added', None, _('show only added files')),
1392 ('a', 'added', None, _('show only added files')),
1362 ('r', 'removed', None, _('show only removed files'))],
1393 ('r', 'removed', None, _('show only removed files'))],
1363 _('FILESPEC...'))
1394 _('FILESPEC...'))
1364 def debugpathcomplete(ui, repo, *specs, **opts):
1395 def debugpathcomplete(ui, repo, *specs, **opts):
1365 '''complete part or all of a tracked path
1396 '''complete part or all of a tracked path
1366
1397
1367 This command supports shells that offer path name completion. It
1398 This command supports shells that offer path name completion. It
1368 currently completes only files already known to the dirstate.
1399 currently completes only files already known to the dirstate.
1369
1400
1370 Completion extends only to the next path segment unless
1401 Completion extends only to the next path segment unless
1371 --full is specified, in which case entire paths are used.'''
1402 --full is specified, in which case entire paths are used.'''
1372
1403
1373 def complete(path, acceptable):
1404 def complete(path, acceptable):
1374 dirstate = repo.dirstate
1405 dirstate = repo.dirstate
1375 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1406 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1376 rootdir = repo.root + pycompat.ossep
1407 rootdir = repo.root + pycompat.ossep
1377 if spec != repo.root and not spec.startswith(rootdir):
1408 if spec != repo.root and not spec.startswith(rootdir):
1378 return [], []
1409 return [], []
1379 if os.path.isdir(spec):
1410 if os.path.isdir(spec):
1380 spec += '/'
1411 spec += '/'
1381 spec = spec[len(rootdir):]
1412 spec = spec[len(rootdir):]
1382 fixpaths = pycompat.ossep != '/'
1413 fixpaths = pycompat.ossep != '/'
1383 if fixpaths:
1414 if fixpaths:
1384 spec = spec.replace(pycompat.ossep, '/')
1415 spec = spec.replace(pycompat.ossep, '/')
1385 speclen = len(spec)
1416 speclen = len(spec)
1386 fullpaths = opts['full']
1417 fullpaths = opts['full']
1387 files, dirs = set(), set()
1418 files, dirs = set(), set()
1388 adddir, addfile = dirs.add, files.add
1419 adddir, addfile = dirs.add, files.add
1389 for f, st in dirstate.iteritems():
1420 for f, st in dirstate.iteritems():
1390 if f.startswith(spec) and st[0] in acceptable:
1421 if f.startswith(spec) and st[0] in acceptable:
1391 if fixpaths:
1422 if fixpaths:
1392 f = f.replace('/', pycompat.ossep)
1423 f = f.replace('/', pycompat.ossep)
1393 if fullpaths:
1424 if fullpaths:
1394 addfile(f)
1425 addfile(f)
1395 continue
1426 continue
1396 s = f.find(pycompat.ossep, speclen)
1427 s = f.find(pycompat.ossep, speclen)
1397 if s >= 0:
1428 if s >= 0:
1398 adddir(f[:s])
1429 adddir(f[:s])
1399 else:
1430 else:
1400 addfile(f)
1431 addfile(f)
1401 return files, dirs
1432 return files, dirs
1402
1433
1403 acceptable = ''
1434 acceptable = ''
1404 if opts['normal']:
1435 if opts['normal']:
1405 acceptable += 'nm'
1436 acceptable += 'nm'
1406 if opts['added']:
1437 if opts['added']:
1407 acceptable += 'a'
1438 acceptable += 'a'
1408 if opts['removed']:
1439 if opts['removed']:
1409 acceptable += 'r'
1440 acceptable += 'r'
1410 cwd = repo.getcwd()
1441 cwd = repo.getcwd()
1411 if not specs:
1442 if not specs:
1412 specs = ['.']
1443 specs = ['.']
1413
1444
1414 files, dirs = set(), set()
1445 files, dirs = set(), set()
1415 for spec in specs:
1446 for spec in specs:
1416 f, d = complete(spec, acceptable or 'nmar')
1447 f, d = complete(spec, acceptable or 'nmar')
1417 files.update(f)
1448 files.update(f)
1418 dirs.update(d)
1449 dirs.update(d)
1419 files.update(dirs)
1450 files.update(dirs)
1420 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1451 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1421 ui.write('\n')
1452 ui.write('\n')
1422
1453
1423 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1454 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1424 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1455 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1425 '''access the pushkey key/value protocol
1456 '''access the pushkey key/value protocol
1426
1457
1427 With two args, list the keys in the given namespace.
1458 With two args, list the keys in the given namespace.
1428
1459
1429 With five args, set a key to new if it currently is set to old.
1460 With five args, set a key to new if it currently is set to old.
1430 Reports success or failure.
1461 Reports success or failure.
1431 '''
1462 '''
1432
1463
1433 target = hg.peer(ui, {}, repopath)
1464 target = hg.peer(ui, {}, repopath)
1434 if keyinfo:
1465 if keyinfo:
1435 key, old, new = keyinfo
1466 key, old, new = keyinfo
1436 r = target.pushkey(namespace, key, old, new)
1467 r = target.pushkey(namespace, key, old, new)
1437 ui.status(str(r) + '\n')
1468 ui.status(str(r) + '\n')
1438 return not r
1469 return not r
1439 else:
1470 else:
1440 for k, v in sorted(target.listkeys(namespace).iteritems()):
1471 for k, v in sorted(target.listkeys(namespace).iteritems()):
1441 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1472 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1442 v.encode('string-escape')))
1473 v.encode('string-escape')))
1443
1474
1444 @command('debugpvec', [], _('A B'))
1475 @command('debugpvec', [], _('A B'))
1445 def debugpvec(ui, repo, a, b=None):
1476 def debugpvec(ui, repo, a, b=None):
1446 ca = scmutil.revsingle(repo, a)
1477 ca = scmutil.revsingle(repo, a)
1447 cb = scmutil.revsingle(repo, b)
1478 cb = scmutil.revsingle(repo, b)
1448 pa = pvec.ctxpvec(ca)
1479 pa = pvec.ctxpvec(ca)
1449 pb = pvec.ctxpvec(cb)
1480 pb = pvec.ctxpvec(cb)
1450 if pa == pb:
1481 if pa == pb:
1451 rel = "="
1482 rel = "="
1452 elif pa > pb:
1483 elif pa > pb:
1453 rel = ">"
1484 rel = ">"
1454 elif pa < pb:
1485 elif pa < pb:
1455 rel = "<"
1486 rel = "<"
1456 elif pa | pb:
1487 elif pa | pb:
1457 rel = "|"
1488 rel = "|"
1458 ui.write(_("a: %s\n") % pa)
1489 ui.write(_("a: %s\n") % pa)
1459 ui.write(_("b: %s\n") % pb)
1490 ui.write(_("b: %s\n") % pb)
1460 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1491 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1461 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1492 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1462 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1493 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1463 pa.distance(pb), rel))
1494 pa.distance(pb), rel))
1464
1495
1465 @command('debugrebuilddirstate|debugrebuildstate',
1496 @command('debugrebuilddirstate|debugrebuildstate',
1466 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1497 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1467 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1498 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1468 'the working copy parent')),
1499 'the working copy parent')),
1469 ],
1500 ],
1470 _('[-r REV]'))
1501 _('[-r REV]'))
1471 def debugrebuilddirstate(ui, repo, rev, **opts):
1502 def debugrebuilddirstate(ui, repo, rev, **opts):
1472 """rebuild the dirstate as it would look like for the given revision
1503 """rebuild the dirstate as it would look like for the given revision
1473
1504
1474 If no revision is specified the first current parent will be used.
1505 If no revision is specified the first current parent will be used.
1475
1506
1476 The dirstate will be set to the files of the given revision.
1507 The dirstate will be set to the files of the given revision.
1477 The actual working directory content or existing dirstate
1508 The actual working directory content or existing dirstate
1478 information such as adds or removes is not considered.
1509 information such as adds or removes is not considered.
1479
1510
1480 ``minimal`` will only rebuild the dirstate status for files that claim to be
1511 ``minimal`` will only rebuild the dirstate status for files that claim to be
1481 tracked but are not in the parent manifest, or that exist in the parent
1512 tracked but are not in the parent manifest, or that exist in the parent
1482 manifest but are not in the dirstate. It will not change adds, removes, or
1513 manifest but are not in the dirstate. It will not change adds, removes, or
1483 modified files that are in the working copy parent.
1514 modified files that are in the working copy parent.
1484
1515
1485 One use of this command is to make the next :hg:`status` invocation
1516 One use of this command is to make the next :hg:`status` invocation
1486 check the actual file content.
1517 check the actual file content.
1487 """
1518 """
1488 ctx = scmutil.revsingle(repo, rev)
1519 ctx = scmutil.revsingle(repo, rev)
1489 with repo.wlock():
1520 with repo.wlock():
1490 dirstate = repo.dirstate
1521 dirstate = repo.dirstate
1491 changedfiles = None
1522 changedfiles = None
1492 # See command doc for what minimal does.
1523 # See command doc for what minimal does.
1493 if opts.get('minimal'):
1524 if opts.get('minimal'):
1494 manifestfiles = set(ctx.manifest().keys())
1525 manifestfiles = set(ctx.manifest().keys())
1495 dirstatefiles = set(dirstate)
1526 dirstatefiles = set(dirstate)
1496 manifestonly = manifestfiles - dirstatefiles
1527 manifestonly = manifestfiles - dirstatefiles
1497 dsonly = dirstatefiles - manifestfiles
1528 dsonly = dirstatefiles - manifestfiles
1498 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1529 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1499 changedfiles = manifestonly | dsnotadded
1530 changedfiles = manifestonly | dsnotadded
1500
1531
1501 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1532 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1502
1533
1503 @command('debugrebuildfncache', [], '')
1534 @command('debugrebuildfncache', [], '')
1504 def debugrebuildfncache(ui, repo):
1535 def debugrebuildfncache(ui, repo):
1505 """rebuild the fncache file"""
1536 """rebuild the fncache file"""
1506 repair.rebuildfncache(ui, repo)
1537 repair.rebuildfncache(ui, repo)
1507
1538
1508 @command('debugrename',
1539 @command('debugrename',
1509 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1540 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1510 _('[-r REV] FILE'))
1541 _('[-r REV] FILE'))
1511 def debugrename(ui, repo, file1, *pats, **opts):
1542 def debugrename(ui, repo, file1, *pats, **opts):
1512 """dump rename information"""
1543 """dump rename information"""
1513
1544
1514 ctx = scmutil.revsingle(repo, opts.get('rev'))
1545 ctx = scmutil.revsingle(repo, opts.get('rev'))
1515 m = scmutil.match(ctx, (file1,) + pats, opts)
1546 m = scmutil.match(ctx, (file1,) + pats, opts)
1516 for abs in ctx.walk(m):
1547 for abs in ctx.walk(m):
1517 fctx = ctx[abs]
1548 fctx = ctx[abs]
1518 o = fctx.filelog().renamed(fctx.filenode())
1549 o = fctx.filelog().renamed(fctx.filenode())
1519 rel = m.rel(abs)
1550 rel = m.rel(abs)
1520 if o:
1551 if o:
1521 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1552 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1522 else:
1553 else:
1523 ui.write(_("%s not renamed\n") % rel)
1554 ui.write(_("%s not renamed\n") % rel)
1524
1555
1525 @command('debugrevlog', commands.debugrevlogopts +
1556 @command('debugrevlog', commands.debugrevlogopts +
1526 [('d', 'dump', False, _('dump index data'))],
1557 [('d', 'dump', False, _('dump index data'))],
1527 _('-c|-m|FILE'),
1558 _('-c|-m|FILE'),
1528 optionalrepo=True)
1559 optionalrepo=True)
1529 def debugrevlog(ui, repo, file_=None, **opts):
1560 def debugrevlog(ui, repo, file_=None, **opts):
1530 """show data and statistics about a revlog"""
1561 """show data and statistics about a revlog"""
1531 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1562 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1532
1563
1533 if opts.get("dump"):
1564 if opts.get("dump"):
1534 numrevs = len(r)
1565 numrevs = len(r)
1535 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1566 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1536 " rawsize totalsize compression heads chainlen\n"))
1567 " rawsize totalsize compression heads chainlen\n"))
1537 ts = 0
1568 ts = 0
1538 heads = set()
1569 heads = set()
1539
1570
1540 for rev in xrange(numrevs):
1571 for rev in xrange(numrevs):
1541 dbase = r.deltaparent(rev)
1572 dbase = r.deltaparent(rev)
1542 if dbase == -1:
1573 if dbase == -1:
1543 dbase = rev
1574 dbase = rev
1544 cbase = r.chainbase(rev)
1575 cbase = r.chainbase(rev)
1545 clen = r.chainlen(rev)
1576 clen = r.chainlen(rev)
1546 p1, p2 = r.parentrevs(rev)
1577 p1, p2 = r.parentrevs(rev)
1547 rs = r.rawsize(rev)
1578 rs = r.rawsize(rev)
1548 ts = ts + rs
1579 ts = ts + rs
1549 heads -= set(r.parentrevs(rev))
1580 heads -= set(r.parentrevs(rev))
1550 heads.add(rev)
1581 heads.add(rev)
1551 try:
1582 try:
1552 compression = ts / r.end(rev)
1583 compression = ts / r.end(rev)
1553 except ZeroDivisionError:
1584 except ZeroDivisionError:
1554 compression = 0
1585 compression = 0
1555 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1586 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1556 "%11d %5d %8d\n" %
1587 "%11d %5d %8d\n" %
1557 (rev, p1, p2, r.start(rev), r.end(rev),
1588 (rev, p1, p2, r.start(rev), r.end(rev),
1558 r.start(dbase), r.start(cbase),
1589 r.start(dbase), r.start(cbase),
1559 r.start(p1), r.start(p2),
1590 r.start(p1), r.start(p2),
1560 rs, ts, compression, len(heads), clen))
1591 rs, ts, compression, len(heads), clen))
1561 return 0
1592 return 0
1562
1593
1563 v = r.version
1594 v = r.version
1564 format = v & 0xFFFF
1595 format = v & 0xFFFF
1565 flags = []
1596 flags = []
1566 gdelta = False
1597 gdelta = False
1567 if v & revlog.REVLOGNGINLINEDATA:
1598 if v & revlog.REVLOGNGINLINEDATA:
1568 flags.append('inline')
1599 flags.append('inline')
1569 if v & revlog.REVLOGGENERALDELTA:
1600 if v & revlog.REVLOGGENERALDELTA:
1570 gdelta = True
1601 gdelta = True
1571 flags.append('generaldelta')
1602 flags.append('generaldelta')
1572 if not flags:
1603 if not flags:
1573 flags = ['(none)']
1604 flags = ['(none)']
1574
1605
1575 nummerges = 0
1606 nummerges = 0
1576 numfull = 0
1607 numfull = 0
1577 numprev = 0
1608 numprev = 0
1578 nump1 = 0
1609 nump1 = 0
1579 nump2 = 0
1610 nump2 = 0
1580 numother = 0
1611 numother = 0
1581 nump1prev = 0
1612 nump1prev = 0
1582 nump2prev = 0
1613 nump2prev = 0
1583 chainlengths = []
1614 chainlengths = []
1584
1615
1585 datasize = [None, 0, 0]
1616 datasize = [None, 0, 0]
1586 fullsize = [None, 0, 0]
1617 fullsize = [None, 0, 0]
1587 deltasize = [None, 0, 0]
1618 deltasize = [None, 0, 0]
1588 chunktypecounts = {}
1619 chunktypecounts = {}
1589 chunktypesizes = {}
1620 chunktypesizes = {}
1590
1621
1591 def addsize(size, l):
1622 def addsize(size, l):
1592 if l[0] is None or size < l[0]:
1623 if l[0] is None or size < l[0]:
1593 l[0] = size
1624 l[0] = size
1594 if size > l[1]:
1625 if size > l[1]:
1595 l[1] = size
1626 l[1] = size
1596 l[2] += size
1627 l[2] += size
1597
1628
1598 numrevs = len(r)
1629 numrevs = len(r)
1599 for rev in xrange(numrevs):
1630 for rev in xrange(numrevs):
1600 p1, p2 = r.parentrevs(rev)
1631 p1, p2 = r.parentrevs(rev)
1601 delta = r.deltaparent(rev)
1632 delta = r.deltaparent(rev)
1602 if format > 0:
1633 if format > 0:
1603 addsize(r.rawsize(rev), datasize)
1634 addsize(r.rawsize(rev), datasize)
1604 if p2 != nullrev:
1635 if p2 != nullrev:
1605 nummerges += 1
1636 nummerges += 1
1606 size = r.length(rev)
1637 size = r.length(rev)
1607 if delta == nullrev:
1638 if delta == nullrev:
1608 chainlengths.append(0)
1639 chainlengths.append(0)
1609 numfull += 1
1640 numfull += 1
1610 addsize(size, fullsize)
1641 addsize(size, fullsize)
1611 else:
1642 else:
1612 chainlengths.append(chainlengths[delta] + 1)
1643 chainlengths.append(chainlengths[delta] + 1)
1613 addsize(size, deltasize)
1644 addsize(size, deltasize)
1614 if delta == rev - 1:
1645 if delta == rev - 1:
1615 numprev += 1
1646 numprev += 1
1616 if delta == p1:
1647 if delta == p1:
1617 nump1prev += 1
1648 nump1prev += 1
1618 elif delta == p2:
1649 elif delta == p2:
1619 nump2prev += 1
1650 nump2prev += 1
1620 elif delta == p1:
1651 elif delta == p1:
1621 nump1 += 1
1652 nump1 += 1
1622 elif delta == p2:
1653 elif delta == p2:
1623 nump2 += 1
1654 nump2 += 1
1624 elif delta != nullrev:
1655 elif delta != nullrev:
1625 numother += 1
1656 numother += 1
1626
1657
1627 # Obtain data on the raw chunks in the revlog.
1658 # Obtain data on the raw chunks in the revlog.
1628 chunk = r._chunkraw(rev, rev)[1]
1659 chunk = r._chunkraw(rev, rev)[1]
1629 if chunk:
1660 if chunk:
1630 chunktype = chunk[0]
1661 chunktype = chunk[0]
1631 else:
1662 else:
1632 chunktype = 'empty'
1663 chunktype = 'empty'
1633
1664
1634 if chunktype not in chunktypecounts:
1665 if chunktype not in chunktypecounts:
1635 chunktypecounts[chunktype] = 0
1666 chunktypecounts[chunktype] = 0
1636 chunktypesizes[chunktype] = 0
1667 chunktypesizes[chunktype] = 0
1637
1668
1638 chunktypecounts[chunktype] += 1
1669 chunktypecounts[chunktype] += 1
1639 chunktypesizes[chunktype] += size
1670 chunktypesizes[chunktype] += size
1640
1671
1641 # Adjust size min value for empty cases
1672 # Adjust size min value for empty cases
1642 for size in (datasize, fullsize, deltasize):
1673 for size in (datasize, fullsize, deltasize):
1643 if size[0] is None:
1674 if size[0] is None:
1644 size[0] = 0
1675 size[0] = 0
1645
1676
1646 numdeltas = numrevs - numfull
1677 numdeltas = numrevs - numfull
1647 numoprev = numprev - nump1prev - nump2prev
1678 numoprev = numprev - nump1prev - nump2prev
1648 totalrawsize = datasize[2]
1679 totalrawsize = datasize[2]
1649 datasize[2] /= numrevs
1680 datasize[2] /= numrevs
1650 fulltotal = fullsize[2]
1681 fulltotal = fullsize[2]
1651 fullsize[2] /= numfull
1682 fullsize[2] /= numfull
1652 deltatotal = deltasize[2]
1683 deltatotal = deltasize[2]
1653 if numrevs - numfull > 0:
1684 if numrevs - numfull > 0:
1654 deltasize[2] /= numrevs - numfull
1685 deltasize[2] /= numrevs - numfull
1655 totalsize = fulltotal + deltatotal
1686 totalsize = fulltotal + deltatotal
1656 avgchainlen = sum(chainlengths) / numrevs
1687 avgchainlen = sum(chainlengths) / numrevs
1657 maxchainlen = max(chainlengths)
1688 maxchainlen = max(chainlengths)
1658 compratio = 1
1689 compratio = 1
1659 if totalsize:
1690 if totalsize:
1660 compratio = totalrawsize / totalsize
1691 compratio = totalrawsize / totalsize
1661
1692
1662 basedfmtstr = '%%%dd\n'
1693 basedfmtstr = '%%%dd\n'
1663 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1694 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1664
1695
1665 def dfmtstr(max):
1696 def dfmtstr(max):
1666 return basedfmtstr % len(str(max))
1697 return basedfmtstr % len(str(max))
1667 def pcfmtstr(max, padding=0):
1698 def pcfmtstr(max, padding=0):
1668 return basepcfmtstr % (len(str(max)), ' ' * padding)
1699 return basepcfmtstr % (len(str(max)), ' ' * padding)
1669
1700
1670 def pcfmt(value, total):
1701 def pcfmt(value, total):
1671 if total:
1702 if total:
1672 return (value, 100 * float(value) / total)
1703 return (value, 100 * float(value) / total)
1673 else:
1704 else:
1674 return value, 100.0
1705 return value, 100.0
1675
1706
1676 ui.write(('format : %d\n') % format)
1707 ui.write(('format : %d\n') % format)
1677 ui.write(('flags : %s\n') % ', '.join(flags))
1708 ui.write(('flags : %s\n') % ', '.join(flags))
1678
1709
1679 ui.write('\n')
1710 ui.write('\n')
1680 fmt = pcfmtstr(totalsize)
1711 fmt = pcfmtstr(totalsize)
1681 fmt2 = dfmtstr(totalsize)
1712 fmt2 = dfmtstr(totalsize)
1682 ui.write(('revisions : ') + fmt2 % numrevs)
1713 ui.write(('revisions : ') + fmt2 % numrevs)
1683 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
1714 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
1684 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
1715 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
1685 ui.write(('revisions : ') + fmt2 % numrevs)
1716 ui.write(('revisions : ') + fmt2 % numrevs)
1686 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
1717 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
1687 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
1718 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
1688 ui.write(('revision size : ') + fmt2 % totalsize)
1719 ui.write(('revision size : ') + fmt2 % totalsize)
1689 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
1720 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
1690 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
1721 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
1691
1722
1692 def fmtchunktype(chunktype):
1723 def fmtchunktype(chunktype):
1693 if chunktype == 'empty':
1724 if chunktype == 'empty':
1694 return ' %s : ' % chunktype
1725 return ' %s : ' % chunktype
1695 elif chunktype in string.ascii_letters:
1726 elif chunktype in string.ascii_letters:
1696 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
1727 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
1697 else:
1728 else:
1698 return ' 0x%s : ' % hex(chunktype)
1729 return ' 0x%s : ' % hex(chunktype)
1699
1730
1700 ui.write('\n')
1731 ui.write('\n')
1701 ui.write(('chunks : ') + fmt2 % numrevs)
1732 ui.write(('chunks : ') + fmt2 % numrevs)
1702 for chunktype in sorted(chunktypecounts):
1733 for chunktype in sorted(chunktypecounts):
1703 ui.write(fmtchunktype(chunktype))
1734 ui.write(fmtchunktype(chunktype))
1704 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
1735 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
1705 ui.write(('chunks size : ') + fmt2 % totalsize)
1736 ui.write(('chunks size : ') + fmt2 % totalsize)
1706 for chunktype in sorted(chunktypecounts):
1737 for chunktype in sorted(chunktypecounts):
1707 ui.write(fmtchunktype(chunktype))
1738 ui.write(fmtchunktype(chunktype))
1708 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
1739 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
1709
1740
1710 ui.write('\n')
1741 ui.write('\n')
1711 fmt = dfmtstr(max(avgchainlen, compratio))
1742 fmt = dfmtstr(max(avgchainlen, compratio))
1712 ui.write(('avg chain length : ') + fmt % avgchainlen)
1743 ui.write(('avg chain length : ') + fmt % avgchainlen)
1713 ui.write(('max chain length : ') + fmt % maxchainlen)
1744 ui.write(('max chain length : ') + fmt % maxchainlen)
1714 ui.write(('compression ratio : ') + fmt % compratio)
1745 ui.write(('compression ratio : ') + fmt % compratio)
1715
1746
1716 if format > 0:
1747 if format > 0:
1717 ui.write('\n')
1748 ui.write('\n')
1718 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
1749 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
1719 % tuple(datasize))
1750 % tuple(datasize))
1720 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
1751 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
1721 % tuple(fullsize))
1752 % tuple(fullsize))
1722 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
1753 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
1723 % tuple(deltasize))
1754 % tuple(deltasize))
1724
1755
1725 if numdeltas > 0:
1756 if numdeltas > 0:
1726 ui.write('\n')
1757 ui.write('\n')
1727 fmt = pcfmtstr(numdeltas)
1758 fmt = pcfmtstr(numdeltas)
1728 fmt2 = pcfmtstr(numdeltas, 4)
1759 fmt2 = pcfmtstr(numdeltas, 4)
1729 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
1760 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
1730 if numprev > 0:
1761 if numprev > 0:
1731 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
1762 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
1732 numprev))
1763 numprev))
1733 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
1764 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
1734 numprev))
1765 numprev))
1735 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
1766 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
1736 numprev))
1767 numprev))
1737 if gdelta:
1768 if gdelta:
1738 ui.write(('deltas against p1 : ')
1769 ui.write(('deltas against p1 : ')
1739 + fmt % pcfmt(nump1, numdeltas))
1770 + fmt % pcfmt(nump1, numdeltas))
1740 ui.write(('deltas against p2 : ')
1771 ui.write(('deltas against p2 : ')
1741 + fmt % pcfmt(nump2, numdeltas))
1772 + fmt % pcfmt(nump2, numdeltas))
1742 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
1773 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
1743 numdeltas))
1774 numdeltas))
1744
1775
1745 @command('debugrevspec',
1776 @command('debugrevspec',
1746 [('', 'optimize', None,
1777 [('', 'optimize', None,
1747 _('print parsed tree after optimizing (DEPRECATED)')),
1778 _('print parsed tree after optimizing (DEPRECATED)')),
1748 ('p', 'show-stage', [],
1779 ('p', 'show-stage', [],
1749 _('print parsed tree at the given stage'), _('NAME')),
1780 _('print parsed tree at the given stage'), _('NAME')),
1750 ('', 'no-optimized', False, _('evaluate tree without optimization')),
1781 ('', 'no-optimized', False, _('evaluate tree without optimization')),
1751 ('', 'verify-optimized', False, _('verify optimized result')),
1782 ('', 'verify-optimized', False, _('verify optimized result')),
1752 ],
1783 ],
1753 ('REVSPEC'))
1784 ('REVSPEC'))
1754 def debugrevspec(ui, repo, expr, **opts):
1785 def debugrevspec(ui, repo, expr, **opts):
1755 """parse and apply a revision specification
1786 """parse and apply a revision specification
1756
1787
1757 Use -p/--show-stage option to print the parsed tree at the given stages.
1788 Use -p/--show-stage option to print the parsed tree at the given stages.
1758 Use -p all to print tree at every stage.
1789 Use -p all to print tree at every stage.
1759
1790
1760 Use --verify-optimized to compare the optimized result with the unoptimized
1791 Use --verify-optimized to compare the optimized result with the unoptimized
1761 one. Returns 1 if the optimized result differs.
1792 one. Returns 1 if the optimized result differs.
1762 """
1793 """
1763 stages = [
1794 stages = [
1764 ('parsed', lambda tree: tree),
1795 ('parsed', lambda tree: tree),
1765 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
1796 ('expanded', lambda tree: revset.expandaliases(ui, tree)),
1766 ('concatenated', revset.foldconcat),
1797 ('concatenated', revset.foldconcat),
1767 ('analyzed', revset.analyze),
1798 ('analyzed', revset.analyze),
1768 ('optimized', revset.optimize),
1799 ('optimized', revset.optimize),
1769 ]
1800 ]
1770 if opts['no_optimized']:
1801 if opts['no_optimized']:
1771 stages = stages[:-1]
1802 stages = stages[:-1]
1772 if opts['verify_optimized'] and opts['no_optimized']:
1803 if opts['verify_optimized'] and opts['no_optimized']:
1773 raise error.Abort(_('cannot use --verify-optimized with '
1804 raise error.Abort(_('cannot use --verify-optimized with '
1774 '--no-optimized'))
1805 '--no-optimized'))
1775 stagenames = set(n for n, f in stages)
1806 stagenames = set(n for n, f in stages)
1776
1807
1777 showalways = set()
1808 showalways = set()
1778 showchanged = set()
1809 showchanged = set()
1779 if ui.verbose and not opts['show_stage']:
1810 if ui.verbose and not opts['show_stage']:
1780 # show parsed tree by --verbose (deprecated)
1811 # show parsed tree by --verbose (deprecated)
1781 showalways.add('parsed')
1812 showalways.add('parsed')
1782 showchanged.update(['expanded', 'concatenated'])
1813 showchanged.update(['expanded', 'concatenated'])
1783 if opts['optimize']:
1814 if opts['optimize']:
1784 showalways.add('optimized')
1815 showalways.add('optimized')
1785 if opts['show_stage'] and opts['optimize']:
1816 if opts['show_stage'] and opts['optimize']:
1786 raise error.Abort(_('cannot use --optimize with --show-stage'))
1817 raise error.Abort(_('cannot use --optimize with --show-stage'))
1787 if opts['show_stage'] == ['all']:
1818 if opts['show_stage'] == ['all']:
1788 showalways.update(stagenames)
1819 showalways.update(stagenames)
1789 else:
1820 else:
1790 for n in opts['show_stage']:
1821 for n in opts['show_stage']:
1791 if n not in stagenames:
1822 if n not in stagenames:
1792 raise error.Abort(_('invalid stage name: %s') % n)
1823 raise error.Abort(_('invalid stage name: %s') % n)
1793 showalways.update(opts['show_stage'])
1824 showalways.update(opts['show_stage'])
1794
1825
1795 treebystage = {}
1826 treebystage = {}
1796 printedtree = None
1827 printedtree = None
1797 tree = revset.parse(expr, lookup=repo.__contains__)
1828 tree = revset.parse(expr, lookup=repo.__contains__)
1798 for n, f in stages:
1829 for n, f in stages:
1799 treebystage[n] = tree = f(tree)
1830 treebystage[n] = tree = f(tree)
1800 if n in showalways or (n in showchanged and tree != printedtree):
1831 if n in showalways or (n in showchanged and tree != printedtree):
1801 if opts['show_stage'] or n != 'parsed':
1832 if opts['show_stage'] or n != 'parsed':
1802 ui.write(("* %s:\n") % n)
1833 ui.write(("* %s:\n") % n)
1803 ui.write(revset.prettyformat(tree), "\n")
1834 ui.write(revset.prettyformat(tree), "\n")
1804 printedtree = tree
1835 printedtree = tree
1805
1836
1806 if opts['verify_optimized']:
1837 if opts['verify_optimized']:
1807 arevs = revset.makematcher(treebystage['analyzed'])(repo)
1838 arevs = revset.makematcher(treebystage['analyzed'])(repo)
1808 brevs = revset.makematcher(treebystage['optimized'])(repo)
1839 brevs = revset.makematcher(treebystage['optimized'])(repo)
1809 if ui.verbose:
1840 if ui.verbose:
1810 ui.note(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
1841 ui.note(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
1811 ui.note(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
1842 ui.note(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
1812 arevs = list(arevs)
1843 arevs = list(arevs)
1813 brevs = list(brevs)
1844 brevs = list(brevs)
1814 if arevs == brevs:
1845 if arevs == brevs:
1815 return 0
1846 return 0
1816 ui.write(('--- analyzed\n'), label='diff.file_a')
1847 ui.write(('--- analyzed\n'), label='diff.file_a')
1817 ui.write(('+++ optimized\n'), label='diff.file_b')
1848 ui.write(('+++ optimized\n'), label='diff.file_b')
1818 sm = difflib.SequenceMatcher(None, arevs, brevs)
1849 sm = difflib.SequenceMatcher(None, arevs, brevs)
1819 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1850 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1820 if tag in ('delete', 'replace'):
1851 if tag in ('delete', 'replace'):
1821 for c in arevs[alo:ahi]:
1852 for c in arevs[alo:ahi]:
1822 ui.write('-%s\n' % c, label='diff.deleted')
1853 ui.write('-%s\n' % c, label='diff.deleted')
1823 if tag in ('insert', 'replace'):
1854 if tag in ('insert', 'replace'):
1824 for c in brevs[blo:bhi]:
1855 for c in brevs[blo:bhi]:
1825 ui.write('+%s\n' % c, label='diff.inserted')
1856 ui.write('+%s\n' % c, label='diff.inserted')
1826 if tag == 'equal':
1857 if tag == 'equal':
1827 for c in arevs[alo:ahi]:
1858 for c in arevs[alo:ahi]:
1828 ui.write(' %s\n' % c)
1859 ui.write(' %s\n' % c)
1829 return 1
1860 return 1
1830
1861
1831 func = revset.makematcher(tree)
1862 func = revset.makematcher(tree)
1832 revs = func(repo)
1863 revs = func(repo)
1833 if ui.verbose:
1864 if ui.verbose:
1834 ui.note(("* set:\n"), smartset.prettyformat(revs), "\n")
1865 ui.note(("* set:\n"), smartset.prettyformat(revs), "\n")
1835 for c in revs:
1866 for c in revs:
1836 ui.write("%s\n" % c)
1867 ui.write("%s\n" % c)
1837
1868
1838 @command('debugsetparents', [], _('REV1 [REV2]'))
1869 @command('debugsetparents', [], _('REV1 [REV2]'))
1839 def debugsetparents(ui, repo, rev1, rev2=None):
1870 def debugsetparents(ui, repo, rev1, rev2=None):
1840 """manually set the parents of the current working directory
1871 """manually set the parents of the current working directory
1841
1872
1842 This is useful for writing repository conversion tools, but should
1873 This is useful for writing repository conversion tools, but should
1843 be used with care. For example, neither the working directory nor the
1874 be used with care. For example, neither the working directory nor the
1844 dirstate is updated, so file status may be incorrect after running this
1875 dirstate is updated, so file status may be incorrect after running this
1845 command.
1876 command.
1846
1877
1847 Returns 0 on success.
1878 Returns 0 on success.
1848 """
1879 """
1849
1880
1850 r1 = scmutil.revsingle(repo, rev1).node()
1881 r1 = scmutil.revsingle(repo, rev1).node()
1851 r2 = scmutil.revsingle(repo, rev2, 'null').node()
1882 r2 = scmutil.revsingle(repo, rev2, 'null').node()
1852
1883
1853 with repo.wlock():
1884 with repo.wlock():
1854 repo.setparents(r1, r2)
1885 repo.setparents(r1, r2)
1855
1886
1856 @command('debugupgraderepo', [
1887 @command('debugupgraderepo', [
1857 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
1888 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
1858 ('', 'run', False, _('performs an upgrade')),
1889 ('', 'run', False, _('performs an upgrade')),
1859 ])
1890 ])
1860 def debugupgraderepo(ui, repo, run=False, optimize=None):
1891 def debugupgraderepo(ui, repo, run=False, optimize=None):
1861 """upgrade a repository to use different features
1892 """upgrade a repository to use different features
1862
1893
1863 If no arguments are specified, the repository is evaluated for upgrade
1894 If no arguments are specified, the repository is evaluated for upgrade
1864 and a list of problems and potential optimizations is printed.
1895 and a list of problems and potential optimizations is printed.
1865
1896
1866 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
1897 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
1867 can be influenced via additional arguments. More details will be provided
1898 can be influenced via additional arguments. More details will be provided
1868 by the command output when run without ``--run``.
1899 by the command output when run without ``--run``.
1869
1900
1870 During the upgrade, the repository will be locked and no writes will be
1901 During the upgrade, the repository will be locked and no writes will be
1871 allowed.
1902 allowed.
1872
1903
1873 At the end of the upgrade, the repository may not be readable while new
1904 At the end of the upgrade, the repository may not be readable while new
1874 repository data is swapped in. This window will be as long as it takes to
1905 repository data is swapped in. This window will be as long as it takes to
1875 rename some directories inside the ``.hg`` directory. On most machines, this
1906 rename some directories inside the ``.hg`` directory. On most machines, this
1876 should complete almost instantaneously and the chances of a consumer being
1907 should complete almost instantaneously and the chances of a consumer being
1877 unable to access the repository should be low.
1908 unable to access the repository should be low.
1878 """
1909 """
1879 return repair.upgraderepo(ui, repo, run=run, optimize=optimize)
1910 return repair.upgraderepo(ui, repo, run=run, optimize=optimize)
General Comments 0
You need to be logged in to leave comments. Login now