##// END OF EJS Templates
pull: add help information about pulling active bookmark
liscju -
r29384:c75c8ea2 default
parent child Browse files
Show More
@@ -1,7270 +1,7273
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import operator
12 import operator
13 import os
13 import os
14 import random
14 import random
15 import re
15 import re
16 import shlex
16 import shlex
17 import socket
17 import socket
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 import time
20 import time
21
21
22 from .i18n import _
22 from .i18n import _
23 from .node import (
23 from .node import (
24 bin,
24 bin,
25 hex,
25 hex,
26 nullhex,
26 nullhex,
27 nullid,
27 nullid,
28 nullrev,
28 nullrev,
29 short,
29 short,
30 )
30 )
31 from . import (
31 from . import (
32 archival,
32 archival,
33 bookmarks,
33 bookmarks,
34 bundle2,
34 bundle2,
35 changegroup,
35 changegroup,
36 cmdutil,
36 cmdutil,
37 commandserver,
37 commandserver,
38 context,
38 context,
39 copies,
39 copies,
40 dagparser,
40 dagparser,
41 dagutil,
41 dagutil,
42 destutil,
42 destutil,
43 discovery,
43 discovery,
44 encoding,
44 encoding,
45 error,
45 error,
46 exchange,
46 exchange,
47 extensions,
47 extensions,
48 fileset,
48 fileset,
49 formatter,
49 formatter,
50 graphmod,
50 graphmod,
51 hbisect,
51 hbisect,
52 help,
52 help,
53 hg,
53 hg,
54 hgweb,
54 hgweb,
55 localrepo,
55 localrepo,
56 lock as lockmod,
56 lock as lockmod,
57 merge as mergemod,
57 merge as mergemod,
58 minirst,
58 minirst,
59 obsolete,
59 obsolete,
60 patch,
60 patch,
61 phases,
61 phases,
62 policy,
62 policy,
63 pvec,
63 pvec,
64 repair,
64 repair,
65 revlog,
65 revlog,
66 revset,
66 revset,
67 scmutil,
67 scmutil,
68 setdiscovery,
68 setdiscovery,
69 simplemerge,
69 simplemerge,
70 sshserver,
70 sshserver,
71 streamclone,
71 streamclone,
72 templatekw,
72 templatekw,
73 templater,
73 templater,
74 treediscovery,
74 treediscovery,
75 ui as uimod,
75 ui as uimod,
76 util,
76 util,
77 )
77 )
78
78
79 release = lockmod.release
79 release = lockmod.release
80
80
81 table = {}
81 table = {}
82
82
83 command = cmdutil.command(table)
83 command = cmdutil.command(table)
84
84
85 # label constants
85 # label constants
86 # until 3.5, bookmarks.current was the advertised name, not
86 # until 3.5, bookmarks.current was the advertised name, not
87 # bookmarks.active, so we must use both to avoid breaking old
87 # bookmarks.active, so we must use both to avoid breaking old
88 # custom styles
88 # custom styles
89 activebookmarklabel = 'bookmarks.active bookmarks.current'
89 activebookmarklabel = 'bookmarks.active bookmarks.current'
90
90
91 # common command options
91 # common command options
92
92
93 globalopts = [
93 globalopts = [
94 ('R', 'repository', '',
94 ('R', 'repository', '',
95 _('repository root directory or name of overlay bundle file'),
95 _('repository root directory or name of overlay bundle file'),
96 _('REPO')),
96 _('REPO')),
97 ('', 'cwd', '',
97 ('', 'cwd', '',
98 _('change working directory'), _('DIR')),
98 _('change working directory'), _('DIR')),
99 ('y', 'noninteractive', None,
99 ('y', 'noninteractive', None,
100 _('do not prompt, automatically pick the first choice for all prompts')),
100 _('do not prompt, automatically pick the first choice for all prompts')),
101 ('q', 'quiet', None, _('suppress output')),
101 ('q', 'quiet', None, _('suppress output')),
102 ('v', 'verbose', None, _('enable additional output')),
102 ('v', 'verbose', None, _('enable additional output')),
103 ('', 'config', [],
103 ('', 'config', [],
104 _('set/override config option (use \'section.name=value\')'),
104 _('set/override config option (use \'section.name=value\')'),
105 _('CONFIG')),
105 _('CONFIG')),
106 ('', 'debug', None, _('enable debugging output')),
106 ('', 'debug', None, _('enable debugging output')),
107 ('', 'debugger', None, _('start debugger')),
107 ('', 'debugger', None, _('start debugger')),
108 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
108 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
109 _('ENCODE')),
109 _('ENCODE')),
110 ('', 'encodingmode', encoding.encodingmode,
110 ('', 'encodingmode', encoding.encodingmode,
111 _('set the charset encoding mode'), _('MODE')),
111 _('set the charset encoding mode'), _('MODE')),
112 ('', 'traceback', None, _('always print a traceback on exception')),
112 ('', 'traceback', None, _('always print a traceback on exception')),
113 ('', 'time', None, _('time how long the command takes')),
113 ('', 'time', None, _('time how long the command takes')),
114 ('', 'profile', None, _('print command execution profile')),
114 ('', 'profile', None, _('print command execution profile')),
115 ('', 'version', None, _('output version information and exit')),
115 ('', 'version', None, _('output version information and exit')),
116 ('h', 'help', None, _('display help and exit')),
116 ('h', 'help', None, _('display help and exit')),
117 ('', 'hidden', False, _('consider hidden changesets')),
117 ('', 'hidden', False, _('consider hidden changesets')),
118 ]
118 ]
119
119
120 dryrunopts = [('n', 'dry-run', None,
120 dryrunopts = [('n', 'dry-run', None,
121 _('do not perform actions, just print output'))]
121 _('do not perform actions, just print output'))]
122
122
123 remoteopts = [
123 remoteopts = [
124 ('e', 'ssh', '',
124 ('e', 'ssh', '',
125 _('specify ssh command to use'), _('CMD')),
125 _('specify ssh command to use'), _('CMD')),
126 ('', 'remotecmd', '',
126 ('', 'remotecmd', '',
127 _('specify hg command to run on the remote side'), _('CMD')),
127 _('specify hg command to run on the remote side'), _('CMD')),
128 ('', 'insecure', None,
128 ('', 'insecure', None,
129 _('do not verify server certificate (ignoring web.cacerts config)')),
129 _('do not verify server certificate (ignoring web.cacerts config)')),
130 ]
130 ]
131
131
132 walkopts = [
132 walkopts = [
133 ('I', 'include', [],
133 ('I', 'include', [],
134 _('include names matching the given patterns'), _('PATTERN')),
134 _('include names matching the given patterns'), _('PATTERN')),
135 ('X', 'exclude', [],
135 ('X', 'exclude', [],
136 _('exclude names matching the given patterns'), _('PATTERN')),
136 _('exclude names matching the given patterns'), _('PATTERN')),
137 ]
137 ]
138
138
139 commitopts = [
139 commitopts = [
140 ('m', 'message', '',
140 ('m', 'message', '',
141 _('use text as commit message'), _('TEXT')),
141 _('use text as commit message'), _('TEXT')),
142 ('l', 'logfile', '',
142 ('l', 'logfile', '',
143 _('read commit message from file'), _('FILE')),
143 _('read commit message from file'), _('FILE')),
144 ]
144 ]
145
145
146 commitopts2 = [
146 commitopts2 = [
147 ('d', 'date', '',
147 ('d', 'date', '',
148 _('record the specified date as commit date'), _('DATE')),
148 _('record the specified date as commit date'), _('DATE')),
149 ('u', 'user', '',
149 ('u', 'user', '',
150 _('record the specified user as committer'), _('USER')),
150 _('record the specified user as committer'), _('USER')),
151 ]
151 ]
152
152
153 # hidden for now
153 # hidden for now
154 formatteropts = [
154 formatteropts = [
155 ('T', 'template', '',
155 ('T', 'template', '',
156 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
156 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
157 ]
157 ]
158
158
159 templateopts = [
159 templateopts = [
160 ('', 'style', '',
160 ('', 'style', '',
161 _('display using template map file (DEPRECATED)'), _('STYLE')),
161 _('display using template map file (DEPRECATED)'), _('STYLE')),
162 ('T', 'template', '',
162 ('T', 'template', '',
163 _('display with template'), _('TEMPLATE')),
163 _('display with template'), _('TEMPLATE')),
164 ]
164 ]
165
165
166 logopts = [
166 logopts = [
167 ('p', 'patch', None, _('show patch')),
167 ('p', 'patch', None, _('show patch')),
168 ('g', 'git', None, _('use git extended diff format')),
168 ('g', 'git', None, _('use git extended diff format')),
169 ('l', 'limit', '',
169 ('l', 'limit', '',
170 _('limit number of changes displayed'), _('NUM')),
170 _('limit number of changes displayed'), _('NUM')),
171 ('M', 'no-merges', None, _('do not show merges')),
171 ('M', 'no-merges', None, _('do not show merges')),
172 ('', 'stat', None, _('output diffstat-style summary of changes')),
172 ('', 'stat', None, _('output diffstat-style summary of changes')),
173 ('G', 'graph', None, _("show the revision DAG")),
173 ('G', 'graph', None, _("show the revision DAG")),
174 ] + templateopts
174 ] + templateopts
175
175
176 diffopts = [
176 diffopts = [
177 ('a', 'text', None, _('treat all files as text')),
177 ('a', 'text', None, _('treat all files as text')),
178 ('g', 'git', None, _('use git extended diff format')),
178 ('g', 'git', None, _('use git extended diff format')),
179 ('', 'nodates', None, _('omit dates from diff headers'))
179 ('', 'nodates', None, _('omit dates from diff headers'))
180 ]
180 ]
181
181
182 diffwsopts = [
182 diffwsopts = [
183 ('w', 'ignore-all-space', None,
183 ('w', 'ignore-all-space', None,
184 _('ignore white space when comparing lines')),
184 _('ignore white space when comparing lines')),
185 ('b', 'ignore-space-change', None,
185 ('b', 'ignore-space-change', None,
186 _('ignore changes in the amount of white space')),
186 _('ignore changes in the amount of white space')),
187 ('B', 'ignore-blank-lines', None,
187 ('B', 'ignore-blank-lines', None,
188 _('ignore changes whose lines are all blank')),
188 _('ignore changes whose lines are all blank')),
189 ]
189 ]
190
190
191 diffopts2 = [
191 diffopts2 = [
192 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
192 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
193 ('p', 'show-function', None, _('show which function each change is in')),
193 ('p', 'show-function', None, _('show which function each change is in')),
194 ('', 'reverse', None, _('produce a diff that undoes the changes')),
194 ('', 'reverse', None, _('produce a diff that undoes the changes')),
195 ] + diffwsopts + [
195 ] + diffwsopts + [
196 ('U', 'unified', '',
196 ('U', 'unified', '',
197 _('number of lines of context to show'), _('NUM')),
197 _('number of lines of context to show'), _('NUM')),
198 ('', 'stat', None, _('output diffstat-style summary of changes')),
198 ('', 'stat', None, _('output diffstat-style summary of changes')),
199 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
199 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
200 ]
200 ]
201
201
202 mergetoolopts = [
202 mergetoolopts = [
203 ('t', 'tool', '', _('specify merge tool')),
203 ('t', 'tool', '', _('specify merge tool')),
204 ]
204 ]
205
205
206 similarityopts = [
206 similarityopts = [
207 ('s', 'similarity', '',
207 ('s', 'similarity', '',
208 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
208 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
209 ]
209 ]
210
210
211 subrepoopts = [
211 subrepoopts = [
212 ('S', 'subrepos', None,
212 ('S', 'subrepos', None,
213 _('recurse into subrepositories'))
213 _('recurse into subrepositories'))
214 ]
214 ]
215
215
216 debugrevlogopts = [
216 debugrevlogopts = [
217 ('c', 'changelog', False, _('open changelog')),
217 ('c', 'changelog', False, _('open changelog')),
218 ('m', 'manifest', False, _('open manifest')),
218 ('m', 'manifest', False, _('open manifest')),
219 ('', 'dir', False, _('open directory manifest')),
219 ('', 'dir', False, _('open directory manifest')),
220 ]
220 ]
221
221
222 # Commands start here, listed alphabetically
222 # Commands start here, listed alphabetically
223
223
224 @command('^add',
224 @command('^add',
225 walkopts + subrepoopts + dryrunopts,
225 walkopts + subrepoopts + dryrunopts,
226 _('[OPTION]... [FILE]...'),
226 _('[OPTION]... [FILE]...'),
227 inferrepo=True)
227 inferrepo=True)
228 def add(ui, repo, *pats, **opts):
228 def add(ui, repo, *pats, **opts):
229 """add the specified files on the next commit
229 """add the specified files on the next commit
230
230
231 Schedule files to be version controlled and added to the
231 Schedule files to be version controlled and added to the
232 repository.
232 repository.
233
233
234 The files will be added to the repository at the next commit. To
234 The files will be added to the repository at the next commit. To
235 undo an add before that, see :hg:`forget`.
235 undo an add before that, see :hg:`forget`.
236
236
237 If no names are given, add all files to the repository (except
237 If no names are given, add all files to the repository (except
238 files matching ``.hgignore``).
238 files matching ``.hgignore``).
239
239
240 .. container:: verbose
240 .. container:: verbose
241
241
242 Examples:
242 Examples:
243
243
244 - New (unknown) files are added
244 - New (unknown) files are added
245 automatically by :hg:`add`::
245 automatically by :hg:`add`::
246
246
247 $ ls
247 $ ls
248 foo.c
248 foo.c
249 $ hg status
249 $ hg status
250 ? foo.c
250 ? foo.c
251 $ hg add
251 $ hg add
252 adding foo.c
252 adding foo.c
253 $ hg status
253 $ hg status
254 A foo.c
254 A foo.c
255
255
256 - Specific files to be added can be specified::
256 - Specific files to be added can be specified::
257
257
258 $ ls
258 $ ls
259 bar.c foo.c
259 bar.c foo.c
260 $ hg status
260 $ hg status
261 ? bar.c
261 ? bar.c
262 ? foo.c
262 ? foo.c
263 $ hg add bar.c
263 $ hg add bar.c
264 $ hg status
264 $ hg status
265 A bar.c
265 A bar.c
266 ? foo.c
266 ? foo.c
267
267
268 Returns 0 if all files are successfully added.
268 Returns 0 if all files are successfully added.
269 """
269 """
270
270
271 m = scmutil.match(repo[None], pats, opts)
271 m = scmutil.match(repo[None], pats, opts)
272 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
272 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
273 return rejected and 1 or 0
273 return rejected and 1 or 0
274
274
275 @command('addremove',
275 @command('addremove',
276 similarityopts + subrepoopts + walkopts + dryrunopts,
276 similarityopts + subrepoopts + walkopts + dryrunopts,
277 _('[OPTION]... [FILE]...'),
277 _('[OPTION]... [FILE]...'),
278 inferrepo=True)
278 inferrepo=True)
279 def addremove(ui, repo, *pats, **opts):
279 def addremove(ui, repo, *pats, **opts):
280 """add all new files, delete all missing files
280 """add all new files, delete all missing files
281
281
282 Add all new files and remove all missing files from the
282 Add all new files and remove all missing files from the
283 repository.
283 repository.
284
284
285 Unless names are given, new files are ignored if they match any of
285 Unless names are given, new files are ignored if they match any of
286 the patterns in ``.hgignore``. As with add, these changes take
286 the patterns in ``.hgignore``. As with add, these changes take
287 effect at the next commit.
287 effect at the next commit.
288
288
289 Use the -s/--similarity option to detect renamed files. This
289 Use the -s/--similarity option to detect renamed files. This
290 option takes a percentage between 0 (disabled) and 100 (files must
290 option takes a percentage between 0 (disabled) and 100 (files must
291 be identical) as its parameter. With a parameter greater than 0,
291 be identical) as its parameter. With a parameter greater than 0,
292 this compares every removed file with every added file and records
292 this compares every removed file with every added file and records
293 those similar enough as renames. Detecting renamed files this way
293 those similar enough as renames. Detecting renamed files this way
294 can be expensive. After using this option, :hg:`status -C` can be
294 can be expensive. After using this option, :hg:`status -C` can be
295 used to check which files were identified as moved or renamed. If
295 used to check which files were identified as moved or renamed. If
296 not specified, -s/--similarity defaults to 100 and only renames of
296 not specified, -s/--similarity defaults to 100 and only renames of
297 identical files are detected.
297 identical files are detected.
298
298
299 .. container:: verbose
299 .. container:: verbose
300
300
301 Examples:
301 Examples:
302
302
303 - A number of files (bar.c and foo.c) are new,
303 - A number of files (bar.c and foo.c) are new,
304 while foobar.c has been removed (without using :hg:`remove`)
304 while foobar.c has been removed (without using :hg:`remove`)
305 from the repository::
305 from the repository::
306
306
307 $ ls
307 $ ls
308 bar.c foo.c
308 bar.c foo.c
309 $ hg status
309 $ hg status
310 ! foobar.c
310 ! foobar.c
311 ? bar.c
311 ? bar.c
312 ? foo.c
312 ? foo.c
313 $ hg addremove
313 $ hg addremove
314 adding bar.c
314 adding bar.c
315 adding foo.c
315 adding foo.c
316 removing foobar.c
316 removing foobar.c
317 $ hg status
317 $ hg status
318 A bar.c
318 A bar.c
319 A foo.c
319 A foo.c
320 R foobar.c
320 R foobar.c
321
321
322 - A file foobar.c was moved to foo.c without using :hg:`rename`.
322 - A file foobar.c was moved to foo.c without using :hg:`rename`.
323 Afterwards, it was edited slightly::
323 Afterwards, it was edited slightly::
324
324
325 $ ls
325 $ ls
326 foo.c
326 foo.c
327 $ hg status
327 $ hg status
328 ! foobar.c
328 ! foobar.c
329 ? foo.c
329 ? foo.c
330 $ hg addremove --similarity 90
330 $ hg addremove --similarity 90
331 removing foobar.c
331 removing foobar.c
332 adding foo.c
332 adding foo.c
333 recording removal of foobar.c as rename to foo.c (94% similar)
333 recording removal of foobar.c as rename to foo.c (94% similar)
334 $ hg status -C
334 $ hg status -C
335 A foo.c
335 A foo.c
336 foobar.c
336 foobar.c
337 R foobar.c
337 R foobar.c
338
338
339 Returns 0 if all files are successfully added.
339 Returns 0 if all files are successfully added.
340 """
340 """
341 try:
341 try:
342 sim = float(opts.get('similarity') or 100)
342 sim = float(opts.get('similarity') or 100)
343 except ValueError:
343 except ValueError:
344 raise error.Abort(_('similarity must be a number'))
344 raise error.Abort(_('similarity must be a number'))
345 if sim < 0 or sim > 100:
345 if sim < 0 or sim > 100:
346 raise error.Abort(_('similarity must be between 0 and 100'))
346 raise error.Abort(_('similarity must be between 0 and 100'))
347 matcher = scmutil.match(repo[None], pats, opts)
347 matcher = scmutil.match(repo[None], pats, opts)
348 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
348 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
349
349
350 @command('^annotate|blame',
350 @command('^annotate|blame',
351 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
351 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
352 ('', 'follow', None,
352 ('', 'follow', None,
353 _('follow copies/renames and list the filename (DEPRECATED)')),
353 _('follow copies/renames and list the filename (DEPRECATED)')),
354 ('', 'no-follow', None, _("don't follow copies and renames")),
354 ('', 'no-follow', None, _("don't follow copies and renames")),
355 ('a', 'text', None, _('treat all files as text')),
355 ('a', 'text', None, _('treat all files as text')),
356 ('u', 'user', None, _('list the author (long with -v)')),
356 ('u', 'user', None, _('list the author (long with -v)')),
357 ('f', 'file', None, _('list the filename')),
357 ('f', 'file', None, _('list the filename')),
358 ('d', 'date', None, _('list the date (short with -q)')),
358 ('d', 'date', None, _('list the date (short with -q)')),
359 ('n', 'number', None, _('list the revision number (default)')),
359 ('n', 'number', None, _('list the revision number (default)')),
360 ('c', 'changeset', None, _('list the changeset')),
360 ('c', 'changeset', None, _('list the changeset')),
361 ('l', 'line-number', None, _('show line number at the first appearance'))
361 ('l', 'line-number', None, _('show line number at the first appearance'))
362 ] + diffwsopts + walkopts + formatteropts,
362 ] + diffwsopts + walkopts + formatteropts,
363 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
363 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
364 inferrepo=True)
364 inferrepo=True)
365 def annotate(ui, repo, *pats, **opts):
365 def annotate(ui, repo, *pats, **opts):
366 """show changeset information by line for each file
366 """show changeset information by line for each file
367
367
368 List changes in files, showing the revision id responsible for
368 List changes in files, showing the revision id responsible for
369 each line.
369 each line.
370
370
371 This command is useful for discovering when a change was made and
371 This command is useful for discovering when a change was made and
372 by whom.
372 by whom.
373
373
374 If you include --file, --user, or --date, the revision number is
374 If you include --file, --user, or --date, the revision number is
375 suppressed unless you also include --number.
375 suppressed unless you also include --number.
376
376
377 Without the -a/--text option, annotate will avoid processing files
377 Without the -a/--text option, annotate will avoid processing files
378 it detects as binary. With -a, annotate will annotate the file
378 it detects as binary. With -a, annotate will annotate the file
379 anyway, although the results will probably be neither useful
379 anyway, although the results will probably be neither useful
380 nor desirable.
380 nor desirable.
381
381
382 Returns 0 on success.
382 Returns 0 on success.
383 """
383 """
384 if not pats:
384 if not pats:
385 raise error.Abort(_('at least one filename or pattern is required'))
385 raise error.Abort(_('at least one filename or pattern is required'))
386
386
387 if opts.get('follow'):
387 if opts.get('follow'):
388 # --follow is deprecated and now just an alias for -f/--file
388 # --follow is deprecated and now just an alias for -f/--file
389 # to mimic the behavior of Mercurial before version 1.5
389 # to mimic the behavior of Mercurial before version 1.5
390 opts['file'] = True
390 opts['file'] = True
391
391
392 ctx = scmutil.revsingle(repo, opts.get('rev'))
392 ctx = scmutil.revsingle(repo, opts.get('rev'))
393
393
394 fm = ui.formatter('annotate', opts)
394 fm = ui.formatter('annotate', opts)
395 if ui.quiet:
395 if ui.quiet:
396 datefunc = util.shortdate
396 datefunc = util.shortdate
397 else:
397 else:
398 datefunc = util.datestr
398 datefunc = util.datestr
399 if ctx.rev() is None:
399 if ctx.rev() is None:
400 def hexfn(node):
400 def hexfn(node):
401 if node is None:
401 if node is None:
402 return None
402 return None
403 else:
403 else:
404 return fm.hexfunc(node)
404 return fm.hexfunc(node)
405 if opts.get('changeset'):
405 if opts.get('changeset'):
406 # omit "+" suffix which is appended to node hex
406 # omit "+" suffix which is appended to node hex
407 def formatrev(rev):
407 def formatrev(rev):
408 if rev is None:
408 if rev is None:
409 return '%d' % ctx.p1().rev()
409 return '%d' % ctx.p1().rev()
410 else:
410 else:
411 return '%d' % rev
411 return '%d' % rev
412 else:
412 else:
413 def formatrev(rev):
413 def formatrev(rev):
414 if rev is None:
414 if rev is None:
415 return '%d+' % ctx.p1().rev()
415 return '%d+' % ctx.p1().rev()
416 else:
416 else:
417 return '%d ' % rev
417 return '%d ' % rev
418 def formathex(hex):
418 def formathex(hex):
419 if hex is None:
419 if hex is None:
420 return '%s+' % fm.hexfunc(ctx.p1().node())
420 return '%s+' % fm.hexfunc(ctx.p1().node())
421 else:
421 else:
422 return '%s ' % hex
422 return '%s ' % hex
423 else:
423 else:
424 hexfn = fm.hexfunc
424 hexfn = fm.hexfunc
425 formatrev = formathex = str
425 formatrev = formathex = str
426
426
427 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
427 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
428 ('number', ' ', lambda x: x[0].rev(), formatrev),
428 ('number', ' ', lambda x: x[0].rev(), formatrev),
429 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
429 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
430 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
430 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
431 ('file', ' ', lambda x: x[0].path(), str),
431 ('file', ' ', lambda x: x[0].path(), str),
432 ('line_number', ':', lambda x: x[1], str),
432 ('line_number', ':', lambda x: x[1], str),
433 ]
433 ]
434 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
434 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
435
435
436 if (not opts.get('user') and not opts.get('changeset')
436 if (not opts.get('user') and not opts.get('changeset')
437 and not opts.get('date') and not opts.get('file')):
437 and not opts.get('date') and not opts.get('file')):
438 opts['number'] = True
438 opts['number'] = True
439
439
440 linenumber = opts.get('line_number') is not None
440 linenumber = opts.get('line_number') is not None
441 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
441 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
442 raise error.Abort(_('at least one of -n/-c is required for -l'))
442 raise error.Abort(_('at least one of -n/-c is required for -l'))
443
443
444 if fm:
444 if fm:
445 def makefunc(get, fmt):
445 def makefunc(get, fmt):
446 return get
446 return get
447 else:
447 else:
448 def makefunc(get, fmt):
448 def makefunc(get, fmt):
449 return lambda x: fmt(get(x))
449 return lambda x: fmt(get(x))
450 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
450 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
451 if opts.get(op)]
451 if opts.get(op)]
452 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
452 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
453 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
453 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
454 if opts.get(op))
454 if opts.get(op))
455
455
456 def bad(x, y):
456 def bad(x, y):
457 raise error.Abort("%s: %s" % (x, y))
457 raise error.Abort("%s: %s" % (x, y))
458
458
459 m = scmutil.match(ctx, pats, opts, badfn=bad)
459 m = scmutil.match(ctx, pats, opts, badfn=bad)
460
460
461 follow = not opts.get('no_follow')
461 follow = not opts.get('no_follow')
462 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
462 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
463 whitespace=True)
463 whitespace=True)
464 for abs in ctx.walk(m):
464 for abs in ctx.walk(m):
465 fctx = ctx[abs]
465 fctx = ctx[abs]
466 if not opts.get('text') and util.binary(fctx.data()):
466 if not opts.get('text') and util.binary(fctx.data()):
467 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
467 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
468 continue
468 continue
469
469
470 lines = fctx.annotate(follow=follow, linenumber=linenumber,
470 lines = fctx.annotate(follow=follow, linenumber=linenumber,
471 diffopts=diffopts)
471 diffopts=diffopts)
472 formats = []
472 formats = []
473 pieces = []
473 pieces = []
474
474
475 for f, sep in funcmap:
475 for f, sep in funcmap:
476 l = [f(n) for n, dummy in lines]
476 l = [f(n) for n, dummy in lines]
477 if l:
477 if l:
478 if fm:
478 if fm:
479 formats.append(['%s' for x in l])
479 formats.append(['%s' for x in l])
480 else:
480 else:
481 sizes = [encoding.colwidth(x) for x in l]
481 sizes = [encoding.colwidth(x) for x in l]
482 ml = max(sizes)
482 ml = max(sizes)
483 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
483 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
484 pieces.append(l)
484 pieces.append(l)
485
485
486 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
486 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
487 fm.startitem()
487 fm.startitem()
488 fm.write(fields, "".join(f), *p)
488 fm.write(fields, "".join(f), *p)
489 fm.write('line', ": %s", l[1])
489 fm.write('line', ": %s", l[1])
490
490
491 if lines and not lines[-1][1].endswith('\n'):
491 if lines and not lines[-1][1].endswith('\n'):
492 fm.plain('\n')
492 fm.plain('\n')
493
493
494 fm.end()
494 fm.end()
495
495
496 @command('archive',
496 @command('archive',
497 [('', 'no-decode', None, _('do not pass files through decoders')),
497 [('', 'no-decode', None, _('do not pass files through decoders')),
498 ('p', 'prefix', '', _('directory prefix for files in archive'),
498 ('p', 'prefix', '', _('directory prefix for files in archive'),
499 _('PREFIX')),
499 _('PREFIX')),
500 ('r', 'rev', '', _('revision to distribute'), _('REV')),
500 ('r', 'rev', '', _('revision to distribute'), _('REV')),
501 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
501 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
502 ] + subrepoopts + walkopts,
502 ] + subrepoopts + walkopts,
503 _('[OPTION]... DEST'))
503 _('[OPTION]... DEST'))
504 def archive(ui, repo, dest, **opts):
504 def archive(ui, repo, dest, **opts):
505 '''create an unversioned archive of a repository revision
505 '''create an unversioned archive of a repository revision
506
506
507 By default, the revision used is the parent of the working
507 By default, the revision used is the parent of the working
508 directory; use -r/--rev to specify a different revision.
508 directory; use -r/--rev to specify a different revision.
509
509
510 The archive type is automatically detected based on file
510 The archive type is automatically detected based on file
511 extension (to override, use -t/--type).
511 extension (to override, use -t/--type).
512
512
513 .. container:: verbose
513 .. container:: verbose
514
514
515 Examples:
515 Examples:
516
516
517 - create a zip file containing the 1.0 release::
517 - create a zip file containing the 1.0 release::
518
518
519 hg archive -r 1.0 project-1.0.zip
519 hg archive -r 1.0 project-1.0.zip
520
520
521 - create a tarball excluding .hg files::
521 - create a tarball excluding .hg files::
522
522
523 hg archive project.tar.gz -X ".hg*"
523 hg archive project.tar.gz -X ".hg*"
524
524
525 Valid types are:
525 Valid types are:
526
526
527 :``files``: a directory full of files (default)
527 :``files``: a directory full of files (default)
528 :``tar``: tar archive, uncompressed
528 :``tar``: tar archive, uncompressed
529 :``tbz2``: tar archive, compressed using bzip2
529 :``tbz2``: tar archive, compressed using bzip2
530 :``tgz``: tar archive, compressed using gzip
530 :``tgz``: tar archive, compressed using gzip
531 :``uzip``: zip archive, uncompressed
531 :``uzip``: zip archive, uncompressed
532 :``zip``: zip archive, compressed using deflate
532 :``zip``: zip archive, compressed using deflate
533
533
534 The exact name of the destination archive or directory is given
534 The exact name of the destination archive or directory is given
535 using a format string; see :hg:`help export` for details.
535 using a format string; see :hg:`help export` for details.
536
536
537 Each member added to an archive file has a directory prefix
537 Each member added to an archive file has a directory prefix
538 prepended. Use -p/--prefix to specify a format string for the
538 prepended. Use -p/--prefix to specify a format string for the
539 prefix. The default is the basename of the archive, with suffixes
539 prefix. The default is the basename of the archive, with suffixes
540 removed.
540 removed.
541
541
542 Returns 0 on success.
542 Returns 0 on success.
543 '''
543 '''
544
544
545 ctx = scmutil.revsingle(repo, opts.get('rev'))
545 ctx = scmutil.revsingle(repo, opts.get('rev'))
546 if not ctx:
546 if not ctx:
547 raise error.Abort(_('no working directory: please specify a revision'))
547 raise error.Abort(_('no working directory: please specify a revision'))
548 node = ctx.node()
548 node = ctx.node()
549 dest = cmdutil.makefilename(repo, dest, node)
549 dest = cmdutil.makefilename(repo, dest, node)
550 if os.path.realpath(dest) == repo.root:
550 if os.path.realpath(dest) == repo.root:
551 raise error.Abort(_('repository root cannot be destination'))
551 raise error.Abort(_('repository root cannot be destination'))
552
552
553 kind = opts.get('type') or archival.guesskind(dest) or 'files'
553 kind = opts.get('type') or archival.guesskind(dest) or 'files'
554 prefix = opts.get('prefix')
554 prefix = opts.get('prefix')
555
555
556 if dest == '-':
556 if dest == '-':
557 if kind == 'files':
557 if kind == 'files':
558 raise error.Abort(_('cannot archive plain files to stdout'))
558 raise error.Abort(_('cannot archive plain files to stdout'))
559 dest = cmdutil.makefileobj(repo, dest)
559 dest = cmdutil.makefileobj(repo, dest)
560 if not prefix:
560 if not prefix:
561 prefix = os.path.basename(repo.root) + '-%h'
561 prefix = os.path.basename(repo.root) + '-%h'
562
562
563 prefix = cmdutil.makefilename(repo, prefix, node)
563 prefix = cmdutil.makefilename(repo, prefix, node)
564 matchfn = scmutil.match(ctx, [], opts)
564 matchfn = scmutil.match(ctx, [], opts)
565 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
565 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
566 matchfn, prefix, subrepos=opts.get('subrepos'))
566 matchfn, prefix, subrepos=opts.get('subrepos'))
567
567
568 @command('backout',
568 @command('backout',
569 [('', 'merge', None, _('merge with old dirstate parent after backout')),
569 [('', 'merge', None, _('merge with old dirstate parent after backout')),
570 ('', 'commit', None,
570 ('', 'commit', None,
571 _('commit if no conflicts were encountered (DEPRECATED)')),
571 _('commit if no conflicts were encountered (DEPRECATED)')),
572 ('', 'no-commit', None, _('do not commit')),
572 ('', 'no-commit', None, _('do not commit')),
573 ('', 'parent', '',
573 ('', 'parent', '',
574 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
574 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
575 ('r', 'rev', '', _('revision to backout'), _('REV')),
575 ('r', 'rev', '', _('revision to backout'), _('REV')),
576 ('e', 'edit', False, _('invoke editor on commit messages')),
576 ('e', 'edit', False, _('invoke editor on commit messages')),
577 ] + mergetoolopts + walkopts + commitopts + commitopts2,
577 ] + mergetoolopts + walkopts + commitopts + commitopts2,
578 _('[OPTION]... [-r] REV'))
578 _('[OPTION]... [-r] REV'))
579 def backout(ui, repo, node=None, rev=None, **opts):
579 def backout(ui, repo, node=None, rev=None, **opts):
580 '''reverse effect of earlier changeset
580 '''reverse effect of earlier changeset
581
581
582 Prepare a new changeset with the effect of REV undone in the
582 Prepare a new changeset with the effect of REV undone in the
583 current working directory. If no conflicts were encountered,
583 current working directory. If no conflicts were encountered,
584 it will be committed immediately.
584 it will be committed immediately.
585
585
586 If REV is the parent of the working directory, then this new changeset
586 If REV is the parent of the working directory, then this new changeset
587 is committed automatically (unless --no-commit is specified).
587 is committed automatically (unless --no-commit is specified).
588
588
589 .. note::
589 .. note::
590
590
591 :hg:`backout` cannot be used to fix either an unwanted or
591 :hg:`backout` cannot be used to fix either an unwanted or
592 incorrect merge.
592 incorrect merge.
593
593
594 .. container:: verbose
594 .. container:: verbose
595
595
596 Examples:
596 Examples:
597
597
598 - Reverse the effect of the parent of the working directory.
598 - Reverse the effect of the parent of the working directory.
599 This backout will be committed immediately::
599 This backout will be committed immediately::
600
600
601 hg backout -r .
601 hg backout -r .
602
602
603 - Reverse the effect of previous bad revision 23::
603 - Reverse the effect of previous bad revision 23::
604
604
605 hg backout -r 23
605 hg backout -r 23
606
606
607 - Reverse the effect of previous bad revision 23 and
607 - Reverse the effect of previous bad revision 23 and
608 leave changes uncommitted::
608 leave changes uncommitted::
609
609
610 hg backout -r 23 --no-commit
610 hg backout -r 23 --no-commit
611 hg commit -m "Backout revision 23"
611 hg commit -m "Backout revision 23"
612
612
613 By default, the pending changeset will have one parent,
613 By default, the pending changeset will have one parent,
614 maintaining a linear history. With --merge, the pending
614 maintaining a linear history. With --merge, the pending
615 changeset will instead have two parents: the old parent of the
615 changeset will instead have two parents: the old parent of the
616 working directory and a new child of REV that simply undoes REV.
616 working directory and a new child of REV that simply undoes REV.
617
617
618 Before version 1.7, the behavior without --merge was equivalent
618 Before version 1.7, the behavior without --merge was equivalent
619 to specifying --merge followed by :hg:`update --clean .` to
619 to specifying --merge followed by :hg:`update --clean .` to
620 cancel the merge and leave the child of REV as a head to be
620 cancel the merge and leave the child of REV as a head to be
621 merged separately.
621 merged separately.
622
622
623 See :hg:`help dates` for a list of formats valid for -d/--date.
623 See :hg:`help dates` for a list of formats valid for -d/--date.
624
624
625 See :hg:`help revert` for a way to restore files to the state
625 See :hg:`help revert` for a way to restore files to the state
626 of another revision.
626 of another revision.
627
627
628 Returns 0 on success, 1 if nothing to backout or there are unresolved
628 Returns 0 on success, 1 if nothing to backout or there are unresolved
629 files.
629 files.
630 '''
630 '''
631 wlock = lock = None
631 wlock = lock = None
632 try:
632 try:
633 wlock = repo.wlock()
633 wlock = repo.wlock()
634 lock = repo.lock()
634 lock = repo.lock()
635 return _dobackout(ui, repo, node, rev, **opts)
635 return _dobackout(ui, repo, node, rev, **opts)
636 finally:
636 finally:
637 release(lock, wlock)
637 release(lock, wlock)
638
638
639 def _dobackout(ui, repo, node=None, rev=None, **opts):
639 def _dobackout(ui, repo, node=None, rev=None, **opts):
640 if opts.get('commit') and opts.get('no_commit'):
640 if opts.get('commit') and opts.get('no_commit'):
641 raise error.Abort(_("cannot use --commit with --no-commit"))
641 raise error.Abort(_("cannot use --commit with --no-commit"))
642 if opts.get('merge') and opts.get('no_commit'):
642 if opts.get('merge') and opts.get('no_commit'):
643 raise error.Abort(_("cannot use --merge with --no-commit"))
643 raise error.Abort(_("cannot use --merge with --no-commit"))
644
644
645 if rev and node:
645 if rev and node:
646 raise error.Abort(_("please specify just one revision"))
646 raise error.Abort(_("please specify just one revision"))
647
647
648 if not rev:
648 if not rev:
649 rev = node
649 rev = node
650
650
651 if not rev:
651 if not rev:
652 raise error.Abort(_("please specify a revision to backout"))
652 raise error.Abort(_("please specify a revision to backout"))
653
653
654 date = opts.get('date')
654 date = opts.get('date')
655 if date:
655 if date:
656 opts['date'] = util.parsedate(date)
656 opts['date'] = util.parsedate(date)
657
657
658 cmdutil.checkunfinished(repo)
658 cmdutil.checkunfinished(repo)
659 cmdutil.bailifchanged(repo)
659 cmdutil.bailifchanged(repo)
660 node = scmutil.revsingle(repo, rev).node()
660 node = scmutil.revsingle(repo, rev).node()
661
661
662 op1, op2 = repo.dirstate.parents()
662 op1, op2 = repo.dirstate.parents()
663 if not repo.changelog.isancestor(node, op1):
663 if not repo.changelog.isancestor(node, op1):
664 raise error.Abort(_('cannot backout change that is not an ancestor'))
664 raise error.Abort(_('cannot backout change that is not an ancestor'))
665
665
666 p1, p2 = repo.changelog.parents(node)
666 p1, p2 = repo.changelog.parents(node)
667 if p1 == nullid:
667 if p1 == nullid:
668 raise error.Abort(_('cannot backout a change with no parents'))
668 raise error.Abort(_('cannot backout a change with no parents'))
669 if p2 != nullid:
669 if p2 != nullid:
670 if not opts.get('parent'):
670 if not opts.get('parent'):
671 raise error.Abort(_('cannot backout a merge changeset'))
671 raise error.Abort(_('cannot backout a merge changeset'))
672 p = repo.lookup(opts['parent'])
672 p = repo.lookup(opts['parent'])
673 if p not in (p1, p2):
673 if p not in (p1, p2):
674 raise error.Abort(_('%s is not a parent of %s') %
674 raise error.Abort(_('%s is not a parent of %s') %
675 (short(p), short(node)))
675 (short(p), short(node)))
676 parent = p
676 parent = p
677 else:
677 else:
678 if opts.get('parent'):
678 if opts.get('parent'):
679 raise error.Abort(_('cannot use --parent on non-merge changeset'))
679 raise error.Abort(_('cannot use --parent on non-merge changeset'))
680 parent = p1
680 parent = p1
681
681
682 # the backout should appear on the same branch
682 # the backout should appear on the same branch
683 branch = repo.dirstate.branch()
683 branch = repo.dirstate.branch()
684 bheads = repo.branchheads(branch)
684 bheads = repo.branchheads(branch)
685 rctx = scmutil.revsingle(repo, hex(parent))
685 rctx = scmutil.revsingle(repo, hex(parent))
686 if not opts.get('merge') and op1 != node:
686 if not opts.get('merge') and op1 != node:
687 dsguard = cmdutil.dirstateguard(repo, 'backout')
687 dsguard = cmdutil.dirstateguard(repo, 'backout')
688 try:
688 try:
689 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
689 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
690 'backout')
690 'backout')
691 stats = mergemod.update(repo, parent, True, True, node, False)
691 stats = mergemod.update(repo, parent, True, True, node, False)
692 repo.setparents(op1, op2)
692 repo.setparents(op1, op2)
693 dsguard.close()
693 dsguard.close()
694 hg._showstats(repo, stats)
694 hg._showstats(repo, stats)
695 if stats[3]:
695 if stats[3]:
696 repo.ui.status(_("use 'hg resolve' to retry unresolved "
696 repo.ui.status(_("use 'hg resolve' to retry unresolved "
697 "file merges\n"))
697 "file merges\n"))
698 return 1
698 return 1
699 finally:
699 finally:
700 ui.setconfig('ui', 'forcemerge', '', '')
700 ui.setconfig('ui', 'forcemerge', '', '')
701 lockmod.release(dsguard)
701 lockmod.release(dsguard)
702 else:
702 else:
703 hg.clean(repo, node, show_stats=False)
703 hg.clean(repo, node, show_stats=False)
704 repo.dirstate.setbranch(branch)
704 repo.dirstate.setbranch(branch)
705 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
705 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
706
706
707 if opts.get('no_commit'):
707 if opts.get('no_commit'):
708 msg = _("changeset %s backed out, "
708 msg = _("changeset %s backed out, "
709 "don't forget to commit.\n")
709 "don't forget to commit.\n")
710 ui.status(msg % short(node))
710 ui.status(msg % short(node))
711 return 0
711 return 0
712
712
713 def commitfunc(ui, repo, message, match, opts):
713 def commitfunc(ui, repo, message, match, opts):
714 editform = 'backout'
714 editform = 'backout'
715 e = cmdutil.getcommiteditor(editform=editform, **opts)
715 e = cmdutil.getcommiteditor(editform=editform, **opts)
716 if not message:
716 if not message:
717 # we don't translate commit messages
717 # we don't translate commit messages
718 message = "Backed out changeset %s" % short(node)
718 message = "Backed out changeset %s" % short(node)
719 e = cmdutil.getcommiteditor(edit=True, editform=editform)
719 e = cmdutil.getcommiteditor(edit=True, editform=editform)
720 return repo.commit(message, opts.get('user'), opts.get('date'),
720 return repo.commit(message, opts.get('user'), opts.get('date'),
721 match, editor=e)
721 match, editor=e)
722 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
722 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
723 if not newnode:
723 if not newnode:
724 ui.status(_("nothing changed\n"))
724 ui.status(_("nothing changed\n"))
725 return 1
725 return 1
726 cmdutil.commitstatus(repo, newnode, branch, bheads)
726 cmdutil.commitstatus(repo, newnode, branch, bheads)
727
727
728 def nice(node):
728 def nice(node):
729 return '%d:%s' % (repo.changelog.rev(node), short(node))
729 return '%d:%s' % (repo.changelog.rev(node), short(node))
730 ui.status(_('changeset %s backs out changeset %s\n') %
730 ui.status(_('changeset %s backs out changeset %s\n') %
731 (nice(repo.changelog.tip()), nice(node)))
731 (nice(repo.changelog.tip()), nice(node)))
732 if opts.get('merge') and op1 != node:
732 if opts.get('merge') and op1 != node:
733 hg.clean(repo, op1, show_stats=False)
733 hg.clean(repo, op1, show_stats=False)
734 ui.status(_('merging with changeset %s\n')
734 ui.status(_('merging with changeset %s\n')
735 % nice(repo.changelog.tip()))
735 % nice(repo.changelog.tip()))
736 try:
736 try:
737 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
737 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
738 'backout')
738 'backout')
739 return hg.merge(repo, hex(repo.changelog.tip()))
739 return hg.merge(repo, hex(repo.changelog.tip()))
740 finally:
740 finally:
741 ui.setconfig('ui', 'forcemerge', '', '')
741 ui.setconfig('ui', 'forcemerge', '', '')
742 return 0
742 return 0
743
743
744 @command('bisect',
744 @command('bisect',
745 [('r', 'reset', False, _('reset bisect state')),
745 [('r', 'reset', False, _('reset bisect state')),
746 ('g', 'good', False, _('mark changeset good')),
746 ('g', 'good', False, _('mark changeset good')),
747 ('b', 'bad', False, _('mark changeset bad')),
747 ('b', 'bad', False, _('mark changeset bad')),
748 ('s', 'skip', False, _('skip testing changeset')),
748 ('s', 'skip', False, _('skip testing changeset')),
749 ('e', 'extend', False, _('extend the bisect range')),
749 ('e', 'extend', False, _('extend the bisect range')),
750 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
750 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
751 ('U', 'noupdate', False, _('do not update to target'))],
751 ('U', 'noupdate', False, _('do not update to target'))],
752 _("[-gbsr] [-U] [-c CMD] [REV]"))
752 _("[-gbsr] [-U] [-c CMD] [REV]"))
753 def bisect(ui, repo, rev=None, extra=None, command=None,
753 def bisect(ui, repo, rev=None, extra=None, command=None,
754 reset=None, good=None, bad=None, skip=None, extend=None,
754 reset=None, good=None, bad=None, skip=None, extend=None,
755 noupdate=None):
755 noupdate=None):
756 """subdivision search of changesets
756 """subdivision search of changesets
757
757
758 This command helps to find changesets which introduce problems. To
758 This command helps to find changesets which introduce problems. To
759 use, mark the earliest changeset you know exhibits the problem as
759 use, mark the earliest changeset you know exhibits the problem as
760 bad, then mark the latest changeset which is free from the problem
760 bad, then mark the latest changeset which is free from the problem
761 as good. Bisect will update your working directory to a revision
761 as good. Bisect will update your working directory to a revision
762 for testing (unless the -U/--noupdate option is specified). Once
762 for testing (unless the -U/--noupdate option is specified). Once
763 you have performed tests, mark the working directory as good or
763 you have performed tests, mark the working directory as good or
764 bad, and bisect will either update to another candidate changeset
764 bad, and bisect will either update to another candidate changeset
765 or announce that it has found the bad revision.
765 or announce that it has found the bad revision.
766
766
767 As a shortcut, you can also use the revision argument to mark a
767 As a shortcut, you can also use the revision argument to mark a
768 revision as good or bad without checking it out first.
768 revision as good or bad without checking it out first.
769
769
770 If you supply a command, it will be used for automatic bisection.
770 If you supply a command, it will be used for automatic bisection.
771 The environment variable HG_NODE will contain the ID of the
771 The environment variable HG_NODE will contain the ID of the
772 changeset being tested. The exit status of the command will be
772 changeset being tested. The exit status of the command will be
773 used to mark revisions as good or bad: status 0 means good, 125
773 used to mark revisions as good or bad: status 0 means good, 125
774 means to skip the revision, 127 (command not found) will abort the
774 means to skip the revision, 127 (command not found) will abort the
775 bisection, and any other non-zero exit status means the revision
775 bisection, and any other non-zero exit status means the revision
776 is bad.
776 is bad.
777
777
778 .. container:: verbose
778 .. container:: verbose
779
779
780 Some examples:
780 Some examples:
781
781
782 - start a bisection with known bad revision 34, and good revision 12::
782 - start a bisection with known bad revision 34, and good revision 12::
783
783
784 hg bisect --bad 34
784 hg bisect --bad 34
785 hg bisect --good 12
785 hg bisect --good 12
786
786
787 - advance the current bisection by marking current revision as good or
787 - advance the current bisection by marking current revision as good or
788 bad::
788 bad::
789
789
790 hg bisect --good
790 hg bisect --good
791 hg bisect --bad
791 hg bisect --bad
792
792
793 - mark the current revision, or a known revision, to be skipped (e.g. if
793 - mark the current revision, or a known revision, to be skipped (e.g. if
794 that revision is not usable because of another issue)::
794 that revision is not usable because of another issue)::
795
795
796 hg bisect --skip
796 hg bisect --skip
797 hg bisect --skip 23
797 hg bisect --skip 23
798
798
799 - skip all revisions that do not touch directories ``foo`` or ``bar``::
799 - skip all revisions that do not touch directories ``foo`` or ``bar``::
800
800
801 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
801 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
802
802
803 - forget the current bisection::
803 - forget the current bisection::
804
804
805 hg bisect --reset
805 hg bisect --reset
806
806
807 - use 'make && make tests' to automatically find the first broken
807 - use 'make && make tests' to automatically find the first broken
808 revision::
808 revision::
809
809
810 hg bisect --reset
810 hg bisect --reset
811 hg bisect --bad 34
811 hg bisect --bad 34
812 hg bisect --good 12
812 hg bisect --good 12
813 hg bisect --command "make && make tests"
813 hg bisect --command "make && make tests"
814
814
815 - see all changesets whose states are already known in the current
815 - see all changesets whose states are already known in the current
816 bisection::
816 bisection::
817
817
818 hg log -r "bisect(pruned)"
818 hg log -r "bisect(pruned)"
819
819
820 - see the changeset currently being bisected (especially useful
820 - see the changeset currently being bisected (especially useful
821 if running with -U/--noupdate)::
821 if running with -U/--noupdate)::
822
822
823 hg log -r "bisect(current)"
823 hg log -r "bisect(current)"
824
824
825 - see all changesets that took part in the current bisection::
825 - see all changesets that took part in the current bisection::
826
826
827 hg log -r "bisect(range)"
827 hg log -r "bisect(range)"
828
828
829 - you can even get a nice graph::
829 - you can even get a nice graph::
830
830
831 hg log --graph -r "bisect(range)"
831 hg log --graph -r "bisect(range)"
832
832
833 See :hg:`help revsets` for more about the `bisect()` keyword.
833 See :hg:`help revsets` for more about the `bisect()` keyword.
834
834
835 Returns 0 on success.
835 Returns 0 on success.
836 """
836 """
837 def extendbisectrange(nodes, good):
837 def extendbisectrange(nodes, good):
838 # bisect is incomplete when it ends on a merge node and
838 # bisect is incomplete when it ends on a merge node and
839 # one of the parent was not checked.
839 # one of the parent was not checked.
840 parents = repo[nodes[0]].parents()
840 parents = repo[nodes[0]].parents()
841 if len(parents) > 1:
841 if len(parents) > 1:
842 if good:
842 if good:
843 side = state['bad']
843 side = state['bad']
844 else:
844 else:
845 side = state['good']
845 side = state['good']
846 num = len(set(i.node() for i in parents) & set(side))
846 num = len(set(i.node() for i in parents) & set(side))
847 if num == 1:
847 if num == 1:
848 return parents[0].ancestor(parents[1])
848 return parents[0].ancestor(parents[1])
849 return None
849 return None
850
850
851 def print_result(nodes, good):
851 def print_result(nodes, good):
852 displayer = cmdutil.show_changeset(ui, repo, {})
852 displayer = cmdutil.show_changeset(ui, repo, {})
853 if len(nodes) == 1:
853 if len(nodes) == 1:
854 # narrowed it down to a single revision
854 # narrowed it down to a single revision
855 if good:
855 if good:
856 ui.write(_("The first good revision is:\n"))
856 ui.write(_("The first good revision is:\n"))
857 else:
857 else:
858 ui.write(_("The first bad revision is:\n"))
858 ui.write(_("The first bad revision is:\n"))
859 displayer.show(repo[nodes[0]])
859 displayer.show(repo[nodes[0]])
860 extendnode = extendbisectrange(nodes, good)
860 extendnode = extendbisectrange(nodes, good)
861 if extendnode is not None:
861 if extendnode is not None:
862 ui.write(_('Not all ancestors of this changeset have been'
862 ui.write(_('Not all ancestors of this changeset have been'
863 ' checked.\nUse bisect --extend to continue the '
863 ' checked.\nUse bisect --extend to continue the '
864 'bisection from\nthe common ancestor, %s.\n')
864 'bisection from\nthe common ancestor, %s.\n')
865 % extendnode)
865 % extendnode)
866 else:
866 else:
867 # multiple possible revisions
867 # multiple possible revisions
868 if good:
868 if good:
869 ui.write(_("Due to skipped revisions, the first "
869 ui.write(_("Due to skipped revisions, the first "
870 "good revision could be any of:\n"))
870 "good revision could be any of:\n"))
871 else:
871 else:
872 ui.write(_("Due to skipped revisions, the first "
872 ui.write(_("Due to skipped revisions, the first "
873 "bad revision could be any of:\n"))
873 "bad revision could be any of:\n"))
874 for n in nodes:
874 for n in nodes:
875 displayer.show(repo[n])
875 displayer.show(repo[n])
876 displayer.close()
876 displayer.close()
877
877
878 def check_state(state, interactive=True):
878 def check_state(state, interactive=True):
879 if not state['good'] or not state['bad']:
879 if not state['good'] or not state['bad']:
880 if (good or bad or skip or reset) and interactive:
880 if (good or bad or skip or reset) and interactive:
881 return
881 return
882 if not state['good']:
882 if not state['good']:
883 raise error.Abort(_('cannot bisect (no known good revisions)'))
883 raise error.Abort(_('cannot bisect (no known good revisions)'))
884 else:
884 else:
885 raise error.Abort(_('cannot bisect (no known bad revisions)'))
885 raise error.Abort(_('cannot bisect (no known bad revisions)'))
886 return True
886 return True
887
887
888 # backward compatibility
888 # backward compatibility
889 if rev in "good bad reset init".split():
889 if rev in "good bad reset init".split():
890 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
890 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
891 cmd, rev, extra = rev, extra, None
891 cmd, rev, extra = rev, extra, None
892 if cmd == "good":
892 if cmd == "good":
893 good = True
893 good = True
894 elif cmd == "bad":
894 elif cmd == "bad":
895 bad = True
895 bad = True
896 else:
896 else:
897 reset = True
897 reset = True
898 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
898 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
899 raise error.Abort(_('incompatible arguments'))
899 raise error.Abort(_('incompatible arguments'))
900
900
901 cmdutil.checkunfinished(repo)
901 cmdutil.checkunfinished(repo)
902
902
903 if reset:
903 if reset:
904 p = repo.join("bisect.state")
904 p = repo.join("bisect.state")
905 if os.path.exists(p):
905 if os.path.exists(p):
906 os.unlink(p)
906 os.unlink(p)
907 return
907 return
908
908
909 state = hbisect.load_state(repo)
909 state = hbisect.load_state(repo)
910
910
911 if command:
911 if command:
912 changesets = 1
912 changesets = 1
913 if noupdate:
913 if noupdate:
914 try:
914 try:
915 node = state['current'][0]
915 node = state['current'][0]
916 except LookupError:
916 except LookupError:
917 raise error.Abort(_('current bisect revision is unknown - '
917 raise error.Abort(_('current bisect revision is unknown - '
918 'start a new bisect to fix'))
918 'start a new bisect to fix'))
919 else:
919 else:
920 node, p2 = repo.dirstate.parents()
920 node, p2 = repo.dirstate.parents()
921 if p2 != nullid:
921 if p2 != nullid:
922 raise error.Abort(_('current bisect revision is a merge'))
922 raise error.Abort(_('current bisect revision is a merge'))
923 try:
923 try:
924 while changesets:
924 while changesets:
925 # update state
925 # update state
926 state['current'] = [node]
926 state['current'] = [node]
927 hbisect.save_state(repo, state)
927 hbisect.save_state(repo, state)
928 status = ui.system(command, environ={'HG_NODE': hex(node)})
928 status = ui.system(command, environ={'HG_NODE': hex(node)})
929 if status == 125:
929 if status == 125:
930 transition = "skip"
930 transition = "skip"
931 elif status == 0:
931 elif status == 0:
932 transition = "good"
932 transition = "good"
933 # status < 0 means process was killed
933 # status < 0 means process was killed
934 elif status == 127:
934 elif status == 127:
935 raise error.Abort(_("failed to execute %s") % command)
935 raise error.Abort(_("failed to execute %s") % command)
936 elif status < 0:
936 elif status < 0:
937 raise error.Abort(_("%s killed") % command)
937 raise error.Abort(_("%s killed") % command)
938 else:
938 else:
939 transition = "bad"
939 transition = "bad"
940 ctx = scmutil.revsingle(repo, rev, node)
940 ctx = scmutil.revsingle(repo, rev, node)
941 rev = None # clear for future iterations
941 rev = None # clear for future iterations
942 state[transition].append(ctx.node())
942 state[transition].append(ctx.node())
943 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
943 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
944 check_state(state, interactive=False)
944 check_state(state, interactive=False)
945 # bisect
945 # bisect
946 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
946 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
947 # update to next check
947 # update to next check
948 node = nodes[0]
948 node = nodes[0]
949 if not noupdate:
949 if not noupdate:
950 cmdutil.bailifchanged(repo)
950 cmdutil.bailifchanged(repo)
951 hg.clean(repo, node, show_stats=False)
951 hg.clean(repo, node, show_stats=False)
952 finally:
952 finally:
953 state['current'] = [node]
953 state['current'] = [node]
954 hbisect.save_state(repo, state)
954 hbisect.save_state(repo, state)
955 print_result(nodes, bgood)
955 print_result(nodes, bgood)
956 return
956 return
957
957
958 # update state
958 # update state
959
959
960 if rev:
960 if rev:
961 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
961 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
962 else:
962 else:
963 nodes = [repo.lookup('.')]
963 nodes = [repo.lookup('.')]
964
964
965 if good or bad or skip:
965 if good or bad or skip:
966 if good:
966 if good:
967 state['good'] += nodes
967 state['good'] += nodes
968 elif bad:
968 elif bad:
969 state['bad'] += nodes
969 state['bad'] += nodes
970 elif skip:
970 elif skip:
971 state['skip'] += nodes
971 state['skip'] += nodes
972 hbisect.save_state(repo, state)
972 hbisect.save_state(repo, state)
973
973
974 if not check_state(state):
974 if not check_state(state):
975 return
975 return
976
976
977 # actually bisect
977 # actually bisect
978 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
978 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
979 if extend:
979 if extend:
980 if not changesets:
980 if not changesets:
981 extendnode = extendbisectrange(nodes, good)
981 extendnode = extendbisectrange(nodes, good)
982 if extendnode is not None:
982 if extendnode is not None:
983 ui.write(_("Extending search to changeset %d:%s\n")
983 ui.write(_("Extending search to changeset %d:%s\n")
984 % (extendnode.rev(), extendnode))
984 % (extendnode.rev(), extendnode))
985 state['current'] = [extendnode.node()]
985 state['current'] = [extendnode.node()]
986 hbisect.save_state(repo, state)
986 hbisect.save_state(repo, state)
987 if noupdate:
987 if noupdate:
988 return
988 return
989 cmdutil.bailifchanged(repo)
989 cmdutil.bailifchanged(repo)
990 return hg.clean(repo, extendnode.node())
990 return hg.clean(repo, extendnode.node())
991 raise error.Abort(_("nothing to extend"))
991 raise error.Abort(_("nothing to extend"))
992
992
993 if changesets == 0:
993 if changesets == 0:
994 print_result(nodes, good)
994 print_result(nodes, good)
995 else:
995 else:
996 assert len(nodes) == 1 # only a single node can be tested next
996 assert len(nodes) == 1 # only a single node can be tested next
997 node = nodes[0]
997 node = nodes[0]
998 # compute the approximate number of remaining tests
998 # compute the approximate number of remaining tests
999 tests, size = 0, 2
999 tests, size = 0, 2
1000 while size <= changesets:
1000 while size <= changesets:
1001 tests, size = tests + 1, size * 2
1001 tests, size = tests + 1, size * 2
1002 rev = repo.changelog.rev(node)
1002 rev = repo.changelog.rev(node)
1003 ui.write(_("Testing changeset %d:%s "
1003 ui.write(_("Testing changeset %d:%s "
1004 "(%d changesets remaining, ~%d tests)\n")
1004 "(%d changesets remaining, ~%d tests)\n")
1005 % (rev, short(node), changesets, tests))
1005 % (rev, short(node), changesets, tests))
1006 state['current'] = [node]
1006 state['current'] = [node]
1007 hbisect.save_state(repo, state)
1007 hbisect.save_state(repo, state)
1008 if not noupdate:
1008 if not noupdate:
1009 cmdutil.bailifchanged(repo)
1009 cmdutil.bailifchanged(repo)
1010 return hg.clean(repo, node)
1010 return hg.clean(repo, node)
1011
1011
1012 @command('bookmarks|bookmark',
1012 @command('bookmarks|bookmark',
1013 [('f', 'force', False, _('force')),
1013 [('f', 'force', False, _('force')),
1014 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1014 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1015 ('d', 'delete', False, _('delete a given bookmark')),
1015 ('d', 'delete', False, _('delete a given bookmark')),
1016 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1016 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1017 ('i', 'inactive', False, _('mark a bookmark inactive')),
1017 ('i', 'inactive', False, _('mark a bookmark inactive')),
1018 ] + formatteropts,
1018 ] + formatteropts,
1019 _('hg bookmarks [OPTIONS]... [NAME]...'))
1019 _('hg bookmarks [OPTIONS]... [NAME]...'))
1020 def bookmark(ui, repo, *names, **opts):
1020 def bookmark(ui, repo, *names, **opts):
1021 '''create a new bookmark or list existing bookmarks
1021 '''create a new bookmark or list existing bookmarks
1022
1022
1023 Bookmarks are labels on changesets to help track lines of development.
1023 Bookmarks are labels on changesets to help track lines of development.
1024 Bookmarks are unversioned and can be moved, renamed and deleted.
1024 Bookmarks are unversioned and can be moved, renamed and deleted.
1025 Deleting or moving a bookmark has no effect on the associated changesets.
1025 Deleting or moving a bookmark has no effect on the associated changesets.
1026
1026
1027 Creating or updating to a bookmark causes it to be marked as 'active'.
1027 Creating or updating to a bookmark causes it to be marked as 'active'.
1028 The active bookmark is indicated with a '*'.
1028 The active bookmark is indicated with a '*'.
1029 When a commit is made, the active bookmark will advance to the new commit.
1029 When a commit is made, the active bookmark will advance to the new commit.
1030 A plain :hg:`update` will also advance an active bookmark, if possible.
1030 A plain :hg:`update` will also advance an active bookmark, if possible.
1031 Updating away from a bookmark will cause it to be deactivated.
1031 Updating away from a bookmark will cause it to be deactivated.
1032
1032
1033 Bookmarks can be pushed and pulled between repositories (see
1033 Bookmarks can be pushed and pulled between repositories (see
1034 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1034 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1035 diverged, a new 'divergent bookmark' of the form 'name@path' will
1035 diverged, a new 'divergent bookmark' of the form 'name@path' will
1036 be created. Using :hg:`merge` will resolve the divergence.
1036 be created. Using :hg:`merge` will resolve the divergence.
1037
1037
1038 A bookmark named '@' has the special property that :hg:`clone` will
1038 A bookmark named '@' has the special property that :hg:`clone` will
1039 check it out by default if it exists.
1039 check it out by default if it exists.
1040
1040
1041 .. container:: verbose
1041 .. container:: verbose
1042
1042
1043 Examples:
1043 Examples:
1044
1044
1045 - create an active bookmark for a new line of development::
1045 - create an active bookmark for a new line of development::
1046
1046
1047 hg book new-feature
1047 hg book new-feature
1048
1048
1049 - create an inactive bookmark as a place marker::
1049 - create an inactive bookmark as a place marker::
1050
1050
1051 hg book -i reviewed
1051 hg book -i reviewed
1052
1052
1053 - create an inactive bookmark on another changeset::
1053 - create an inactive bookmark on another changeset::
1054
1054
1055 hg book -r .^ tested
1055 hg book -r .^ tested
1056
1056
1057 - rename bookmark turkey to dinner::
1057 - rename bookmark turkey to dinner::
1058
1058
1059 hg book -m turkey dinner
1059 hg book -m turkey dinner
1060
1060
1061 - move the '@' bookmark from another branch::
1061 - move the '@' bookmark from another branch::
1062
1062
1063 hg book -f @
1063 hg book -f @
1064 '''
1064 '''
1065 force = opts.get('force')
1065 force = opts.get('force')
1066 rev = opts.get('rev')
1066 rev = opts.get('rev')
1067 delete = opts.get('delete')
1067 delete = opts.get('delete')
1068 rename = opts.get('rename')
1068 rename = opts.get('rename')
1069 inactive = opts.get('inactive')
1069 inactive = opts.get('inactive')
1070
1070
1071 def checkformat(mark):
1071 def checkformat(mark):
1072 mark = mark.strip()
1072 mark = mark.strip()
1073 if not mark:
1073 if not mark:
1074 raise error.Abort(_("bookmark names cannot consist entirely of "
1074 raise error.Abort(_("bookmark names cannot consist entirely of "
1075 "whitespace"))
1075 "whitespace"))
1076 scmutil.checknewlabel(repo, mark, 'bookmark')
1076 scmutil.checknewlabel(repo, mark, 'bookmark')
1077 return mark
1077 return mark
1078
1078
1079 def checkconflict(repo, mark, cur, force=False, target=None):
1079 def checkconflict(repo, mark, cur, force=False, target=None):
1080 if mark in marks and not force:
1080 if mark in marks and not force:
1081 if target:
1081 if target:
1082 if marks[mark] == target and target == cur:
1082 if marks[mark] == target and target == cur:
1083 # re-activating a bookmark
1083 # re-activating a bookmark
1084 return
1084 return
1085 anc = repo.changelog.ancestors([repo[target].rev()])
1085 anc = repo.changelog.ancestors([repo[target].rev()])
1086 bmctx = repo[marks[mark]]
1086 bmctx = repo[marks[mark]]
1087 divs = [repo[b].node() for b in marks
1087 divs = [repo[b].node() for b in marks
1088 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1088 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1089
1089
1090 # allow resolving a single divergent bookmark even if moving
1090 # allow resolving a single divergent bookmark even if moving
1091 # the bookmark across branches when a revision is specified
1091 # the bookmark across branches when a revision is specified
1092 # that contains a divergent bookmark
1092 # that contains a divergent bookmark
1093 if bmctx.rev() not in anc and target in divs:
1093 if bmctx.rev() not in anc and target in divs:
1094 bookmarks.deletedivergent(repo, [target], mark)
1094 bookmarks.deletedivergent(repo, [target], mark)
1095 return
1095 return
1096
1096
1097 deletefrom = [b for b in divs
1097 deletefrom = [b for b in divs
1098 if repo[b].rev() in anc or b == target]
1098 if repo[b].rev() in anc or b == target]
1099 bookmarks.deletedivergent(repo, deletefrom, mark)
1099 bookmarks.deletedivergent(repo, deletefrom, mark)
1100 if bookmarks.validdest(repo, bmctx, repo[target]):
1100 if bookmarks.validdest(repo, bmctx, repo[target]):
1101 ui.status(_("moving bookmark '%s' forward from %s\n") %
1101 ui.status(_("moving bookmark '%s' forward from %s\n") %
1102 (mark, short(bmctx.node())))
1102 (mark, short(bmctx.node())))
1103 return
1103 return
1104 raise error.Abort(_("bookmark '%s' already exists "
1104 raise error.Abort(_("bookmark '%s' already exists "
1105 "(use -f to force)") % mark)
1105 "(use -f to force)") % mark)
1106 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1106 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1107 and not force):
1107 and not force):
1108 raise error.Abort(
1108 raise error.Abort(
1109 _("a bookmark cannot have the name of an existing branch"))
1109 _("a bookmark cannot have the name of an existing branch"))
1110
1110
1111 if delete and rename:
1111 if delete and rename:
1112 raise error.Abort(_("--delete and --rename are incompatible"))
1112 raise error.Abort(_("--delete and --rename are incompatible"))
1113 if delete and rev:
1113 if delete and rev:
1114 raise error.Abort(_("--rev is incompatible with --delete"))
1114 raise error.Abort(_("--rev is incompatible with --delete"))
1115 if rename and rev:
1115 if rename and rev:
1116 raise error.Abort(_("--rev is incompatible with --rename"))
1116 raise error.Abort(_("--rev is incompatible with --rename"))
1117 if not names and (delete or rev):
1117 if not names and (delete or rev):
1118 raise error.Abort(_("bookmark name required"))
1118 raise error.Abort(_("bookmark name required"))
1119
1119
1120 if delete or rename or names or inactive:
1120 if delete or rename or names or inactive:
1121 wlock = lock = tr = None
1121 wlock = lock = tr = None
1122 try:
1122 try:
1123 wlock = repo.wlock()
1123 wlock = repo.wlock()
1124 lock = repo.lock()
1124 lock = repo.lock()
1125 cur = repo.changectx('.').node()
1125 cur = repo.changectx('.').node()
1126 marks = repo._bookmarks
1126 marks = repo._bookmarks
1127 if delete:
1127 if delete:
1128 tr = repo.transaction('bookmark')
1128 tr = repo.transaction('bookmark')
1129 for mark in names:
1129 for mark in names:
1130 if mark not in marks:
1130 if mark not in marks:
1131 raise error.Abort(_("bookmark '%s' does not exist") %
1131 raise error.Abort(_("bookmark '%s' does not exist") %
1132 mark)
1132 mark)
1133 if mark == repo._activebookmark:
1133 if mark == repo._activebookmark:
1134 bookmarks.deactivate(repo)
1134 bookmarks.deactivate(repo)
1135 del marks[mark]
1135 del marks[mark]
1136
1136
1137 elif rename:
1137 elif rename:
1138 tr = repo.transaction('bookmark')
1138 tr = repo.transaction('bookmark')
1139 if not names:
1139 if not names:
1140 raise error.Abort(_("new bookmark name required"))
1140 raise error.Abort(_("new bookmark name required"))
1141 elif len(names) > 1:
1141 elif len(names) > 1:
1142 raise error.Abort(_("only one new bookmark name allowed"))
1142 raise error.Abort(_("only one new bookmark name allowed"))
1143 mark = checkformat(names[0])
1143 mark = checkformat(names[0])
1144 if rename not in marks:
1144 if rename not in marks:
1145 raise error.Abort(_("bookmark '%s' does not exist")
1145 raise error.Abort(_("bookmark '%s' does not exist")
1146 % rename)
1146 % rename)
1147 checkconflict(repo, mark, cur, force)
1147 checkconflict(repo, mark, cur, force)
1148 marks[mark] = marks[rename]
1148 marks[mark] = marks[rename]
1149 if repo._activebookmark == rename and not inactive:
1149 if repo._activebookmark == rename and not inactive:
1150 bookmarks.activate(repo, mark)
1150 bookmarks.activate(repo, mark)
1151 del marks[rename]
1151 del marks[rename]
1152 elif names:
1152 elif names:
1153 tr = repo.transaction('bookmark')
1153 tr = repo.transaction('bookmark')
1154 newact = None
1154 newact = None
1155 for mark in names:
1155 for mark in names:
1156 mark = checkformat(mark)
1156 mark = checkformat(mark)
1157 if newact is None:
1157 if newact is None:
1158 newact = mark
1158 newact = mark
1159 if inactive and mark == repo._activebookmark:
1159 if inactive and mark == repo._activebookmark:
1160 bookmarks.deactivate(repo)
1160 bookmarks.deactivate(repo)
1161 return
1161 return
1162 tgt = cur
1162 tgt = cur
1163 if rev:
1163 if rev:
1164 tgt = scmutil.revsingle(repo, rev).node()
1164 tgt = scmutil.revsingle(repo, rev).node()
1165 checkconflict(repo, mark, cur, force, tgt)
1165 checkconflict(repo, mark, cur, force, tgt)
1166 marks[mark] = tgt
1166 marks[mark] = tgt
1167 if not inactive and cur == marks[newact] and not rev:
1167 if not inactive and cur == marks[newact] and not rev:
1168 bookmarks.activate(repo, newact)
1168 bookmarks.activate(repo, newact)
1169 elif cur != tgt and newact == repo._activebookmark:
1169 elif cur != tgt and newact == repo._activebookmark:
1170 bookmarks.deactivate(repo)
1170 bookmarks.deactivate(repo)
1171 elif inactive:
1171 elif inactive:
1172 if len(marks) == 0:
1172 if len(marks) == 0:
1173 ui.status(_("no bookmarks set\n"))
1173 ui.status(_("no bookmarks set\n"))
1174 elif not repo._activebookmark:
1174 elif not repo._activebookmark:
1175 ui.status(_("no active bookmark\n"))
1175 ui.status(_("no active bookmark\n"))
1176 else:
1176 else:
1177 bookmarks.deactivate(repo)
1177 bookmarks.deactivate(repo)
1178 if tr is not None:
1178 if tr is not None:
1179 marks.recordchange(tr)
1179 marks.recordchange(tr)
1180 tr.close()
1180 tr.close()
1181 finally:
1181 finally:
1182 lockmod.release(tr, lock, wlock)
1182 lockmod.release(tr, lock, wlock)
1183 else: # show bookmarks
1183 else: # show bookmarks
1184 fm = ui.formatter('bookmarks', opts)
1184 fm = ui.formatter('bookmarks', opts)
1185 hexfn = fm.hexfunc
1185 hexfn = fm.hexfunc
1186 marks = repo._bookmarks
1186 marks = repo._bookmarks
1187 if len(marks) == 0 and not fm:
1187 if len(marks) == 0 and not fm:
1188 ui.status(_("no bookmarks set\n"))
1188 ui.status(_("no bookmarks set\n"))
1189 for bmark, n in sorted(marks.iteritems()):
1189 for bmark, n in sorted(marks.iteritems()):
1190 active = repo._activebookmark
1190 active = repo._activebookmark
1191 if bmark == active:
1191 if bmark == active:
1192 prefix, label = '*', activebookmarklabel
1192 prefix, label = '*', activebookmarklabel
1193 else:
1193 else:
1194 prefix, label = ' ', ''
1194 prefix, label = ' ', ''
1195
1195
1196 fm.startitem()
1196 fm.startitem()
1197 if not ui.quiet:
1197 if not ui.quiet:
1198 fm.plain(' %s ' % prefix, label=label)
1198 fm.plain(' %s ' % prefix, label=label)
1199 fm.write('bookmark', '%s', bmark, label=label)
1199 fm.write('bookmark', '%s', bmark, label=label)
1200 pad = " " * (25 - encoding.colwidth(bmark))
1200 pad = " " * (25 - encoding.colwidth(bmark))
1201 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1201 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1202 repo.changelog.rev(n), hexfn(n), label=label)
1202 repo.changelog.rev(n), hexfn(n), label=label)
1203 fm.data(active=(bmark == active))
1203 fm.data(active=(bmark == active))
1204 fm.plain('\n')
1204 fm.plain('\n')
1205 fm.end()
1205 fm.end()
1206
1206
1207 @command('branch',
1207 @command('branch',
1208 [('f', 'force', None,
1208 [('f', 'force', None,
1209 _('set branch name even if it shadows an existing branch')),
1209 _('set branch name even if it shadows an existing branch')),
1210 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1210 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1211 _('[-fC] [NAME]'))
1211 _('[-fC] [NAME]'))
1212 def branch(ui, repo, label=None, **opts):
1212 def branch(ui, repo, label=None, **opts):
1213 """set or show the current branch name
1213 """set or show the current branch name
1214
1214
1215 .. note::
1215 .. note::
1216
1216
1217 Branch names are permanent and global. Use :hg:`bookmark` to create a
1217 Branch names are permanent and global. Use :hg:`bookmark` to create a
1218 light-weight bookmark instead. See :hg:`help glossary` for more
1218 light-weight bookmark instead. See :hg:`help glossary` for more
1219 information about named branches and bookmarks.
1219 information about named branches and bookmarks.
1220
1220
1221 With no argument, show the current branch name. With one argument,
1221 With no argument, show the current branch name. With one argument,
1222 set the working directory branch name (the branch will not exist
1222 set the working directory branch name (the branch will not exist
1223 in the repository until the next commit). Standard practice
1223 in the repository until the next commit). Standard practice
1224 recommends that primary development take place on the 'default'
1224 recommends that primary development take place on the 'default'
1225 branch.
1225 branch.
1226
1226
1227 Unless -f/--force is specified, branch will not let you set a
1227 Unless -f/--force is specified, branch will not let you set a
1228 branch name that already exists.
1228 branch name that already exists.
1229
1229
1230 Use -C/--clean to reset the working directory branch to that of
1230 Use -C/--clean to reset the working directory branch to that of
1231 the parent of the working directory, negating a previous branch
1231 the parent of the working directory, negating a previous branch
1232 change.
1232 change.
1233
1233
1234 Use the command :hg:`update` to switch to an existing branch. Use
1234 Use the command :hg:`update` to switch to an existing branch. Use
1235 :hg:`commit --close-branch` to mark this branch head as closed.
1235 :hg:`commit --close-branch` to mark this branch head as closed.
1236 When all heads of a branch are closed, the branch will be
1236 When all heads of a branch are closed, the branch will be
1237 considered closed.
1237 considered closed.
1238
1238
1239 Returns 0 on success.
1239 Returns 0 on success.
1240 """
1240 """
1241 if label:
1241 if label:
1242 label = label.strip()
1242 label = label.strip()
1243
1243
1244 if not opts.get('clean') and not label:
1244 if not opts.get('clean') and not label:
1245 ui.write("%s\n" % repo.dirstate.branch())
1245 ui.write("%s\n" % repo.dirstate.branch())
1246 return
1246 return
1247
1247
1248 with repo.wlock():
1248 with repo.wlock():
1249 if opts.get('clean'):
1249 if opts.get('clean'):
1250 label = repo[None].p1().branch()
1250 label = repo[None].p1().branch()
1251 repo.dirstate.setbranch(label)
1251 repo.dirstate.setbranch(label)
1252 ui.status(_('reset working directory to branch %s\n') % label)
1252 ui.status(_('reset working directory to branch %s\n') % label)
1253 elif label:
1253 elif label:
1254 if not opts.get('force') and label in repo.branchmap():
1254 if not opts.get('force') and label in repo.branchmap():
1255 if label not in [p.branch() for p in repo[None].parents()]:
1255 if label not in [p.branch() for p in repo[None].parents()]:
1256 raise error.Abort(_('a branch of the same name already'
1256 raise error.Abort(_('a branch of the same name already'
1257 ' exists'),
1257 ' exists'),
1258 # i18n: "it" refers to an existing branch
1258 # i18n: "it" refers to an existing branch
1259 hint=_("use 'hg update' to switch to it"))
1259 hint=_("use 'hg update' to switch to it"))
1260 scmutil.checknewlabel(repo, label, 'branch')
1260 scmutil.checknewlabel(repo, label, 'branch')
1261 repo.dirstate.setbranch(label)
1261 repo.dirstate.setbranch(label)
1262 ui.status(_('marked working directory as branch %s\n') % label)
1262 ui.status(_('marked working directory as branch %s\n') % label)
1263
1263
1264 # find any open named branches aside from default
1264 # find any open named branches aside from default
1265 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1265 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1266 if n != "default" and not c]
1266 if n != "default" and not c]
1267 if not others:
1267 if not others:
1268 ui.status(_('(branches are permanent and global, '
1268 ui.status(_('(branches are permanent and global, '
1269 'did you want a bookmark?)\n'))
1269 'did you want a bookmark?)\n'))
1270
1270
1271 @command('branches',
1271 @command('branches',
1272 [('a', 'active', False,
1272 [('a', 'active', False,
1273 _('show only branches that have unmerged heads (DEPRECATED)')),
1273 _('show only branches that have unmerged heads (DEPRECATED)')),
1274 ('c', 'closed', False, _('show normal and closed branches')),
1274 ('c', 'closed', False, _('show normal and closed branches')),
1275 ] + formatteropts,
1275 ] + formatteropts,
1276 _('[-c]'))
1276 _('[-c]'))
1277 def branches(ui, repo, active=False, closed=False, **opts):
1277 def branches(ui, repo, active=False, closed=False, **opts):
1278 """list repository named branches
1278 """list repository named branches
1279
1279
1280 List the repository's named branches, indicating which ones are
1280 List the repository's named branches, indicating which ones are
1281 inactive. If -c/--closed is specified, also list branches which have
1281 inactive. If -c/--closed is specified, also list branches which have
1282 been marked closed (see :hg:`commit --close-branch`).
1282 been marked closed (see :hg:`commit --close-branch`).
1283
1283
1284 Use the command :hg:`update` to switch to an existing branch.
1284 Use the command :hg:`update` to switch to an existing branch.
1285
1285
1286 Returns 0.
1286 Returns 0.
1287 """
1287 """
1288
1288
1289 fm = ui.formatter('branches', opts)
1289 fm = ui.formatter('branches', opts)
1290 hexfunc = fm.hexfunc
1290 hexfunc = fm.hexfunc
1291
1291
1292 allheads = set(repo.heads())
1292 allheads = set(repo.heads())
1293 branches = []
1293 branches = []
1294 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1294 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1295 isactive = not isclosed and bool(set(heads) & allheads)
1295 isactive = not isclosed and bool(set(heads) & allheads)
1296 branches.append((tag, repo[tip], isactive, not isclosed))
1296 branches.append((tag, repo[tip], isactive, not isclosed))
1297 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1297 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1298 reverse=True)
1298 reverse=True)
1299
1299
1300 for tag, ctx, isactive, isopen in branches:
1300 for tag, ctx, isactive, isopen in branches:
1301 if active and not isactive:
1301 if active and not isactive:
1302 continue
1302 continue
1303 if isactive:
1303 if isactive:
1304 label = 'branches.active'
1304 label = 'branches.active'
1305 notice = ''
1305 notice = ''
1306 elif not isopen:
1306 elif not isopen:
1307 if not closed:
1307 if not closed:
1308 continue
1308 continue
1309 label = 'branches.closed'
1309 label = 'branches.closed'
1310 notice = _(' (closed)')
1310 notice = _(' (closed)')
1311 else:
1311 else:
1312 label = 'branches.inactive'
1312 label = 'branches.inactive'
1313 notice = _(' (inactive)')
1313 notice = _(' (inactive)')
1314 current = (tag == repo.dirstate.branch())
1314 current = (tag == repo.dirstate.branch())
1315 if current:
1315 if current:
1316 label = 'branches.current'
1316 label = 'branches.current'
1317
1317
1318 fm.startitem()
1318 fm.startitem()
1319 fm.write('branch', '%s', tag, label=label)
1319 fm.write('branch', '%s', tag, label=label)
1320 rev = ctx.rev()
1320 rev = ctx.rev()
1321 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1321 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1322 fmt = ' ' * padsize + ' %d:%s'
1322 fmt = ' ' * padsize + ' %d:%s'
1323 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1323 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1324 label='log.changeset changeset.%s' % ctx.phasestr())
1324 label='log.changeset changeset.%s' % ctx.phasestr())
1325 fm.data(active=isactive, closed=not isopen, current=current)
1325 fm.data(active=isactive, closed=not isopen, current=current)
1326 if not ui.quiet:
1326 if not ui.quiet:
1327 fm.plain(notice)
1327 fm.plain(notice)
1328 fm.plain('\n')
1328 fm.plain('\n')
1329 fm.end()
1329 fm.end()
1330
1330
1331 @command('bundle',
1331 @command('bundle',
1332 [('f', 'force', None, _('run even when the destination is unrelated')),
1332 [('f', 'force', None, _('run even when the destination is unrelated')),
1333 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1333 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1334 _('REV')),
1334 _('REV')),
1335 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1335 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1336 _('BRANCH')),
1336 _('BRANCH')),
1337 ('', 'base', [],
1337 ('', 'base', [],
1338 _('a base changeset assumed to be available at the destination'),
1338 _('a base changeset assumed to be available at the destination'),
1339 _('REV')),
1339 _('REV')),
1340 ('a', 'all', None, _('bundle all changesets in the repository')),
1340 ('a', 'all', None, _('bundle all changesets in the repository')),
1341 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1341 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1342 ] + remoteopts,
1342 ] + remoteopts,
1343 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1343 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1344 def bundle(ui, repo, fname, dest=None, **opts):
1344 def bundle(ui, repo, fname, dest=None, **opts):
1345 """create a changegroup file
1345 """create a changegroup file
1346
1346
1347 Generate a changegroup file collecting changesets to be added
1347 Generate a changegroup file collecting changesets to be added
1348 to a repository.
1348 to a repository.
1349
1349
1350 To create a bundle containing all changesets, use -a/--all
1350 To create a bundle containing all changesets, use -a/--all
1351 (or --base null). Otherwise, hg assumes the destination will have
1351 (or --base null). Otherwise, hg assumes the destination will have
1352 all the nodes you specify with --base parameters. Otherwise, hg
1352 all the nodes you specify with --base parameters. Otherwise, hg
1353 will assume the repository has all the nodes in destination, or
1353 will assume the repository has all the nodes in destination, or
1354 default-push/default if no destination is specified.
1354 default-push/default if no destination is specified.
1355
1355
1356 You can change bundle format with the -t/--type option. You can
1356 You can change bundle format with the -t/--type option. You can
1357 specify a compression, a bundle version or both using a dash
1357 specify a compression, a bundle version or both using a dash
1358 (comp-version). The available compression methods are: none, bzip2,
1358 (comp-version). The available compression methods are: none, bzip2,
1359 and gzip (by default, bundles are compressed using bzip2). The
1359 and gzip (by default, bundles are compressed using bzip2). The
1360 available formats are: v1, v2 (default to most suitable).
1360 available formats are: v1, v2 (default to most suitable).
1361
1361
1362 The bundle file can then be transferred using conventional means
1362 The bundle file can then be transferred using conventional means
1363 and applied to another repository with the unbundle or pull
1363 and applied to another repository with the unbundle or pull
1364 command. This is useful when direct push and pull are not
1364 command. This is useful when direct push and pull are not
1365 available or when exporting an entire repository is undesirable.
1365 available or when exporting an entire repository is undesirable.
1366
1366
1367 Applying bundles preserves all changeset contents including
1367 Applying bundles preserves all changeset contents including
1368 permissions, copy/rename information, and revision history.
1368 permissions, copy/rename information, and revision history.
1369
1369
1370 Returns 0 on success, 1 if no changes found.
1370 Returns 0 on success, 1 if no changes found.
1371 """
1371 """
1372 revs = None
1372 revs = None
1373 if 'rev' in opts:
1373 if 'rev' in opts:
1374 revstrings = opts['rev']
1374 revstrings = opts['rev']
1375 revs = scmutil.revrange(repo, revstrings)
1375 revs = scmutil.revrange(repo, revstrings)
1376 if revstrings and not revs:
1376 if revstrings and not revs:
1377 raise error.Abort(_('no commits to bundle'))
1377 raise error.Abort(_('no commits to bundle'))
1378
1378
1379 bundletype = opts.get('type', 'bzip2').lower()
1379 bundletype = opts.get('type', 'bzip2').lower()
1380 try:
1380 try:
1381 bcompression, cgversion, params = exchange.parsebundlespec(
1381 bcompression, cgversion, params = exchange.parsebundlespec(
1382 repo, bundletype, strict=False)
1382 repo, bundletype, strict=False)
1383 except error.UnsupportedBundleSpecification as e:
1383 except error.UnsupportedBundleSpecification as e:
1384 raise error.Abort(str(e),
1384 raise error.Abort(str(e),
1385 hint=_('see "hg help bundle" for supported '
1385 hint=_('see "hg help bundle" for supported '
1386 'values for --type'))
1386 'values for --type'))
1387
1387
1388 # Packed bundles are a pseudo bundle format for now.
1388 # Packed bundles are a pseudo bundle format for now.
1389 if cgversion == 's1':
1389 if cgversion == 's1':
1390 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1390 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1391 hint=_("use 'hg debugcreatestreamclonebundle'"))
1391 hint=_("use 'hg debugcreatestreamclonebundle'"))
1392
1392
1393 if opts.get('all'):
1393 if opts.get('all'):
1394 if dest:
1394 if dest:
1395 raise error.Abort(_("--all is incompatible with specifying "
1395 raise error.Abort(_("--all is incompatible with specifying "
1396 "a destination"))
1396 "a destination"))
1397 if opts.get('base'):
1397 if opts.get('base'):
1398 ui.warn(_("ignoring --base because --all was specified\n"))
1398 ui.warn(_("ignoring --base because --all was specified\n"))
1399 base = ['null']
1399 base = ['null']
1400 else:
1400 else:
1401 base = scmutil.revrange(repo, opts.get('base'))
1401 base = scmutil.revrange(repo, opts.get('base'))
1402 # TODO: get desired bundlecaps from command line.
1402 # TODO: get desired bundlecaps from command line.
1403 bundlecaps = None
1403 bundlecaps = None
1404 if cgversion not in changegroup.supportedoutgoingversions(repo):
1404 if cgversion not in changegroup.supportedoutgoingversions(repo):
1405 raise error.Abort(_("repository does not support bundle version %s") %
1405 raise error.Abort(_("repository does not support bundle version %s") %
1406 cgversion)
1406 cgversion)
1407
1407
1408 if base:
1408 if base:
1409 if dest:
1409 if dest:
1410 raise error.Abort(_("--base is incompatible with specifying "
1410 raise error.Abort(_("--base is incompatible with specifying "
1411 "a destination"))
1411 "a destination"))
1412 common = [repo.lookup(rev) for rev in base]
1412 common = [repo.lookup(rev) for rev in base]
1413 heads = revs and map(repo.lookup, revs) or revs
1413 heads = revs and map(repo.lookup, revs) or revs
1414 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1414 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1415 common=common, bundlecaps=bundlecaps,
1415 common=common, bundlecaps=bundlecaps,
1416 version=cgversion)
1416 version=cgversion)
1417 outgoing = None
1417 outgoing = None
1418 else:
1418 else:
1419 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1419 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1420 dest, branches = hg.parseurl(dest, opts.get('branch'))
1420 dest, branches = hg.parseurl(dest, opts.get('branch'))
1421 other = hg.peer(repo, opts, dest)
1421 other = hg.peer(repo, opts, dest)
1422 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1422 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1423 heads = revs and map(repo.lookup, revs) or revs
1423 heads = revs and map(repo.lookup, revs) or revs
1424 outgoing = discovery.findcommonoutgoing(repo, other,
1424 outgoing = discovery.findcommonoutgoing(repo, other,
1425 onlyheads=heads,
1425 onlyheads=heads,
1426 force=opts.get('force'),
1426 force=opts.get('force'),
1427 portable=True)
1427 portable=True)
1428 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1428 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1429 bundlecaps, version=cgversion)
1429 bundlecaps, version=cgversion)
1430 if not cg:
1430 if not cg:
1431 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1431 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1432 return 1
1432 return 1
1433
1433
1434 if cgversion == '01': #bundle1
1434 if cgversion == '01': #bundle1
1435 if bcompression is None:
1435 if bcompression is None:
1436 bcompression = 'UN'
1436 bcompression = 'UN'
1437 bversion = 'HG10' + bcompression
1437 bversion = 'HG10' + bcompression
1438 bcompression = None
1438 bcompression = None
1439 else:
1439 else:
1440 assert cgversion == '02'
1440 assert cgversion == '02'
1441 bversion = 'HG20'
1441 bversion = 'HG20'
1442
1442
1443 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1443 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1444
1444
1445 @command('cat',
1445 @command('cat',
1446 [('o', 'output', '',
1446 [('o', 'output', '',
1447 _('print output to file with formatted name'), _('FORMAT')),
1447 _('print output to file with formatted name'), _('FORMAT')),
1448 ('r', 'rev', '', _('print the given revision'), _('REV')),
1448 ('r', 'rev', '', _('print the given revision'), _('REV')),
1449 ('', 'decode', None, _('apply any matching decode filter')),
1449 ('', 'decode', None, _('apply any matching decode filter')),
1450 ] + walkopts,
1450 ] + walkopts,
1451 _('[OPTION]... FILE...'),
1451 _('[OPTION]... FILE...'),
1452 inferrepo=True)
1452 inferrepo=True)
1453 def cat(ui, repo, file1, *pats, **opts):
1453 def cat(ui, repo, file1, *pats, **opts):
1454 """output the current or given revision of files
1454 """output the current or given revision of files
1455
1455
1456 Print the specified files as they were at the given revision. If
1456 Print the specified files as they were at the given revision. If
1457 no revision is given, the parent of the working directory is used.
1457 no revision is given, the parent of the working directory is used.
1458
1458
1459 Output may be to a file, in which case the name of the file is
1459 Output may be to a file, in which case the name of the file is
1460 given using a format string. The formatting rules as follows:
1460 given using a format string. The formatting rules as follows:
1461
1461
1462 :``%%``: literal "%" character
1462 :``%%``: literal "%" character
1463 :``%s``: basename of file being printed
1463 :``%s``: basename of file being printed
1464 :``%d``: dirname of file being printed, or '.' if in repository root
1464 :``%d``: dirname of file being printed, or '.' if in repository root
1465 :``%p``: root-relative path name of file being printed
1465 :``%p``: root-relative path name of file being printed
1466 :``%H``: changeset hash (40 hexadecimal digits)
1466 :``%H``: changeset hash (40 hexadecimal digits)
1467 :``%R``: changeset revision number
1467 :``%R``: changeset revision number
1468 :``%h``: short-form changeset hash (12 hexadecimal digits)
1468 :``%h``: short-form changeset hash (12 hexadecimal digits)
1469 :``%r``: zero-padded changeset revision number
1469 :``%r``: zero-padded changeset revision number
1470 :``%b``: basename of the exporting repository
1470 :``%b``: basename of the exporting repository
1471
1471
1472 Returns 0 on success.
1472 Returns 0 on success.
1473 """
1473 """
1474 ctx = scmutil.revsingle(repo, opts.get('rev'))
1474 ctx = scmutil.revsingle(repo, opts.get('rev'))
1475 m = scmutil.match(ctx, (file1,) + pats, opts)
1475 m = scmutil.match(ctx, (file1,) + pats, opts)
1476
1476
1477 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1477 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1478
1478
1479 @command('^clone',
1479 @command('^clone',
1480 [('U', 'noupdate', None, _('the clone will include an empty working '
1480 [('U', 'noupdate', None, _('the clone will include an empty working '
1481 'directory (only a repository)')),
1481 'directory (only a repository)')),
1482 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1482 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1483 _('REV')),
1483 _('REV')),
1484 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1484 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1485 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1485 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1486 ('', 'pull', None, _('use pull protocol to copy metadata')),
1486 ('', 'pull', None, _('use pull protocol to copy metadata')),
1487 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1487 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1488 ] + remoteopts,
1488 ] + remoteopts,
1489 _('[OPTION]... SOURCE [DEST]'),
1489 _('[OPTION]... SOURCE [DEST]'),
1490 norepo=True)
1490 norepo=True)
1491 def clone(ui, source, dest=None, **opts):
1491 def clone(ui, source, dest=None, **opts):
1492 """make a copy of an existing repository
1492 """make a copy of an existing repository
1493
1493
1494 Create a copy of an existing repository in a new directory.
1494 Create a copy of an existing repository in a new directory.
1495
1495
1496 If no destination directory name is specified, it defaults to the
1496 If no destination directory name is specified, it defaults to the
1497 basename of the source.
1497 basename of the source.
1498
1498
1499 The location of the source is added to the new repository's
1499 The location of the source is added to the new repository's
1500 ``.hg/hgrc`` file, as the default to be used for future pulls.
1500 ``.hg/hgrc`` file, as the default to be used for future pulls.
1501
1501
1502 Only local paths and ``ssh://`` URLs are supported as
1502 Only local paths and ``ssh://`` URLs are supported as
1503 destinations. For ``ssh://`` destinations, no working directory or
1503 destinations. For ``ssh://`` destinations, no working directory or
1504 ``.hg/hgrc`` will be created on the remote side.
1504 ``.hg/hgrc`` will be created on the remote side.
1505
1505
1506 If the source repository has a bookmark called '@' set, that
1506 If the source repository has a bookmark called '@' set, that
1507 revision will be checked out in the new repository by default.
1507 revision will be checked out in the new repository by default.
1508
1508
1509 To check out a particular version, use -u/--update, or
1509 To check out a particular version, use -u/--update, or
1510 -U/--noupdate to create a clone with no working directory.
1510 -U/--noupdate to create a clone with no working directory.
1511
1511
1512 To pull only a subset of changesets, specify one or more revisions
1512 To pull only a subset of changesets, specify one or more revisions
1513 identifiers with -r/--rev or branches with -b/--branch. The
1513 identifiers with -r/--rev or branches with -b/--branch. The
1514 resulting clone will contain only the specified changesets and
1514 resulting clone will contain only the specified changesets and
1515 their ancestors. These options (or 'clone src#rev dest') imply
1515 their ancestors. These options (or 'clone src#rev dest') imply
1516 --pull, even for local source repositories.
1516 --pull, even for local source repositories.
1517
1517
1518 .. note::
1518 .. note::
1519
1519
1520 Specifying a tag will include the tagged changeset but not the
1520 Specifying a tag will include the tagged changeset but not the
1521 changeset containing the tag.
1521 changeset containing the tag.
1522
1522
1523 .. container:: verbose
1523 .. container:: verbose
1524
1524
1525 For efficiency, hardlinks are used for cloning whenever the
1525 For efficiency, hardlinks are used for cloning whenever the
1526 source and destination are on the same filesystem (note this
1526 source and destination are on the same filesystem (note this
1527 applies only to the repository data, not to the working
1527 applies only to the repository data, not to the working
1528 directory). Some filesystems, such as AFS, implement hardlinking
1528 directory). Some filesystems, such as AFS, implement hardlinking
1529 incorrectly, but do not report errors. In these cases, use the
1529 incorrectly, but do not report errors. In these cases, use the
1530 --pull option to avoid hardlinking.
1530 --pull option to avoid hardlinking.
1531
1531
1532 In some cases, you can clone repositories and the working
1532 In some cases, you can clone repositories and the working
1533 directory using full hardlinks with ::
1533 directory using full hardlinks with ::
1534
1534
1535 $ cp -al REPO REPOCLONE
1535 $ cp -al REPO REPOCLONE
1536
1536
1537 This is the fastest way to clone, but it is not always safe. The
1537 This is the fastest way to clone, but it is not always safe. The
1538 operation is not atomic (making sure REPO is not modified during
1538 operation is not atomic (making sure REPO is not modified during
1539 the operation is up to you) and you have to make sure your
1539 the operation is up to you) and you have to make sure your
1540 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1540 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1541 so). Also, this is not compatible with certain extensions that
1541 so). Also, this is not compatible with certain extensions that
1542 place their metadata under the .hg directory, such as mq.
1542 place their metadata under the .hg directory, such as mq.
1543
1543
1544 Mercurial will update the working directory to the first applicable
1544 Mercurial will update the working directory to the first applicable
1545 revision from this list:
1545 revision from this list:
1546
1546
1547 a) null if -U or the source repository has no changesets
1547 a) null if -U or the source repository has no changesets
1548 b) if -u . and the source repository is local, the first parent of
1548 b) if -u . and the source repository is local, the first parent of
1549 the source repository's working directory
1549 the source repository's working directory
1550 c) the changeset specified with -u (if a branch name, this means the
1550 c) the changeset specified with -u (if a branch name, this means the
1551 latest head of that branch)
1551 latest head of that branch)
1552 d) the changeset specified with -r
1552 d) the changeset specified with -r
1553 e) the tipmost head specified with -b
1553 e) the tipmost head specified with -b
1554 f) the tipmost head specified with the url#branch source syntax
1554 f) the tipmost head specified with the url#branch source syntax
1555 g) the revision marked with the '@' bookmark, if present
1555 g) the revision marked with the '@' bookmark, if present
1556 h) the tipmost head of the default branch
1556 h) the tipmost head of the default branch
1557 i) tip
1557 i) tip
1558
1558
1559 When cloning from servers that support it, Mercurial may fetch
1559 When cloning from servers that support it, Mercurial may fetch
1560 pre-generated data from a server-advertised URL. When this is done,
1560 pre-generated data from a server-advertised URL. When this is done,
1561 hooks operating on incoming changesets and changegroups may fire twice,
1561 hooks operating on incoming changesets and changegroups may fire twice,
1562 once for the bundle fetched from the URL and another for any additional
1562 once for the bundle fetched from the URL and another for any additional
1563 data not fetched from this URL. In addition, if an error occurs, the
1563 data not fetched from this URL. In addition, if an error occurs, the
1564 repository may be rolled back to a partial clone. This behavior may
1564 repository may be rolled back to a partial clone. This behavior may
1565 change in future releases. See :hg:`help -e clonebundles` for more.
1565 change in future releases. See :hg:`help -e clonebundles` for more.
1566
1566
1567 Examples:
1567 Examples:
1568
1568
1569 - clone a remote repository to a new directory named hg/::
1569 - clone a remote repository to a new directory named hg/::
1570
1570
1571 hg clone http://selenic.com/hg
1571 hg clone http://selenic.com/hg
1572
1572
1573 - create a lightweight local clone::
1573 - create a lightweight local clone::
1574
1574
1575 hg clone project/ project-feature/
1575 hg clone project/ project-feature/
1576
1576
1577 - clone from an absolute path on an ssh server (note double-slash)::
1577 - clone from an absolute path on an ssh server (note double-slash)::
1578
1578
1579 hg clone ssh://user@server//home/projects/alpha/
1579 hg clone ssh://user@server//home/projects/alpha/
1580
1580
1581 - do a high-speed clone over a LAN while checking out a
1581 - do a high-speed clone over a LAN while checking out a
1582 specified version::
1582 specified version::
1583
1583
1584 hg clone --uncompressed http://server/repo -u 1.5
1584 hg clone --uncompressed http://server/repo -u 1.5
1585
1585
1586 - create a repository without changesets after a particular revision::
1586 - create a repository without changesets after a particular revision::
1587
1587
1588 hg clone -r 04e544 experimental/ good/
1588 hg clone -r 04e544 experimental/ good/
1589
1589
1590 - clone (and track) a particular named branch::
1590 - clone (and track) a particular named branch::
1591
1591
1592 hg clone http://selenic.com/hg#stable
1592 hg clone http://selenic.com/hg#stable
1593
1593
1594 See :hg:`help urls` for details on specifying URLs.
1594 See :hg:`help urls` for details on specifying URLs.
1595
1595
1596 Returns 0 on success.
1596 Returns 0 on success.
1597 """
1597 """
1598 if opts.get('noupdate') and opts.get('updaterev'):
1598 if opts.get('noupdate') and opts.get('updaterev'):
1599 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1599 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1600
1600
1601 r = hg.clone(ui, opts, source, dest,
1601 r = hg.clone(ui, opts, source, dest,
1602 pull=opts.get('pull'),
1602 pull=opts.get('pull'),
1603 stream=opts.get('uncompressed'),
1603 stream=opts.get('uncompressed'),
1604 rev=opts.get('rev'),
1604 rev=opts.get('rev'),
1605 update=opts.get('updaterev') or not opts.get('noupdate'),
1605 update=opts.get('updaterev') or not opts.get('noupdate'),
1606 branch=opts.get('branch'),
1606 branch=opts.get('branch'),
1607 shareopts=opts.get('shareopts'))
1607 shareopts=opts.get('shareopts'))
1608
1608
1609 return r is None
1609 return r is None
1610
1610
1611 @command('^commit|ci',
1611 @command('^commit|ci',
1612 [('A', 'addremove', None,
1612 [('A', 'addremove', None,
1613 _('mark new/missing files as added/removed before committing')),
1613 _('mark new/missing files as added/removed before committing')),
1614 ('', 'close-branch', None,
1614 ('', 'close-branch', None,
1615 _('mark a branch head as closed')),
1615 _('mark a branch head as closed')),
1616 ('', 'amend', None, _('amend the parent of the working directory')),
1616 ('', 'amend', None, _('amend the parent of the working directory')),
1617 ('s', 'secret', None, _('use the secret phase for committing')),
1617 ('s', 'secret', None, _('use the secret phase for committing')),
1618 ('e', 'edit', None, _('invoke editor on commit messages')),
1618 ('e', 'edit', None, _('invoke editor on commit messages')),
1619 ('i', 'interactive', None, _('use interactive mode')),
1619 ('i', 'interactive', None, _('use interactive mode')),
1620 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1620 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1621 _('[OPTION]... [FILE]...'),
1621 _('[OPTION]... [FILE]...'),
1622 inferrepo=True)
1622 inferrepo=True)
1623 def commit(ui, repo, *pats, **opts):
1623 def commit(ui, repo, *pats, **opts):
1624 """commit the specified files or all outstanding changes
1624 """commit the specified files or all outstanding changes
1625
1625
1626 Commit changes to the given files into the repository. Unlike a
1626 Commit changes to the given files into the repository. Unlike a
1627 centralized SCM, this operation is a local operation. See
1627 centralized SCM, this operation is a local operation. See
1628 :hg:`push` for a way to actively distribute your changes.
1628 :hg:`push` for a way to actively distribute your changes.
1629
1629
1630 If a list of files is omitted, all changes reported by :hg:`status`
1630 If a list of files is omitted, all changes reported by :hg:`status`
1631 will be committed.
1631 will be committed.
1632
1632
1633 If you are committing the result of a merge, do not provide any
1633 If you are committing the result of a merge, do not provide any
1634 filenames or -I/-X filters.
1634 filenames or -I/-X filters.
1635
1635
1636 If no commit message is specified, Mercurial starts your
1636 If no commit message is specified, Mercurial starts your
1637 configured editor where you can enter a message. In case your
1637 configured editor where you can enter a message. In case your
1638 commit fails, you will find a backup of your message in
1638 commit fails, you will find a backup of your message in
1639 ``.hg/last-message.txt``.
1639 ``.hg/last-message.txt``.
1640
1640
1641 The --close-branch flag can be used to mark the current branch
1641 The --close-branch flag can be used to mark the current branch
1642 head closed. When all heads of a branch are closed, the branch
1642 head closed. When all heads of a branch are closed, the branch
1643 will be considered closed and no longer listed.
1643 will be considered closed and no longer listed.
1644
1644
1645 The --amend flag can be used to amend the parent of the
1645 The --amend flag can be used to amend the parent of the
1646 working directory with a new commit that contains the changes
1646 working directory with a new commit that contains the changes
1647 in the parent in addition to those currently reported by :hg:`status`,
1647 in the parent in addition to those currently reported by :hg:`status`,
1648 if there are any. The old commit is stored in a backup bundle in
1648 if there are any. The old commit is stored in a backup bundle in
1649 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1649 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1650 on how to restore it).
1650 on how to restore it).
1651
1651
1652 Message, user and date are taken from the amended commit unless
1652 Message, user and date are taken from the amended commit unless
1653 specified. When a message isn't specified on the command line,
1653 specified. When a message isn't specified on the command line,
1654 the editor will open with the message of the amended commit.
1654 the editor will open with the message of the amended commit.
1655
1655
1656 It is not possible to amend public changesets (see :hg:`help phases`)
1656 It is not possible to amend public changesets (see :hg:`help phases`)
1657 or changesets that have children.
1657 or changesets that have children.
1658
1658
1659 See :hg:`help dates` for a list of formats valid for -d/--date.
1659 See :hg:`help dates` for a list of formats valid for -d/--date.
1660
1660
1661 Returns 0 on success, 1 if nothing changed.
1661 Returns 0 on success, 1 if nothing changed.
1662
1662
1663 .. container:: verbose
1663 .. container:: verbose
1664
1664
1665 Examples:
1665 Examples:
1666
1666
1667 - commit all files ending in .py::
1667 - commit all files ending in .py::
1668
1668
1669 hg commit --include "set:**.py"
1669 hg commit --include "set:**.py"
1670
1670
1671 - commit all non-binary files::
1671 - commit all non-binary files::
1672
1672
1673 hg commit --exclude "set:binary()"
1673 hg commit --exclude "set:binary()"
1674
1674
1675 - amend the current commit and set the date to now::
1675 - amend the current commit and set the date to now::
1676
1676
1677 hg commit --amend --date now
1677 hg commit --amend --date now
1678 """
1678 """
1679 wlock = lock = None
1679 wlock = lock = None
1680 try:
1680 try:
1681 wlock = repo.wlock()
1681 wlock = repo.wlock()
1682 lock = repo.lock()
1682 lock = repo.lock()
1683 return _docommit(ui, repo, *pats, **opts)
1683 return _docommit(ui, repo, *pats, **opts)
1684 finally:
1684 finally:
1685 release(lock, wlock)
1685 release(lock, wlock)
1686
1686
1687 def _docommit(ui, repo, *pats, **opts):
1687 def _docommit(ui, repo, *pats, **opts):
1688 if opts.get('interactive'):
1688 if opts.get('interactive'):
1689 opts.pop('interactive')
1689 opts.pop('interactive')
1690 cmdutil.dorecord(ui, repo, commit, None, False,
1690 cmdutil.dorecord(ui, repo, commit, None, False,
1691 cmdutil.recordfilter, *pats, **opts)
1691 cmdutil.recordfilter, *pats, **opts)
1692 return
1692 return
1693
1693
1694 if opts.get('subrepos'):
1694 if opts.get('subrepos'):
1695 if opts.get('amend'):
1695 if opts.get('amend'):
1696 raise error.Abort(_('cannot amend with --subrepos'))
1696 raise error.Abort(_('cannot amend with --subrepos'))
1697 # Let --subrepos on the command line override config setting.
1697 # Let --subrepos on the command line override config setting.
1698 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1698 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1699
1699
1700 cmdutil.checkunfinished(repo, commit=True)
1700 cmdutil.checkunfinished(repo, commit=True)
1701
1701
1702 branch = repo[None].branch()
1702 branch = repo[None].branch()
1703 bheads = repo.branchheads(branch)
1703 bheads = repo.branchheads(branch)
1704
1704
1705 extra = {}
1705 extra = {}
1706 if opts.get('close_branch'):
1706 if opts.get('close_branch'):
1707 extra['close'] = 1
1707 extra['close'] = 1
1708
1708
1709 if not bheads:
1709 if not bheads:
1710 raise error.Abort(_('can only close branch heads'))
1710 raise error.Abort(_('can only close branch heads'))
1711 elif opts.get('amend'):
1711 elif opts.get('amend'):
1712 if repo[None].parents()[0].p1().branch() != branch and \
1712 if repo[None].parents()[0].p1().branch() != branch and \
1713 repo[None].parents()[0].p2().branch() != branch:
1713 repo[None].parents()[0].p2().branch() != branch:
1714 raise error.Abort(_('can only close branch heads'))
1714 raise error.Abort(_('can only close branch heads'))
1715
1715
1716 if opts.get('amend'):
1716 if opts.get('amend'):
1717 if ui.configbool('ui', 'commitsubrepos'):
1717 if ui.configbool('ui', 'commitsubrepos'):
1718 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1718 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1719
1719
1720 old = repo['.']
1720 old = repo['.']
1721 if not old.mutable():
1721 if not old.mutable():
1722 raise error.Abort(_('cannot amend public changesets'))
1722 raise error.Abort(_('cannot amend public changesets'))
1723 if len(repo[None].parents()) > 1:
1723 if len(repo[None].parents()) > 1:
1724 raise error.Abort(_('cannot amend while merging'))
1724 raise error.Abort(_('cannot amend while merging'))
1725 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1725 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1726 if not allowunstable and old.children():
1726 if not allowunstable and old.children():
1727 raise error.Abort(_('cannot amend changeset with children'))
1727 raise error.Abort(_('cannot amend changeset with children'))
1728
1728
1729 # Currently histedit gets confused if an amend happens while histedit
1729 # Currently histedit gets confused if an amend happens while histedit
1730 # is in progress. Since we have a checkunfinished command, we are
1730 # is in progress. Since we have a checkunfinished command, we are
1731 # temporarily honoring it.
1731 # temporarily honoring it.
1732 #
1732 #
1733 # Note: eventually this guard will be removed. Please do not expect
1733 # Note: eventually this guard will be removed. Please do not expect
1734 # this behavior to remain.
1734 # this behavior to remain.
1735 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1735 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1736 cmdutil.checkunfinished(repo)
1736 cmdutil.checkunfinished(repo)
1737
1737
1738 # commitfunc is used only for temporary amend commit by cmdutil.amend
1738 # commitfunc is used only for temporary amend commit by cmdutil.amend
1739 def commitfunc(ui, repo, message, match, opts):
1739 def commitfunc(ui, repo, message, match, opts):
1740 return repo.commit(message,
1740 return repo.commit(message,
1741 opts.get('user') or old.user(),
1741 opts.get('user') or old.user(),
1742 opts.get('date') or old.date(),
1742 opts.get('date') or old.date(),
1743 match,
1743 match,
1744 extra=extra)
1744 extra=extra)
1745
1745
1746 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1746 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1747 if node == old.node():
1747 if node == old.node():
1748 ui.status(_("nothing changed\n"))
1748 ui.status(_("nothing changed\n"))
1749 return 1
1749 return 1
1750 else:
1750 else:
1751 def commitfunc(ui, repo, message, match, opts):
1751 def commitfunc(ui, repo, message, match, opts):
1752 backup = ui.backupconfig('phases', 'new-commit')
1752 backup = ui.backupconfig('phases', 'new-commit')
1753 baseui = repo.baseui
1753 baseui = repo.baseui
1754 basebackup = baseui.backupconfig('phases', 'new-commit')
1754 basebackup = baseui.backupconfig('phases', 'new-commit')
1755 try:
1755 try:
1756 if opts.get('secret'):
1756 if opts.get('secret'):
1757 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1757 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1758 # Propagate to subrepos
1758 # Propagate to subrepos
1759 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1759 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1760
1760
1761 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1761 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1762 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1762 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1763 return repo.commit(message, opts.get('user'), opts.get('date'),
1763 return repo.commit(message, opts.get('user'), opts.get('date'),
1764 match,
1764 match,
1765 editor=editor,
1765 editor=editor,
1766 extra=extra)
1766 extra=extra)
1767 finally:
1767 finally:
1768 ui.restoreconfig(backup)
1768 ui.restoreconfig(backup)
1769 repo.baseui.restoreconfig(basebackup)
1769 repo.baseui.restoreconfig(basebackup)
1770
1770
1771
1771
1772 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1772 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1773
1773
1774 if not node:
1774 if not node:
1775 stat = cmdutil.postcommitstatus(repo, pats, opts)
1775 stat = cmdutil.postcommitstatus(repo, pats, opts)
1776 if stat[3]:
1776 if stat[3]:
1777 ui.status(_("nothing changed (%d missing files, see "
1777 ui.status(_("nothing changed (%d missing files, see "
1778 "'hg status')\n") % len(stat[3]))
1778 "'hg status')\n") % len(stat[3]))
1779 else:
1779 else:
1780 ui.status(_("nothing changed\n"))
1780 ui.status(_("nothing changed\n"))
1781 return 1
1781 return 1
1782
1782
1783 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1783 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1784
1784
1785 @command('config|showconfig|debugconfig',
1785 @command('config|showconfig|debugconfig',
1786 [('u', 'untrusted', None, _('show untrusted configuration options')),
1786 [('u', 'untrusted', None, _('show untrusted configuration options')),
1787 ('e', 'edit', None, _('edit user config')),
1787 ('e', 'edit', None, _('edit user config')),
1788 ('l', 'local', None, _('edit repository config')),
1788 ('l', 'local', None, _('edit repository config')),
1789 ('g', 'global', None, _('edit global config'))],
1789 ('g', 'global', None, _('edit global config'))],
1790 _('[-u] [NAME]...'),
1790 _('[-u] [NAME]...'),
1791 optionalrepo=True)
1791 optionalrepo=True)
1792 def config(ui, repo, *values, **opts):
1792 def config(ui, repo, *values, **opts):
1793 """show combined config settings from all hgrc files
1793 """show combined config settings from all hgrc files
1794
1794
1795 With no arguments, print names and values of all config items.
1795 With no arguments, print names and values of all config items.
1796
1796
1797 With one argument of the form section.name, print just the value
1797 With one argument of the form section.name, print just the value
1798 of that config item.
1798 of that config item.
1799
1799
1800 With multiple arguments, print names and values of all config
1800 With multiple arguments, print names and values of all config
1801 items with matching section names.
1801 items with matching section names.
1802
1802
1803 With --edit, start an editor on the user-level config file. With
1803 With --edit, start an editor on the user-level config file. With
1804 --global, edit the system-wide config file. With --local, edit the
1804 --global, edit the system-wide config file. With --local, edit the
1805 repository-level config file.
1805 repository-level config file.
1806
1806
1807 With --debug, the source (filename and line number) is printed
1807 With --debug, the source (filename and line number) is printed
1808 for each config item.
1808 for each config item.
1809
1809
1810 See :hg:`help config` for more information about config files.
1810 See :hg:`help config` for more information about config files.
1811
1811
1812 Returns 0 on success, 1 if NAME does not exist.
1812 Returns 0 on success, 1 if NAME does not exist.
1813
1813
1814 """
1814 """
1815
1815
1816 if opts.get('edit') or opts.get('local') or opts.get('global'):
1816 if opts.get('edit') or opts.get('local') or opts.get('global'):
1817 if opts.get('local') and opts.get('global'):
1817 if opts.get('local') and opts.get('global'):
1818 raise error.Abort(_("can't use --local and --global together"))
1818 raise error.Abort(_("can't use --local and --global together"))
1819
1819
1820 if opts.get('local'):
1820 if opts.get('local'):
1821 if not repo:
1821 if not repo:
1822 raise error.Abort(_("can't use --local outside a repository"))
1822 raise error.Abort(_("can't use --local outside a repository"))
1823 paths = [repo.join('hgrc')]
1823 paths = [repo.join('hgrc')]
1824 elif opts.get('global'):
1824 elif opts.get('global'):
1825 paths = scmutil.systemrcpath()
1825 paths = scmutil.systemrcpath()
1826 else:
1826 else:
1827 paths = scmutil.userrcpath()
1827 paths = scmutil.userrcpath()
1828
1828
1829 for f in paths:
1829 for f in paths:
1830 if os.path.exists(f):
1830 if os.path.exists(f):
1831 break
1831 break
1832 else:
1832 else:
1833 if opts.get('global'):
1833 if opts.get('global'):
1834 samplehgrc = uimod.samplehgrcs['global']
1834 samplehgrc = uimod.samplehgrcs['global']
1835 elif opts.get('local'):
1835 elif opts.get('local'):
1836 samplehgrc = uimod.samplehgrcs['local']
1836 samplehgrc = uimod.samplehgrcs['local']
1837 else:
1837 else:
1838 samplehgrc = uimod.samplehgrcs['user']
1838 samplehgrc = uimod.samplehgrcs['user']
1839
1839
1840 f = paths[0]
1840 f = paths[0]
1841 fp = open(f, "w")
1841 fp = open(f, "w")
1842 fp.write(samplehgrc)
1842 fp.write(samplehgrc)
1843 fp.close()
1843 fp.close()
1844
1844
1845 editor = ui.geteditor()
1845 editor = ui.geteditor()
1846 ui.system("%s \"%s\"" % (editor, f),
1846 ui.system("%s \"%s\"" % (editor, f),
1847 onerr=error.Abort, errprefix=_("edit failed"))
1847 onerr=error.Abort, errprefix=_("edit failed"))
1848 return
1848 return
1849
1849
1850 for f in scmutil.rcpath():
1850 for f in scmutil.rcpath():
1851 ui.debug('read config from: %s\n' % f)
1851 ui.debug('read config from: %s\n' % f)
1852 untrusted = bool(opts.get('untrusted'))
1852 untrusted = bool(opts.get('untrusted'))
1853 if values:
1853 if values:
1854 sections = [v for v in values if '.' not in v]
1854 sections = [v for v in values if '.' not in v]
1855 items = [v for v in values if '.' in v]
1855 items = [v for v in values if '.' in v]
1856 if len(items) > 1 or items and sections:
1856 if len(items) > 1 or items and sections:
1857 raise error.Abort(_('only one config item permitted'))
1857 raise error.Abort(_('only one config item permitted'))
1858 matched = False
1858 matched = False
1859 for section, name, value in ui.walkconfig(untrusted=untrusted):
1859 for section, name, value in ui.walkconfig(untrusted=untrusted):
1860 value = str(value).replace('\n', '\\n')
1860 value = str(value).replace('\n', '\\n')
1861 sectname = section + '.' + name
1861 sectname = section + '.' + name
1862 if values:
1862 if values:
1863 for v in values:
1863 for v in values:
1864 if v == section:
1864 if v == section:
1865 ui.debug('%s: ' %
1865 ui.debug('%s: ' %
1866 ui.configsource(section, name, untrusted))
1866 ui.configsource(section, name, untrusted))
1867 ui.write('%s=%s\n' % (sectname, value))
1867 ui.write('%s=%s\n' % (sectname, value))
1868 matched = True
1868 matched = True
1869 elif v == sectname:
1869 elif v == sectname:
1870 ui.debug('%s: ' %
1870 ui.debug('%s: ' %
1871 ui.configsource(section, name, untrusted))
1871 ui.configsource(section, name, untrusted))
1872 ui.write(value, '\n')
1872 ui.write(value, '\n')
1873 matched = True
1873 matched = True
1874 else:
1874 else:
1875 ui.debug('%s: ' %
1875 ui.debug('%s: ' %
1876 ui.configsource(section, name, untrusted))
1876 ui.configsource(section, name, untrusted))
1877 ui.write('%s=%s\n' % (sectname, value))
1877 ui.write('%s=%s\n' % (sectname, value))
1878 matched = True
1878 matched = True
1879 if matched:
1879 if matched:
1880 return 0
1880 return 0
1881 return 1
1881 return 1
1882
1882
1883 @command('copy|cp',
1883 @command('copy|cp',
1884 [('A', 'after', None, _('record a copy that has already occurred')),
1884 [('A', 'after', None, _('record a copy that has already occurred')),
1885 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1885 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1886 ] + walkopts + dryrunopts,
1886 ] + walkopts + dryrunopts,
1887 _('[OPTION]... [SOURCE]... DEST'))
1887 _('[OPTION]... [SOURCE]... DEST'))
1888 def copy(ui, repo, *pats, **opts):
1888 def copy(ui, repo, *pats, **opts):
1889 """mark files as copied for the next commit
1889 """mark files as copied for the next commit
1890
1890
1891 Mark dest as having copies of source files. If dest is a
1891 Mark dest as having copies of source files. If dest is a
1892 directory, copies are put in that directory. If dest is a file,
1892 directory, copies are put in that directory. If dest is a file,
1893 the source must be a single file.
1893 the source must be a single file.
1894
1894
1895 By default, this command copies the contents of files as they
1895 By default, this command copies the contents of files as they
1896 exist in the working directory. If invoked with -A/--after, the
1896 exist in the working directory. If invoked with -A/--after, the
1897 operation is recorded, but no copying is performed.
1897 operation is recorded, but no copying is performed.
1898
1898
1899 This command takes effect with the next commit. To undo a copy
1899 This command takes effect with the next commit. To undo a copy
1900 before that, see :hg:`revert`.
1900 before that, see :hg:`revert`.
1901
1901
1902 Returns 0 on success, 1 if errors are encountered.
1902 Returns 0 on success, 1 if errors are encountered.
1903 """
1903 """
1904 with repo.wlock(False):
1904 with repo.wlock(False):
1905 return cmdutil.copy(ui, repo, pats, opts)
1905 return cmdutil.copy(ui, repo, pats, opts)
1906
1906
1907 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1907 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1908 def debugancestor(ui, repo, *args):
1908 def debugancestor(ui, repo, *args):
1909 """find the ancestor revision of two revisions in a given index"""
1909 """find the ancestor revision of two revisions in a given index"""
1910 if len(args) == 3:
1910 if len(args) == 3:
1911 index, rev1, rev2 = args
1911 index, rev1, rev2 = args
1912 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1912 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1913 lookup = r.lookup
1913 lookup = r.lookup
1914 elif len(args) == 2:
1914 elif len(args) == 2:
1915 if not repo:
1915 if not repo:
1916 raise error.Abort(_("there is no Mercurial repository here "
1916 raise error.Abort(_("there is no Mercurial repository here "
1917 "(.hg not found)"))
1917 "(.hg not found)"))
1918 rev1, rev2 = args
1918 rev1, rev2 = args
1919 r = repo.changelog
1919 r = repo.changelog
1920 lookup = repo.lookup
1920 lookup = repo.lookup
1921 else:
1921 else:
1922 raise error.Abort(_('either two or three arguments required'))
1922 raise error.Abort(_('either two or three arguments required'))
1923 a = r.ancestor(lookup(rev1), lookup(rev2))
1923 a = r.ancestor(lookup(rev1), lookup(rev2))
1924 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1924 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1925
1925
1926 @command('debugbuilddag',
1926 @command('debugbuilddag',
1927 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1927 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1928 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1928 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1929 ('n', 'new-file', None, _('add new file at each rev'))],
1929 ('n', 'new-file', None, _('add new file at each rev'))],
1930 _('[OPTION]... [TEXT]'))
1930 _('[OPTION]... [TEXT]'))
1931 def debugbuilddag(ui, repo, text=None,
1931 def debugbuilddag(ui, repo, text=None,
1932 mergeable_file=False,
1932 mergeable_file=False,
1933 overwritten_file=False,
1933 overwritten_file=False,
1934 new_file=False):
1934 new_file=False):
1935 """builds a repo with a given DAG from scratch in the current empty repo
1935 """builds a repo with a given DAG from scratch in the current empty repo
1936
1936
1937 The description of the DAG is read from stdin if not given on the
1937 The description of the DAG is read from stdin if not given on the
1938 command line.
1938 command line.
1939
1939
1940 Elements:
1940 Elements:
1941
1941
1942 - "+n" is a linear run of n nodes based on the current default parent
1942 - "+n" is a linear run of n nodes based on the current default parent
1943 - "." is a single node based on the current default parent
1943 - "." is a single node based on the current default parent
1944 - "$" resets the default parent to null (implied at the start);
1944 - "$" resets the default parent to null (implied at the start);
1945 otherwise the default parent is always the last node created
1945 otherwise the default parent is always the last node created
1946 - "<p" sets the default parent to the backref p
1946 - "<p" sets the default parent to the backref p
1947 - "*p" is a fork at parent p, which is a backref
1947 - "*p" is a fork at parent p, which is a backref
1948 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1948 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1949 - "/p2" is a merge of the preceding node and p2
1949 - "/p2" is a merge of the preceding node and p2
1950 - ":tag" defines a local tag for the preceding node
1950 - ":tag" defines a local tag for the preceding node
1951 - "@branch" sets the named branch for subsequent nodes
1951 - "@branch" sets the named branch for subsequent nodes
1952 - "#...\\n" is a comment up to the end of the line
1952 - "#...\\n" is a comment up to the end of the line
1953
1953
1954 Whitespace between the above elements is ignored.
1954 Whitespace between the above elements is ignored.
1955
1955
1956 A backref is either
1956 A backref is either
1957
1957
1958 - a number n, which references the node curr-n, where curr is the current
1958 - a number n, which references the node curr-n, where curr is the current
1959 node, or
1959 node, or
1960 - the name of a local tag you placed earlier using ":tag", or
1960 - the name of a local tag you placed earlier using ":tag", or
1961 - empty to denote the default parent.
1961 - empty to denote the default parent.
1962
1962
1963 All string valued-elements are either strictly alphanumeric, or must
1963 All string valued-elements are either strictly alphanumeric, or must
1964 be enclosed in double quotes ("..."), with "\\" as escape character.
1964 be enclosed in double quotes ("..."), with "\\" as escape character.
1965 """
1965 """
1966
1966
1967 if text is None:
1967 if text is None:
1968 ui.status(_("reading DAG from stdin\n"))
1968 ui.status(_("reading DAG from stdin\n"))
1969 text = ui.fin.read()
1969 text = ui.fin.read()
1970
1970
1971 cl = repo.changelog
1971 cl = repo.changelog
1972 if len(cl) > 0:
1972 if len(cl) > 0:
1973 raise error.Abort(_('repository is not empty'))
1973 raise error.Abort(_('repository is not empty'))
1974
1974
1975 # determine number of revs in DAG
1975 # determine number of revs in DAG
1976 total = 0
1976 total = 0
1977 for type, data in dagparser.parsedag(text):
1977 for type, data in dagparser.parsedag(text):
1978 if type == 'n':
1978 if type == 'n':
1979 total += 1
1979 total += 1
1980
1980
1981 if mergeable_file:
1981 if mergeable_file:
1982 linesperrev = 2
1982 linesperrev = 2
1983 # make a file with k lines per rev
1983 # make a file with k lines per rev
1984 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1984 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1985 initialmergedlines.append("")
1985 initialmergedlines.append("")
1986
1986
1987 tags = []
1987 tags = []
1988
1988
1989 lock = tr = None
1989 lock = tr = None
1990 try:
1990 try:
1991 lock = repo.lock()
1991 lock = repo.lock()
1992 tr = repo.transaction("builddag")
1992 tr = repo.transaction("builddag")
1993
1993
1994 at = -1
1994 at = -1
1995 atbranch = 'default'
1995 atbranch = 'default'
1996 nodeids = []
1996 nodeids = []
1997 id = 0
1997 id = 0
1998 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1998 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1999 for type, data in dagparser.parsedag(text):
1999 for type, data in dagparser.parsedag(text):
2000 if type == 'n':
2000 if type == 'n':
2001 ui.note(('node %s\n' % str(data)))
2001 ui.note(('node %s\n' % str(data)))
2002 id, ps = data
2002 id, ps = data
2003
2003
2004 files = []
2004 files = []
2005 fctxs = {}
2005 fctxs = {}
2006
2006
2007 p2 = None
2007 p2 = None
2008 if mergeable_file:
2008 if mergeable_file:
2009 fn = "mf"
2009 fn = "mf"
2010 p1 = repo[ps[0]]
2010 p1 = repo[ps[0]]
2011 if len(ps) > 1:
2011 if len(ps) > 1:
2012 p2 = repo[ps[1]]
2012 p2 = repo[ps[1]]
2013 pa = p1.ancestor(p2)
2013 pa = p1.ancestor(p2)
2014 base, local, other = [x[fn].data() for x in (pa, p1,
2014 base, local, other = [x[fn].data() for x in (pa, p1,
2015 p2)]
2015 p2)]
2016 m3 = simplemerge.Merge3Text(base, local, other)
2016 m3 = simplemerge.Merge3Text(base, local, other)
2017 ml = [l.strip() for l in m3.merge_lines()]
2017 ml = [l.strip() for l in m3.merge_lines()]
2018 ml.append("")
2018 ml.append("")
2019 elif at > 0:
2019 elif at > 0:
2020 ml = p1[fn].data().split("\n")
2020 ml = p1[fn].data().split("\n")
2021 else:
2021 else:
2022 ml = initialmergedlines
2022 ml = initialmergedlines
2023 ml[id * linesperrev] += " r%i" % id
2023 ml[id * linesperrev] += " r%i" % id
2024 mergedtext = "\n".join(ml)
2024 mergedtext = "\n".join(ml)
2025 files.append(fn)
2025 files.append(fn)
2026 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2026 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2027
2027
2028 if overwritten_file:
2028 if overwritten_file:
2029 fn = "of"
2029 fn = "of"
2030 files.append(fn)
2030 files.append(fn)
2031 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2031 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2032
2032
2033 if new_file:
2033 if new_file:
2034 fn = "nf%i" % id
2034 fn = "nf%i" % id
2035 files.append(fn)
2035 files.append(fn)
2036 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2036 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2037 if len(ps) > 1:
2037 if len(ps) > 1:
2038 if not p2:
2038 if not p2:
2039 p2 = repo[ps[1]]
2039 p2 = repo[ps[1]]
2040 for fn in p2:
2040 for fn in p2:
2041 if fn.startswith("nf"):
2041 if fn.startswith("nf"):
2042 files.append(fn)
2042 files.append(fn)
2043 fctxs[fn] = p2[fn]
2043 fctxs[fn] = p2[fn]
2044
2044
2045 def fctxfn(repo, cx, path):
2045 def fctxfn(repo, cx, path):
2046 return fctxs.get(path)
2046 return fctxs.get(path)
2047
2047
2048 if len(ps) == 0 or ps[0] < 0:
2048 if len(ps) == 0 or ps[0] < 0:
2049 pars = [None, None]
2049 pars = [None, None]
2050 elif len(ps) == 1:
2050 elif len(ps) == 1:
2051 pars = [nodeids[ps[0]], None]
2051 pars = [nodeids[ps[0]], None]
2052 else:
2052 else:
2053 pars = [nodeids[p] for p in ps]
2053 pars = [nodeids[p] for p in ps]
2054 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2054 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2055 date=(id, 0),
2055 date=(id, 0),
2056 user="debugbuilddag",
2056 user="debugbuilddag",
2057 extra={'branch': atbranch})
2057 extra={'branch': atbranch})
2058 nodeid = repo.commitctx(cx)
2058 nodeid = repo.commitctx(cx)
2059 nodeids.append(nodeid)
2059 nodeids.append(nodeid)
2060 at = id
2060 at = id
2061 elif type == 'l':
2061 elif type == 'l':
2062 id, name = data
2062 id, name = data
2063 ui.note(('tag %s\n' % name))
2063 ui.note(('tag %s\n' % name))
2064 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2064 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2065 elif type == 'a':
2065 elif type == 'a':
2066 ui.note(('branch %s\n' % data))
2066 ui.note(('branch %s\n' % data))
2067 atbranch = data
2067 atbranch = data
2068 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2068 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2069 tr.close()
2069 tr.close()
2070
2070
2071 if tags:
2071 if tags:
2072 repo.vfs.write("localtags", "".join(tags))
2072 repo.vfs.write("localtags", "".join(tags))
2073 finally:
2073 finally:
2074 ui.progress(_('building'), None)
2074 ui.progress(_('building'), None)
2075 release(tr, lock)
2075 release(tr, lock)
2076
2076
2077 @command('debugbundle',
2077 @command('debugbundle',
2078 [('a', 'all', None, _('show all details')),
2078 [('a', 'all', None, _('show all details')),
2079 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2079 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2080 _('FILE'),
2080 _('FILE'),
2081 norepo=True)
2081 norepo=True)
2082 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2082 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2083 """lists the contents of a bundle"""
2083 """lists the contents of a bundle"""
2084 with hg.openpath(ui, bundlepath) as f:
2084 with hg.openpath(ui, bundlepath) as f:
2085 if spec:
2085 if spec:
2086 spec = exchange.getbundlespec(ui, f)
2086 spec = exchange.getbundlespec(ui, f)
2087 ui.write('%s\n' % spec)
2087 ui.write('%s\n' % spec)
2088 return
2088 return
2089
2089
2090 gen = exchange.readbundle(ui, f, bundlepath)
2090 gen = exchange.readbundle(ui, f, bundlepath)
2091 if isinstance(gen, bundle2.unbundle20):
2091 if isinstance(gen, bundle2.unbundle20):
2092 return _debugbundle2(ui, gen, all=all, **opts)
2092 return _debugbundle2(ui, gen, all=all, **opts)
2093 _debugchangegroup(ui, gen, all=all, **opts)
2093 _debugchangegroup(ui, gen, all=all, **opts)
2094
2094
2095 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2095 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2096 indent_string = ' ' * indent
2096 indent_string = ' ' * indent
2097 if all:
2097 if all:
2098 ui.write("%sformat: id, p1, p2, cset, delta base, len(delta)\n"
2098 ui.write("%sformat: id, p1, p2, cset, delta base, len(delta)\n"
2099 % indent_string)
2099 % indent_string)
2100
2100
2101 def showchunks(named):
2101 def showchunks(named):
2102 ui.write("\n%s%s\n" % (indent_string, named))
2102 ui.write("\n%s%s\n" % (indent_string, named))
2103 chain = None
2103 chain = None
2104 while True:
2104 while True:
2105 chunkdata = gen.deltachunk(chain)
2105 chunkdata = gen.deltachunk(chain)
2106 if not chunkdata:
2106 if not chunkdata:
2107 break
2107 break
2108 node = chunkdata['node']
2108 node = chunkdata['node']
2109 p1 = chunkdata['p1']
2109 p1 = chunkdata['p1']
2110 p2 = chunkdata['p2']
2110 p2 = chunkdata['p2']
2111 cs = chunkdata['cs']
2111 cs = chunkdata['cs']
2112 deltabase = chunkdata['deltabase']
2112 deltabase = chunkdata['deltabase']
2113 delta = chunkdata['delta']
2113 delta = chunkdata['delta']
2114 ui.write("%s%s %s %s %s %s %s\n" %
2114 ui.write("%s%s %s %s %s %s %s\n" %
2115 (indent_string, hex(node), hex(p1), hex(p2),
2115 (indent_string, hex(node), hex(p1), hex(p2),
2116 hex(cs), hex(deltabase), len(delta)))
2116 hex(cs), hex(deltabase), len(delta)))
2117 chain = node
2117 chain = node
2118
2118
2119 chunkdata = gen.changelogheader()
2119 chunkdata = gen.changelogheader()
2120 showchunks("changelog")
2120 showchunks("changelog")
2121 chunkdata = gen.manifestheader()
2121 chunkdata = gen.manifestheader()
2122 showchunks("manifest")
2122 showchunks("manifest")
2123 while True:
2123 while True:
2124 chunkdata = gen.filelogheader()
2124 chunkdata = gen.filelogheader()
2125 if not chunkdata:
2125 if not chunkdata:
2126 break
2126 break
2127 fname = chunkdata['filename']
2127 fname = chunkdata['filename']
2128 showchunks(fname)
2128 showchunks(fname)
2129 else:
2129 else:
2130 if isinstance(gen, bundle2.unbundle20):
2130 if isinstance(gen, bundle2.unbundle20):
2131 raise error.Abort(_('use debugbundle2 for this file'))
2131 raise error.Abort(_('use debugbundle2 for this file'))
2132 chunkdata = gen.changelogheader()
2132 chunkdata = gen.changelogheader()
2133 chain = None
2133 chain = None
2134 while True:
2134 while True:
2135 chunkdata = gen.deltachunk(chain)
2135 chunkdata = gen.deltachunk(chain)
2136 if not chunkdata:
2136 if not chunkdata:
2137 break
2137 break
2138 node = chunkdata['node']
2138 node = chunkdata['node']
2139 ui.write("%s%s\n" % (indent_string, hex(node)))
2139 ui.write("%s%s\n" % (indent_string, hex(node)))
2140 chain = node
2140 chain = node
2141
2141
2142 def _debugbundle2(ui, gen, all=None, **opts):
2142 def _debugbundle2(ui, gen, all=None, **opts):
2143 """lists the contents of a bundle2"""
2143 """lists the contents of a bundle2"""
2144 if not isinstance(gen, bundle2.unbundle20):
2144 if not isinstance(gen, bundle2.unbundle20):
2145 raise error.Abort(_('not a bundle2 file'))
2145 raise error.Abort(_('not a bundle2 file'))
2146 ui.write(('Stream params: %s\n' % repr(gen.params)))
2146 ui.write(('Stream params: %s\n' % repr(gen.params)))
2147 for part in gen.iterparts():
2147 for part in gen.iterparts():
2148 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2148 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2149 if part.type == 'changegroup':
2149 if part.type == 'changegroup':
2150 version = part.params.get('version', '01')
2150 version = part.params.get('version', '01')
2151 cg = changegroup.getunbundler(version, part, 'UN')
2151 cg = changegroup.getunbundler(version, part, 'UN')
2152 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2152 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2153
2153
2154 @command('debugcreatestreamclonebundle', [], 'FILE')
2154 @command('debugcreatestreamclonebundle', [], 'FILE')
2155 def debugcreatestreamclonebundle(ui, repo, fname):
2155 def debugcreatestreamclonebundle(ui, repo, fname):
2156 """create a stream clone bundle file
2156 """create a stream clone bundle file
2157
2157
2158 Stream bundles are special bundles that are essentially archives of
2158 Stream bundles are special bundles that are essentially archives of
2159 revlog files. They are commonly used for cloning very quickly.
2159 revlog files. They are commonly used for cloning very quickly.
2160 """
2160 """
2161 requirements, gen = streamclone.generatebundlev1(repo)
2161 requirements, gen = streamclone.generatebundlev1(repo)
2162 changegroup.writechunks(ui, gen, fname)
2162 changegroup.writechunks(ui, gen, fname)
2163
2163
2164 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2164 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2165
2165
2166 @command('debugapplystreamclonebundle', [], 'FILE')
2166 @command('debugapplystreamclonebundle', [], 'FILE')
2167 def debugapplystreamclonebundle(ui, repo, fname):
2167 def debugapplystreamclonebundle(ui, repo, fname):
2168 """apply a stream clone bundle file"""
2168 """apply a stream clone bundle file"""
2169 f = hg.openpath(ui, fname)
2169 f = hg.openpath(ui, fname)
2170 gen = exchange.readbundle(ui, f, fname)
2170 gen = exchange.readbundle(ui, f, fname)
2171 gen.apply(repo)
2171 gen.apply(repo)
2172
2172
2173 @command('debugcheckstate', [], '')
2173 @command('debugcheckstate', [], '')
2174 def debugcheckstate(ui, repo):
2174 def debugcheckstate(ui, repo):
2175 """validate the correctness of the current dirstate"""
2175 """validate the correctness of the current dirstate"""
2176 parent1, parent2 = repo.dirstate.parents()
2176 parent1, parent2 = repo.dirstate.parents()
2177 m1 = repo[parent1].manifest()
2177 m1 = repo[parent1].manifest()
2178 m2 = repo[parent2].manifest()
2178 m2 = repo[parent2].manifest()
2179 errors = 0
2179 errors = 0
2180 for f in repo.dirstate:
2180 for f in repo.dirstate:
2181 state = repo.dirstate[f]
2181 state = repo.dirstate[f]
2182 if state in "nr" and f not in m1:
2182 if state in "nr" and f not in m1:
2183 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2183 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2184 errors += 1
2184 errors += 1
2185 if state in "a" and f in m1:
2185 if state in "a" and f in m1:
2186 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2186 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2187 errors += 1
2187 errors += 1
2188 if state in "m" and f not in m1 and f not in m2:
2188 if state in "m" and f not in m1 and f not in m2:
2189 ui.warn(_("%s in state %s, but not in either manifest\n") %
2189 ui.warn(_("%s in state %s, but not in either manifest\n") %
2190 (f, state))
2190 (f, state))
2191 errors += 1
2191 errors += 1
2192 for f in m1:
2192 for f in m1:
2193 state = repo.dirstate[f]
2193 state = repo.dirstate[f]
2194 if state not in "nrm":
2194 if state not in "nrm":
2195 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2195 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2196 errors += 1
2196 errors += 1
2197 if errors:
2197 if errors:
2198 error = _(".hg/dirstate inconsistent with current parent's manifest")
2198 error = _(".hg/dirstate inconsistent with current parent's manifest")
2199 raise error.Abort(error)
2199 raise error.Abort(error)
2200
2200
2201 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2201 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2202 def debugcommands(ui, cmd='', *args):
2202 def debugcommands(ui, cmd='', *args):
2203 """list all available commands and options"""
2203 """list all available commands and options"""
2204 for cmd, vals in sorted(table.iteritems()):
2204 for cmd, vals in sorted(table.iteritems()):
2205 cmd = cmd.split('|')[0].strip('^')
2205 cmd = cmd.split('|')[0].strip('^')
2206 opts = ', '.join([i[1] for i in vals[1]])
2206 opts = ', '.join([i[1] for i in vals[1]])
2207 ui.write('%s: %s\n' % (cmd, opts))
2207 ui.write('%s: %s\n' % (cmd, opts))
2208
2208
2209 @command('debugcomplete',
2209 @command('debugcomplete',
2210 [('o', 'options', None, _('show the command options'))],
2210 [('o', 'options', None, _('show the command options'))],
2211 _('[-o] CMD'),
2211 _('[-o] CMD'),
2212 norepo=True)
2212 norepo=True)
2213 def debugcomplete(ui, cmd='', **opts):
2213 def debugcomplete(ui, cmd='', **opts):
2214 """returns the completion list associated with the given command"""
2214 """returns the completion list associated with the given command"""
2215
2215
2216 if opts.get('options'):
2216 if opts.get('options'):
2217 options = []
2217 options = []
2218 otables = [globalopts]
2218 otables = [globalopts]
2219 if cmd:
2219 if cmd:
2220 aliases, entry = cmdutil.findcmd(cmd, table, False)
2220 aliases, entry = cmdutil.findcmd(cmd, table, False)
2221 otables.append(entry[1])
2221 otables.append(entry[1])
2222 for t in otables:
2222 for t in otables:
2223 for o in t:
2223 for o in t:
2224 if "(DEPRECATED)" in o[3]:
2224 if "(DEPRECATED)" in o[3]:
2225 continue
2225 continue
2226 if o[0]:
2226 if o[0]:
2227 options.append('-%s' % o[0])
2227 options.append('-%s' % o[0])
2228 options.append('--%s' % o[1])
2228 options.append('--%s' % o[1])
2229 ui.write("%s\n" % "\n".join(options))
2229 ui.write("%s\n" % "\n".join(options))
2230 return
2230 return
2231
2231
2232 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2232 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2233 if ui.verbose:
2233 if ui.verbose:
2234 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2234 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2235 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2235 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2236
2236
2237 @command('debugdag',
2237 @command('debugdag',
2238 [('t', 'tags', None, _('use tags as labels')),
2238 [('t', 'tags', None, _('use tags as labels')),
2239 ('b', 'branches', None, _('annotate with branch names')),
2239 ('b', 'branches', None, _('annotate with branch names')),
2240 ('', 'dots', None, _('use dots for runs')),
2240 ('', 'dots', None, _('use dots for runs')),
2241 ('s', 'spaces', None, _('separate elements by spaces'))],
2241 ('s', 'spaces', None, _('separate elements by spaces'))],
2242 _('[OPTION]... [FILE [REV]...]'),
2242 _('[OPTION]... [FILE [REV]...]'),
2243 optionalrepo=True)
2243 optionalrepo=True)
2244 def debugdag(ui, repo, file_=None, *revs, **opts):
2244 def debugdag(ui, repo, file_=None, *revs, **opts):
2245 """format the changelog or an index DAG as a concise textual description
2245 """format the changelog or an index DAG as a concise textual description
2246
2246
2247 If you pass a revlog index, the revlog's DAG is emitted. If you list
2247 If you pass a revlog index, the revlog's DAG is emitted. If you list
2248 revision numbers, they get labeled in the output as rN.
2248 revision numbers, they get labeled in the output as rN.
2249
2249
2250 Otherwise, the changelog DAG of the current repo is emitted.
2250 Otherwise, the changelog DAG of the current repo is emitted.
2251 """
2251 """
2252 spaces = opts.get('spaces')
2252 spaces = opts.get('spaces')
2253 dots = opts.get('dots')
2253 dots = opts.get('dots')
2254 if file_:
2254 if file_:
2255 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2255 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2256 revs = set((int(r) for r in revs))
2256 revs = set((int(r) for r in revs))
2257 def events():
2257 def events():
2258 for r in rlog:
2258 for r in rlog:
2259 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2259 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2260 if p != -1))
2260 if p != -1))
2261 if r in revs:
2261 if r in revs:
2262 yield 'l', (r, "r%i" % r)
2262 yield 'l', (r, "r%i" % r)
2263 elif repo:
2263 elif repo:
2264 cl = repo.changelog
2264 cl = repo.changelog
2265 tags = opts.get('tags')
2265 tags = opts.get('tags')
2266 branches = opts.get('branches')
2266 branches = opts.get('branches')
2267 if tags:
2267 if tags:
2268 labels = {}
2268 labels = {}
2269 for l, n in repo.tags().items():
2269 for l, n in repo.tags().items():
2270 labels.setdefault(cl.rev(n), []).append(l)
2270 labels.setdefault(cl.rev(n), []).append(l)
2271 def events():
2271 def events():
2272 b = "default"
2272 b = "default"
2273 for r in cl:
2273 for r in cl:
2274 if branches:
2274 if branches:
2275 newb = cl.read(cl.node(r))[5]['branch']
2275 newb = cl.read(cl.node(r))[5]['branch']
2276 if newb != b:
2276 if newb != b:
2277 yield 'a', newb
2277 yield 'a', newb
2278 b = newb
2278 b = newb
2279 yield 'n', (r, list(p for p in cl.parentrevs(r)
2279 yield 'n', (r, list(p for p in cl.parentrevs(r)
2280 if p != -1))
2280 if p != -1))
2281 if tags:
2281 if tags:
2282 ls = labels.get(r)
2282 ls = labels.get(r)
2283 if ls:
2283 if ls:
2284 for l in ls:
2284 for l in ls:
2285 yield 'l', (r, l)
2285 yield 'l', (r, l)
2286 else:
2286 else:
2287 raise error.Abort(_('need repo for changelog dag'))
2287 raise error.Abort(_('need repo for changelog dag'))
2288
2288
2289 for line in dagparser.dagtextlines(events(),
2289 for line in dagparser.dagtextlines(events(),
2290 addspaces=spaces,
2290 addspaces=spaces,
2291 wraplabels=True,
2291 wraplabels=True,
2292 wrapannotations=True,
2292 wrapannotations=True,
2293 wrapnonlinear=dots,
2293 wrapnonlinear=dots,
2294 usedots=dots,
2294 usedots=dots,
2295 maxlinewidth=70):
2295 maxlinewidth=70):
2296 ui.write(line)
2296 ui.write(line)
2297 ui.write("\n")
2297 ui.write("\n")
2298
2298
2299 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2299 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2300 def debugdata(ui, repo, file_, rev=None, **opts):
2300 def debugdata(ui, repo, file_, rev=None, **opts):
2301 """dump the contents of a data file revision"""
2301 """dump the contents of a data file revision"""
2302 if opts.get('changelog') or opts.get('manifest'):
2302 if opts.get('changelog') or opts.get('manifest'):
2303 file_, rev = None, file_
2303 file_, rev = None, file_
2304 elif rev is None:
2304 elif rev is None:
2305 raise error.CommandError('debugdata', _('invalid arguments'))
2305 raise error.CommandError('debugdata', _('invalid arguments'))
2306 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2306 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2307 try:
2307 try:
2308 ui.write(r.revision(r.lookup(rev)))
2308 ui.write(r.revision(r.lookup(rev)))
2309 except KeyError:
2309 except KeyError:
2310 raise error.Abort(_('invalid revision identifier %s') % rev)
2310 raise error.Abort(_('invalid revision identifier %s') % rev)
2311
2311
2312 @command('debugdate',
2312 @command('debugdate',
2313 [('e', 'extended', None, _('try extended date formats'))],
2313 [('e', 'extended', None, _('try extended date formats'))],
2314 _('[-e] DATE [RANGE]'),
2314 _('[-e] DATE [RANGE]'),
2315 norepo=True, optionalrepo=True)
2315 norepo=True, optionalrepo=True)
2316 def debugdate(ui, date, range=None, **opts):
2316 def debugdate(ui, date, range=None, **opts):
2317 """parse and display a date"""
2317 """parse and display a date"""
2318 if opts["extended"]:
2318 if opts["extended"]:
2319 d = util.parsedate(date, util.extendeddateformats)
2319 d = util.parsedate(date, util.extendeddateformats)
2320 else:
2320 else:
2321 d = util.parsedate(date)
2321 d = util.parsedate(date)
2322 ui.write(("internal: %s %s\n") % d)
2322 ui.write(("internal: %s %s\n") % d)
2323 ui.write(("standard: %s\n") % util.datestr(d))
2323 ui.write(("standard: %s\n") % util.datestr(d))
2324 if range:
2324 if range:
2325 m = util.matchdate(range)
2325 m = util.matchdate(range)
2326 ui.write(("match: %s\n") % m(d[0]))
2326 ui.write(("match: %s\n") % m(d[0]))
2327
2327
2328 @command('debugdiscovery',
2328 @command('debugdiscovery',
2329 [('', 'old', None, _('use old-style discovery')),
2329 [('', 'old', None, _('use old-style discovery')),
2330 ('', 'nonheads', None,
2330 ('', 'nonheads', None,
2331 _('use old-style discovery with non-heads included')),
2331 _('use old-style discovery with non-heads included')),
2332 ] + remoteopts,
2332 ] + remoteopts,
2333 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2333 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2334 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2334 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2335 """runs the changeset discovery protocol in isolation"""
2335 """runs the changeset discovery protocol in isolation"""
2336 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2336 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2337 opts.get('branch'))
2337 opts.get('branch'))
2338 remote = hg.peer(repo, opts, remoteurl)
2338 remote = hg.peer(repo, opts, remoteurl)
2339 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2339 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2340
2340
2341 # make sure tests are repeatable
2341 # make sure tests are repeatable
2342 random.seed(12323)
2342 random.seed(12323)
2343
2343
2344 def doit(localheads, remoteheads, remote=remote):
2344 def doit(localheads, remoteheads, remote=remote):
2345 if opts.get('old'):
2345 if opts.get('old'):
2346 if localheads:
2346 if localheads:
2347 raise error.Abort('cannot use localheads with old style '
2347 raise error.Abort('cannot use localheads with old style '
2348 'discovery')
2348 'discovery')
2349 if not util.safehasattr(remote, 'branches'):
2349 if not util.safehasattr(remote, 'branches'):
2350 # enable in-client legacy support
2350 # enable in-client legacy support
2351 remote = localrepo.locallegacypeer(remote.local())
2351 remote = localrepo.locallegacypeer(remote.local())
2352 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2352 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2353 force=True)
2353 force=True)
2354 common = set(common)
2354 common = set(common)
2355 if not opts.get('nonheads'):
2355 if not opts.get('nonheads'):
2356 ui.write(("unpruned common: %s\n") %
2356 ui.write(("unpruned common: %s\n") %
2357 " ".join(sorted(short(n) for n in common)))
2357 " ".join(sorted(short(n) for n in common)))
2358 dag = dagutil.revlogdag(repo.changelog)
2358 dag = dagutil.revlogdag(repo.changelog)
2359 all = dag.ancestorset(dag.internalizeall(common))
2359 all = dag.ancestorset(dag.internalizeall(common))
2360 common = dag.externalizeall(dag.headsetofconnecteds(all))
2360 common = dag.externalizeall(dag.headsetofconnecteds(all))
2361 else:
2361 else:
2362 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2362 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2363 common = set(common)
2363 common = set(common)
2364 rheads = set(hds)
2364 rheads = set(hds)
2365 lheads = set(repo.heads())
2365 lheads = set(repo.heads())
2366 ui.write(("common heads: %s\n") %
2366 ui.write(("common heads: %s\n") %
2367 " ".join(sorted(short(n) for n in common)))
2367 " ".join(sorted(short(n) for n in common)))
2368 if lheads <= common:
2368 if lheads <= common:
2369 ui.write(("local is subset\n"))
2369 ui.write(("local is subset\n"))
2370 elif rheads <= common:
2370 elif rheads <= common:
2371 ui.write(("remote is subset\n"))
2371 ui.write(("remote is subset\n"))
2372
2372
2373 serverlogs = opts.get('serverlog')
2373 serverlogs = opts.get('serverlog')
2374 if serverlogs:
2374 if serverlogs:
2375 for filename in serverlogs:
2375 for filename in serverlogs:
2376 with open(filename, 'r') as logfile:
2376 with open(filename, 'r') as logfile:
2377 line = logfile.readline()
2377 line = logfile.readline()
2378 while line:
2378 while line:
2379 parts = line.strip().split(';')
2379 parts = line.strip().split(';')
2380 op = parts[1]
2380 op = parts[1]
2381 if op == 'cg':
2381 if op == 'cg':
2382 pass
2382 pass
2383 elif op == 'cgss':
2383 elif op == 'cgss':
2384 doit(parts[2].split(' '), parts[3].split(' '))
2384 doit(parts[2].split(' '), parts[3].split(' '))
2385 elif op == 'unb':
2385 elif op == 'unb':
2386 doit(parts[3].split(' '), parts[2].split(' '))
2386 doit(parts[3].split(' '), parts[2].split(' '))
2387 line = logfile.readline()
2387 line = logfile.readline()
2388 else:
2388 else:
2389 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2389 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2390 opts.get('remote_head'))
2390 opts.get('remote_head'))
2391 localrevs = opts.get('local_head')
2391 localrevs = opts.get('local_head')
2392 doit(localrevs, remoterevs)
2392 doit(localrevs, remoterevs)
2393
2393
2394 @command('debugextensions', formatteropts, [], norepo=True)
2394 @command('debugextensions', formatteropts, [], norepo=True)
2395 def debugextensions(ui, **opts):
2395 def debugextensions(ui, **opts):
2396 '''show information about active extensions'''
2396 '''show information about active extensions'''
2397 exts = extensions.extensions(ui)
2397 exts = extensions.extensions(ui)
2398 fm = ui.formatter('debugextensions', opts)
2398 fm = ui.formatter('debugextensions', opts)
2399 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2399 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2400 extsource = extmod.__file__
2400 extsource = extmod.__file__
2401 exttestedwith = getattr(extmod, 'testedwith', None)
2401 exttestedwith = getattr(extmod, 'testedwith', None)
2402 if exttestedwith is not None:
2402 if exttestedwith is not None:
2403 exttestedwith = exttestedwith.split()
2403 exttestedwith = exttestedwith.split()
2404 extbuglink = getattr(extmod, 'buglink', None)
2404 extbuglink = getattr(extmod, 'buglink', None)
2405
2405
2406 fm.startitem()
2406 fm.startitem()
2407
2407
2408 if ui.quiet or ui.verbose:
2408 if ui.quiet or ui.verbose:
2409 fm.write('name', '%s\n', extname)
2409 fm.write('name', '%s\n', extname)
2410 else:
2410 else:
2411 fm.write('name', '%s', extname)
2411 fm.write('name', '%s', extname)
2412 if not exttestedwith:
2412 if not exttestedwith:
2413 fm.plain(_(' (untested!)\n'))
2413 fm.plain(_(' (untested!)\n'))
2414 else:
2414 else:
2415 if exttestedwith == ['internal'] or \
2415 if exttestedwith == ['internal'] or \
2416 util.version() in exttestedwith:
2416 util.version() in exttestedwith:
2417 fm.plain('\n')
2417 fm.plain('\n')
2418 else:
2418 else:
2419 lasttestedversion = exttestedwith[-1]
2419 lasttestedversion = exttestedwith[-1]
2420 fm.plain(' (%s!)\n' % lasttestedversion)
2420 fm.plain(' (%s!)\n' % lasttestedversion)
2421
2421
2422 fm.condwrite(ui.verbose and extsource, 'source',
2422 fm.condwrite(ui.verbose and extsource, 'source',
2423 _(' location: %s\n'), extsource or "")
2423 _(' location: %s\n'), extsource or "")
2424
2424
2425 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2425 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2426 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2426 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2427
2427
2428 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2428 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2429 _(' bug reporting: %s\n'), extbuglink or "")
2429 _(' bug reporting: %s\n'), extbuglink or "")
2430
2430
2431 fm.end()
2431 fm.end()
2432
2432
2433 @command('debugfileset',
2433 @command('debugfileset',
2434 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2434 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2435 _('[-r REV] FILESPEC'))
2435 _('[-r REV] FILESPEC'))
2436 def debugfileset(ui, repo, expr, **opts):
2436 def debugfileset(ui, repo, expr, **opts):
2437 '''parse and apply a fileset specification'''
2437 '''parse and apply a fileset specification'''
2438 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2438 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2439 if ui.verbose:
2439 if ui.verbose:
2440 tree = fileset.parse(expr)
2440 tree = fileset.parse(expr)
2441 ui.note(fileset.prettyformat(tree), "\n")
2441 ui.note(fileset.prettyformat(tree), "\n")
2442
2442
2443 for f in ctx.getfileset(expr):
2443 for f in ctx.getfileset(expr):
2444 ui.write("%s\n" % f)
2444 ui.write("%s\n" % f)
2445
2445
2446 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2446 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2447 def debugfsinfo(ui, path="."):
2447 def debugfsinfo(ui, path="."):
2448 """show information detected about current filesystem"""
2448 """show information detected about current filesystem"""
2449 util.writefile('.debugfsinfo', '')
2449 util.writefile('.debugfsinfo', '')
2450 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2450 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2451 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2451 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2452 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2452 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2453 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2453 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2454 and 'yes' or 'no'))
2454 and 'yes' or 'no'))
2455 os.unlink('.debugfsinfo')
2455 os.unlink('.debugfsinfo')
2456
2456
2457 @command('debuggetbundle',
2457 @command('debuggetbundle',
2458 [('H', 'head', [], _('id of head node'), _('ID')),
2458 [('H', 'head', [], _('id of head node'), _('ID')),
2459 ('C', 'common', [], _('id of common node'), _('ID')),
2459 ('C', 'common', [], _('id of common node'), _('ID')),
2460 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2460 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2461 _('REPO FILE [-H|-C ID]...'),
2461 _('REPO FILE [-H|-C ID]...'),
2462 norepo=True)
2462 norepo=True)
2463 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2463 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2464 """retrieves a bundle from a repo
2464 """retrieves a bundle from a repo
2465
2465
2466 Every ID must be a full-length hex node id string. Saves the bundle to the
2466 Every ID must be a full-length hex node id string. Saves the bundle to the
2467 given file.
2467 given file.
2468 """
2468 """
2469 repo = hg.peer(ui, opts, repopath)
2469 repo = hg.peer(ui, opts, repopath)
2470 if not repo.capable('getbundle'):
2470 if not repo.capable('getbundle'):
2471 raise error.Abort("getbundle() not supported by target repository")
2471 raise error.Abort("getbundle() not supported by target repository")
2472 args = {}
2472 args = {}
2473 if common:
2473 if common:
2474 args['common'] = [bin(s) for s in common]
2474 args['common'] = [bin(s) for s in common]
2475 if head:
2475 if head:
2476 args['heads'] = [bin(s) for s in head]
2476 args['heads'] = [bin(s) for s in head]
2477 # TODO: get desired bundlecaps from command line.
2477 # TODO: get desired bundlecaps from command line.
2478 args['bundlecaps'] = None
2478 args['bundlecaps'] = None
2479 bundle = repo.getbundle('debug', **args)
2479 bundle = repo.getbundle('debug', **args)
2480
2480
2481 bundletype = opts.get('type', 'bzip2').lower()
2481 bundletype = opts.get('type', 'bzip2').lower()
2482 btypes = {'none': 'HG10UN',
2482 btypes = {'none': 'HG10UN',
2483 'bzip2': 'HG10BZ',
2483 'bzip2': 'HG10BZ',
2484 'gzip': 'HG10GZ',
2484 'gzip': 'HG10GZ',
2485 'bundle2': 'HG20'}
2485 'bundle2': 'HG20'}
2486 bundletype = btypes.get(bundletype)
2486 bundletype = btypes.get(bundletype)
2487 if bundletype not in bundle2.bundletypes:
2487 if bundletype not in bundle2.bundletypes:
2488 raise error.Abort(_('unknown bundle type specified with --type'))
2488 raise error.Abort(_('unknown bundle type specified with --type'))
2489 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2489 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2490
2490
2491 @command('debugignore', [], '[FILE]')
2491 @command('debugignore', [], '[FILE]')
2492 def debugignore(ui, repo, *files, **opts):
2492 def debugignore(ui, repo, *files, **opts):
2493 """display the combined ignore pattern and information about ignored files
2493 """display the combined ignore pattern and information about ignored files
2494
2494
2495 With no argument display the combined ignore pattern.
2495 With no argument display the combined ignore pattern.
2496
2496
2497 Given space separated file names, shows if the given file is ignored and
2497 Given space separated file names, shows if the given file is ignored and
2498 if so, show the ignore rule (file and line number) that matched it.
2498 if so, show the ignore rule (file and line number) that matched it.
2499 """
2499 """
2500 ignore = repo.dirstate._ignore
2500 ignore = repo.dirstate._ignore
2501 if not files:
2501 if not files:
2502 # Show all the patterns
2502 # Show all the patterns
2503 includepat = getattr(ignore, 'includepat', None)
2503 includepat = getattr(ignore, 'includepat', None)
2504 if includepat is not None:
2504 if includepat is not None:
2505 ui.write("%s\n" % includepat)
2505 ui.write("%s\n" % includepat)
2506 else:
2506 else:
2507 raise error.Abort(_("no ignore patterns found"))
2507 raise error.Abort(_("no ignore patterns found"))
2508 else:
2508 else:
2509 for f in files:
2509 for f in files:
2510 nf = util.normpath(f)
2510 nf = util.normpath(f)
2511 ignored = None
2511 ignored = None
2512 ignoredata = None
2512 ignoredata = None
2513 if nf != '.':
2513 if nf != '.':
2514 if ignore(nf):
2514 if ignore(nf):
2515 ignored = nf
2515 ignored = nf
2516 ignoredata = repo.dirstate._ignorefileandline(nf)
2516 ignoredata = repo.dirstate._ignorefileandline(nf)
2517 else:
2517 else:
2518 for p in util.finddirs(nf):
2518 for p in util.finddirs(nf):
2519 if ignore(p):
2519 if ignore(p):
2520 ignored = p
2520 ignored = p
2521 ignoredata = repo.dirstate._ignorefileandline(p)
2521 ignoredata = repo.dirstate._ignorefileandline(p)
2522 break
2522 break
2523 if ignored:
2523 if ignored:
2524 if ignored == nf:
2524 if ignored == nf:
2525 ui.write(_("%s is ignored\n") % f)
2525 ui.write(_("%s is ignored\n") % f)
2526 else:
2526 else:
2527 ui.write(_("%s is ignored because of "
2527 ui.write(_("%s is ignored because of "
2528 "containing folder %s\n")
2528 "containing folder %s\n")
2529 % (f, ignored))
2529 % (f, ignored))
2530 ignorefile, lineno, line = ignoredata
2530 ignorefile, lineno, line = ignoredata
2531 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2531 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2532 % (ignorefile, lineno, line))
2532 % (ignorefile, lineno, line))
2533 else:
2533 else:
2534 ui.write(_("%s is not ignored\n") % f)
2534 ui.write(_("%s is not ignored\n") % f)
2535
2535
2536 @command('debugindex', debugrevlogopts +
2536 @command('debugindex', debugrevlogopts +
2537 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2537 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2538 _('[-f FORMAT] -c|-m|FILE'),
2538 _('[-f FORMAT] -c|-m|FILE'),
2539 optionalrepo=True)
2539 optionalrepo=True)
2540 def debugindex(ui, repo, file_=None, **opts):
2540 def debugindex(ui, repo, file_=None, **opts):
2541 """dump the contents of an index file"""
2541 """dump the contents of an index file"""
2542 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2542 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2543 format = opts.get('format', 0)
2543 format = opts.get('format', 0)
2544 if format not in (0, 1):
2544 if format not in (0, 1):
2545 raise error.Abort(_("unknown format %d") % format)
2545 raise error.Abort(_("unknown format %d") % format)
2546
2546
2547 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2547 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2548 if generaldelta:
2548 if generaldelta:
2549 basehdr = ' delta'
2549 basehdr = ' delta'
2550 else:
2550 else:
2551 basehdr = ' base'
2551 basehdr = ' base'
2552
2552
2553 if ui.debugflag:
2553 if ui.debugflag:
2554 shortfn = hex
2554 shortfn = hex
2555 else:
2555 else:
2556 shortfn = short
2556 shortfn = short
2557
2557
2558 # There might not be anything in r, so have a sane default
2558 # There might not be anything in r, so have a sane default
2559 idlen = 12
2559 idlen = 12
2560 for i in r:
2560 for i in r:
2561 idlen = len(shortfn(r.node(i)))
2561 idlen = len(shortfn(r.node(i)))
2562 break
2562 break
2563
2563
2564 if format == 0:
2564 if format == 0:
2565 ui.write(" rev offset length " + basehdr + " linkrev"
2565 ui.write(" rev offset length " + basehdr + " linkrev"
2566 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2566 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2567 elif format == 1:
2567 elif format == 1:
2568 ui.write(" rev flag offset length"
2568 ui.write(" rev flag offset length"
2569 " size " + basehdr + " link p1 p2"
2569 " size " + basehdr + " link p1 p2"
2570 " %s\n" % "nodeid".rjust(idlen))
2570 " %s\n" % "nodeid".rjust(idlen))
2571
2571
2572 for i in r:
2572 for i in r:
2573 node = r.node(i)
2573 node = r.node(i)
2574 if generaldelta:
2574 if generaldelta:
2575 base = r.deltaparent(i)
2575 base = r.deltaparent(i)
2576 else:
2576 else:
2577 base = r.chainbase(i)
2577 base = r.chainbase(i)
2578 if format == 0:
2578 if format == 0:
2579 try:
2579 try:
2580 pp = r.parents(node)
2580 pp = r.parents(node)
2581 except Exception:
2581 except Exception:
2582 pp = [nullid, nullid]
2582 pp = [nullid, nullid]
2583 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2583 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2584 i, r.start(i), r.length(i), base, r.linkrev(i),
2584 i, r.start(i), r.length(i), base, r.linkrev(i),
2585 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2585 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2586 elif format == 1:
2586 elif format == 1:
2587 pr = r.parentrevs(i)
2587 pr = r.parentrevs(i)
2588 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2588 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2589 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2589 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2590 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2590 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2591
2591
2592 @command('debugindexdot', debugrevlogopts,
2592 @command('debugindexdot', debugrevlogopts,
2593 _('-c|-m|FILE'), optionalrepo=True)
2593 _('-c|-m|FILE'), optionalrepo=True)
2594 def debugindexdot(ui, repo, file_=None, **opts):
2594 def debugindexdot(ui, repo, file_=None, **opts):
2595 """dump an index DAG as a graphviz dot file"""
2595 """dump an index DAG as a graphviz dot file"""
2596 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2596 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2597 ui.write(("digraph G {\n"))
2597 ui.write(("digraph G {\n"))
2598 for i in r:
2598 for i in r:
2599 node = r.node(i)
2599 node = r.node(i)
2600 pp = r.parents(node)
2600 pp = r.parents(node)
2601 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2601 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2602 if pp[1] != nullid:
2602 if pp[1] != nullid:
2603 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2603 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2604 ui.write("}\n")
2604 ui.write("}\n")
2605
2605
2606 @command('debugdeltachain',
2606 @command('debugdeltachain',
2607 debugrevlogopts + formatteropts,
2607 debugrevlogopts + formatteropts,
2608 _('-c|-m|FILE'),
2608 _('-c|-m|FILE'),
2609 optionalrepo=True)
2609 optionalrepo=True)
2610 def debugdeltachain(ui, repo, file_=None, **opts):
2610 def debugdeltachain(ui, repo, file_=None, **opts):
2611 """dump information about delta chains in a revlog
2611 """dump information about delta chains in a revlog
2612
2612
2613 Output can be templatized. Available template keywords are:
2613 Output can be templatized. Available template keywords are:
2614
2614
2615 rev revision number
2615 rev revision number
2616 chainid delta chain identifier (numbered by unique base)
2616 chainid delta chain identifier (numbered by unique base)
2617 chainlen delta chain length to this revision
2617 chainlen delta chain length to this revision
2618 prevrev previous revision in delta chain
2618 prevrev previous revision in delta chain
2619 deltatype role of delta / how it was computed
2619 deltatype role of delta / how it was computed
2620 compsize compressed size of revision
2620 compsize compressed size of revision
2621 uncompsize uncompressed size of revision
2621 uncompsize uncompressed size of revision
2622 chainsize total size of compressed revisions in chain
2622 chainsize total size of compressed revisions in chain
2623 chainratio total chain size divided by uncompressed revision size
2623 chainratio total chain size divided by uncompressed revision size
2624 (new delta chains typically start at ratio 2.00)
2624 (new delta chains typically start at ratio 2.00)
2625 lindist linear distance from base revision in delta chain to end
2625 lindist linear distance from base revision in delta chain to end
2626 of this revision
2626 of this revision
2627 extradist total size of revisions not part of this delta chain from
2627 extradist total size of revisions not part of this delta chain from
2628 base of delta chain to end of this revision; a measurement
2628 base of delta chain to end of this revision; a measurement
2629 of how much extra data we need to read/seek across to read
2629 of how much extra data we need to read/seek across to read
2630 the delta chain for this revision
2630 the delta chain for this revision
2631 extraratio extradist divided by chainsize; another representation of
2631 extraratio extradist divided by chainsize; another representation of
2632 how much unrelated data is needed to load this delta chain
2632 how much unrelated data is needed to load this delta chain
2633 """
2633 """
2634 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2634 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2635 index = r.index
2635 index = r.index
2636 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2636 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2637
2637
2638 def revinfo(rev):
2638 def revinfo(rev):
2639 e = index[rev]
2639 e = index[rev]
2640 compsize = e[1]
2640 compsize = e[1]
2641 uncompsize = e[2]
2641 uncompsize = e[2]
2642 chainsize = 0
2642 chainsize = 0
2643
2643
2644 if generaldelta:
2644 if generaldelta:
2645 if e[3] == e[5]:
2645 if e[3] == e[5]:
2646 deltatype = 'p1'
2646 deltatype = 'p1'
2647 elif e[3] == e[6]:
2647 elif e[3] == e[6]:
2648 deltatype = 'p2'
2648 deltatype = 'p2'
2649 elif e[3] == rev - 1:
2649 elif e[3] == rev - 1:
2650 deltatype = 'prev'
2650 deltatype = 'prev'
2651 elif e[3] == rev:
2651 elif e[3] == rev:
2652 deltatype = 'base'
2652 deltatype = 'base'
2653 else:
2653 else:
2654 deltatype = 'other'
2654 deltatype = 'other'
2655 else:
2655 else:
2656 if e[3] == rev:
2656 if e[3] == rev:
2657 deltatype = 'base'
2657 deltatype = 'base'
2658 else:
2658 else:
2659 deltatype = 'prev'
2659 deltatype = 'prev'
2660
2660
2661 chain = r._deltachain(rev)[0]
2661 chain = r._deltachain(rev)[0]
2662 for iterrev in chain:
2662 for iterrev in chain:
2663 e = index[iterrev]
2663 e = index[iterrev]
2664 chainsize += e[1]
2664 chainsize += e[1]
2665
2665
2666 return compsize, uncompsize, deltatype, chain, chainsize
2666 return compsize, uncompsize, deltatype, chain, chainsize
2667
2667
2668 fm = ui.formatter('debugdeltachain', opts)
2668 fm = ui.formatter('debugdeltachain', opts)
2669
2669
2670 fm.plain(' rev chain# chainlen prev delta '
2670 fm.plain(' rev chain# chainlen prev delta '
2671 'size rawsize chainsize ratio lindist extradist '
2671 'size rawsize chainsize ratio lindist extradist '
2672 'extraratio\n')
2672 'extraratio\n')
2673
2673
2674 chainbases = {}
2674 chainbases = {}
2675 for rev in r:
2675 for rev in r:
2676 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2676 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2677 chainbase = chain[0]
2677 chainbase = chain[0]
2678 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2678 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2679 basestart = r.start(chainbase)
2679 basestart = r.start(chainbase)
2680 revstart = r.start(rev)
2680 revstart = r.start(rev)
2681 lineardist = revstart + comp - basestart
2681 lineardist = revstart + comp - basestart
2682 extradist = lineardist - chainsize
2682 extradist = lineardist - chainsize
2683 try:
2683 try:
2684 prevrev = chain[-2]
2684 prevrev = chain[-2]
2685 except IndexError:
2685 except IndexError:
2686 prevrev = -1
2686 prevrev = -1
2687
2687
2688 chainratio = float(chainsize) / float(uncomp)
2688 chainratio = float(chainsize) / float(uncomp)
2689 extraratio = float(extradist) / float(chainsize)
2689 extraratio = float(extradist) / float(chainsize)
2690
2690
2691 fm.startitem()
2691 fm.startitem()
2692 fm.write('rev chainid chainlen prevrev deltatype compsize '
2692 fm.write('rev chainid chainlen prevrev deltatype compsize '
2693 'uncompsize chainsize chainratio lindist extradist '
2693 'uncompsize chainsize chainratio lindist extradist '
2694 'extraratio',
2694 'extraratio',
2695 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2695 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2696 rev, chainid, len(chain), prevrev, deltatype, comp,
2696 rev, chainid, len(chain), prevrev, deltatype, comp,
2697 uncomp, chainsize, chainratio, lineardist, extradist,
2697 uncomp, chainsize, chainratio, lineardist, extradist,
2698 extraratio,
2698 extraratio,
2699 rev=rev, chainid=chainid, chainlen=len(chain),
2699 rev=rev, chainid=chainid, chainlen=len(chain),
2700 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2700 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2701 uncompsize=uncomp, chainsize=chainsize,
2701 uncompsize=uncomp, chainsize=chainsize,
2702 chainratio=chainratio, lindist=lineardist,
2702 chainratio=chainratio, lindist=lineardist,
2703 extradist=extradist, extraratio=extraratio)
2703 extradist=extradist, extraratio=extraratio)
2704
2704
2705 fm.end()
2705 fm.end()
2706
2706
2707 @command('debuginstall', [] + formatteropts, '', norepo=True)
2707 @command('debuginstall', [] + formatteropts, '', norepo=True)
2708 def debuginstall(ui, **opts):
2708 def debuginstall(ui, **opts):
2709 '''test Mercurial installation
2709 '''test Mercurial installation
2710
2710
2711 Returns 0 on success.
2711 Returns 0 on success.
2712 '''
2712 '''
2713
2713
2714 def writetemp(contents):
2714 def writetemp(contents):
2715 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2715 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2716 f = os.fdopen(fd, "wb")
2716 f = os.fdopen(fd, "wb")
2717 f.write(contents)
2717 f.write(contents)
2718 f.close()
2718 f.close()
2719 return name
2719 return name
2720
2720
2721 problems = 0
2721 problems = 0
2722
2722
2723 fm = ui.formatter('debuginstall', opts)
2723 fm = ui.formatter('debuginstall', opts)
2724 fm.startitem()
2724 fm.startitem()
2725
2725
2726 # encoding
2726 # encoding
2727 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2727 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2728 err = None
2728 err = None
2729 try:
2729 try:
2730 encoding.fromlocal("test")
2730 encoding.fromlocal("test")
2731 except error.Abort as inst:
2731 except error.Abort as inst:
2732 err = inst
2732 err = inst
2733 problems += 1
2733 problems += 1
2734 fm.condwrite(err, 'encodingerror', _(" %s\n"
2734 fm.condwrite(err, 'encodingerror', _(" %s\n"
2735 " (check that your locale is properly set)\n"), err)
2735 " (check that your locale is properly set)\n"), err)
2736
2736
2737 # Python
2737 # Python
2738 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2738 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2739 sys.executable)
2739 sys.executable)
2740 fm.write('pythonver', _("checking Python version (%s)\n"),
2740 fm.write('pythonver', _("checking Python version (%s)\n"),
2741 ("%s.%s.%s" % sys.version_info[:3]))
2741 ("%s.%s.%s" % sys.version_info[:3]))
2742 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2742 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2743 os.path.dirname(os.__file__))
2743 os.path.dirname(os.__file__))
2744
2744
2745 # hg version
2745 # hg version
2746 hgver = util.version()
2746 hgver = util.version()
2747 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2747 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2748 hgver.split('+')[0])
2748 hgver.split('+')[0])
2749 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2749 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2750 '+'.join(hgver.split('+')[1:]))
2750 '+'.join(hgver.split('+')[1:]))
2751
2751
2752 # compiled modules
2752 # compiled modules
2753 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2753 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2754 policy.policy)
2754 policy.policy)
2755 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2755 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2756 os.path.dirname(__file__))
2756 os.path.dirname(__file__))
2757
2757
2758 err = None
2758 err = None
2759 try:
2759 try:
2760 from . import (
2760 from . import (
2761 base85,
2761 base85,
2762 bdiff,
2762 bdiff,
2763 mpatch,
2763 mpatch,
2764 osutil,
2764 osutil,
2765 )
2765 )
2766 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2766 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2767 except Exception as inst:
2767 except Exception as inst:
2768 err = inst
2768 err = inst
2769 problems += 1
2769 problems += 1
2770 fm.condwrite(err, 'extensionserror', " %s\n", err)
2770 fm.condwrite(err, 'extensionserror', " %s\n", err)
2771
2771
2772 # templates
2772 # templates
2773 p = templater.templatepaths()
2773 p = templater.templatepaths()
2774 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2774 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2775 fm.condwrite(not p, '', _(" no template directories found\n"))
2775 fm.condwrite(not p, '', _(" no template directories found\n"))
2776 if p:
2776 if p:
2777 m = templater.templatepath("map-cmdline.default")
2777 m = templater.templatepath("map-cmdline.default")
2778 if m:
2778 if m:
2779 # template found, check if it is working
2779 # template found, check if it is working
2780 err = None
2780 err = None
2781 try:
2781 try:
2782 templater.templater.frommapfile(m)
2782 templater.templater.frommapfile(m)
2783 except Exception as inst:
2783 except Exception as inst:
2784 err = inst
2784 err = inst
2785 p = None
2785 p = None
2786 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2786 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2787 else:
2787 else:
2788 p = None
2788 p = None
2789 fm.condwrite(p, 'defaulttemplate',
2789 fm.condwrite(p, 'defaulttemplate',
2790 _("checking default template (%s)\n"), m)
2790 _("checking default template (%s)\n"), m)
2791 fm.condwrite(not m, 'defaulttemplatenotfound',
2791 fm.condwrite(not m, 'defaulttemplatenotfound',
2792 _(" template '%s' not found\n"), "default")
2792 _(" template '%s' not found\n"), "default")
2793 if not p:
2793 if not p:
2794 problems += 1
2794 problems += 1
2795 fm.condwrite(not p, '',
2795 fm.condwrite(not p, '',
2796 _(" (templates seem to have been installed incorrectly)\n"))
2796 _(" (templates seem to have been installed incorrectly)\n"))
2797
2797
2798 # editor
2798 # editor
2799 editor = ui.geteditor()
2799 editor = ui.geteditor()
2800 editor = util.expandpath(editor)
2800 editor = util.expandpath(editor)
2801 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2801 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2802 cmdpath = util.findexe(shlex.split(editor)[0])
2802 cmdpath = util.findexe(shlex.split(editor)[0])
2803 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2803 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2804 _(" No commit editor set and can't find %s in PATH\n"
2804 _(" No commit editor set and can't find %s in PATH\n"
2805 " (specify a commit editor in your configuration"
2805 " (specify a commit editor in your configuration"
2806 " file)\n"), not cmdpath and editor == 'vi' and editor)
2806 " file)\n"), not cmdpath and editor == 'vi' and editor)
2807 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2807 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2808 _(" Can't find editor '%s' in PATH\n"
2808 _(" Can't find editor '%s' in PATH\n"
2809 " (specify a commit editor in your configuration"
2809 " (specify a commit editor in your configuration"
2810 " file)\n"), not cmdpath and editor)
2810 " file)\n"), not cmdpath and editor)
2811 if not cmdpath and editor != 'vi':
2811 if not cmdpath and editor != 'vi':
2812 problems += 1
2812 problems += 1
2813
2813
2814 # check username
2814 # check username
2815 username = None
2815 username = None
2816 err = None
2816 err = None
2817 try:
2817 try:
2818 username = ui.username()
2818 username = ui.username()
2819 except error.Abort as e:
2819 except error.Abort as e:
2820 err = e
2820 err = e
2821 problems += 1
2821 problems += 1
2822
2822
2823 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2823 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2824 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2824 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2825 " (specify a username in your configuration file)\n"), err)
2825 " (specify a username in your configuration file)\n"), err)
2826
2826
2827 fm.condwrite(not problems, '',
2827 fm.condwrite(not problems, '',
2828 _("no problems detected\n"))
2828 _("no problems detected\n"))
2829 if not problems:
2829 if not problems:
2830 fm.data(problems=problems)
2830 fm.data(problems=problems)
2831 fm.condwrite(problems, 'problems',
2831 fm.condwrite(problems, 'problems',
2832 _("%s problems detected,"
2832 _("%s problems detected,"
2833 " please check your install!\n"), problems)
2833 " please check your install!\n"), problems)
2834 fm.end()
2834 fm.end()
2835
2835
2836 return problems
2836 return problems
2837
2837
2838 @command('debugknown', [], _('REPO ID...'), norepo=True)
2838 @command('debugknown', [], _('REPO ID...'), norepo=True)
2839 def debugknown(ui, repopath, *ids, **opts):
2839 def debugknown(ui, repopath, *ids, **opts):
2840 """test whether node ids are known to a repo
2840 """test whether node ids are known to a repo
2841
2841
2842 Every ID must be a full-length hex node id string. Returns a list of 0s
2842 Every ID must be a full-length hex node id string. Returns a list of 0s
2843 and 1s indicating unknown/known.
2843 and 1s indicating unknown/known.
2844 """
2844 """
2845 repo = hg.peer(ui, opts, repopath)
2845 repo = hg.peer(ui, opts, repopath)
2846 if not repo.capable('known'):
2846 if not repo.capable('known'):
2847 raise error.Abort("known() not supported by target repository")
2847 raise error.Abort("known() not supported by target repository")
2848 flags = repo.known([bin(s) for s in ids])
2848 flags = repo.known([bin(s) for s in ids])
2849 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2849 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2850
2850
2851 @command('debuglabelcomplete', [], _('LABEL...'))
2851 @command('debuglabelcomplete', [], _('LABEL...'))
2852 def debuglabelcomplete(ui, repo, *args):
2852 def debuglabelcomplete(ui, repo, *args):
2853 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2853 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2854 debugnamecomplete(ui, repo, *args)
2854 debugnamecomplete(ui, repo, *args)
2855
2855
2856 @command('debugmergestate', [], '')
2856 @command('debugmergestate', [], '')
2857 def debugmergestate(ui, repo, *args):
2857 def debugmergestate(ui, repo, *args):
2858 """print merge state
2858 """print merge state
2859
2859
2860 Use --verbose to print out information about whether v1 or v2 merge state
2860 Use --verbose to print out information about whether v1 or v2 merge state
2861 was chosen."""
2861 was chosen."""
2862 def _hashornull(h):
2862 def _hashornull(h):
2863 if h == nullhex:
2863 if h == nullhex:
2864 return 'null'
2864 return 'null'
2865 else:
2865 else:
2866 return h
2866 return h
2867
2867
2868 def printrecords(version):
2868 def printrecords(version):
2869 ui.write(('* version %s records\n') % version)
2869 ui.write(('* version %s records\n') % version)
2870 if version == 1:
2870 if version == 1:
2871 records = v1records
2871 records = v1records
2872 else:
2872 else:
2873 records = v2records
2873 records = v2records
2874
2874
2875 for rtype, record in records:
2875 for rtype, record in records:
2876 # pretty print some record types
2876 # pretty print some record types
2877 if rtype == 'L':
2877 if rtype == 'L':
2878 ui.write(('local: %s\n') % record)
2878 ui.write(('local: %s\n') % record)
2879 elif rtype == 'O':
2879 elif rtype == 'O':
2880 ui.write(('other: %s\n') % record)
2880 ui.write(('other: %s\n') % record)
2881 elif rtype == 'm':
2881 elif rtype == 'm':
2882 driver, mdstate = record.split('\0', 1)
2882 driver, mdstate = record.split('\0', 1)
2883 ui.write(('merge driver: %s (state "%s")\n')
2883 ui.write(('merge driver: %s (state "%s")\n')
2884 % (driver, mdstate))
2884 % (driver, mdstate))
2885 elif rtype in 'FDC':
2885 elif rtype in 'FDC':
2886 r = record.split('\0')
2886 r = record.split('\0')
2887 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2887 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2888 if version == 1:
2888 if version == 1:
2889 onode = 'not stored in v1 format'
2889 onode = 'not stored in v1 format'
2890 flags = r[7]
2890 flags = r[7]
2891 else:
2891 else:
2892 onode, flags = r[7:9]
2892 onode, flags = r[7:9]
2893 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2893 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2894 % (f, rtype, state, _hashornull(hash)))
2894 % (f, rtype, state, _hashornull(hash)))
2895 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2895 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2896 ui.write((' ancestor path: %s (node %s)\n')
2896 ui.write((' ancestor path: %s (node %s)\n')
2897 % (afile, _hashornull(anode)))
2897 % (afile, _hashornull(anode)))
2898 ui.write((' other path: %s (node %s)\n')
2898 ui.write((' other path: %s (node %s)\n')
2899 % (ofile, _hashornull(onode)))
2899 % (ofile, _hashornull(onode)))
2900 elif rtype == 'f':
2900 elif rtype == 'f':
2901 filename, rawextras = record.split('\0', 1)
2901 filename, rawextras = record.split('\0', 1)
2902 extras = rawextras.split('\0')
2902 extras = rawextras.split('\0')
2903 i = 0
2903 i = 0
2904 extrastrings = []
2904 extrastrings = []
2905 while i < len(extras):
2905 while i < len(extras):
2906 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2906 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2907 i += 2
2907 i += 2
2908
2908
2909 ui.write(('file extras: %s (%s)\n')
2909 ui.write(('file extras: %s (%s)\n')
2910 % (filename, ', '.join(extrastrings)))
2910 % (filename, ', '.join(extrastrings)))
2911 elif rtype == 'l':
2911 elif rtype == 'l':
2912 labels = record.split('\0', 2)
2912 labels = record.split('\0', 2)
2913 labels = [l for l in labels if len(l) > 0]
2913 labels = [l for l in labels if len(l) > 0]
2914 ui.write(('labels:\n'))
2914 ui.write(('labels:\n'))
2915 ui.write((' local: %s\n' % labels[0]))
2915 ui.write((' local: %s\n' % labels[0]))
2916 ui.write((' other: %s\n' % labels[1]))
2916 ui.write((' other: %s\n' % labels[1]))
2917 if len(labels) > 2:
2917 if len(labels) > 2:
2918 ui.write((' base: %s\n' % labels[2]))
2918 ui.write((' base: %s\n' % labels[2]))
2919 else:
2919 else:
2920 ui.write(('unrecognized entry: %s\t%s\n')
2920 ui.write(('unrecognized entry: %s\t%s\n')
2921 % (rtype, record.replace('\0', '\t')))
2921 % (rtype, record.replace('\0', '\t')))
2922
2922
2923 # Avoid mergestate.read() since it may raise an exception for unsupported
2923 # Avoid mergestate.read() since it may raise an exception for unsupported
2924 # merge state records. We shouldn't be doing this, but this is OK since this
2924 # merge state records. We shouldn't be doing this, but this is OK since this
2925 # command is pretty low-level.
2925 # command is pretty low-level.
2926 ms = mergemod.mergestate(repo)
2926 ms = mergemod.mergestate(repo)
2927
2927
2928 # sort so that reasonable information is on top
2928 # sort so that reasonable information is on top
2929 v1records = ms._readrecordsv1()
2929 v1records = ms._readrecordsv1()
2930 v2records = ms._readrecordsv2()
2930 v2records = ms._readrecordsv2()
2931 order = 'LOml'
2931 order = 'LOml'
2932 def key(r):
2932 def key(r):
2933 idx = order.find(r[0])
2933 idx = order.find(r[0])
2934 if idx == -1:
2934 if idx == -1:
2935 return (1, r[1])
2935 return (1, r[1])
2936 else:
2936 else:
2937 return (0, idx)
2937 return (0, idx)
2938 v1records.sort(key=key)
2938 v1records.sort(key=key)
2939 v2records.sort(key=key)
2939 v2records.sort(key=key)
2940
2940
2941 if not v1records and not v2records:
2941 if not v1records and not v2records:
2942 ui.write(('no merge state found\n'))
2942 ui.write(('no merge state found\n'))
2943 elif not v2records:
2943 elif not v2records:
2944 ui.note(('no version 2 merge state\n'))
2944 ui.note(('no version 2 merge state\n'))
2945 printrecords(1)
2945 printrecords(1)
2946 elif ms._v1v2match(v1records, v2records):
2946 elif ms._v1v2match(v1records, v2records):
2947 ui.note(('v1 and v2 states match: using v2\n'))
2947 ui.note(('v1 and v2 states match: using v2\n'))
2948 printrecords(2)
2948 printrecords(2)
2949 else:
2949 else:
2950 ui.note(('v1 and v2 states mismatch: using v1\n'))
2950 ui.note(('v1 and v2 states mismatch: using v1\n'))
2951 printrecords(1)
2951 printrecords(1)
2952 if ui.verbose:
2952 if ui.verbose:
2953 printrecords(2)
2953 printrecords(2)
2954
2954
2955 @command('debugnamecomplete', [], _('NAME...'))
2955 @command('debugnamecomplete', [], _('NAME...'))
2956 def debugnamecomplete(ui, repo, *args):
2956 def debugnamecomplete(ui, repo, *args):
2957 '''complete "names" - tags, open branch names, bookmark names'''
2957 '''complete "names" - tags, open branch names, bookmark names'''
2958
2958
2959 names = set()
2959 names = set()
2960 # since we previously only listed open branches, we will handle that
2960 # since we previously only listed open branches, we will handle that
2961 # specially (after this for loop)
2961 # specially (after this for loop)
2962 for name, ns in repo.names.iteritems():
2962 for name, ns in repo.names.iteritems():
2963 if name != 'branches':
2963 if name != 'branches':
2964 names.update(ns.listnames(repo))
2964 names.update(ns.listnames(repo))
2965 names.update(tag for (tag, heads, tip, closed)
2965 names.update(tag for (tag, heads, tip, closed)
2966 in repo.branchmap().iterbranches() if not closed)
2966 in repo.branchmap().iterbranches() if not closed)
2967 completions = set()
2967 completions = set()
2968 if not args:
2968 if not args:
2969 args = ['']
2969 args = ['']
2970 for a in args:
2970 for a in args:
2971 completions.update(n for n in names if n.startswith(a))
2971 completions.update(n for n in names if n.startswith(a))
2972 ui.write('\n'.join(sorted(completions)))
2972 ui.write('\n'.join(sorted(completions)))
2973 ui.write('\n')
2973 ui.write('\n')
2974
2974
2975 @command('debuglocks',
2975 @command('debuglocks',
2976 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2976 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2977 ('W', 'force-wlock', None,
2977 ('W', 'force-wlock', None,
2978 _('free the working state lock (DANGEROUS)'))],
2978 _('free the working state lock (DANGEROUS)'))],
2979 _('[OPTION]...'))
2979 _('[OPTION]...'))
2980 def debuglocks(ui, repo, **opts):
2980 def debuglocks(ui, repo, **opts):
2981 """show or modify state of locks
2981 """show or modify state of locks
2982
2982
2983 By default, this command will show which locks are held. This
2983 By default, this command will show which locks are held. This
2984 includes the user and process holding the lock, the amount of time
2984 includes the user and process holding the lock, the amount of time
2985 the lock has been held, and the machine name where the process is
2985 the lock has been held, and the machine name where the process is
2986 running if it's not local.
2986 running if it's not local.
2987
2987
2988 Locks protect the integrity of Mercurial's data, so should be
2988 Locks protect the integrity of Mercurial's data, so should be
2989 treated with care. System crashes or other interruptions may cause
2989 treated with care. System crashes or other interruptions may cause
2990 locks to not be properly released, though Mercurial will usually
2990 locks to not be properly released, though Mercurial will usually
2991 detect and remove such stale locks automatically.
2991 detect and remove such stale locks automatically.
2992
2992
2993 However, detecting stale locks may not always be possible (for
2993 However, detecting stale locks may not always be possible (for
2994 instance, on a shared filesystem). Removing locks may also be
2994 instance, on a shared filesystem). Removing locks may also be
2995 blocked by filesystem permissions.
2995 blocked by filesystem permissions.
2996
2996
2997 Returns 0 if no locks are held.
2997 Returns 0 if no locks are held.
2998
2998
2999 """
2999 """
3000
3000
3001 if opts.get('force_lock'):
3001 if opts.get('force_lock'):
3002 repo.svfs.unlink('lock')
3002 repo.svfs.unlink('lock')
3003 if opts.get('force_wlock'):
3003 if opts.get('force_wlock'):
3004 repo.vfs.unlink('wlock')
3004 repo.vfs.unlink('wlock')
3005 if opts.get('force_lock') or opts.get('force_lock'):
3005 if opts.get('force_lock') or opts.get('force_lock'):
3006 return 0
3006 return 0
3007
3007
3008 now = time.time()
3008 now = time.time()
3009 held = 0
3009 held = 0
3010
3010
3011 def report(vfs, name, method):
3011 def report(vfs, name, method):
3012 # this causes stale locks to get reaped for more accurate reporting
3012 # this causes stale locks to get reaped for more accurate reporting
3013 try:
3013 try:
3014 l = method(False)
3014 l = method(False)
3015 except error.LockHeld:
3015 except error.LockHeld:
3016 l = None
3016 l = None
3017
3017
3018 if l:
3018 if l:
3019 l.release()
3019 l.release()
3020 else:
3020 else:
3021 try:
3021 try:
3022 stat = vfs.lstat(name)
3022 stat = vfs.lstat(name)
3023 age = now - stat.st_mtime
3023 age = now - stat.st_mtime
3024 user = util.username(stat.st_uid)
3024 user = util.username(stat.st_uid)
3025 locker = vfs.readlock(name)
3025 locker = vfs.readlock(name)
3026 if ":" in locker:
3026 if ":" in locker:
3027 host, pid = locker.split(':')
3027 host, pid = locker.split(':')
3028 if host == socket.gethostname():
3028 if host == socket.gethostname():
3029 locker = 'user %s, process %s' % (user, pid)
3029 locker = 'user %s, process %s' % (user, pid)
3030 else:
3030 else:
3031 locker = 'user %s, process %s, host %s' \
3031 locker = 'user %s, process %s, host %s' \
3032 % (user, pid, host)
3032 % (user, pid, host)
3033 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3033 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3034 return 1
3034 return 1
3035 except OSError as e:
3035 except OSError as e:
3036 if e.errno != errno.ENOENT:
3036 if e.errno != errno.ENOENT:
3037 raise
3037 raise
3038
3038
3039 ui.write("%-6s free\n" % (name + ":"))
3039 ui.write("%-6s free\n" % (name + ":"))
3040 return 0
3040 return 0
3041
3041
3042 held += report(repo.svfs, "lock", repo.lock)
3042 held += report(repo.svfs, "lock", repo.lock)
3043 held += report(repo.vfs, "wlock", repo.wlock)
3043 held += report(repo.vfs, "wlock", repo.wlock)
3044
3044
3045 return held
3045 return held
3046
3046
3047 @command('debugobsolete',
3047 @command('debugobsolete',
3048 [('', 'flags', 0, _('markers flag')),
3048 [('', 'flags', 0, _('markers flag')),
3049 ('', 'record-parents', False,
3049 ('', 'record-parents', False,
3050 _('record parent information for the precursor')),
3050 _('record parent information for the precursor')),
3051 ('r', 'rev', [], _('display markers relevant to REV')),
3051 ('r', 'rev', [], _('display markers relevant to REV')),
3052 ('', 'index', False, _('display index of the marker')),
3052 ('', 'index', False, _('display index of the marker')),
3053 ('', 'delete', [], _('delete markers specified by indices')),
3053 ('', 'delete', [], _('delete markers specified by indices')),
3054 ] + commitopts2,
3054 ] + commitopts2,
3055 _('[OBSOLETED [REPLACEMENT ...]]'))
3055 _('[OBSOLETED [REPLACEMENT ...]]'))
3056 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3056 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3057 """create arbitrary obsolete marker
3057 """create arbitrary obsolete marker
3058
3058
3059 With no arguments, displays the list of obsolescence markers."""
3059 With no arguments, displays the list of obsolescence markers."""
3060
3060
3061 def parsenodeid(s):
3061 def parsenodeid(s):
3062 try:
3062 try:
3063 # We do not use revsingle/revrange functions here to accept
3063 # We do not use revsingle/revrange functions here to accept
3064 # arbitrary node identifiers, possibly not present in the
3064 # arbitrary node identifiers, possibly not present in the
3065 # local repository.
3065 # local repository.
3066 n = bin(s)
3066 n = bin(s)
3067 if len(n) != len(nullid):
3067 if len(n) != len(nullid):
3068 raise TypeError()
3068 raise TypeError()
3069 return n
3069 return n
3070 except TypeError:
3070 except TypeError:
3071 raise error.Abort('changeset references must be full hexadecimal '
3071 raise error.Abort('changeset references must be full hexadecimal '
3072 'node identifiers')
3072 'node identifiers')
3073
3073
3074 if opts.get('delete'):
3074 if opts.get('delete'):
3075 indices = []
3075 indices = []
3076 for v in opts.get('delete'):
3076 for v in opts.get('delete'):
3077 try:
3077 try:
3078 indices.append(int(v))
3078 indices.append(int(v))
3079 except ValueError:
3079 except ValueError:
3080 raise error.Abort(_('invalid index value: %r') % v,
3080 raise error.Abort(_('invalid index value: %r') % v,
3081 hint=_('use integers for indices'))
3081 hint=_('use integers for indices'))
3082
3082
3083 if repo.currenttransaction():
3083 if repo.currenttransaction():
3084 raise error.Abort(_('cannot delete obsmarkers in the middle '
3084 raise error.Abort(_('cannot delete obsmarkers in the middle '
3085 'of transaction.'))
3085 'of transaction.'))
3086
3086
3087 with repo.lock():
3087 with repo.lock():
3088 n = repair.deleteobsmarkers(repo.obsstore, indices)
3088 n = repair.deleteobsmarkers(repo.obsstore, indices)
3089 ui.write(_('deleted %i obsolescense markers\n') % n)
3089 ui.write(_('deleted %i obsolescense markers\n') % n)
3090
3090
3091 return
3091 return
3092
3092
3093 if precursor is not None:
3093 if precursor is not None:
3094 if opts['rev']:
3094 if opts['rev']:
3095 raise error.Abort('cannot select revision when creating marker')
3095 raise error.Abort('cannot select revision when creating marker')
3096 metadata = {}
3096 metadata = {}
3097 metadata['user'] = opts['user'] or ui.username()
3097 metadata['user'] = opts['user'] or ui.username()
3098 succs = tuple(parsenodeid(succ) for succ in successors)
3098 succs = tuple(parsenodeid(succ) for succ in successors)
3099 l = repo.lock()
3099 l = repo.lock()
3100 try:
3100 try:
3101 tr = repo.transaction('debugobsolete')
3101 tr = repo.transaction('debugobsolete')
3102 try:
3102 try:
3103 date = opts.get('date')
3103 date = opts.get('date')
3104 if date:
3104 if date:
3105 date = util.parsedate(date)
3105 date = util.parsedate(date)
3106 else:
3106 else:
3107 date = None
3107 date = None
3108 prec = parsenodeid(precursor)
3108 prec = parsenodeid(precursor)
3109 parents = None
3109 parents = None
3110 if opts['record_parents']:
3110 if opts['record_parents']:
3111 if prec not in repo.unfiltered():
3111 if prec not in repo.unfiltered():
3112 raise error.Abort('cannot used --record-parents on '
3112 raise error.Abort('cannot used --record-parents on '
3113 'unknown changesets')
3113 'unknown changesets')
3114 parents = repo.unfiltered()[prec].parents()
3114 parents = repo.unfiltered()[prec].parents()
3115 parents = tuple(p.node() for p in parents)
3115 parents = tuple(p.node() for p in parents)
3116 repo.obsstore.create(tr, prec, succs, opts['flags'],
3116 repo.obsstore.create(tr, prec, succs, opts['flags'],
3117 parents=parents, date=date,
3117 parents=parents, date=date,
3118 metadata=metadata)
3118 metadata=metadata)
3119 tr.close()
3119 tr.close()
3120 except ValueError as exc:
3120 except ValueError as exc:
3121 raise error.Abort(_('bad obsmarker input: %s') % exc)
3121 raise error.Abort(_('bad obsmarker input: %s') % exc)
3122 finally:
3122 finally:
3123 tr.release()
3123 tr.release()
3124 finally:
3124 finally:
3125 l.release()
3125 l.release()
3126 else:
3126 else:
3127 if opts['rev']:
3127 if opts['rev']:
3128 revs = scmutil.revrange(repo, opts['rev'])
3128 revs = scmutil.revrange(repo, opts['rev'])
3129 nodes = [repo[r].node() for r in revs]
3129 nodes = [repo[r].node() for r in revs]
3130 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3130 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3131 markers.sort(key=lambda x: x._data)
3131 markers.sort(key=lambda x: x._data)
3132 else:
3132 else:
3133 markers = obsolete.getmarkers(repo)
3133 markers = obsolete.getmarkers(repo)
3134
3134
3135 markerstoiter = markers
3135 markerstoiter = markers
3136 isrelevant = lambda m: True
3136 isrelevant = lambda m: True
3137 if opts.get('rev') and opts.get('index'):
3137 if opts.get('rev') and opts.get('index'):
3138 markerstoiter = obsolete.getmarkers(repo)
3138 markerstoiter = obsolete.getmarkers(repo)
3139 markerset = set(markers)
3139 markerset = set(markers)
3140 isrelevant = lambda m: m in markerset
3140 isrelevant = lambda m: m in markerset
3141
3141
3142 for i, m in enumerate(markerstoiter):
3142 for i, m in enumerate(markerstoiter):
3143 if not isrelevant(m):
3143 if not isrelevant(m):
3144 # marker can be irrelevant when we're iterating over a set
3144 # marker can be irrelevant when we're iterating over a set
3145 # of markers (markerstoiter) which is bigger than the set
3145 # of markers (markerstoiter) which is bigger than the set
3146 # of markers we want to display (markers)
3146 # of markers we want to display (markers)
3147 # this can happen if both --index and --rev options are
3147 # this can happen if both --index and --rev options are
3148 # provided and thus we need to iterate over all of the markers
3148 # provided and thus we need to iterate over all of the markers
3149 # to get the correct indices, but only display the ones that
3149 # to get the correct indices, but only display the ones that
3150 # are relevant to --rev value
3150 # are relevant to --rev value
3151 continue
3151 continue
3152 ind = i if opts.get('index') else None
3152 ind = i if opts.get('index') else None
3153 cmdutil.showmarker(ui, m, index=ind)
3153 cmdutil.showmarker(ui, m, index=ind)
3154
3154
3155 @command('debugpathcomplete',
3155 @command('debugpathcomplete',
3156 [('f', 'full', None, _('complete an entire path')),
3156 [('f', 'full', None, _('complete an entire path')),
3157 ('n', 'normal', None, _('show only normal files')),
3157 ('n', 'normal', None, _('show only normal files')),
3158 ('a', 'added', None, _('show only added files')),
3158 ('a', 'added', None, _('show only added files')),
3159 ('r', 'removed', None, _('show only removed files'))],
3159 ('r', 'removed', None, _('show only removed files'))],
3160 _('FILESPEC...'))
3160 _('FILESPEC...'))
3161 def debugpathcomplete(ui, repo, *specs, **opts):
3161 def debugpathcomplete(ui, repo, *specs, **opts):
3162 '''complete part or all of a tracked path
3162 '''complete part or all of a tracked path
3163
3163
3164 This command supports shells that offer path name completion. It
3164 This command supports shells that offer path name completion. It
3165 currently completes only files already known to the dirstate.
3165 currently completes only files already known to the dirstate.
3166
3166
3167 Completion extends only to the next path segment unless
3167 Completion extends only to the next path segment unless
3168 --full is specified, in which case entire paths are used.'''
3168 --full is specified, in which case entire paths are used.'''
3169
3169
3170 def complete(path, acceptable):
3170 def complete(path, acceptable):
3171 dirstate = repo.dirstate
3171 dirstate = repo.dirstate
3172 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3172 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3173 rootdir = repo.root + os.sep
3173 rootdir = repo.root + os.sep
3174 if spec != repo.root and not spec.startswith(rootdir):
3174 if spec != repo.root and not spec.startswith(rootdir):
3175 return [], []
3175 return [], []
3176 if os.path.isdir(spec):
3176 if os.path.isdir(spec):
3177 spec += '/'
3177 spec += '/'
3178 spec = spec[len(rootdir):]
3178 spec = spec[len(rootdir):]
3179 fixpaths = os.sep != '/'
3179 fixpaths = os.sep != '/'
3180 if fixpaths:
3180 if fixpaths:
3181 spec = spec.replace(os.sep, '/')
3181 spec = spec.replace(os.sep, '/')
3182 speclen = len(spec)
3182 speclen = len(spec)
3183 fullpaths = opts['full']
3183 fullpaths = opts['full']
3184 files, dirs = set(), set()
3184 files, dirs = set(), set()
3185 adddir, addfile = dirs.add, files.add
3185 adddir, addfile = dirs.add, files.add
3186 for f, st in dirstate.iteritems():
3186 for f, st in dirstate.iteritems():
3187 if f.startswith(spec) and st[0] in acceptable:
3187 if f.startswith(spec) and st[0] in acceptable:
3188 if fixpaths:
3188 if fixpaths:
3189 f = f.replace('/', os.sep)
3189 f = f.replace('/', os.sep)
3190 if fullpaths:
3190 if fullpaths:
3191 addfile(f)
3191 addfile(f)
3192 continue
3192 continue
3193 s = f.find(os.sep, speclen)
3193 s = f.find(os.sep, speclen)
3194 if s >= 0:
3194 if s >= 0:
3195 adddir(f[:s])
3195 adddir(f[:s])
3196 else:
3196 else:
3197 addfile(f)
3197 addfile(f)
3198 return files, dirs
3198 return files, dirs
3199
3199
3200 acceptable = ''
3200 acceptable = ''
3201 if opts['normal']:
3201 if opts['normal']:
3202 acceptable += 'nm'
3202 acceptable += 'nm'
3203 if opts['added']:
3203 if opts['added']:
3204 acceptable += 'a'
3204 acceptable += 'a'
3205 if opts['removed']:
3205 if opts['removed']:
3206 acceptable += 'r'
3206 acceptable += 'r'
3207 cwd = repo.getcwd()
3207 cwd = repo.getcwd()
3208 if not specs:
3208 if not specs:
3209 specs = ['.']
3209 specs = ['.']
3210
3210
3211 files, dirs = set(), set()
3211 files, dirs = set(), set()
3212 for spec in specs:
3212 for spec in specs:
3213 f, d = complete(spec, acceptable or 'nmar')
3213 f, d = complete(spec, acceptable or 'nmar')
3214 files.update(f)
3214 files.update(f)
3215 dirs.update(d)
3215 dirs.update(d)
3216 files.update(dirs)
3216 files.update(dirs)
3217 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3217 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3218 ui.write('\n')
3218 ui.write('\n')
3219
3219
3220 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3220 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3221 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3221 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3222 '''access the pushkey key/value protocol
3222 '''access the pushkey key/value protocol
3223
3223
3224 With two args, list the keys in the given namespace.
3224 With two args, list the keys in the given namespace.
3225
3225
3226 With five args, set a key to new if it currently is set to old.
3226 With five args, set a key to new if it currently is set to old.
3227 Reports success or failure.
3227 Reports success or failure.
3228 '''
3228 '''
3229
3229
3230 target = hg.peer(ui, {}, repopath)
3230 target = hg.peer(ui, {}, repopath)
3231 if keyinfo:
3231 if keyinfo:
3232 key, old, new = keyinfo
3232 key, old, new = keyinfo
3233 r = target.pushkey(namespace, key, old, new)
3233 r = target.pushkey(namespace, key, old, new)
3234 ui.status(str(r) + '\n')
3234 ui.status(str(r) + '\n')
3235 return not r
3235 return not r
3236 else:
3236 else:
3237 for k, v in sorted(target.listkeys(namespace).iteritems()):
3237 for k, v in sorted(target.listkeys(namespace).iteritems()):
3238 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3238 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3239 v.encode('string-escape')))
3239 v.encode('string-escape')))
3240
3240
3241 @command('debugpvec', [], _('A B'))
3241 @command('debugpvec', [], _('A B'))
3242 def debugpvec(ui, repo, a, b=None):
3242 def debugpvec(ui, repo, a, b=None):
3243 ca = scmutil.revsingle(repo, a)
3243 ca = scmutil.revsingle(repo, a)
3244 cb = scmutil.revsingle(repo, b)
3244 cb = scmutil.revsingle(repo, b)
3245 pa = pvec.ctxpvec(ca)
3245 pa = pvec.ctxpvec(ca)
3246 pb = pvec.ctxpvec(cb)
3246 pb = pvec.ctxpvec(cb)
3247 if pa == pb:
3247 if pa == pb:
3248 rel = "="
3248 rel = "="
3249 elif pa > pb:
3249 elif pa > pb:
3250 rel = ">"
3250 rel = ">"
3251 elif pa < pb:
3251 elif pa < pb:
3252 rel = "<"
3252 rel = "<"
3253 elif pa | pb:
3253 elif pa | pb:
3254 rel = "|"
3254 rel = "|"
3255 ui.write(_("a: %s\n") % pa)
3255 ui.write(_("a: %s\n") % pa)
3256 ui.write(_("b: %s\n") % pb)
3256 ui.write(_("b: %s\n") % pb)
3257 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3257 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3258 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3258 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3259 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3259 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3260 pa.distance(pb), rel))
3260 pa.distance(pb), rel))
3261
3261
3262 @command('debugrebuilddirstate|debugrebuildstate',
3262 @command('debugrebuilddirstate|debugrebuildstate',
3263 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3263 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3264 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3264 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3265 'the working copy parent')),
3265 'the working copy parent')),
3266 ],
3266 ],
3267 _('[-r REV]'))
3267 _('[-r REV]'))
3268 def debugrebuilddirstate(ui, repo, rev, **opts):
3268 def debugrebuilddirstate(ui, repo, rev, **opts):
3269 """rebuild the dirstate as it would look like for the given revision
3269 """rebuild the dirstate as it would look like for the given revision
3270
3270
3271 If no revision is specified the first current parent will be used.
3271 If no revision is specified the first current parent will be used.
3272
3272
3273 The dirstate will be set to the files of the given revision.
3273 The dirstate will be set to the files of the given revision.
3274 The actual working directory content or existing dirstate
3274 The actual working directory content or existing dirstate
3275 information such as adds or removes is not considered.
3275 information such as adds or removes is not considered.
3276
3276
3277 ``minimal`` will only rebuild the dirstate status for files that claim to be
3277 ``minimal`` will only rebuild the dirstate status for files that claim to be
3278 tracked but are not in the parent manifest, or that exist in the parent
3278 tracked but are not in the parent manifest, or that exist in the parent
3279 manifest but are not in the dirstate. It will not change adds, removes, or
3279 manifest but are not in the dirstate. It will not change adds, removes, or
3280 modified files that are in the working copy parent.
3280 modified files that are in the working copy parent.
3281
3281
3282 One use of this command is to make the next :hg:`status` invocation
3282 One use of this command is to make the next :hg:`status` invocation
3283 check the actual file content.
3283 check the actual file content.
3284 """
3284 """
3285 ctx = scmutil.revsingle(repo, rev)
3285 ctx = scmutil.revsingle(repo, rev)
3286 with repo.wlock():
3286 with repo.wlock():
3287 dirstate = repo.dirstate
3287 dirstate = repo.dirstate
3288 changedfiles = None
3288 changedfiles = None
3289 # See command doc for what minimal does.
3289 # See command doc for what minimal does.
3290 if opts.get('minimal'):
3290 if opts.get('minimal'):
3291 manifestfiles = set(ctx.manifest().keys())
3291 manifestfiles = set(ctx.manifest().keys())
3292 dirstatefiles = set(dirstate)
3292 dirstatefiles = set(dirstate)
3293 manifestonly = manifestfiles - dirstatefiles
3293 manifestonly = manifestfiles - dirstatefiles
3294 dsonly = dirstatefiles - manifestfiles
3294 dsonly = dirstatefiles - manifestfiles
3295 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3295 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3296 changedfiles = manifestonly | dsnotadded
3296 changedfiles = manifestonly | dsnotadded
3297
3297
3298 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3298 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3299
3299
3300 @command('debugrebuildfncache', [], '')
3300 @command('debugrebuildfncache', [], '')
3301 def debugrebuildfncache(ui, repo):
3301 def debugrebuildfncache(ui, repo):
3302 """rebuild the fncache file"""
3302 """rebuild the fncache file"""
3303 repair.rebuildfncache(ui, repo)
3303 repair.rebuildfncache(ui, repo)
3304
3304
3305 @command('debugrename',
3305 @command('debugrename',
3306 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3306 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3307 _('[-r REV] FILE'))
3307 _('[-r REV] FILE'))
3308 def debugrename(ui, repo, file1, *pats, **opts):
3308 def debugrename(ui, repo, file1, *pats, **opts):
3309 """dump rename information"""
3309 """dump rename information"""
3310
3310
3311 ctx = scmutil.revsingle(repo, opts.get('rev'))
3311 ctx = scmutil.revsingle(repo, opts.get('rev'))
3312 m = scmutil.match(ctx, (file1,) + pats, opts)
3312 m = scmutil.match(ctx, (file1,) + pats, opts)
3313 for abs in ctx.walk(m):
3313 for abs in ctx.walk(m):
3314 fctx = ctx[abs]
3314 fctx = ctx[abs]
3315 o = fctx.filelog().renamed(fctx.filenode())
3315 o = fctx.filelog().renamed(fctx.filenode())
3316 rel = m.rel(abs)
3316 rel = m.rel(abs)
3317 if o:
3317 if o:
3318 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3318 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3319 else:
3319 else:
3320 ui.write(_("%s not renamed\n") % rel)
3320 ui.write(_("%s not renamed\n") % rel)
3321
3321
3322 @command('debugrevlog', debugrevlogopts +
3322 @command('debugrevlog', debugrevlogopts +
3323 [('d', 'dump', False, _('dump index data'))],
3323 [('d', 'dump', False, _('dump index data'))],
3324 _('-c|-m|FILE'),
3324 _('-c|-m|FILE'),
3325 optionalrepo=True)
3325 optionalrepo=True)
3326 def debugrevlog(ui, repo, file_=None, **opts):
3326 def debugrevlog(ui, repo, file_=None, **opts):
3327 """show data and statistics about a revlog"""
3327 """show data and statistics about a revlog"""
3328 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3328 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3329
3329
3330 if opts.get("dump"):
3330 if opts.get("dump"):
3331 numrevs = len(r)
3331 numrevs = len(r)
3332 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3332 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3333 " rawsize totalsize compression heads chainlen\n")
3333 " rawsize totalsize compression heads chainlen\n")
3334 ts = 0
3334 ts = 0
3335 heads = set()
3335 heads = set()
3336
3336
3337 for rev in xrange(numrevs):
3337 for rev in xrange(numrevs):
3338 dbase = r.deltaparent(rev)
3338 dbase = r.deltaparent(rev)
3339 if dbase == -1:
3339 if dbase == -1:
3340 dbase = rev
3340 dbase = rev
3341 cbase = r.chainbase(rev)
3341 cbase = r.chainbase(rev)
3342 clen = r.chainlen(rev)
3342 clen = r.chainlen(rev)
3343 p1, p2 = r.parentrevs(rev)
3343 p1, p2 = r.parentrevs(rev)
3344 rs = r.rawsize(rev)
3344 rs = r.rawsize(rev)
3345 ts = ts + rs
3345 ts = ts + rs
3346 heads -= set(r.parentrevs(rev))
3346 heads -= set(r.parentrevs(rev))
3347 heads.add(rev)
3347 heads.add(rev)
3348 try:
3348 try:
3349 compression = ts / r.end(rev)
3349 compression = ts / r.end(rev)
3350 except ZeroDivisionError:
3350 except ZeroDivisionError:
3351 compression = 0
3351 compression = 0
3352 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3352 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3353 "%11d %5d %8d\n" %
3353 "%11d %5d %8d\n" %
3354 (rev, p1, p2, r.start(rev), r.end(rev),
3354 (rev, p1, p2, r.start(rev), r.end(rev),
3355 r.start(dbase), r.start(cbase),
3355 r.start(dbase), r.start(cbase),
3356 r.start(p1), r.start(p2),
3356 r.start(p1), r.start(p2),
3357 rs, ts, compression, len(heads), clen))
3357 rs, ts, compression, len(heads), clen))
3358 return 0
3358 return 0
3359
3359
3360 v = r.version
3360 v = r.version
3361 format = v & 0xFFFF
3361 format = v & 0xFFFF
3362 flags = []
3362 flags = []
3363 gdelta = False
3363 gdelta = False
3364 if v & revlog.REVLOGNGINLINEDATA:
3364 if v & revlog.REVLOGNGINLINEDATA:
3365 flags.append('inline')
3365 flags.append('inline')
3366 if v & revlog.REVLOGGENERALDELTA:
3366 if v & revlog.REVLOGGENERALDELTA:
3367 gdelta = True
3367 gdelta = True
3368 flags.append('generaldelta')
3368 flags.append('generaldelta')
3369 if not flags:
3369 if not flags:
3370 flags = ['(none)']
3370 flags = ['(none)']
3371
3371
3372 nummerges = 0
3372 nummerges = 0
3373 numfull = 0
3373 numfull = 0
3374 numprev = 0
3374 numprev = 0
3375 nump1 = 0
3375 nump1 = 0
3376 nump2 = 0
3376 nump2 = 0
3377 numother = 0
3377 numother = 0
3378 nump1prev = 0
3378 nump1prev = 0
3379 nump2prev = 0
3379 nump2prev = 0
3380 chainlengths = []
3380 chainlengths = []
3381
3381
3382 datasize = [None, 0, 0L]
3382 datasize = [None, 0, 0L]
3383 fullsize = [None, 0, 0L]
3383 fullsize = [None, 0, 0L]
3384 deltasize = [None, 0, 0L]
3384 deltasize = [None, 0, 0L]
3385
3385
3386 def addsize(size, l):
3386 def addsize(size, l):
3387 if l[0] is None or size < l[0]:
3387 if l[0] is None or size < l[0]:
3388 l[0] = size
3388 l[0] = size
3389 if size > l[1]:
3389 if size > l[1]:
3390 l[1] = size
3390 l[1] = size
3391 l[2] += size
3391 l[2] += size
3392
3392
3393 numrevs = len(r)
3393 numrevs = len(r)
3394 for rev in xrange(numrevs):
3394 for rev in xrange(numrevs):
3395 p1, p2 = r.parentrevs(rev)
3395 p1, p2 = r.parentrevs(rev)
3396 delta = r.deltaparent(rev)
3396 delta = r.deltaparent(rev)
3397 if format > 0:
3397 if format > 0:
3398 addsize(r.rawsize(rev), datasize)
3398 addsize(r.rawsize(rev), datasize)
3399 if p2 != nullrev:
3399 if p2 != nullrev:
3400 nummerges += 1
3400 nummerges += 1
3401 size = r.length(rev)
3401 size = r.length(rev)
3402 if delta == nullrev:
3402 if delta == nullrev:
3403 chainlengths.append(0)
3403 chainlengths.append(0)
3404 numfull += 1
3404 numfull += 1
3405 addsize(size, fullsize)
3405 addsize(size, fullsize)
3406 else:
3406 else:
3407 chainlengths.append(chainlengths[delta] + 1)
3407 chainlengths.append(chainlengths[delta] + 1)
3408 addsize(size, deltasize)
3408 addsize(size, deltasize)
3409 if delta == rev - 1:
3409 if delta == rev - 1:
3410 numprev += 1
3410 numprev += 1
3411 if delta == p1:
3411 if delta == p1:
3412 nump1prev += 1
3412 nump1prev += 1
3413 elif delta == p2:
3413 elif delta == p2:
3414 nump2prev += 1
3414 nump2prev += 1
3415 elif delta == p1:
3415 elif delta == p1:
3416 nump1 += 1
3416 nump1 += 1
3417 elif delta == p2:
3417 elif delta == p2:
3418 nump2 += 1
3418 nump2 += 1
3419 elif delta != nullrev:
3419 elif delta != nullrev:
3420 numother += 1
3420 numother += 1
3421
3421
3422 # Adjust size min value for empty cases
3422 # Adjust size min value for empty cases
3423 for size in (datasize, fullsize, deltasize):
3423 for size in (datasize, fullsize, deltasize):
3424 if size[0] is None:
3424 if size[0] is None:
3425 size[0] = 0
3425 size[0] = 0
3426
3426
3427 numdeltas = numrevs - numfull
3427 numdeltas = numrevs - numfull
3428 numoprev = numprev - nump1prev - nump2prev
3428 numoprev = numprev - nump1prev - nump2prev
3429 totalrawsize = datasize[2]
3429 totalrawsize = datasize[2]
3430 datasize[2] /= numrevs
3430 datasize[2] /= numrevs
3431 fulltotal = fullsize[2]
3431 fulltotal = fullsize[2]
3432 fullsize[2] /= numfull
3432 fullsize[2] /= numfull
3433 deltatotal = deltasize[2]
3433 deltatotal = deltasize[2]
3434 if numrevs - numfull > 0:
3434 if numrevs - numfull > 0:
3435 deltasize[2] /= numrevs - numfull
3435 deltasize[2] /= numrevs - numfull
3436 totalsize = fulltotal + deltatotal
3436 totalsize = fulltotal + deltatotal
3437 avgchainlen = sum(chainlengths) / numrevs
3437 avgchainlen = sum(chainlengths) / numrevs
3438 maxchainlen = max(chainlengths)
3438 maxchainlen = max(chainlengths)
3439 compratio = 1
3439 compratio = 1
3440 if totalsize:
3440 if totalsize:
3441 compratio = totalrawsize / totalsize
3441 compratio = totalrawsize / totalsize
3442
3442
3443 basedfmtstr = '%%%dd\n'
3443 basedfmtstr = '%%%dd\n'
3444 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3444 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3445
3445
3446 def dfmtstr(max):
3446 def dfmtstr(max):
3447 return basedfmtstr % len(str(max))
3447 return basedfmtstr % len(str(max))
3448 def pcfmtstr(max, padding=0):
3448 def pcfmtstr(max, padding=0):
3449 return basepcfmtstr % (len(str(max)), ' ' * padding)
3449 return basepcfmtstr % (len(str(max)), ' ' * padding)
3450
3450
3451 def pcfmt(value, total):
3451 def pcfmt(value, total):
3452 if total:
3452 if total:
3453 return (value, 100 * float(value) / total)
3453 return (value, 100 * float(value) / total)
3454 else:
3454 else:
3455 return value, 100.0
3455 return value, 100.0
3456
3456
3457 ui.write(('format : %d\n') % format)
3457 ui.write(('format : %d\n') % format)
3458 ui.write(('flags : %s\n') % ', '.join(flags))
3458 ui.write(('flags : %s\n') % ', '.join(flags))
3459
3459
3460 ui.write('\n')
3460 ui.write('\n')
3461 fmt = pcfmtstr(totalsize)
3461 fmt = pcfmtstr(totalsize)
3462 fmt2 = dfmtstr(totalsize)
3462 fmt2 = dfmtstr(totalsize)
3463 ui.write(('revisions : ') + fmt2 % numrevs)
3463 ui.write(('revisions : ') + fmt2 % numrevs)
3464 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3464 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3465 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3465 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3466 ui.write(('revisions : ') + fmt2 % numrevs)
3466 ui.write(('revisions : ') + fmt2 % numrevs)
3467 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3467 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3468 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3468 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3469 ui.write(('revision size : ') + fmt2 % totalsize)
3469 ui.write(('revision size : ') + fmt2 % totalsize)
3470 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3470 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3471 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3471 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3472
3472
3473 ui.write('\n')
3473 ui.write('\n')
3474 fmt = dfmtstr(max(avgchainlen, compratio))
3474 fmt = dfmtstr(max(avgchainlen, compratio))
3475 ui.write(('avg chain length : ') + fmt % avgchainlen)
3475 ui.write(('avg chain length : ') + fmt % avgchainlen)
3476 ui.write(('max chain length : ') + fmt % maxchainlen)
3476 ui.write(('max chain length : ') + fmt % maxchainlen)
3477 ui.write(('compression ratio : ') + fmt % compratio)
3477 ui.write(('compression ratio : ') + fmt % compratio)
3478
3478
3479 if format > 0:
3479 if format > 0:
3480 ui.write('\n')
3480 ui.write('\n')
3481 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3481 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3482 % tuple(datasize))
3482 % tuple(datasize))
3483 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3483 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3484 % tuple(fullsize))
3484 % tuple(fullsize))
3485 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3485 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3486 % tuple(deltasize))
3486 % tuple(deltasize))
3487
3487
3488 if numdeltas > 0:
3488 if numdeltas > 0:
3489 ui.write('\n')
3489 ui.write('\n')
3490 fmt = pcfmtstr(numdeltas)
3490 fmt = pcfmtstr(numdeltas)
3491 fmt2 = pcfmtstr(numdeltas, 4)
3491 fmt2 = pcfmtstr(numdeltas, 4)
3492 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3492 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3493 if numprev > 0:
3493 if numprev > 0:
3494 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3494 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3495 numprev))
3495 numprev))
3496 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3496 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3497 numprev))
3497 numprev))
3498 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3498 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3499 numprev))
3499 numprev))
3500 if gdelta:
3500 if gdelta:
3501 ui.write(('deltas against p1 : ')
3501 ui.write(('deltas against p1 : ')
3502 + fmt % pcfmt(nump1, numdeltas))
3502 + fmt % pcfmt(nump1, numdeltas))
3503 ui.write(('deltas against p2 : ')
3503 ui.write(('deltas against p2 : ')
3504 + fmt % pcfmt(nump2, numdeltas))
3504 + fmt % pcfmt(nump2, numdeltas))
3505 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3505 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3506 numdeltas))
3506 numdeltas))
3507
3507
3508 @command('debugrevspec',
3508 @command('debugrevspec',
3509 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3509 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3510 ('REVSPEC'))
3510 ('REVSPEC'))
3511 def debugrevspec(ui, repo, expr, **opts):
3511 def debugrevspec(ui, repo, expr, **opts):
3512 """parse and apply a revision specification
3512 """parse and apply a revision specification
3513
3513
3514 Use --verbose to print the parsed tree before and after aliases
3514 Use --verbose to print the parsed tree before and after aliases
3515 expansion.
3515 expansion.
3516 """
3516 """
3517 if ui.verbose:
3517 if ui.verbose:
3518 tree = revset.parse(expr, lookup=repo.__contains__)
3518 tree = revset.parse(expr, lookup=repo.__contains__)
3519 ui.note(revset.prettyformat(tree), "\n")
3519 ui.note(revset.prettyformat(tree), "\n")
3520 newtree = revset.expandaliases(ui, tree)
3520 newtree = revset.expandaliases(ui, tree)
3521 if newtree != tree:
3521 if newtree != tree:
3522 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3522 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3523 tree = newtree
3523 tree = newtree
3524 newtree = revset.foldconcat(tree)
3524 newtree = revset.foldconcat(tree)
3525 if newtree != tree:
3525 if newtree != tree:
3526 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3526 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3527 if opts["optimize"]:
3527 if opts["optimize"]:
3528 optimizedtree = revset.optimize(newtree)
3528 optimizedtree = revset.optimize(newtree)
3529 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3529 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3530 func = revset.match(ui, expr, repo)
3530 func = revset.match(ui, expr, repo)
3531 revs = func(repo)
3531 revs = func(repo)
3532 if ui.verbose:
3532 if ui.verbose:
3533 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3533 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3534 for c in revs:
3534 for c in revs:
3535 ui.write("%s\n" % c)
3535 ui.write("%s\n" % c)
3536
3536
3537 @command('debugsetparents', [], _('REV1 [REV2]'))
3537 @command('debugsetparents', [], _('REV1 [REV2]'))
3538 def debugsetparents(ui, repo, rev1, rev2=None):
3538 def debugsetparents(ui, repo, rev1, rev2=None):
3539 """manually set the parents of the current working directory
3539 """manually set the parents of the current working directory
3540
3540
3541 This is useful for writing repository conversion tools, but should
3541 This is useful for writing repository conversion tools, but should
3542 be used with care. For example, neither the working directory nor the
3542 be used with care. For example, neither the working directory nor the
3543 dirstate is updated, so file status may be incorrect after running this
3543 dirstate is updated, so file status may be incorrect after running this
3544 command.
3544 command.
3545
3545
3546 Returns 0 on success.
3546 Returns 0 on success.
3547 """
3547 """
3548
3548
3549 r1 = scmutil.revsingle(repo, rev1).node()
3549 r1 = scmutil.revsingle(repo, rev1).node()
3550 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3550 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3551
3551
3552 with repo.wlock():
3552 with repo.wlock():
3553 repo.setparents(r1, r2)
3553 repo.setparents(r1, r2)
3554
3554
3555 @command('debugdirstate|debugstate',
3555 @command('debugdirstate|debugstate',
3556 [('', 'nodates', None, _('do not display the saved mtime')),
3556 [('', 'nodates', None, _('do not display the saved mtime')),
3557 ('', 'datesort', None, _('sort by saved mtime'))],
3557 ('', 'datesort', None, _('sort by saved mtime'))],
3558 _('[OPTION]...'))
3558 _('[OPTION]...'))
3559 def debugstate(ui, repo, **opts):
3559 def debugstate(ui, repo, **opts):
3560 """show the contents of the current dirstate"""
3560 """show the contents of the current dirstate"""
3561
3561
3562 nodates = opts.get('nodates')
3562 nodates = opts.get('nodates')
3563 datesort = opts.get('datesort')
3563 datesort = opts.get('datesort')
3564
3564
3565 timestr = ""
3565 timestr = ""
3566 if datesort:
3566 if datesort:
3567 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3567 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3568 else:
3568 else:
3569 keyfunc = None # sort by filename
3569 keyfunc = None # sort by filename
3570 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3570 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3571 if ent[3] == -1:
3571 if ent[3] == -1:
3572 timestr = 'unset '
3572 timestr = 'unset '
3573 elif nodates:
3573 elif nodates:
3574 timestr = 'set '
3574 timestr = 'set '
3575 else:
3575 else:
3576 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3576 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3577 time.localtime(ent[3]))
3577 time.localtime(ent[3]))
3578 if ent[1] & 0o20000:
3578 if ent[1] & 0o20000:
3579 mode = 'lnk'
3579 mode = 'lnk'
3580 else:
3580 else:
3581 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3581 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3582 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3582 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3583 for f in repo.dirstate.copies():
3583 for f in repo.dirstate.copies():
3584 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3584 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3585
3585
3586 @command('debugsub',
3586 @command('debugsub',
3587 [('r', 'rev', '',
3587 [('r', 'rev', '',
3588 _('revision to check'), _('REV'))],
3588 _('revision to check'), _('REV'))],
3589 _('[-r REV] [REV]'))
3589 _('[-r REV] [REV]'))
3590 def debugsub(ui, repo, rev=None):
3590 def debugsub(ui, repo, rev=None):
3591 ctx = scmutil.revsingle(repo, rev, None)
3591 ctx = scmutil.revsingle(repo, rev, None)
3592 for k, v in sorted(ctx.substate.items()):
3592 for k, v in sorted(ctx.substate.items()):
3593 ui.write(('path %s\n') % k)
3593 ui.write(('path %s\n') % k)
3594 ui.write((' source %s\n') % v[0])
3594 ui.write((' source %s\n') % v[0])
3595 ui.write((' revision %s\n') % v[1])
3595 ui.write((' revision %s\n') % v[1])
3596
3596
3597 @command('debugsuccessorssets',
3597 @command('debugsuccessorssets',
3598 [],
3598 [],
3599 _('[REV]'))
3599 _('[REV]'))
3600 def debugsuccessorssets(ui, repo, *revs):
3600 def debugsuccessorssets(ui, repo, *revs):
3601 """show set of successors for revision
3601 """show set of successors for revision
3602
3602
3603 A successors set of changeset A is a consistent group of revisions that
3603 A successors set of changeset A is a consistent group of revisions that
3604 succeed A. It contains non-obsolete changesets only.
3604 succeed A. It contains non-obsolete changesets only.
3605
3605
3606 In most cases a changeset A has a single successors set containing a single
3606 In most cases a changeset A has a single successors set containing a single
3607 successor (changeset A replaced by A').
3607 successor (changeset A replaced by A').
3608
3608
3609 A changeset that is made obsolete with no successors are called "pruned".
3609 A changeset that is made obsolete with no successors are called "pruned".
3610 Such changesets have no successors sets at all.
3610 Such changesets have no successors sets at all.
3611
3611
3612 A changeset that has been "split" will have a successors set containing
3612 A changeset that has been "split" will have a successors set containing
3613 more than one successor.
3613 more than one successor.
3614
3614
3615 A changeset that has been rewritten in multiple different ways is called
3615 A changeset that has been rewritten in multiple different ways is called
3616 "divergent". Such changesets have multiple successor sets (each of which
3616 "divergent". Such changesets have multiple successor sets (each of which
3617 may also be split, i.e. have multiple successors).
3617 may also be split, i.e. have multiple successors).
3618
3618
3619 Results are displayed as follows::
3619 Results are displayed as follows::
3620
3620
3621 <rev1>
3621 <rev1>
3622 <successors-1A>
3622 <successors-1A>
3623 <rev2>
3623 <rev2>
3624 <successors-2A>
3624 <successors-2A>
3625 <successors-2B1> <successors-2B2> <successors-2B3>
3625 <successors-2B1> <successors-2B2> <successors-2B3>
3626
3626
3627 Here rev2 has two possible (i.e. divergent) successors sets. The first
3627 Here rev2 has two possible (i.e. divergent) successors sets. The first
3628 holds one element, whereas the second holds three (i.e. the changeset has
3628 holds one element, whereas the second holds three (i.e. the changeset has
3629 been split).
3629 been split).
3630 """
3630 """
3631 # passed to successorssets caching computation from one call to another
3631 # passed to successorssets caching computation from one call to another
3632 cache = {}
3632 cache = {}
3633 ctx2str = str
3633 ctx2str = str
3634 node2str = short
3634 node2str = short
3635 if ui.debug():
3635 if ui.debug():
3636 def ctx2str(ctx):
3636 def ctx2str(ctx):
3637 return ctx.hex()
3637 return ctx.hex()
3638 node2str = hex
3638 node2str = hex
3639 for rev in scmutil.revrange(repo, revs):
3639 for rev in scmutil.revrange(repo, revs):
3640 ctx = repo[rev]
3640 ctx = repo[rev]
3641 ui.write('%s\n'% ctx2str(ctx))
3641 ui.write('%s\n'% ctx2str(ctx))
3642 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3642 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3643 if succsset:
3643 if succsset:
3644 ui.write(' ')
3644 ui.write(' ')
3645 ui.write(node2str(succsset[0]))
3645 ui.write(node2str(succsset[0]))
3646 for node in succsset[1:]:
3646 for node in succsset[1:]:
3647 ui.write(' ')
3647 ui.write(' ')
3648 ui.write(node2str(node))
3648 ui.write(node2str(node))
3649 ui.write('\n')
3649 ui.write('\n')
3650
3650
3651 @command('debugtemplate',
3651 @command('debugtemplate',
3652 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3652 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3653 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3653 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3654 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3654 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3655 optionalrepo=True)
3655 optionalrepo=True)
3656 def debugtemplate(ui, repo, tmpl, **opts):
3656 def debugtemplate(ui, repo, tmpl, **opts):
3657 """parse and apply a template
3657 """parse and apply a template
3658
3658
3659 If -r/--rev is given, the template is processed as a log template and
3659 If -r/--rev is given, the template is processed as a log template and
3660 applied to the given changesets. Otherwise, it is processed as a generic
3660 applied to the given changesets. Otherwise, it is processed as a generic
3661 template.
3661 template.
3662
3662
3663 Use --verbose to print the parsed tree.
3663 Use --verbose to print the parsed tree.
3664 """
3664 """
3665 revs = None
3665 revs = None
3666 if opts['rev']:
3666 if opts['rev']:
3667 if repo is None:
3667 if repo is None:
3668 raise error.RepoError(_('there is no Mercurial repository here '
3668 raise error.RepoError(_('there is no Mercurial repository here '
3669 '(.hg not found)'))
3669 '(.hg not found)'))
3670 revs = scmutil.revrange(repo, opts['rev'])
3670 revs = scmutil.revrange(repo, opts['rev'])
3671
3671
3672 props = {}
3672 props = {}
3673 for d in opts['define']:
3673 for d in opts['define']:
3674 try:
3674 try:
3675 k, v = (e.strip() for e in d.split('=', 1))
3675 k, v = (e.strip() for e in d.split('=', 1))
3676 if not k:
3676 if not k:
3677 raise ValueError
3677 raise ValueError
3678 props[k] = v
3678 props[k] = v
3679 except ValueError:
3679 except ValueError:
3680 raise error.Abort(_('malformed keyword definition: %s') % d)
3680 raise error.Abort(_('malformed keyword definition: %s') % d)
3681
3681
3682 if ui.verbose:
3682 if ui.verbose:
3683 aliases = ui.configitems('templatealias')
3683 aliases = ui.configitems('templatealias')
3684 tree = templater.parse(tmpl)
3684 tree = templater.parse(tmpl)
3685 ui.note(templater.prettyformat(tree), '\n')
3685 ui.note(templater.prettyformat(tree), '\n')
3686 newtree = templater.expandaliases(tree, aliases)
3686 newtree = templater.expandaliases(tree, aliases)
3687 if newtree != tree:
3687 if newtree != tree:
3688 ui.note("* expanded:\n", templater.prettyformat(newtree), '\n')
3688 ui.note("* expanded:\n", templater.prettyformat(newtree), '\n')
3689
3689
3690 mapfile = None
3690 mapfile = None
3691 if revs is None:
3691 if revs is None:
3692 k = 'debugtemplate'
3692 k = 'debugtemplate'
3693 t = formatter.maketemplater(ui, k, tmpl)
3693 t = formatter.maketemplater(ui, k, tmpl)
3694 ui.write(templater.stringify(t(k, **props)))
3694 ui.write(templater.stringify(t(k, **props)))
3695 else:
3695 else:
3696 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3696 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3697 mapfile, buffered=False)
3697 mapfile, buffered=False)
3698 for r in revs:
3698 for r in revs:
3699 displayer.show(repo[r], **props)
3699 displayer.show(repo[r], **props)
3700 displayer.close()
3700 displayer.close()
3701
3701
3702 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3702 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3703 def debugwalk(ui, repo, *pats, **opts):
3703 def debugwalk(ui, repo, *pats, **opts):
3704 """show how files match on given patterns"""
3704 """show how files match on given patterns"""
3705 m = scmutil.match(repo[None], pats, opts)
3705 m = scmutil.match(repo[None], pats, opts)
3706 items = list(repo.walk(m))
3706 items = list(repo.walk(m))
3707 if not items:
3707 if not items:
3708 return
3708 return
3709 f = lambda fn: fn
3709 f = lambda fn: fn
3710 if ui.configbool('ui', 'slash') and os.sep != '/':
3710 if ui.configbool('ui', 'slash') and os.sep != '/':
3711 f = lambda fn: util.normpath(fn)
3711 f = lambda fn: util.normpath(fn)
3712 fmt = 'f %%-%ds %%-%ds %%s' % (
3712 fmt = 'f %%-%ds %%-%ds %%s' % (
3713 max([len(abs) for abs in items]),
3713 max([len(abs) for abs in items]),
3714 max([len(m.rel(abs)) for abs in items]))
3714 max([len(m.rel(abs)) for abs in items]))
3715 for abs in items:
3715 for abs in items:
3716 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3716 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3717 ui.write("%s\n" % line.rstrip())
3717 ui.write("%s\n" % line.rstrip())
3718
3718
3719 @command('debugwireargs',
3719 @command('debugwireargs',
3720 [('', 'three', '', 'three'),
3720 [('', 'three', '', 'three'),
3721 ('', 'four', '', 'four'),
3721 ('', 'four', '', 'four'),
3722 ('', 'five', '', 'five'),
3722 ('', 'five', '', 'five'),
3723 ] + remoteopts,
3723 ] + remoteopts,
3724 _('REPO [OPTIONS]... [ONE [TWO]]'),
3724 _('REPO [OPTIONS]... [ONE [TWO]]'),
3725 norepo=True)
3725 norepo=True)
3726 def debugwireargs(ui, repopath, *vals, **opts):
3726 def debugwireargs(ui, repopath, *vals, **opts):
3727 repo = hg.peer(ui, opts, repopath)
3727 repo = hg.peer(ui, opts, repopath)
3728 for opt in remoteopts:
3728 for opt in remoteopts:
3729 del opts[opt[1]]
3729 del opts[opt[1]]
3730 args = {}
3730 args = {}
3731 for k, v in opts.iteritems():
3731 for k, v in opts.iteritems():
3732 if v:
3732 if v:
3733 args[k] = v
3733 args[k] = v
3734 # run twice to check that we don't mess up the stream for the next command
3734 # run twice to check that we don't mess up the stream for the next command
3735 res1 = repo.debugwireargs(*vals, **args)
3735 res1 = repo.debugwireargs(*vals, **args)
3736 res2 = repo.debugwireargs(*vals, **args)
3736 res2 = repo.debugwireargs(*vals, **args)
3737 ui.write("%s\n" % res1)
3737 ui.write("%s\n" % res1)
3738 if res1 != res2:
3738 if res1 != res2:
3739 ui.warn("%s\n" % res2)
3739 ui.warn("%s\n" % res2)
3740
3740
3741 @command('^diff',
3741 @command('^diff',
3742 [('r', 'rev', [], _('revision'), _('REV')),
3742 [('r', 'rev', [], _('revision'), _('REV')),
3743 ('c', 'change', '', _('change made by revision'), _('REV'))
3743 ('c', 'change', '', _('change made by revision'), _('REV'))
3744 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3744 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3745 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3745 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3746 inferrepo=True)
3746 inferrepo=True)
3747 def diff(ui, repo, *pats, **opts):
3747 def diff(ui, repo, *pats, **opts):
3748 """diff repository (or selected files)
3748 """diff repository (or selected files)
3749
3749
3750 Show differences between revisions for the specified files.
3750 Show differences between revisions for the specified files.
3751
3751
3752 Differences between files are shown using the unified diff format.
3752 Differences between files are shown using the unified diff format.
3753
3753
3754 .. note::
3754 .. note::
3755
3755
3756 :hg:`diff` may generate unexpected results for merges, as it will
3756 :hg:`diff` may generate unexpected results for merges, as it will
3757 default to comparing against the working directory's first
3757 default to comparing against the working directory's first
3758 parent changeset if no revisions are specified.
3758 parent changeset if no revisions are specified.
3759
3759
3760 When two revision arguments are given, then changes are shown
3760 When two revision arguments are given, then changes are shown
3761 between those revisions. If only one revision is specified then
3761 between those revisions. If only one revision is specified then
3762 that revision is compared to the working directory, and, when no
3762 that revision is compared to the working directory, and, when no
3763 revisions are specified, the working directory files are compared
3763 revisions are specified, the working directory files are compared
3764 to its first parent.
3764 to its first parent.
3765
3765
3766 Alternatively you can specify -c/--change with a revision to see
3766 Alternatively you can specify -c/--change with a revision to see
3767 the changes in that changeset relative to its first parent.
3767 the changes in that changeset relative to its first parent.
3768
3768
3769 Without the -a/--text option, diff will avoid generating diffs of
3769 Without the -a/--text option, diff will avoid generating diffs of
3770 files it detects as binary. With -a, diff will generate a diff
3770 files it detects as binary. With -a, diff will generate a diff
3771 anyway, probably with undesirable results.
3771 anyway, probably with undesirable results.
3772
3772
3773 Use the -g/--git option to generate diffs in the git extended diff
3773 Use the -g/--git option to generate diffs in the git extended diff
3774 format. For more information, read :hg:`help diffs`.
3774 format. For more information, read :hg:`help diffs`.
3775
3775
3776 .. container:: verbose
3776 .. container:: verbose
3777
3777
3778 Examples:
3778 Examples:
3779
3779
3780 - compare a file in the current working directory to its parent::
3780 - compare a file in the current working directory to its parent::
3781
3781
3782 hg diff foo.c
3782 hg diff foo.c
3783
3783
3784 - compare two historical versions of a directory, with rename info::
3784 - compare two historical versions of a directory, with rename info::
3785
3785
3786 hg diff --git -r 1.0:1.2 lib/
3786 hg diff --git -r 1.0:1.2 lib/
3787
3787
3788 - get change stats relative to the last change on some date::
3788 - get change stats relative to the last change on some date::
3789
3789
3790 hg diff --stat -r "date('may 2')"
3790 hg diff --stat -r "date('may 2')"
3791
3791
3792 - diff all newly-added files that contain a keyword::
3792 - diff all newly-added files that contain a keyword::
3793
3793
3794 hg diff "set:added() and grep(GNU)"
3794 hg diff "set:added() and grep(GNU)"
3795
3795
3796 - compare a revision and its parents::
3796 - compare a revision and its parents::
3797
3797
3798 hg diff -c 9353 # compare against first parent
3798 hg diff -c 9353 # compare against first parent
3799 hg diff -r 9353^:9353 # same using revset syntax
3799 hg diff -r 9353^:9353 # same using revset syntax
3800 hg diff -r 9353^2:9353 # compare against the second parent
3800 hg diff -r 9353^2:9353 # compare against the second parent
3801
3801
3802 Returns 0 on success.
3802 Returns 0 on success.
3803 """
3803 """
3804
3804
3805 revs = opts.get('rev')
3805 revs = opts.get('rev')
3806 change = opts.get('change')
3806 change = opts.get('change')
3807 stat = opts.get('stat')
3807 stat = opts.get('stat')
3808 reverse = opts.get('reverse')
3808 reverse = opts.get('reverse')
3809
3809
3810 if revs and change:
3810 if revs and change:
3811 msg = _('cannot specify --rev and --change at the same time')
3811 msg = _('cannot specify --rev and --change at the same time')
3812 raise error.Abort(msg)
3812 raise error.Abort(msg)
3813 elif change:
3813 elif change:
3814 node2 = scmutil.revsingle(repo, change, None).node()
3814 node2 = scmutil.revsingle(repo, change, None).node()
3815 node1 = repo[node2].p1().node()
3815 node1 = repo[node2].p1().node()
3816 else:
3816 else:
3817 node1, node2 = scmutil.revpair(repo, revs)
3817 node1, node2 = scmutil.revpair(repo, revs)
3818
3818
3819 if reverse:
3819 if reverse:
3820 node1, node2 = node2, node1
3820 node1, node2 = node2, node1
3821
3821
3822 diffopts = patch.diffallopts(ui, opts)
3822 diffopts = patch.diffallopts(ui, opts)
3823 m = scmutil.match(repo[node2], pats, opts)
3823 m = scmutil.match(repo[node2], pats, opts)
3824 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3824 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3825 listsubrepos=opts.get('subrepos'),
3825 listsubrepos=opts.get('subrepos'),
3826 root=opts.get('root'))
3826 root=opts.get('root'))
3827
3827
3828 @command('^export',
3828 @command('^export',
3829 [('o', 'output', '',
3829 [('o', 'output', '',
3830 _('print output to file with formatted name'), _('FORMAT')),
3830 _('print output to file with formatted name'), _('FORMAT')),
3831 ('', 'switch-parent', None, _('diff against the second parent')),
3831 ('', 'switch-parent', None, _('diff against the second parent')),
3832 ('r', 'rev', [], _('revisions to export'), _('REV')),
3832 ('r', 'rev', [], _('revisions to export'), _('REV')),
3833 ] + diffopts,
3833 ] + diffopts,
3834 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3834 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3835 def export(ui, repo, *changesets, **opts):
3835 def export(ui, repo, *changesets, **opts):
3836 """dump the header and diffs for one or more changesets
3836 """dump the header and diffs for one or more changesets
3837
3837
3838 Print the changeset header and diffs for one or more revisions.
3838 Print the changeset header and diffs for one or more revisions.
3839 If no revision is given, the parent of the working directory is used.
3839 If no revision is given, the parent of the working directory is used.
3840
3840
3841 The information shown in the changeset header is: author, date,
3841 The information shown in the changeset header is: author, date,
3842 branch name (if non-default), changeset hash, parent(s) and commit
3842 branch name (if non-default), changeset hash, parent(s) and commit
3843 comment.
3843 comment.
3844
3844
3845 .. note::
3845 .. note::
3846
3846
3847 :hg:`export` may generate unexpected diff output for merge
3847 :hg:`export` may generate unexpected diff output for merge
3848 changesets, as it will compare the merge changeset against its
3848 changesets, as it will compare the merge changeset against its
3849 first parent only.
3849 first parent only.
3850
3850
3851 Output may be to a file, in which case the name of the file is
3851 Output may be to a file, in which case the name of the file is
3852 given using a format string. The formatting rules are as follows:
3852 given using a format string. The formatting rules are as follows:
3853
3853
3854 :``%%``: literal "%" character
3854 :``%%``: literal "%" character
3855 :``%H``: changeset hash (40 hexadecimal digits)
3855 :``%H``: changeset hash (40 hexadecimal digits)
3856 :``%N``: number of patches being generated
3856 :``%N``: number of patches being generated
3857 :``%R``: changeset revision number
3857 :``%R``: changeset revision number
3858 :``%b``: basename of the exporting repository
3858 :``%b``: basename of the exporting repository
3859 :``%h``: short-form changeset hash (12 hexadecimal digits)
3859 :``%h``: short-form changeset hash (12 hexadecimal digits)
3860 :``%m``: first line of the commit message (only alphanumeric characters)
3860 :``%m``: first line of the commit message (only alphanumeric characters)
3861 :``%n``: zero-padded sequence number, starting at 1
3861 :``%n``: zero-padded sequence number, starting at 1
3862 :``%r``: zero-padded changeset revision number
3862 :``%r``: zero-padded changeset revision number
3863
3863
3864 Without the -a/--text option, export will avoid generating diffs
3864 Without the -a/--text option, export will avoid generating diffs
3865 of files it detects as binary. With -a, export will generate a
3865 of files it detects as binary. With -a, export will generate a
3866 diff anyway, probably with undesirable results.
3866 diff anyway, probably with undesirable results.
3867
3867
3868 Use the -g/--git option to generate diffs in the git extended diff
3868 Use the -g/--git option to generate diffs in the git extended diff
3869 format. See :hg:`help diffs` for more information.
3869 format. See :hg:`help diffs` for more information.
3870
3870
3871 With the --switch-parent option, the diff will be against the
3871 With the --switch-parent option, the diff will be against the
3872 second parent. It can be useful to review a merge.
3872 second parent. It can be useful to review a merge.
3873
3873
3874 .. container:: verbose
3874 .. container:: verbose
3875
3875
3876 Examples:
3876 Examples:
3877
3877
3878 - use export and import to transplant a bugfix to the current
3878 - use export and import to transplant a bugfix to the current
3879 branch::
3879 branch::
3880
3880
3881 hg export -r 9353 | hg import -
3881 hg export -r 9353 | hg import -
3882
3882
3883 - export all the changesets between two revisions to a file with
3883 - export all the changesets between two revisions to a file with
3884 rename information::
3884 rename information::
3885
3885
3886 hg export --git -r 123:150 > changes.txt
3886 hg export --git -r 123:150 > changes.txt
3887
3887
3888 - split outgoing changes into a series of patches with
3888 - split outgoing changes into a series of patches with
3889 descriptive names::
3889 descriptive names::
3890
3890
3891 hg export -r "outgoing()" -o "%n-%m.patch"
3891 hg export -r "outgoing()" -o "%n-%m.patch"
3892
3892
3893 Returns 0 on success.
3893 Returns 0 on success.
3894 """
3894 """
3895 changesets += tuple(opts.get('rev', []))
3895 changesets += tuple(opts.get('rev', []))
3896 if not changesets:
3896 if not changesets:
3897 changesets = ['.']
3897 changesets = ['.']
3898 revs = scmutil.revrange(repo, changesets)
3898 revs = scmutil.revrange(repo, changesets)
3899 if not revs:
3899 if not revs:
3900 raise error.Abort(_("export requires at least one changeset"))
3900 raise error.Abort(_("export requires at least one changeset"))
3901 if len(revs) > 1:
3901 if len(revs) > 1:
3902 ui.note(_('exporting patches:\n'))
3902 ui.note(_('exporting patches:\n'))
3903 else:
3903 else:
3904 ui.note(_('exporting patch:\n'))
3904 ui.note(_('exporting patch:\n'))
3905 cmdutil.export(repo, revs, template=opts.get('output'),
3905 cmdutil.export(repo, revs, template=opts.get('output'),
3906 switch_parent=opts.get('switch_parent'),
3906 switch_parent=opts.get('switch_parent'),
3907 opts=patch.diffallopts(ui, opts))
3907 opts=patch.diffallopts(ui, opts))
3908
3908
3909 @command('files',
3909 @command('files',
3910 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3910 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3911 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3911 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3912 ] + walkopts + formatteropts + subrepoopts,
3912 ] + walkopts + formatteropts + subrepoopts,
3913 _('[OPTION]... [PATTERN]...'))
3913 _('[OPTION]... [PATTERN]...'))
3914 def files(ui, repo, *pats, **opts):
3914 def files(ui, repo, *pats, **opts):
3915 """list tracked files
3915 """list tracked files
3916
3916
3917 Print files under Mercurial control in the working directory or
3917 Print files under Mercurial control in the working directory or
3918 specified revision whose names match the given patterns (excluding
3918 specified revision whose names match the given patterns (excluding
3919 removed files).
3919 removed files).
3920
3920
3921 If no patterns are given to match, this command prints the names
3921 If no patterns are given to match, this command prints the names
3922 of all files under Mercurial control in the working directory.
3922 of all files under Mercurial control in the working directory.
3923
3923
3924 .. container:: verbose
3924 .. container:: verbose
3925
3925
3926 Examples:
3926 Examples:
3927
3927
3928 - list all files under the current directory::
3928 - list all files under the current directory::
3929
3929
3930 hg files .
3930 hg files .
3931
3931
3932 - shows sizes and flags for current revision::
3932 - shows sizes and flags for current revision::
3933
3933
3934 hg files -vr .
3934 hg files -vr .
3935
3935
3936 - list all files named README::
3936 - list all files named README::
3937
3937
3938 hg files -I "**/README"
3938 hg files -I "**/README"
3939
3939
3940 - list all binary files::
3940 - list all binary files::
3941
3941
3942 hg files "set:binary()"
3942 hg files "set:binary()"
3943
3943
3944 - find files containing a regular expression::
3944 - find files containing a regular expression::
3945
3945
3946 hg files "set:grep('bob')"
3946 hg files "set:grep('bob')"
3947
3947
3948 - search tracked file contents with xargs and grep::
3948 - search tracked file contents with xargs and grep::
3949
3949
3950 hg files -0 | xargs -0 grep foo
3950 hg files -0 | xargs -0 grep foo
3951
3951
3952 See :hg:`help patterns` and :hg:`help filesets` for more information
3952 See :hg:`help patterns` and :hg:`help filesets` for more information
3953 on specifying file patterns.
3953 on specifying file patterns.
3954
3954
3955 Returns 0 if a match is found, 1 otherwise.
3955 Returns 0 if a match is found, 1 otherwise.
3956
3956
3957 """
3957 """
3958 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3958 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3959
3959
3960 end = '\n'
3960 end = '\n'
3961 if opts.get('print0'):
3961 if opts.get('print0'):
3962 end = '\0'
3962 end = '\0'
3963 fm = ui.formatter('files', opts)
3963 fm = ui.formatter('files', opts)
3964 fmt = '%s' + end
3964 fmt = '%s' + end
3965
3965
3966 m = scmutil.match(ctx, pats, opts)
3966 m = scmutil.match(ctx, pats, opts)
3967 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3967 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3968
3968
3969 fm.end()
3969 fm.end()
3970
3970
3971 return ret
3971 return ret
3972
3972
3973 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3973 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3974 def forget(ui, repo, *pats, **opts):
3974 def forget(ui, repo, *pats, **opts):
3975 """forget the specified files on the next commit
3975 """forget the specified files on the next commit
3976
3976
3977 Mark the specified files so they will no longer be tracked
3977 Mark the specified files so they will no longer be tracked
3978 after the next commit.
3978 after the next commit.
3979
3979
3980 This only removes files from the current branch, not from the
3980 This only removes files from the current branch, not from the
3981 entire project history, and it does not delete them from the
3981 entire project history, and it does not delete them from the
3982 working directory.
3982 working directory.
3983
3983
3984 To delete the file from the working directory, see :hg:`remove`.
3984 To delete the file from the working directory, see :hg:`remove`.
3985
3985
3986 To undo a forget before the next commit, see :hg:`add`.
3986 To undo a forget before the next commit, see :hg:`add`.
3987
3987
3988 .. container:: verbose
3988 .. container:: verbose
3989
3989
3990 Examples:
3990 Examples:
3991
3991
3992 - forget newly-added binary files::
3992 - forget newly-added binary files::
3993
3993
3994 hg forget "set:added() and binary()"
3994 hg forget "set:added() and binary()"
3995
3995
3996 - forget files that would be excluded by .hgignore::
3996 - forget files that would be excluded by .hgignore::
3997
3997
3998 hg forget "set:hgignore()"
3998 hg forget "set:hgignore()"
3999
3999
4000 Returns 0 on success.
4000 Returns 0 on success.
4001 """
4001 """
4002
4002
4003 if not pats:
4003 if not pats:
4004 raise error.Abort(_('no files specified'))
4004 raise error.Abort(_('no files specified'))
4005
4005
4006 m = scmutil.match(repo[None], pats, opts)
4006 m = scmutil.match(repo[None], pats, opts)
4007 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4007 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4008 return rejected and 1 or 0
4008 return rejected and 1 or 0
4009
4009
4010 @command(
4010 @command(
4011 'graft',
4011 'graft',
4012 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4012 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4013 ('c', 'continue', False, _('resume interrupted graft')),
4013 ('c', 'continue', False, _('resume interrupted graft')),
4014 ('e', 'edit', False, _('invoke editor on commit messages')),
4014 ('e', 'edit', False, _('invoke editor on commit messages')),
4015 ('', 'log', None, _('append graft info to log message')),
4015 ('', 'log', None, _('append graft info to log message')),
4016 ('f', 'force', False, _('force graft')),
4016 ('f', 'force', False, _('force graft')),
4017 ('D', 'currentdate', False,
4017 ('D', 'currentdate', False,
4018 _('record the current date as commit date')),
4018 _('record the current date as commit date')),
4019 ('U', 'currentuser', False,
4019 ('U', 'currentuser', False,
4020 _('record the current user as committer'), _('DATE'))]
4020 _('record the current user as committer'), _('DATE'))]
4021 + commitopts2 + mergetoolopts + dryrunopts,
4021 + commitopts2 + mergetoolopts + dryrunopts,
4022 _('[OPTION]... [-r REV]... REV...'))
4022 _('[OPTION]... [-r REV]... REV...'))
4023 def graft(ui, repo, *revs, **opts):
4023 def graft(ui, repo, *revs, **opts):
4024 '''copy changes from other branches onto the current branch
4024 '''copy changes from other branches onto the current branch
4025
4025
4026 This command uses Mercurial's merge logic to copy individual
4026 This command uses Mercurial's merge logic to copy individual
4027 changes from other branches without merging branches in the
4027 changes from other branches without merging branches in the
4028 history graph. This is sometimes known as 'backporting' or
4028 history graph. This is sometimes known as 'backporting' or
4029 'cherry-picking'. By default, graft will copy user, date, and
4029 'cherry-picking'. By default, graft will copy user, date, and
4030 description from the source changesets.
4030 description from the source changesets.
4031
4031
4032 Changesets that are ancestors of the current revision, that have
4032 Changesets that are ancestors of the current revision, that have
4033 already been grafted, or that are merges will be skipped.
4033 already been grafted, or that are merges will be skipped.
4034
4034
4035 If --log is specified, log messages will have a comment appended
4035 If --log is specified, log messages will have a comment appended
4036 of the form::
4036 of the form::
4037
4037
4038 (grafted from CHANGESETHASH)
4038 (grafted from CHANGESETHASH)
4039
4039
4040 If --force is specified, revisions will be grafted even if they
4040 If --force is specified, revisions will be grafted even if they
4041 are already ancestors of or have been grafted to the destination.
4041 are already ancestors of or have been grafted to the destination.
4042 This is useful when the revisions have since been backed out.
4042 This is useful when the revisions have since been backed out.
4043
4043
4044 If a graft merge results in conflicts, the graft process is
4044 If a graft merge results in conflicts, the graft process is
4045 interrupted so that the current merge can be manually resolved.
4045 interrupted so that the current merge can be manually resolved.
4046 Once all conflicts are addressed, the graft process can be
4046 Once all conflicts are addressed, the graft process can be
4047 continued with the -c/--continue option.
4047 continued with the -c/--continue option.
4048
4048
4049 .. note::
4049 .. note::
4050
4050
4051 The -c/--continue option does not reapply earlier options, except
4051 The -c/--continue option does not reapply earlier options, except
4052 for --force.
4052 for --force.
4053
4053
4054 .. container:: verbose
4054 .. container:: verbose
4055
4055
4056 Examples:
4056 Examples:
4057
4057
4058 - copy a single change to the stable branch and edit its description::
4058 - copy a single change to the stable branch and edit its description::
4059
4059
4060 hg update stable
4060 hg update stable
4061 hg graft --edit 9393
4061 hg graft --edit 9393
4062
4062
4063 - graft a range of changesets with one exception, updating dates::
4063 - graft a range of changesets with one exception, updating dates::
4064
4064
4065 hg graft -D "2085::2093 and not 2091"
4065 hg graft -D "2085::2093 and not 2091"
4066
4066
4067 - continue a graft after resolving conflicts::
4067 - continue a graft after resolving conflicts::
4068
4068
4069 hg graft -c
4069 hg graft -c
4070
4070
4071 - show the source of a grafted changeset::
4071 - show the source of a grafted changeset::
4072
4072
4073 hg log --debug -r .
4073 hg log --debug -r .
4074
4074
4075 - show revisions sorted by date::
4075 - show revisions sorted by date::
4076
4076
4077 hg log -r "sort(all(), date)"
4077 hg log -r "sort(all(), date)"
4078
4078
4079 See :hg:`help revisions` and :hg:`help revsets` for more about
4079 See :hg:`help revisions` and :hg:`help revsets` for more about
4080 specifying revisions.
4080 specifying revisions.
4081
4081
4082 Returns 0 on successful completion.
4082 Returns 0 on successful completion.
4083 '''
4083 '''
4084 with repo.wlock():
4084 with repo.wlock():
4085 return _dograft(ui, repo, *revs, **opts)
4085 return _dograft(ui, repo, *revs, **opts)
4086
4086
4087 def _dograft(ui, repo, *revs, **opts):
4087 def _dograft(ui, repo, *revs, **opts):
4088 if revs and opts['rev']:
4088 if revs and opts['rev']:
4089 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4089 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4090 'revision ordering!\n'))
4090 'revision ordering!\n'))
4091
4091
4092 revs = list(revs)
4092 revs = list(revs)
4093 revs.extend(opts['rev'])
4093 revs.extend(opts['rev'])
4094
4094
4095 if not opts.get('user') and opts.get('currentuser'):
4095 if not opts.get('user') and opts.get('currentuser'):
4096 opts['user'] = ui.username()
4096 opts['user'] = ui.username()
4097 if not opts.get('date') and opts.get('currentdate'):
4097 if not opts.get('date') and opts.get('currentdate'):
4098 opts['date'] = "%d %d" % util.makedate()
4098 opts['date'] = "%d %d" % util.makedate()
4099
4099
4100 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4100 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4101
4101
4102 cont = False
4102 cont = False
4103 if opts['continue']:
4103 if opts['continue']:
4104 cont = True
4104 cont = True
4105 if revs:
4105 if revs:
4106 raise error.Abort(_("can't specify --continue and revisions"))
4106 raise error.Abort(_("can't specify --continue and revisions"))
4107 # read in unfinished revisions
4107 # read in unfinished revisions
4108 try:
4108 try:
4109 nodes = repo.vfs.read('graftstate').splitlines()
4109 nodes = repo.vfs.read('graftstate').splitlines()
4110 revs = [repo[node].rev() for node in nodes]
4110 revs = [repo[node].rev() for node in nodes]
4111 except IOError as inst:
4111 except IOError as inst:
4112 if inst.errno != errno.ENOENT:
4112 if inst.errno != errno.ENOENT:
4113 raise
4113 raise
4114 cmdutil.wrongtooltocontinue(repo, _('graft'))
4114 cmdutil.wrongtooltocontinue(repo, _('graft'))
4115 else:
4115 else:
4116 cmdutil.checkunfinished(repo)
4116 cmdutil.checkunfinished(repo)
4117 cmdutil.bailifchanged(repo)
4117 cmdutil.bailifchanged(repo)
4118 if not revs:
4118 if not revs:
4119 raise error.Abort(_('no revisions specified'))
4119 raise error.Abort(_('no revisions specified'))
4120 revs = scmutil.revrange(repo, revs)
4120 revs = scmutil.revrange(repo, revs)
4121
4121
4122 skipped = set()
4122 skipped = set()
4123 # check for merges
4123 # check for merges
4124 for rev in repo.revs('%ld and merge()', revs):
4124 for rev in repo.revs('%ld and merge()', revs):
4125 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4125 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4126 skipped.add(rev)
4126 skipped.add(rev)
4127 revs = [r for r in revs if r not in skipped]
4127 revs = [r for r in revs if r not in skipped]
4128 if not revs:
4128 if not revs:
4129 return -1
4129 return -1
4130
4130
4131 # Don't check in the --continue case, in effect retaining --force across
4131 # Don't check in the --continue case, in effect retaining --force across
4132 # --continues. That's because without --force, any revisions we decided to
4132 # --continues. That's because without --force, any revisions we decided to
4133 # skip would have been filtered out here, so they wouldn't have made their
4133 # skip would have been filtered out here, so they wouldn't have made their
4134 # way to the graftstate. With --force, any revisions we would have otherwise
4134 # way to the graftstate. With --force, any revisions we would have otherwise
4135 # skipped would not have been filtered out, and if they hadn't been applied
4135 # skipped would not have been filtered out, and if they hadn't been applied
4136 # already, they'd have been in the graftstate.
4136 # already, they'd have been in the graftstate.
4137 if not (cont or opts.get('force')):
4137 if not (cont or opts.get('force')):
4138 # check for ancestors of dest branch
4138 # check for ancestors of dest branch
4139 crev = repo['.'].rev()
4139 crev = repo['.'].rev()
4140 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4140 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4141 # Cannot use x.remove(y) on smart set, this has to be a list.
4141 # Cannot use x.remove(y) on smart set, this has to be a list.
4142 # XXX make this lazy in the future
4142 # XXX make this lazy in the future
4143 revs = list(revs)
4143 revs = list(revs)
4144 # don't mutate while iterating, create a copy
4144 # don't mutate while iterating, create a copy
4145 for rev in list(revs):
4145 for rev in list(revs):
4146 if rev in ancestors:
4146 if rev in ancestors:
4147 ui.warn(_('skipping ancestor revision %d:%s\n') %
4147 ui.warn(_('skipping ancestor revision %d:%s\n') %
4148 (rev, repo[rev]))
4148 (rev, repo[rev]))
4149 # XXX remove on list is slow
4149 # XXX remove on list is slow
4150 revs.remove(rev)
4150 revs.remove(rev)
4151 if not revs:
4151 if not revs:
4152 return -1
4152 return -1
4153
4153
4154 # analyze revs for earlier grafts
4154 # analyze revs for earlier grafts
4155 ids = {}
4155 ids = {}
4156 for ctx in repo.set("%ld", revs):
4156 for ctx in repo.set("%ld", revs):
4157 ids[ctx.hex()] = ctx.rev()
4157 ids[ctx.hex()] = ctx.rev()
4158 n = ctx.extra().get('source')
4158 n = ctx.extra().get('source')
4159 if n:
4159 if n:
4160 ids[n] = ctx.rev()
4160 ids[n] = ctx.rev()
4161
4161
4162 # check ancestors for earlier grafts
4162 # check ancestors for earlier grafts
4163 ui.debug('scanning for duplicate grafts\n')
4163 ui.debug('scanning for duplicate grafts\n')
4164
4164
4165 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4165 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4166 ctx = repo[rev]
4166 ctx = repo[rev]
4167 n = ctx.extra().get('source')
4167 n = ctx.extra().get('source')
4168 if n in ids:
4168 if n in ids:
4169 try:
4169 try:
4170 r = repo[n].rev()
4170 r = repo[n].rev()
4171 except error.RepoLookupError:
4171 except error.RepoLookupError:
4172 r = None
4172 r = None
4173 if r in revs:
4173 if r in revs:
4174 ui.warn(_('skipping revision %d:%s '
4174 ui.warn(_('skipping revision %d:%s '
4175 '(already grafted to %d:%s)\n')
4175 '(already grafted to %d:%s)\n')
4176 % (r, repo[r], rev, ctx))
4176 % (r, repo[r], rev, ctx))
4177 revs.remove(r)
4177 revs.remove(r)
4178 elif ids[n] in revs:
4178 elif ids[n] in revs:
4179 if r is None:
4179 if r is None:
4180 ui.warn(_('skipping already grafted revision %d:%s '
4180 ui.warn(_('skipping already grafted revision %d:%s '
4181 '(%d:%s also has unknown origin %s)\n')
4181 '(%d:%s also has unknown origin %s)\n')
4182 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4182 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4183 else:
4183 else:
4184 ui.warn(_('skipping already grafted revision %d:%s '
4184 ui.warn(_('skipping already grafted revision %d:%s '
4185 '(%d:%s also has origin %d:%s)\n')
4185 '(%d:%s also has origin %d:%s)\n')
4186 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4186 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4187 revs.remove(ids[n])
4187 revs.remove(ids[n])
4188 elif ctx.hex() in ids:
4188 elif ctx.hex() in ids:
4189 r = ids[ctx.hex()]
4189 r = ids[ctx.hex()]
4190 ui.warn(_('skipping already grafted revision %d:%s '
4190 ui.warn(_('skipping already grafted revision %d:%s '
4191 '(was grafted from %d:%s)\n') %
4191 '(was grafted from %d:%s)\n') %
4192 (r, repo[r], rev, ctx))
4192 (r, repo[r], rev, ctx))
4193 revs.remove(r)
4193 revs.remove(r)
4194 if not revs:
4194 if not revs:
4195 return -1
4195 return -1
4196
4196
4197 for pos, ctx in enumerate(repo.set("%ld", revs)):
4197 for pos, ctx in enumerate(repo.set("%ld", revs)):
4198 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4198 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4199 ctx.description().split('\n', 1)[0])
4199 ctx.description().split('\n', 1)[0])
4200 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4200 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4201 if names:
4201 if names:
4202 desc += ' (%s)' % ' '.join(names)
4202 desc += ' (%s)' % ' '.join(names)
4203 ui.status(_('grafting %s\n') % desc)
4203 ui.status(_('grafting %s\n') % desc)
4204 if opts.get('dry_run'):
4204 if opts.get('dry_run'):
4205 continue
4205 continue
4206
4206
4207 source = ctx.extra().get('source')
4207 source = ctx.extra().get('source')
4208 extra = {}
4208 extra = {}
4209 if source:
4209 if source:
4210 extra['source'] = source
4210 extra['source'] = source
4211 extra['intermediate-source'] = ctx.hex()
4211 extra['intermediate-source'] = ctx.hex()
4212 else:
4212 else:
4213 extra['source'] = ctx.hex()
4213 extra['source'] = ctx.hex()
4214 user = ctx.user()
4214 user = ctx.user()
4215 if opts.get('user'):
4215 if opts.get('user'):
4216 user = opts['user']
4216 user = opts['user']
4217 date = ctx.date()
4217 date = ctx.date()
4218 if opts.get('date'):
4218 if opts.get('date'):
4219 date = opts['date']
4219 date = opts['date']
4220 message = ctx.description()
4220 message = ctx.description()
4221 if opts.get('log'):
4221 if opts.get('log'):
4222 message += '\n(grafted from %s)' % ctx.hex()
4222 message += '\n(grafted from %s)' % ctx.hex()
4223
4223
4224 # we don't merge the first commit when continuing
4224 # we don't merge the first commit when continuing
4225 if not cont:
4225 if not cont:
4226 # perform the graft merge with p1(rev) as 'ancestor'
4226 # perform the graft merge with p1(rev) as 'ancestor'
4227 try:
4227 try:
4228 # ui.forcemerge is an internal variable, do not document
4228 # ui.forcemerge is an internal variable, do not document
4229 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4229 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4230 'graft')
4230 'graft')
4231 stats = mergemod.graft(repo, ctx, ctx.p1(),
4231 stats = mergemod.graft(repo, ctx, ctx.p1(),
4232 ['local', 'graft'])
4232 ['local', 'graft'])
4233 finally:
4233 finally:
4234 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4234 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4235 # report any conflicts
4235 # report any conflicts
4236 if stats and stats[3] > 0:
4236 if stats and stats[3] > 0:
4237 # write out state for --continue
4237 # write out state for --continue
4238 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4238 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4239 repo.vfs.write('graftstate', ''.join(nodelines))
4239 repo.vfs.write('graftstate', ''.join(nodelines))
4240 extra = ''
4240 extra = ''
4241 if opts.get('user'):
4241 if opts.get('user'):
4242 extra += ' --user %s' % util.shellquote(opts['user'])
4242 extra += ' --user %s' % util.shellquote(opts['user'])
4243 if opts.get('date'):
4243 if opts.get('date'):
4244 extra += ' --date %s' % util.shellquote(opts['date'])
4244 extra += ' --date %s' % util.shellquote(opts['date'])
4245 if opts.get('log'):
4245 if opts.get('log'):
4246 extra += ' --log'
4246 extra += ' --log'
4247 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4247 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4248 raise error.Abort(
4248 raise error.Abort(
4249 _("unresolved conflicts, can't continue"),
4249 _("unresolved conflicts, can't continue"),
4250 hint=hint)
4250 hint=hint)
4251 else:
4251 else:
4252 cont = False
4252 cont = False
4253
4253
4254 # commit
4254 # commit
4255 node = repo.commit(text=message, user=user,
4255 node = repo.commit(text=message, user=user,
4256 date=date, extra=extra, editor=editor)
4256 date=date, extra=extra, editor=editor)
4257 if node is None:
4257 if node is None:
4258 ui.warn(
4258 ui.warn(
4259 _('note: graft of %d:%s created no changes to commit\n') %
4259 _('note: graft of %d:%s created no changes to commit\n') %
4260 (ctx.rev(), ctx))
4260 (ctx.rev(), ctx))
4261
4261
4262 # remove state when we complete successfully
4262 # remove state when we complete successfully
4263 if not opts.get('dry_run'):
4263 if not opts.get('dry_run'):
4264 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4264 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4265
4265
4266 return 0
4266 return 0
4267
4267
4268 @command('grep',
4268 @command('grep',
4269 [('0', 'print0', None, _('end fields with NUL')),
4269 [('0', 'print0', None, _('end fields with NUL')),
4270 ('', 'all', None, _('print all revisions that match')),
4270 ('', 'all', None, _('print all revisions that match')),
4271 ('a', 'text', None, _('treat all files as text')),
4271 ('a', 'text', None, _('treat all files as text')),
4272 ('f', 'follow', None,
4272 ('f', 'follow', None,
4273 _('follow changeset history,'
4273 _('follow changeset history,'
4274 ' or file history across copies and renames')),
4274 ' or file history across copies and renames')),
4275 ('i', 'ignore-case', None, _('ignore case when matching')),
4275 ('i', 'ignore-case', None, _('ignore case when matching')),
4276 ('l', 'files-with-matches', None,
4276 ('l', 'files-with-matches', None,
4277 _('print only filenames and revisions that match')),
4277 _('print only filenames and revisions that match')),
4278 ('n', 'line-number', None, _('print matching line numbers')),
4278 ('n', 'line-number', None, _('print matching line numbers')),
4279 ('r', 'rev', [],
4279 ('r', 'rev', [],
4280 _('only search files changed within revision range'), _('REV')),
4280 _('only search files changed within revision range'), _('REV')),
4281 ('u', 'user', None, _('list the author (long with -v)')),
4281 ('u', 'user', None, _('list the author (long with -v)')),
4282 ('d', 'date', None, _('list the date (short with -q)')),
4282 ('d', 'date', None, _('list the date (short with -q)')),
4283 ] + walkopts,
4283 ] + walkopts,
4284 _('[OPTION]... PATTERN [FILE]...'),
4284 _('[OPTION]... PATTERN [FILE]...'),
4285 inferrepo=True)
4285 inferrepo=True)
4286 def grep(ui, repo, pattern, *pats, **opts):
4286 def grep(ui, repo, pattern, *pats, **opts):
4287 """search for a pattern in specified files and revisions
4287 """search for a pattern in specified files and revisions
4288
4288
4289 Search revisions of files for a regular expression.
4289 Search revisions of files for a regular expression.
4290
4290
4291 This command behaves differently than Unix grep. It only accepts
4291 This command behaves differently than Unix grep. It only accepts
4292 Python/Perl regexps. It searches repository history, not the
4292 Python/Perl regexps. It searches repository history, not the
4293 working directory. It always prints the revision number in which a
4293 working directory. It always prints the revision number in which a
4294 match appears.
4294 match appears.
4295
4295
4296 By default, grep only prints output for the first revision of a
4296 By default, grep only prints output for the first revision of a
4297 file in which it finds a match. To get it to print every revision
4297 file in which it finds a match. To get it to print every revision
4298 that contains a change in match status ("-" for a match that
4298 that contains a change in match status ("-" for a match that
4299 becomes a non-match, or "+" for a non-match that becomes a match),
4299 becomes a non-match, or "+" for a non-match that becomes a match),
4300 use the --all flag.
4300 use the --all flag.
4301
4301
4302 Returns 0 if a match is found, 1 otherwise.
4302 Returns 0 if a match is found, 1 otherwise.
4303 """
4303 """
4304 reflags = re.M
4304 reflags = re.M
4305 if opts.get('ignore_case'):
4305 if opts.get('ignore_case'):
4306 reflags |= re.I
4306 reflags |= re.I
4307 try:
4307 try:
4308 regexp = util.re.compile(pattern, reflags)
4308 regexp = util.re.compile(pattern, reflags)
4309 except re.error as inst:
4309 except re.error as inst:
4310 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4310 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4311 return 1
4311 return 1
4312 sep, eol = ':', '\n'
4312 sep, eol = ':', '\n'
4313 if opts.get('print0'):
4313 if opts.get('print0'):
4314 sep = eol = '\0'
4314 sep = eol = '\0'
4315
4315
4316 getfile = util.lrucachefunc(repo.file)
4316 getfile = util.lrucachefunc(repo.file)
4317
4317
4318 def matchlines(body):
4318 def matchlines(body):
4319 begin = 0
4319 begin = 0
4320 linenum = 0
4320 linenum = 0
4321 while begin < len(body):
4321 while begin < len(body):
4322 match = regexp.search(body, begin)
4322 match = regexp.search(body, begin)
4323 if not match:
4323 if not match:
4324 break
4324 break
4325 mstart, mend = match.span()
4325 mstart, mend = match.span()
4326 linenum += body.count('\n', begin, mstart) + 1
4326 linenum += body.count('\n', begin, mstart) + 1
4327 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4327 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4328 begin = body.find('\n', mend) + 1 or len(body) + 1
4328 begin = body.find('\n', mend) + 1 or len(body) + 1
4329 lend = begin - 1
4329 lend = begin - 1
4330 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4330 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4331
4331
4332 class linestate(object):
4332 class linestate(object):
4333 def __init__(self, line, linenum, colstart, colend):
4333 def __init__(self, line, linenum, colstart, colend):
4334 self.line = line
4334 self.line = line
4335 self.linenum = linenum
4335 self.linenum = linenum
4336 self.colstart = colstart
4336 self.colstart = colstart
4337 self.colend = colend
4337 self.colend = colend
4338
4338
4339 def __hash__(self):
4339 def __hash__(self):
4340 return hash((self.linenum, self.line))
4340 return hash((self.linenum, self.line))
4341
4341
4342 def __eq__(self, other):
4342 def __eq__(self, other):
4343 return self.line == other.line
4343 return self.line == other.line
4344
4344
4345 def __iter__(self):
4345 def __iter__(self):
4346 yield (self.line[:self.colstart], '')
4346 yield (self.line[:self.colstart], '')
4347 yield (self.line[self.colstart:self.colend], 'grep.match')
4347 yield (self.line[self.colstart:self.colend], 'grep.match')
4348 rest = self.line[self.colend:]
4348 rest = self.line[self.colend:]
4349 while rest != '':
4349 while rest != '':
4350 match = regexp.search(rest)
4350 match = regexp.search(rest)
4351 if not match:
4351 if not match:
4352 yield (rest, '')
4352 yield (rest, '')
4353 break
4353 break
4354 mstart, mend = match.span()
4354 mstart, mend = match.span()
4355 yield (rest[:mstart], '')
4355 yield (rest[:mstart], '')
4356 yield (rest[mstart:mend], 'grep.match')
4356 yield (rest[mstart:mend], 'grep.match')
4357 rest = rest[mend:]
4357 rest = rest[mend:]
4358
4358
4359 matches = {}
4359 matches = {}
4360 copies = {}
4360 copies = {}
4361 def grepbody(fn, rev, body):
4361 def grepbody(fn, rev, body):
4362 matches[rev].setdefault(fn, [])
4362 matches[rev].setdefault(fn, [])
4363 m = matches[rev][fn]
4363 m = matches[rev][fn]
4364 for lnum, cstart, cend, line in matchlines(body):
4364 for lnum, cstart, cend, line in matchlines(body):
4365 s = linestate(line, lnum, cstart, cend)
4365 s = linestate(line, lnum, cstart, cend)
4366 m.append(s)
4366 m.append(s)
4367
4367
4368 def difflinestates(a, b):
4368 def difflinestates(a, b):
4369 sm = difflib.SequenceMatcher(None, a, b)
4369 sm = difflib.SequenceMatcher(None, a, b)
4370 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4370 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4371 if tag == 'insert':
4371 if tag == 'insert':
4372 for i in xrange(blo, bhi):
4372 for i in xrange(blo, bhi):
4373 yield ('+', b[i])
4373 yield ('+', b[i])
4374 elif tag == 'delete':
4374 elif tag == 'delete':
4375 for i in xrange(alo, ahi):
4375 for i in xrange(alo, ahi):
4376 yield ('-', a[i])
4376 yield ('-', a[i])
4377 elif tag == 'replace':
4377 elif tag == 'replace':
4378 for i in xrange(alo, ahi):
4378 for i in xrange(alo, ahi):
4379 yield ('-', a[i])
4379 yield ('-', a[i])
4380 for i in xrange(blo, bhi):
4380 for i in xrange(blo, bhi):
4381 yield ('+', b[i])
4381 yield ('+', b[i])
4382
4382
4383 def display(fn, ctx, pstates, states):
4383 def display(fn, ctx, pstates, states):
4384 rev = ctx.rev()
4384 rev = ctx.rev()
4385 if ui.quiet:
4385 if ui.quiet:
4386 datefunc = util.shortdate
4386 datefunc = util.shortdate
4387 else:
4387 else:
4388 datefunc = util.datestr
4388 datefunc = util.datestr
4389 found = False
4389 found = False
4390 @util.cachefunc
4390 @util.cachefunc
4391 def binary():
4391 def binary():
4392 flog = getfile(fn)
4392 flog = getfile(fn)
4393 return util.binary(flog.read(ctx.filenode(fn)))
4393 return util.binary(flog.read(ctx.filenode(fn)))
4394
4394
4395 if opts.get('all'):
4395 if opts.get('all'):
4396 iter = difflinestates(pstates, states)
4396 iter = difflinestates(pstates, states)
4397 else:
4397 else:
4398 iter = [('', l) for l in states]
4398 iter = [('', l) for l in states]
4399 for change, l in iter:
4399 for change, l in iter:
4400 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4400 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4401
4401
4402 if opts.get('line_number'):
4402 if opts.get('line_number'):
4403 cols.append((str(l.linenum), 'grep.linenumber'))
4403 cols.append((str(l.linenum), 'grep.linenumber'))
4404 if opts.get('all'):
4404 if opts.get('all'):
4405 cols.append((change, 'grep.change'))
4405 cols.append((change, 'grep.change'))
4406 if opts.get('user'):
4406 if opts.get('user'):
4407 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4407 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4408 if opts.get('date'):
4408 if opts.get('date'):
4409 cols.append((datefunc(ctx.date()), 'grep.date'))
4409 cols.append((datefunc(ctx.date()), 'grep.date'))
4410 for col, label in cols[:-1]:
4410 for col, label in cols[:-1]:
4411 ui.write(col, label=label)
4411 ui.write(col, label=label)
4412 ui.write(sep, label='grep.sep')
4412 ui.write(sep, label='grep.sep')
4413 ui.write(cols[-1][0], label=cols[-1][1])
4413 ui.write(cols[-1][0], label=cols[-1][1])
4414 if not opts.get('files_with_matches'):
4414 if not opts.get('files_with_matches'):
4415 ui.write(sep, label='grep.sep')
4415 ui.write(sep, label='grep.sep')
4416 if not opts.get('text') and binary():
4416 if not opts.get('text') and binary():
4417 ui.write(_(" Binary file matches"))
4417 ui.write(_(" Binary file matches"))
4418 else:
4418 else:
4419 for s, label in l:
4419 for s, label in l:
4420 ui.write(s, label=label)
4420 ui.write(s, label=label)
4421 ui.write(eol)
4421 ui.write(eol)
4422 found = True
4422 found = True
4423 if opts.get('files_with_matches'):
4423 if opts.get('files_with_matches'):
4424 break
4424 break
4425 return found
4425 return found
4426
4426
4427 skip = {}
4427 skip = {}
4428 revfiles = {}
4428 revfiles = {}
4429 matchfn = scmutil.match(repo[None], pats, opts)
4429 matchfn = scmutil.match(repo[None], pats, opts)
4430 found = False
4430 found = False
4431 follow = opts.get('follow')
4431 follow = opts.get('follow')
4432
4432
4433 def prep(ctx, fns):
4433 def prep(ctx, fns):
4434 rev = ctx.rev()
4434 rev = ctx.rev()
4435 pctx = ctx.p1()
4435 pctx = ctx.p1()
4436 parent = pctx.rev()
4436 parent = pctx.rev()
4437 matches.setdefault(rev, {})
4437 matches.setdefault(rev, {})
4438 matches.setdefault(parent, {})
4438 matches.setdefault(parent, {})
4439 files = revfiles.setdefault(rev, [])
4439 files = revfiles.setdefault(rev, [])
4440 for fn in fns:
4440 for fn in fns:
4441 flog = getfile(fn)
4441 flog = getfile(fn)
4442 try:
4442 try:
4443 fnode = ctx.filenode(fn)
4443 fnode = ctx.filenode(fn)
4444 except error.LookupError:
4444 except error.LookupError:
4445 continue
4445 continue
4446
4446
4447 copied = flog.renamed(fnode)
4447 copied = flog.renamed(fnode)
4448 copy = follow and copied and copied[0]
4448 copy = follow and copied and copied[0]
4449 if copy:
4449 if copy:
4450 copies.setdefault(rev, {})[fn] = copy
4450 copies.setdefault(rev, {})[fn] = copy
4451 if fn in skip:
4451 if fn in skip:
4452 if copy:
4452 if copy:
4453 skip[copy] = True
4453 skip[copy] = True
4454 continue
4454 continue
4455 files.append(fn)
4455 files.append(fn)
4456
4456
4457 if fn not in matches[rev]:
4457 if fn not in matches[rev]:
4458 grepbody(fn, rev, flog.read(fnode))
4458 grepbody(fn, rev, flog.read(fnode))
4459
4459
4460 pfn = copy or fn
4460 pfn = copy or fn
4461 if pfn not in matches[parent]:
4461 if pfn not in matches[parent]:
4462 try:
4462 try:
4463 fnode = pctx.filenode(pfn)
4463 fnode = pctx.filenode(pfn)
4464 grepbody(pfn, parent, flog.read(fnode))
4464 grepbody(pfn, parent, flog.read(fnode))
4465 except error.LookupError:
4465 except error.LookupError:
4466 pass
4466 pass
4467
4467
4468 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4468 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4469 rev = ctx.rev()
4469 rev = ctx.rev()
4470 parent = ctx.p1().rev()
4470 parent = ctx.p1().rev()
4471 for fn in sorted(revfiles.get(rev, [])):
4471 for fn in sorted(revfiles.get(rev, [])):
4472 states = matches[rev][fn]
4472 states = matches[rev][fn]
4473 copy = copies.get(rev, {}).get(fn)
4473 copy = copies.get(rev, {}).get(fn)
4474 if fn in skip:
4474 if fn in skip:
4475 if copy:
4475 if copy:
4476 skip[copy] = True
4476 skip[copy] = True
4477 continue
4477 continue
4478 pstates = matches.get(parent, {}).get(copy or fn, [])
4478 pstates = matches.get(parent, {}).get(copy or fn, [])
4479 if pstates or states:
4479 if pstates or states:
4480 r = display(fn, ctx, pstates, states)
4480 r = display(fn, ctx, pstates, states)
4481 found = found or r
4481 found = found or r
4482 if r and not opts.get('all'):
4482 if r and not opts.get('all'):
4483 skip[fn] = True
4483 skip[fn] = True
4484 if copy:
4484 if copy:
4485 skip[copy] = True
4485 skip[copy] = True
4486 del matches[rev]
4486 del matches[rev]
4487 del revfiles[rev]
4487 del revfiles[rev]
4488
4488
4489 return not found
4489 return not found
4490
4490
4491 @command('heads',
4491 @command('heads',
4492 [('r', 'rev', '',
4492 [('r', 'rev', '',
4493 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4493 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4494 ('t', 'topo', False, _('show topological heads only')),
4494 ('t', 'topo', False, _('show topological heads only')),
4495 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4495 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4496 ('c', 'closed', False, _('show normal and closed branch heads')),
4496 ('c', 'closed', False, _('show normal and closed branch heads')),
4497 ] + templateopts,
4497 ] + templateopts,
4498 _('[-ct] [-r STARTREV] [REV]...'))
4498 _('[-ct] [-r STARTREV] [REV]...'))
4499 def heads(ui, repo, *branchrevs, **opts):
4499 def heads(ui, repo, *branchrevs, **opts):
4500 """show branch heads
4500 """show branch heads
4501
4501
4502 With no arguments, show all open branch heads in the repository.
4502 With no arguments, show all open branch heads in the repository.
4503 Branch heads are changesets that have no descendants on the
4503 Branch heads are changesets that have no descendants on the
4504 same branch. They are where development generally takes place and
4504 same branch. They are where development generally takes place and
4505 are the usual targets for update and merge operations.
4505 are the usual targets for update and merge operations.
4506
4506
4507 If one or more REVs are given, only open branch heads on the
4507 If one or more REVs are given, only open branch heads on the
4508 branches associated with the specified changesets are shown. This
4508 branches associated with the specified changesets are shown. This
4509 means that you can use :hg:`heads .` to see the heads on the
4509 means that you can use :hg:`heads .` to see the heads on the
4510 currently checked-out branch.
4510 currently checked-out branch.
4511
4511
4512 If -c/--closed is specified, also show branch heads marked closed
4512 If -c/--closed is specified, also show branch heads marked closed
4513 (see :hg:`commit --close-branch`).
4513 (see :hg:`commit --close-branch`).
4514
4514
4515 If STARTREV is specified, only those heads that are descendants of
4515 If STARTREV is specified, only those heads that are descendants of
4516 STARTREV will be displayed.
4516 STARTREV will be displayed.
4517
4517
4518 If -t/--topo is specified, named branch mechanics will be ignored and only
4518 If -t/--topo is specified, named branch mechanics will be ignored and only
4519 topological heads (changesets with no children) will be shown.
4519 topological heads (changesets with no children) will be shown.
4520
4520
4521 Returns 0 if matching heads are found, 1 if not.
4521 Returns 0 if matching heads are found, 1 if not.
4522 """
4522 """
4523
4523
4524 start = None
4524 start = None
4525 if 'rev' in opts:
4525 if 'rev' in opts:
4526 start = scmutil.revsingle(repo, opts['rev'], None).node()
4526 start = scmutil.revsingle(repo, opts['rev'], None).node()
4527
4527
4528 if opts.get('topo'):
4528 if opts.get('topo'):
4529 heads = [repo[h] for h in repo.heads(start)]
4529 heads = [repo[h] for h in repo.heads(start)]
4530 else:
4530 else:
4531 heads = []
4531 heads = []
4532 for branch in repo.branchmap():
4532 for branch in repo.branchmap():
4533 heads += repo.branchheads(branch, start, opts.get('closed'))
4533 heads += repo.branchheads(branch, start, opts.get('closed'))
4534 heads = [repo[h] for h in heads]
4534 heads = [repo[h] for h in heads]
4535
4535
4536 if branchrevs:
4536 if branchrevs:
4537 branches = set(repo[br].branch() for br in branchrevs)
4537 branches = set(repo[br].branch() for br in branchrevs)
4538 heads = [h for h in heads if h.branch() in branches]
4538 heads = [h for h in heads if h.branch() in branches]
4539
4539
4540 if opts.get('active') and branchrevs:
4540 if opts.get('active') and branchrevs:
4541 dagheads = repo.heads(start)
4541 dagheads = repo.heads(start)
4542 heads = [h for h in heads if h.node() in dagheads]
4542 heads = [h for h in heads if h.node() in dagheads]
4543
4543
4544 if branchrevs:
4544 if branchrevs:
4545 haveheads = set(h.branch() for h in heads)
4545 haveheads = set(h.branch() for h in heads)
4546 if branches - haveheads:
4546 if branches - haveheads:
4547 headless = ', '.join(b for b in branches - haveheads)
4547 headless = ', '.join(b for b in branches - haveheads)
4548 msg = _('no open branch heads found on branches %s')
4548 msg = _('no open branch heads found on branches %s')
4549 if opts.get('rev'):
4549 if opts.get('rev'):
4550 msg += _(' (started at %s)') % opts['rev']
4550 msg += _(' (started at %s)') % opts['rev']
4551 ui.warn((msg + '\n') % headless)
4551 ui.warn((msg + '\n') % headless)
4552
4552
4553 if not heads:
4553 if not heads:
4554 return 1
4554 return 1
4555
4555
4556 heads = sorted(heads, key=lambda x: -x.rev())
4556 heads = sorted(heads, key=lambda x: -x.rev())
4557 displayer = cmdutil.show_changeset(ui, repo, opts)
4557 displayer = cmdutil.show_changeset(ui, repo, opts)
4558 for ctx in heads:
4558 for ctx in heads:
4559 displayer.show(ctx)
4559 displayer.show(ctx)
4560 displayer.close()
4560 displayer.close()
4561
4561
4562 @command('help',
4562 @command('help',
4563 [('e', 'extension', None, _('show only help for extensions')),
4563 [('e', 'extension', None, _('show only help for extensions')),
4564 ('c', 'command', None, _('show only help for commands')),
4564 ('c', 'command', None, _('show only help for commands')),
4565 ('k', 'keyword', None, _('show topics matching keyword')),
4565 ('k', 'keyword', None, _('show topics matching keyword')),
4566 ('s', 'system', [], _('show help for specific platform(s)')),
4566 ('s', 'system', [], _('show help for specific platform(s)')),
4567 ],
4567 ],
4568 _('[-ecks] [TOPIC]'),
4568 _('[-ecks] [TOPIC]'),
4569 norepo=True)
4569 norepo=True)
4570 def help_(ui, name=None, **opts):
4570 def help_(ui, name=None, **opts):
4571 """show help for a given topic or a help overview
4571 """show help for a given topic or a help overview
4572
4572
4573 With no arguments, print a list of commands with short help messages.
4573 With no arguments, print a list of commands with short help messages.
4574
4574
4575 Given a topic, extension, or command name, print help for that
4575 Given a topic, extension, or command name, print help for that
4576 topic.
4576 topic.
4577
4577
4578 Returns 0 if successful.
4578 Returns 0 if successful.
4579 """
4579 """
4580
4580
4581 textwidth = ui.configint('ui', 'textwidth', 78)
4581 textwidth = ui.configint('ui', 'textwidth', 78)
4582 termwidth = ui.termwidth() - 2
4582 termwidth = ui.termwidth() - 2
4583 if textwidth <= 0 or termwidth < textwidth:
4583 if textwidth <= 0 or termwidth < textwidth:
4584 textwidth = termwidth
4584 textwidth = termwidth
4585
4585
4586 keep = opts.get('system') or []
4586 keep = opts.get('system') or []
4587 if len(keep) == 0:
4587 if len(keep) == 0:
4588 if sys.platform.startswith('win'):
4588 if sys.platform.startswith('win'):
4589 keep.append('windows')
4589 keep.append('windows')
4590 elif sys.platform == 'OpenVMS':
4590 elif sys.platform == 'OpenVMS':
4591 keep.append('vms')
4591 keep.append('vms')
4592 elif sys.platform == 'plan9':
4592 elif sys.platform == 'plan9':
4593 keep.append('plan9')
4593 keep.append('plan9')
4594 else:
4594 else:
4595 keep.append('unix')
4595 keep.append('unix')
4596 keep.append(sys.platform.lower())
4596 keep.append(sys.platform.lower())
4597 if ui.verbose:
4597 if ui.verbose:
4598 keep.append('verbose')
4598 keep.append('verbose')
4599
4599
4600 section = None
4600 section = None
4601 subtopic = None
4601 subtopic = None
4602 if name and '.' in name:
4602 if name and '.' in name:
4603 name, section = name.split('.', 1)
4603 name, section = name.split('.', 1)
4604 section = encoding.lower(section)
4604 section = encoding.lower(section)
4605 if '.' in section:
4605 if '.' in section:
4606 subtopic, section = section.split('.', 1)
4606 subtopic, section = section.split('.', 1)
4607 else:
4607 else:
4608 subtopic = section
4608 subtopic = section
4609
4609
4610 text = help.help_(ui, name, subtopic=subtopic, **opts)
4610 text = help.help_(ui, name, subtopic=subtopic, **opts)
4611
4611
4612 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4612 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4613 section=section)
4613 section=section)
4614
4614
4615 # We could have been given a weird ".foo" section without a name
4615 # We could have been given a weird ".foo" section without a name
4616 # to look for, or we could have simply failed to found "foo.bar"
4616 # to look for, or we could have simply failed to found "foo.bar"
4617 # because bar isn't a section of foo
4617 # because bar isn't a section of foo
4618 if section and not (formatted and name):
4618 if section and not (formatted and name):
4619 raise error.Abort(_("help section not found"))
4619 raise error.Abort(_("help section not found"))
4620
4620
4621 if 'verbose' in pruned:
4621 if 'verbose' in pruned:
4622 keep.append('omitted')
4622 keep.append('omitted')
4623 else:
4623 else:
4624 keep.append('notomitted')
4624 keep.append('notomitted')
4625 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4625 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4626 section=section)
4626 section=section)
4627 ui.write(formatted)
4627 ui.write(formatted)
4628
4628
4629
4629
4630 @command('identify|id',
4630 @command('identify|id',
4631 [('r', 'rev', '',
4631 [('r', 'rev', '',
4632 _('identify the specified revision'), _('REV')),
4632 _('identify the specified revision'), _('REV')),
4633 ('n', 'num', None, _('show local revision number')),
4633 ('n', 'num', None, _('show local revision number')),
4634 ('i', 'id', None, _('show global revision id')),
4634 ('i', 'id', None, _('show global revision id')),
4635 ('b', 'branch', None, _('show branch')),
4635 ('b', 'branch', None, _('show branch')),
4636 ('t', 'tags', None, _('show tags')),
4636 ('t', 'tags', None, _('show tags')),
4637 ('B', 'bookmarks', None, _('show bookmarks')),
4637 ('B', 'bookmarks', None, _('show bookmarks')),
4638 ] + remoteopts,
4638 ] + remoteopts,
4639 _('[-nibtB] [-r REV] [SOURCE]'),
4639 _('[-nibtB] [-r REV] [SOURCE]'),
4640 optionalrepo=True)
4640 optionalrepo=True)
4641 def identify(ui, repo, source=None, rev=None,
4641 def identify(ui, repo, source=None, rev=None,
4642 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4642 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4643 """identify the working directory or specified revision
4643 """identify the working directory or specified revision
4644
4644
4645 Print a summary identifying the repository state at REV using one or
4645 Print a summary identifying the repository state at REV using one or
4646 two parent hash identifiers, followed by a "+" if the working
4646 two parent hash identifiers, followed by a "+" if the working
4647 directory has uncommitted changes, the branch name (if not default),
4647 directory has uncommitted changes, the branch name (if not default),
4648 a list of tags, and a list of bookmarks.
4648 a list of tags, and a list of bookmarks.
4649
4649
4650 When REV is not given, print a summary of the current state of the
4650 When REV is not given, print a summary of the current state of the
4651 repository.
4651 repository.
4652
4652
4653 Specifying a path to a repository root or Mercurial bundle will
4653 Specifying a path to a repository root or Mercurial bundle will
4654 cause lookup to operate on that repository/bundle.
4654 cause lookup to operate on that repository/bundle.
4655
4655
4656 .. container:: verbose
4656 .. container:: verbose
4657
4657
4658 Examples:
4658 Examples:
4659
4659
4660 - generate a build identifier for the working directory::
4660 - generate a build identifier for the working directory::
4661
4661
4662 hg id --id > build-id.dat
4662 hg id --id > build-id.dat
4663
4663
4664 - find the revision corresponding to a tag::
4664 - find the revision corresponding to a tag::
4665
4665
4666 hg id -n -r 1.3
4666 hg id -n -r 1.3
4667
4667
4668 - check the most recent revision of a remote repository::
4668 - check the most recent revision of a remote repository::
4669
4669
4670 hg id -r tip http://selenic.com/hg/
4670 hg id -r tip http://selenic.com/hg/
4671
4671
4672 See :hg:`log` for generating more information about specific revisions,
4672 See :hg:`log` for generating more information about specific revisions,
4673 including full hash identifiers.
4673 including full hash identifiers.
4674
4674
4675 Returns 0 if successful.
4675 Returns 0 if successful.
4676 """
4676 """
4677
4677
4678 if not repo and not source:
4678 if not repo and not source:
4679 raise error.Abort(_("there is no Mercurial repository here "
4679 raise error.Abort(_("there is no Mercurial repository here "
4680 "(.hg not found)"))
4680 "(.hg not found)"))
4681
4681
4682 if ui.debugflag:
4682 if ui.debugflag:
4683 hexfunc = hex
4683 hexfunc = hex
4684 else:
4684 else:
4685 hexfunc = short
4685 hexfunc = short
4686 default = not (num or id or branch or tags or bookmarks)
4686 default = not (num or id or branch or tags or bookmarks)
4687 output = []
4687 output = []
4688 revs = []
4688 revs = []
4689
4689
4690 if source:
4690 if source:
4691 source, branches = hg.parseurl(ui.expandpath(source))
4691 source, branches = hg.parseurl(ui.expandpath(source))
4692 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4692 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4693 repo = peer.local()
4693 repo = peer.local()
4694 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4694 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4695
4695
4696 if not repo:
4696 if not repo:
4697 if num or branch or tags:
4697 if num or branch or tags:
4698 raise error.Abort(
4698 raise error.Abort(
4699 _("can't query remote revision number, branch, or tags"))
4699 _("can't query remote revision number, branch, or tags"))
4700 if not rev and revs:
4700 if not rev and revs:
4701 rev = revs[0]
4701 rev = revs[0]
4702 if not rev:
4702 if not rev:
4703 rev = "tip"
4703 rev = "tip"
4704
4704
4705 remoterev = peer.lookup(rev)
4705 remoterev = peer.lookup(rev)
4706 if default or id:
4706 if default or id:
4707 output = [hexfunc(remoterev)]
4707 output = [hexfunc(remoterev)]
4708
4708
4709 def getbms():
4709 def getbms():
4710 bms = []
4710 bms = []
4711
4711
4712 if 'bookmarks' in peer.listkeys('namespaces'):
4712 if 'bookmarks' in peer.listkeys('namespaces'):
4713 hexremoterev = hex(remoterev)
4713 hexremoterev = hex(remoterev)
4714 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4714 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4715 if bmr == hexremoterev]
4715 if bmr == hexremoterev]
4716
4716
4717 return sorted(bms)
4717 return sorted(bms)
4718
4718
4719 if bookmarks:
4719 if bookmarks:
4720 output.extend(getbms())
4720 output.extend(getbms())
4721 elif default and not ui.quiet:
4721 elif default and not ui.quiet:
4722 # multiple bookmarks for a single parent separated by '/'
4722 # multiple bookmarks for a single parent separated by '/'
4723 bm = '/'.join(getbms())
4723 bm = '/'.join(getbms())
4724 if bm:
4724 if bm:
4725 output.append(bm)
4725 output.append(bm)
4726 else:
4726 else:
4727 ctx = scmutil.revsingle(repo, rev, None)
4727 ctx = scmutil.revsingle(repo, rev, None)
4728
4728
4729 if ctx.rev() is None:
4729 if ctx.rev() is None:
4730 ctx = repo[None]
4730 ctx = repo[None]
4731 parents = ctx.parents()
4731 parents = ctx.parents()
4732 taglist = []
4732 taglist = []
4733 for p in parents:
4733 for p in parents:
4734 taglist.extend(p.tags())
4734 taglist.extend(p.tags())
4735
4735
4736 changed = ""
4736 changed = ""
4737 if default or id or num:
4737 if default or id or num:
4738 if (any(repo.status())
4738 if (any(repo.status())
4739 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4739 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4740 changed = '+'
4740 changed = '+'
4741 if default or id:
4741 if default or id:
4742 output = ["%s%s" %
4742 output = ["%s%s" %
4743 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4743 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4744 if num:
4744 if num:
4745 output.append("%s%s" %
4745 output.append("%s%s" %
4746 ('+'.join([str(p.rev()) for p in parents]), changed))
4746 ('+'.join([str(p.rev()) for p in parents]), changed))
4747 else:
4747 else:
4748 if default or id:
4748 if default or id:
4749 output = [hexfunc(ctx.node())]
4749 output = [hexfunc(ctx.node())]
4750 if num:
4750 if num:
4751 output.append(str(ctx.rev()))
4751 output.append(str(ctx.rev()))
4752 taglist = ctx.tags()
4752 taglist = ctx.tags()
4753
4753
4754 if default and not ui.quiet:
4754 if default and not ui.quiet:
4755 b = ctx.branch()
4755 b = ctx.branch()
4756 if b != 'default':
4756 if b != 'default':
4757 output.append("(%s)" % b)
4757 output.append("(%s)" % b)
4758
4758
4759 # multiple tags for a single parent separated by '/'
4759 # multiple tags for a single parent separated by '/'
4760 t = '/'.join(taglist)
4760 t = '/'.join(taglist)
4761 if t:
4761 if t:
4762 output.append(t)
4762 output.append(t)
4763
4763
4764 # multiple bookmarks for a single parent separated by '/'
4764 # multiple bookmarks for a single parent separated by '/'
4765 bm = '/'.join(ctx.bookmarks())
4765 bm = '/'.join(ctx.bookmarks())
4766 if bm:
4766 if bm:
4767 output.append(bm)
4767 output.append(bm)
4768 else:
4768 else:
4769 if branch:
4769 if branch:
4770 output.append(ctx.branch())
4770 output.append(ctx.branch())
4771
4771
4772 if tags:
4772 if tags:
4773 output.extend(taglist)
4773 output.extend(taglist)
4774
4774
4775 if bookmarks:
4775 if bookmarks:
4776 output.extend(ctx.bookmarks())
4776 output.extend(ctx.bookmarks())
4777
4777
4778 ui.write("%s\n" % ' '.join(output))
4778 ui.write("%s\n" % ' '.join(output))
4779
4779
4780 @command('import|patch',
4780 @command('import|patch',
4781 [('p', 'strip', 1,
4781 [('p', 'strip', 1,
4782 _('directory strip option for patch. This has the same '
4782 _('directory strip option for patch. This has the same '
4783 'meaning as the corresponding patch option'), _('NUM')),
4783 'meaning as the corresponding patch option'), _('NUM')),
4784 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4784 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4785 ('e', 'edit', False, _('invoke editor on commit messages')),
4785 ('e', 'edit', False, _('invoke editor on commit messages')),
4786 ('f', 'force', None,
4786 ('f', 'force', None,
4787 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4787 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4788 ('', 'no-commit', None,
4788 ('', 'no-commit', None,
4789 _("don't commit, just update the working directory")),
4789 _("don't commit, just update the working directory")),
4790 ('', 'bypass', None,
4790 ('', 'bypass', None,
4791 _("apply patch without touching the working directory")),
4791 _("apply patch without touching the working directory")),
4792 ('', 'partial', None,
4792 ('', 'partial', None,
4793 _('commit even if some hunks fail')),
4793 _('commit even if some hunks fail')),
4794 ('', 'exact', None,
4794 ('', 'exact', None,
4795 _('abort if patch would apply lossily')),
4795 _('abort if patch would apply lossily')),
4796 ('', 'prefix', '',
4796 ('', 'prefix', '',
4797 _('apply patch to subdirectory'), _('DIR')),
4797 _('apply patch to subdirectory'), _('DIR')),
4798 ('', 'import-branch', None,
4798 ('', 'import-branch', None,
4799 _('use any branch information in patch (implied by --exact)'))] +
4799 _('use any branch information in patch (implied by --exact)'))] +
4800 commitopts + commitopts2 + similarityopts,
4800 commitopts + commitopts2 + similarityopts,
4801 _('[OPTION]... PATCH...'))
4801 _('[OPTION]... PATCH...'))
4802 def import_(ui, repo, patch1=None, *patches, **opts):
4802 def import_(ui, repo, patch1=None, *patches, **opts):
4803 """import an ordered set of patches
4803 """import an ordered set of patches
4804
4804
4805 Import a list of patches and commit them individually (unless
4805 Import a list of patches and commit them individually (unless
4806 --no-commit is specified).
4806 --no-commit is specified).
4807
4807
4808 To read a patch from standard input, use "-" as the patch name. If
4808 To read a patch from standard input, use "-" as the patch name. If
4809 a URL is specified, the patch will be downloaded from there.
4809 a URL is specified, the patch will be downloaded from there.
4810
4810
4811 Import first applies changes to the working directory (unless
4811 Import first applies changes to the working directory (unless
4812 --bypass is specified), import will abort if there are outstanding
4812 --bypass is specified), import will abort if there are outstanding
4813 changes.
4813 changes.
4814
4814
4815 Use --bypass to apply and commit patches directly to the
4815 Use --bypass to apply and commit patches directly to the
4816 repository, without affecting the working directory. Without
4816 repository, without affecting the working directory. Without
4817 --exact, patches will be applied on top of the working directory
4817 --exact, patches will be applied on top of the working directory
4818 parent revision.
4818 parent revision.
4819
4819
4820 You can import a patch straight from a mail message. Even patches
4820 You can import a patch straight from a mail message. Even patches
4821 as attachments work (to use the body part, it must have type
4821 as attachments work (to use the body part, it must have type
4822 text/plain or text/x-patch). From and Subject headers of email
4822 text/plain or text/x-patch). From and Subject headers of email
4823 message are used as default committer and commit message. All
4823 message are used as default committer and commit message. All
4824 text/plain body parts before first diff are added to the commit
4824 text/plain body parts before first diff are added to the commit
4825 message.
4825 message.
4826
4826
4827 If the imported patch was generated by :hg:`export`, user and
4827 If the imported patch was generated by :hg:`export`, user and
4828 description from patch override values from message headers and
4828 description from patch override values from message headers and
4829 body. Values given on command line with -m/--message and -u/--user
4829 body. Values given on command line with -m/--message and -u/--user
4830 override these.
4830 override these.
4831
4831
4832 If --exact is specified, import will set the working directory to
4832 If --exact is specified, import will set the working directory to
4833 the parent of each patch before applying it, and will abort if the
4833 the parent of each patch before applying it, and will abort if the
4834 resulting changeset has a different ID than the one recorded in
4834 resulting changeset has a different ID than the one recorded in
4835 the patch. This will guard against various ways that portable
4835 the patch. This will guard against various ways that portable
4836 patch formats and mail systems might fail to transfer Mercurial
4836 patch formats and mail systems might fail to transfer Mercurial
4837 data or metadata. See ':hg: bundle' for lossless transmission.
4837 data or metadata. See ':hg: bundle' for lossless transmission.
4838
4838
4839 Use --partial to ensure a changeset will be created from the patch
4839 Use --partial to ensure a changeset will be created from the patch
4840 even if some hunks fail to apply. Hunks that fail to apply will be
4840 even if some hunks fail to apply. Hunks that fail to apply will be
4841 written to a <target-file>.rej file. Conflicts can then be resolved
4841 written to a <target-file>.rej file. Conflicts can then be resolved
4842 by hand before :hg:`commit --amend` is run to update the created
4842 by hand before :hg:`commit --amend` is run to update the created
4843 changeset. This flag exists to let people import patches that
4843 changeset. This flag exists to let people import patches that
4844 partially apply without losing the associated metadata (author,
4844 partially apply without losing the associated metadata (author,
4845 date, description, ...).
4845 date, description, ...).
4846
4846
4847 .. note::
4847 .. note::
4848
4848
4849 When no hunks apply cleanly, :hg:`import --partial` will create
4849 When no hunks apply cleanly, :hg:`import --partial` will create
4850 an empty changeset, importing only the patch metadata.
4850 an empty changeset, importing only the patch metadata.
4851
4851
4852 With -s/--similarity, hg will attempt to discover renames and
4852 With -s/--similarity, hg will attempt to discover renames and
4853 copies in the patch in the same way as :hg:`addremove`.
4853 copies in the patch in the same way as :hg:`addremove`.
4854
4854
4855 It is possible to use external patch programs to perform the patch
4855 It is possible to use external patch programs to perform the patch
4856 by setting the ``ui.patch`` configuration option. For the default
4856 by setting the ``ui.patch`` configuration option. For the default
4857 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4857 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4858 See :hg:`help config` for more information about configuration
4858 See :hg:`help config` for more information about configuration
4859 files and how to use these options.
4859 files and how to use these options.
4860
4860
4861 See :hg:`help dates` for a list of formats valid for -d/--date.
4861 See :hg:`help dates` for a list of formats valid for -d/--date.
4862
4862
4863 .. container:: verbose
4863 .. container:: verbose
4864
4864
4865 Examples:
4865 Examples:
4866
4866
4867 - import a traditional patch from a website and detect renames::
4867 - import a traditional patch from a website and detect renames::
4868
4868
4869 hg import -s 80 http://example.com/bugfix.patch
4869 hg import -s 80 http://example.com/bugfix.patch
4870
4870
4871 - import a changeset from an hgweb server::
4871 - import a changeset from an hgweb server::
4872
4872
4873 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4873 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4874
4874
4875 - import all the patches in an Unix-style mbox::
4875 - import all the patches in an Unix-style mbox::
4876
4876
4877 hg import incoming-patches.mbox
4877 hg import incoming-patches.mbox
4878
4878
4879 - attempt to exactly restore an exported changeset (not always
4879 - attempt to exactly restore an exported changeset (not always
4880 possible)::
4880 possible)::
4881
4881
4882 hg import --exact proposed-fix.patch
4882 hg import --exact proposed-fix.patch
4883
4883
4884 - use an external tool to apply a patch which is too fuzzy for
4884 - use an external tool to apply a patch which is too fuzzy for
4885 the default internal tool.
4885 the default internal tool.
4886
4886
4887 hg import --config ui.patch="patch --merge" fuzzy.patch
4887 hg import --config ui.patch="patch --merge" fuzzy.patch
4888
4888
4889 - change the default fuzzing from 2 to a less strict 7
4889 - change the default fuzzing from 2 to a less strict 7
4890
4890
4891 hg import --config ui.fuzz=7 fuzz.patch
4891 hg import --config ui.fuzz=7 fuzz.patch
4892
4892
4893 Returns 0 on success, 1 on partial success (see --partial).
4893 Returns 0 on success, 1 on partial success (see --partial).
4894 """
4894 """
4895
4895
4896 if not patch1:
4896 if not patch1:
4897 raise error.Abort(_('need at least one patch to import'))
4897 raise error.Abort(_('need at least one patch to import'))
4898
4898
4899 patches = (patch1,) + patches
4899 patches = (patch1,) + patches
4900
4900
4901 date = opts.get('date')
4901 date = opts.get('date')
4902 if date:
4902 if date:
4903 opts['date'] = util.parsedate(date)
4903 opts['date'] = util.parsedate(date)
4904
4904
4905 exact = opts.get('exact')
4905 exact = opts.get('exact')
4906 update = not opts.get('bypass')
4906 update = not opts.get('bypass')
4907 if not update and opts.get('no_commit'):
4907 if not update and opts.get('no_commit'):
4908 raise error.Abort(_('cannot use --no-commit with --bypass'))
4908 raise error.Abort(_('cannot use --no-commit with --bypass'))
4909 try:
4909 try:
4910 sim = float(opts.get('similarity') or 0)
4910 sim = float(opts.get('similarity') or 0)
4911 except ValueError:
4911 except ValueError:
4912 raise error.Abort(_('similarity must be a number'))
4912 raise error.Abort(_('similarity must be a number'))
4913 if sim < 0 or sim > 100:
4913 if sim < 0 or sim > 100:
4914 raise error.Abort(_('similarity must be between 0 and 100'))
4914 raise error.Abort(_('similarity must be between 0 and 100'))
4915 if sim and not update:
4915 if sim and not update:
4916 raise error.Abort(_('cannot use --similarity with --bypass'))
4916 raise error.Abort(_('cannot use --similarity with --bypass'))
4917 if exact:
4917 if exact:
4918 if opts.get('edit'):
4918 if opts.get('edit'):
4919 raise error.Abort(_('cannot use --exact with --edit'))
4919 raise error.Abort(_('cannot use --exact with --edit'))
4920 if opts.get('prefix'):
4920 if opts.get('prefix'):
4921 raise error.Abort(_('cannot use --exact with --prefix'))
4921 raise error.Abort(_('cannot use --exact with --prefix'))
4922
4922
4923 base = opts["base"]
4923 base = opts["base"]
4924 wlock = dsguard = lock = tr = None
4924 wlock = dsguard = lock = tr = None
4925 msgs = []
4925 msgs = []
4926 ret = 0
4926 ret = 0
4927
4927
4928
4928
4929 try:
4929 try:
4930 wlock = repo.wlock()
4930 wlock = repo.wlock()
4931
4931
4932 if update:
4932 if update:
4933 cmdutil.checkunfinished(repo)
4933 cmdutil.checkunfinished(repo)
4934 if (exact or not opts.get('force')):
4934 if (exact or not opts.get('force')):
4935 cmdutil.bailifchanged(repo)
4935 cmdutil.bailifchanged(repo)
4936
4936
4937 if not opts.get('no_commit'):
4937 if not opts.get('no_commit'):
4938 lock = repo.lock()
4938 lock = repo.lock()
4939 tr = repo.transaction('import')
4939 tr = repo.transaction('import')
4940 else:
4940 else:
4941 dsguard = cmdutil.dirstateguard(repo, 'import')
4941 dsguard = cmdutil.dirstateguard(repo, 'import')
4942 parents = repo[None].parents()
4942 parents = repo[None].parents()
4943 for patchurl in patches:
4943 for patchurl in patches:
4944 if patchurl == '-':
4944 if patchurl == '-':
4945 ui.status(_('applying patch from stdin\n'))
4945 ui.status(_('applying patch from stdin\n'))
4946 patchfile = ui.fin
4946 patchfile = ui.fin
4947 patchurl = 'stdin' # for error message
4947 patchurl = 'stdin' # for error message
4948 else:
4948 else:
4949 patchurl = os.path.join(base, patchurl)
4949 patchurl = os.path.join(base, patchurl)
4950 ui.status(_('applying %s\n') % patchurl)
4950 ui.status(_('applying %s\n') % patchurl)
4951 patchfile = hg.openpath(ui, patchurl)
4951 patchfile = hg.openpath(ui, patchurl)
4952
4952
4953 haspatch = False
4953 haspatch = False
4954 for hunk in patch.split(patchfile):
4954 for hunk in patch.split(patchfile):
4955 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4955 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4956 parents, opts,
4956 parents, opts,
4957 msgs, hg.clean)
4957 msgs, hg.clean)
4958 if msg:
4958 if msg:
4959 haspatch = True
4959 haspatch = True
4960 ui.note(msg + '\n')
4960 ui.note(msg + '\n')
4961 if update or exact:
4961 if update or exact:
4962 parents = repo[None].parents()
4962 parents = repo[None].parents()
4963 else:
4963 else:
4964 parents = [repo[node]]
4964 parents = [repo[node]]
4965 if rej:
4965 if rej:
4966 ui.write_err(_("patch applied partially\n"))
4966 ui.write_err(_("patch applied partially\n"))
4967 ui.write_err(_("(fix the .rej files and run "
4967 ui.write_err(_("(fix the .rej files and run "
4968 "`hg commit --amend`)\n"))
4968 "`hg commit --amend`)\n"))
4969 ret = 1
4969 ret = 1
4970 break
4970 break
4971
4971
4972 if not haspatch:
4972 if not haspatch:
4973 raise error.Abort(_('%s: no diffs found') % patchurl)
4973 raise error.Abort(_('%s: no diffs found') % patchurl)
4974
4974
4975 if tr:
4975 if tr:
4976 tr.close()
4976 tr.close()
4977 if msgs:
4977 if msgs:
4978 repo.savecommitmessage('\n* * *\n'.join(msgs))
4978 repo.savecommitmessage('\n* * *\n'.join(msgs))
4979 if dsguard:
4979 if dsguard:
4980 dsguard.close()
4980 dsguard.close()
4981 return ret
4981 return ret
4982 finally:
4982 finally:
4983 if tr:
4983 if tr:
4984 tr.release()
4984 tr.release()
4985 release(lock, dsguard, wlock)
4985 release(lock, dsguard, wlock)
4986
4986
4987 @command('incoming|in',
4987 @command('incoming|in',
4988 [('f', 'force', None,
4988 [('f', 'force', None,
4989 _('run even if remote repository is unrelated')),
4989 _('run even if remote repository is unrelated')),
4990 ('n', 'newest-first', None, _('show newest record first')),
4990 ('n', 'newest-first', None, _('show newest record first')),
4991 ('', 'bundle', '',
4991 ('', 'bundle', '',
4992 _('file to store the bundles into'), _('FILE')),
4992 _('file to store the bundles into'), _('FILE')),
4993 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4993 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4994 ('B', 'bookmarks', False, _("compare bookmarks")),
4994 ('B', 'bookmarks', False, _("compare bookmarks")),
4995 ('b', 'branch', [],
4995 ('b', 'branch', [],
4996 _('a specific branch you would like to pull'), _('BRANCH')),
4996 _('a specific branch you would like to pull'), _('BRANCH')),
4997 ] + logopts + remoteopts + subrepoopts,
4997 ] + logopts + remoteopts + subrepoopts,
4998 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4998 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4999 def incoming(ui, repo, source="default", **opts):
4999 def incoming(ui, repo, source="default", **opts):
5000 """show new changesets found in source
5000 """show new changesets found in source
5001
5001
5002 Show new changesets found in the specified path/URL or the default
5002 Show new changesets found in the specified path/URL or the default
5003 pull location. These are the changesets that would have been pulled
5003 pull location. These are the changesets that would have been pulled
5004 if a pull at the time you issued this command.
5004 if a pull at the time you issued this command.
5005
5005
5006 See pull for valid source format details.
5006 See pull for valid source format details.
5007
5007
5008 .. container:: verbose
5008 .. container:: verbose
5009
5009
5010 With -B/--bookmarks, the result of bookmark comparison between
5010 With -B/--bookmarks, the result of bookmark comparison between
5011 local and remote repositories is displayed. With -v/--verbose,
5011 local and remote repositories is displayed. With -v/--verbose,
5012 status is also displayed for each bookmark like below::
5012 status is also displayed for each bookmark like below::
5013
5013
5014 BM1 01234567890a added
5014 BM1 01234567890a added
5015 BM2 1234567890ab advanced
5015 BM2 1234567890ab advanced
5016 BM3 234567890abc diverged
5016 BM3 234567890abc diverged
5017 BM4 34567890abcd changed
5017 BM4 34567890abcd changed
5018
5018
5019 The action taken locally when pulling depends on the
5019 The action taken locally when pulling depends on the
5020 status of each bookmark:
5020 status of each bookmark:
5021
5021
5022 :``added``: pull will create it
5022 :``added``: pull will create it
5023 :``advanced``: pull will update it
5023 :``advanced``: pull will update it
5024 :``diverged``: pull will create a divergent bookmark
5024 :``diverged``: pull will create a divergent bookmark
5025 :``changed``: result depends on remote changesets
5025 :``changed``: result depends on remote changesets
5026
5026
5027 From the point of view of pulling behavior, bookmark
5027 From the point of view of pulling behavior, bookmark
5028 existing only in the remote repository are treated as ``added``,
5028 existing only in the remote repository are treated as ``added``,
5029 even if it is in fact locally deleted.
5029 even if it is in fact locally deleted.
5030
5030
5031 .. container:: verbose
5031 .. container:: verbose
5032
5032
5033 For remote repository, using --bundle avoids downloading the
5033 For remote repository, using --bundle avoids downloading the
5034 changesets twice if the incoming is followed by a pull.
5034 changesets twice if the incoming is followed by a pull.
5035
5035
5036 Examples:
5036 Examples:
5037
5037
5038 - show incoming changes with patches and full description::
5038 - show incoming changes with patches and full description::
5039
5039
5040 hg incoming -vp
5040 hg incoming -vp
5041
5041
5042 - show incoming changes excluding merges, store a bundle::
5042 - show incoming changes excluding merges, store a bundle::
5043
5043
5044 hg in -vpM --bundle incoming.hg
5044 hg in -vpM --bundle incoming.hg
5045 hg pull incoming.hg
5045 hg pull incoming.hg
5046
5046
5047 - briefly list changes inside a bundle::
5047 - briefly list changes inside a bundle::
5048
5048
5049 hg in changes.hg -T "{desc|firstline}\\n"
5049 hg in changes.hg -T "{desc|firstline}\\n"
5050
5050
5051 Returns 0 if there are incoming changes, 1 otherwise.
5051 Returns 0 if there are incoming changes, 1 otherwise.
5052 """
5052 """
5053 if opts.get('graph'):
5053 if opts.get('graph'):
5054 cmdutil.checkunsupportedgraphflags([], opts)
5054 cmdutil.checkunsupportedgraphflags([], opts)
5055 def display(other, chlist, displayer):
5055 def display(other, chlist, displayer):
5056 revdag = cmdutil.graphrevs(other, chlist, opts)
5056 revdag = cmdutil.graphrevs(other, chlist, opts)
5057 cmdutil.displaygraph(ui, repo, revdag, displayer,
5057 cmdutil.displaygraph(ui, repo, revdag, displayer,
5058 graphmod.asciiedges)
5058 graphmod.asciiedges)
5059
5059
5060 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5060 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5061 return 0
5061 return 0
5062
5062
5063 if opts.get('bundle') and opts.get('subrepos'):
5063 if opts.get('bundle') and opts.get('subrepos'):
5064 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5064 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5065
5065
5066 if opts.get('bookmarks'):
5066 if opts.get('bookmarks'):
5067 source, branches = hg.parseurl(ui.expandpath(source),
5067 source, branches = hg.parseurl(ui.expandpath(source),
5068 opts.get('branch'))
5068 opts.get('branch'))
5069 other = hg.peer(repo, opts, source)
5069 other = hg.peer(repo, opts, source)
5070 if 'bookmarks' not in other.listkeys('namespaces'):
5070 if 'bookmarks' not in other.listkeys('namespaces'):
5071 ui.warn(_("remote doesn't support bookmarks\n"))
5071 ui.warn(_("remote doesn't support bookmarks\n"))
5072 return 0
5072 return 0
5073 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5073 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5074 return bookmarks.incoming(ui, repo, other)
5074 return bookmarks.incoming(ui, repo, other)
5075
5075
5076 repo._subtoppath = ui.expandpath(source)
5076 repo._subtoppath = ui.expandpath(source)
5077 try:
5077 try:
5078 return hg.incoming(ui, repo, source, opts)
5078 return hg.incoming(ui, repo, source, opts)
5079 finally:
5079 finally:
5080 del repo._subtoppath
5080 del repo._subtoppath
5081
5081
5082
5082
5083 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5083 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5084 norepo=True)
5084 norepo=True)
5085 def init(ui, dest=".", **opts):
5085 def init(ui, dest=".", **opts):
5086 """create a new repository in the given directory
5086 """create a new repository in the given directory
5087
5087
5088 Initialize a new repository in the given directory. If the given
5088 Initialize a new repository in the given directory. If the given
5089 directory does not exist, it will be created.
5089 directory does not exist, it will be created.
5090
5090
5091 If no directory is given, the current directory is used.
5091 If no directory is given, the current directory is used.
5092
5092
5093 It is possible to specify an ``ssh://`` URL as the destination.
5093 It is possible to specify an ``ssh://`` URL as the destination.
5094 See :hg:`help urls` for more information.
5094 See :hg:`help urls` for more information.
5095
5095
5096 Returns 0 on success.
5096 Returns 0 on success.
5097 """
5097 """
5098 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5098 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5099
5099
5100 @command('locate',
5100 @command('locate',
5101 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5101 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5102 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5102 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5103 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5103 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5104 ] + walkopts,
5104 ] + walkopts,
5105 _('[OPTION]... [PATTERN]...'))
5105 _('[OPTION]... [PATTERN]...'))
5106 def locate(ui, repo, *pats, **opts):
5106 def locate(ui, repo, *pats, **opts):
5107 """locate files matching specific patterns (DEPRECATED)
5107 """locate files matching specific patterns (DEPRECATED)
5108
5108
5109 Print files under Mercurial control in the working directory whose
5109 Print files under Mercurial control in the working directory whose
5110 names match the given patterns.
5110 names match the given patterns.
5111
5111
5112 By default, this command searches all directories in the working
5112 By default, this command searches all directories in the working
5113 directory. To search just the current directory and its
5113 directory. To search just the current directory and its
5114 subdirectories, use "--include .".
5114 subdirectories, use "--include .".
5115
5115
5116 If no patterns are given to match, this command prints the names
5116 If no patterns are given to match, this command prints the names
5117 of all files under Mercurial control in the working directory.
5117 of all files under Mercurial control in the working directory.
5118
5118
5119 If you want to feed the output of this command into the "xargs"
5119 If you want to feed the output of this command into the "xargs"
5120 command, use the -0 option to both this command and "xargs". This
5120 command, use the -0 option to both this command and "xargs". This
5121 will avoid the problem of "xargs" treating single filenames that
5121 will avoid the problem of "xargs" treating single filenames that
5122 contain whitespace as multiple filenames.
5122 contain whitespace as multiple filenames.
5123
5123
5124 See :hg:`help files` for a more versatile command.
5124 See :hg:`help files` for a more versatile command.
5125
5125
5126 Returns 0 if a match is found, 1 otherwise.
5126 Returns 0 if a match is found, 1 otherwise.
5127 """
5127 """
5128 if opts.get('print0'):
5128 if opts.get('print0'):
5129 end = '\0'
5129 end = '\0'
5130 else:
5130 else:
5131 end = '\n'
5131 end = '\n'
5132 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5132 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5133
5133
5134 ret = 1
5134 ret = 1
5135 ctx = repo[rev]
5135 ctx = repo[rev]
5136 m = scmutil.match(ctx, pats, opts, default='relglob',
5136 m = scmutil.match(ctx, pats, opts, default='relglob',
5137 badfn=lambda x, y: False)
5137 badfn=lambda x, y: False)
5138
5138
5139 for abs in ctx.matches(m):
5139 for abs in ctx.matches(m):
5140 if opts.get('fullpath'):
5140 if opts.get('fullpath'):
5141 ui.write(repo.wjoin(abs), end)
5141 ui.write(repo.wjoin(abs), end)
5142 else:
5142 else:
5143 ui.write(((pats and m.rel(abs)) or abs), end)
5143 ui.write(((pats and m.rel(abs)) or abs), end)
5144 ret = 0
5144 ret = 0
5145
5145
5146 return ret
5146 return ret
5147
5147
5148 @command('^log|history',
5148 @command('^log|history',
5149 [('f', 'follow', None,
5149 [('f', 'follow', None,
5150 _('follow changeset history, or file history across copies and renames')),
5150 _('follow changeset history, or file history across copies and renames')),
5151 ('', 'follow-first', None,
5151 ('', 'follow-first', None,
5152 _('only follow the first parent of merge changesets (DEPRECATED)')),
5152 _('only follow the first parent of merge changesets (DEPRECATED)')),
5153 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5153 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5154 ('C', 'copies', None, _('show copied files')),
5154 ('C', 'copies', None, _('show copied files')),
5155 ('k', 'keyword', [],
5155 ('k', 'keyword', [],
5156 _('do case-insensitive search for a given text'), _('TEXT')),
5156 _('do case-insensitive search for a given text'), _('TEXT')),
5157 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5157 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5158 ('', 'removed', None, _('include revisions where files were removed')),
5158 ('', 'removed', None, _('include revisions where files were removed')),
5159 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5159 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5160 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5160 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5161 ('', 'only-branch', [],
5161 ('', 'only-branch', [],
5162 _('show only changesets within the given named branch (DEPRECATED)'),
5162 _('show only changesets within the given named branch (DEPRECATED)'),
5163 _('BRANCH')),
5163 _('BRANCH')),
5164 ('b', 'branch', [],
5164 ('b', 'branch', [],
5165 _('show changesets within the given named branch'), _('BRANCH')),
5165 _('show changesets within the given named branch'), _('BRANCH')),
5166 ('P', 'prune', [],
5166 ('P', 'prune', [],
5167 _('do not display revision or any of its ancestors'), _('REV')),
5167 _('do not display revision or any of its ancestors'), _('REV')),
5168 ] + logopts + walkopts,
5168 ] + logopts + walkopts,
5169 _('[OPTION]... [FILE]'),
5169 _('[OPTION]... [FILE]'),
5170 inferrepo=True)
5170 inferrepo=True)
5171 def log(ui, repo, *pats, **opts):
5171 def log(ui, repo, *pats, **opts):
5172 """show revision history of entire repository or files
5172 """show revision history of entire repository or files
5173
5173
5174 Print the revision history of the specified files or the entire
5174 Print the revision history of the specified files or the entire
5175 project.
5175 project.
5176
5176
5177 If no revision range is specified, the default is ``tip:0`` unless
5177 If no revision range is specified, the default is ``tip:0`` unless
5178 --follow is set, in which case the working directory parent is
5178 --follow is set, in which case the working directory parent is
5179 used as the starting revision.
5179 used as the starting revision.
5180
5180
5181 File history is shown without following rename or copy history of
5181 File history is shown without following rename or copy history of
5182 files. Use -f/--follow with a filename to follow history across
5182 files. Use -f/--follow with a filename to follow history across
5183 renames and copies. --follow without a filename will only show
5183 renames and copies. --follow without a filename will only show
5184 ancestors or descendants of the starting revision.
5184 ancestors or descendants of the starting revision.
5185
5185
5186 By default this command prints revision number and changeset id,
5186 By default this command prints revision number and changeset id,
5187 tags, non-trivial parents, user, date and time, and a summary for
5187 tags, non-trivial parents, user, date and time, and a summary for
5188 each commit. When the -v/--verbose switch is used, the list of
5188 each commit. When the -v/--verbose switch is used, the list of
5189 changed files and full commit message are shown.
5189 changed files and full commit message are shown.
5190
5190
5191 With --graph the revisions are shown as an ASCII art DAG with the most
5191 With --graph the revisions are shown as an ASCII art DAG with the most
5192 recent changeset at the top.
5192 recent changeset at the top.
5193 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5193 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5194 and '+' represents a fork where the changeset from the lines below is a
5194 and '+' represents a fork where the changeset from the lines below is a
5195 parent of the 'o' merge on the same line.
5195 parent of the 'o' merge on the same line.
5196
5196
5197 .. note::
5197 .. note::
5198
5198
5199 :hg:`log --patch` may generate unexpected diff output for merge
5199 :hg:`log --patch` may generate unexpected diff output for merge
5200 changesets, as it will only compare the merge changeset against
5200 changesets, as it will only compare the merge changeset against
5201 its first parent. Also, only files different from BOTH parents
5201 its first parent. Also, only files different from BOTH parents
5202 will appear in files:.
5202 will appear in files:.
5203
5203
5204 .. note::
5204 .. note::
5205
5205
5206 For performance reasons, :hg:`log FILE` may omit duplicate changes
5206 For performance reasons, :hg:`log FILE` may omit duplicate changes
5207 made on branches and will not show removals or mode changes. To
5207 made on branches and will not show removals or mode changes. To
5208 see all such changes, use the --removed switch.
5208 see all such changes, use the --removed switch.
5209
5209
5210 .. container:: verbose
5210 .. container:: verbose
5211
5211
5212 Some examples:
5212 Some examples:
5213
5213
5214 - changesets with full descriptions and file lists::
5214 - changesets with full descriptions and file lists::
5215
5215
5216 hg log -v
5216 hg log -v
5217
5217
5218 - changesets ancestral to the working directory::
5218 - changesets ancestral to the working directory::
5219
5219
5220 hg log -f
5220 hg log -f
5221
5221
5222 - last 10 commits on the current branch::
5222 - last 10 commits on the current branch::
5223
5223
5224 hg log -l 10 -b .
5224 hg log -l 10 -b .
5225
5225
5226 - changesets showing all modifications of a file, including removals::
5226 - changesets showing all modifications of a file, including removals::
5227
5227
5228 hg log --removed file.c
5228 hg log --removed file.c
5229
5229
5230 - all changesets that touch a directory, with diffs, excluding merges::
5230 - all changesets that touch a directory, with diffs, excluding merges::
5231
5231
5232 hg log -Mp lib/
5232 hg log -Mp lib/
5233
5233
5234 - all revision numbers that match a keyword::
5234 - all revision numbers that match a keyword::
5235
5235
5236 hg log -k bug --template "{rev}\\n"
5236 hg log -k bug --template "{rev}\\n"
5237
5237
5238 - the full hash identifier of the working directory parent::
5238 - the full hash identifier of the working directory parent::
5239
5239
5240 hg log -r . --template "{node}\\n"
5240 hg log -r . --template "{node}\\n"
5241
5241
5242 - list available log templates::
5242 - list available log templates::
5243
5243
5244 hg log -T list
5244 hg log -T list
5245
5245
5246 - check if a given changeset is included in a tagged release::
5246 - check if a given changeset is included in a tagged release::
5247
5247
5248 hg log -r "a21ccf and ancestor(1.9)"
5248 hg log -r "a21ccf and ancestor(1.9)"
5249
5249
5250 - find all changesets by some user in a date range::
5250 - find all changesets by some user in a date range::
5251
5251
5252 hg log -k alice -d "may 2008 to jul 2008"
5252 hg log -k alice -d "may 2008 to jul 2008"
5253
5253
5254 - summary of all changesets after the last tag::
5254 - summary of all changesets after the last tag::
5255
5255
5256 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5256 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5257
5257
5258 See :hg:`help dates` for a list of formats valid for -d/--date.
5258 See :hg:`help dates` for a list of formats valid for -d/--date.
5259
5259
5260 See :hg:`help revisions` and :hg:`help revsets` for more about
5260 See :hg:`help revisions` and :hg:`help revsets` for more about
5261 specifying and ordering revisions.
5261 specifying and ordering revisions.
5262
5262
5263 See :hg:`help templates` for more about pre-packaged styles and
5263 See :hg:`help templates` for more about pre-packaged styles and
5264 specifying custom templates.
5264 specifying custom templates.
5265
5265
5266 Returns 0 on success.
5266 Returns 0 on success.
5267
5267
5268 """
5268 """
5269 if opts.get('follow') and opts.get('rev'):
5269 if opts.get('follow') and opts.get('rev'):
5270 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5270 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5271 del opts['follow']
5271 del opts['follow']
5272
5272
5273 if opts.get('graph'):
5273 if opts.get('graph'):
5274 return cmdutil.graphlog(ui, repo, *pats, **opts)
5274 return cmdutil.graphlog(ui, repo, *pats, **opts)
5275
5275
5276 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5276 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5277 limit = cmdutil.loglimit(opts)
5277 limit = cmdutil.loglimit(opts)
5278 count = 0
5278 count = 0
5279
5279
5280 getrenamed = None
5280 getrenamed = None
5281 if opts.get('copies'):
5281 if opts.get('copies'):
5282 endrev = None
5282 endrev = None
5283 if opts.get('rev'):
5283 if opts.get('rev'):
5284 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5284 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5285 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5285 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5286
5286
5287 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5287 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5288 for rev in revs:
5288 for rev in revs:
5289 if count == limit:
5289 if count == limit:
5290 break
5290 break
5291 ctx = repo[rev]
5291 ctx = repo[rev]
5292 copies = None
5292 copies = None
5293 if getrenamed is not None and rev:
5293 if getrenamed is not None and rev:
5294 copies = []
5294 copies = []
5295 for fn in ctx.files():
5295 for fn in ctx.files():
5296 rename = getrenamed(fn, rev)
5296 rename = getrenamed(fn, rev)
5297 if rename:
5297 if rename:
5298 copies.append((fn, rename[0]))
5298 copies.append((fn, rename[0]))
5299 if filematcher:
5299 if filematcher:
5300 revmatchfn = filematcher(ctx.rev())
5300 revmatchfn = filematcher(ctx.rev())
5301 else:
5301 else:
5302 revmatchfn = None
5302 revmatchfn = None
5303 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5303 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5304 if displayer.flush(ctx):
5304 if displayer.flush(ctx):
5305 count += 1
5305 count += 1
5306
5306
5307 displayer.close()
5307 displayer.close()
5308
5308
5309 @command('manifest',
5309 @command('manifest',
5310 [('r', 'rev', '', _('revision to display'), _('REV')),
5310 [('r', 'rev', '', _('revision to display'), _('REV')),
5311 ('', 'all', False, _("list files from all revisions"))]
5311 ('', 'all', False, _("list files from all revisions"))]
5312 + formatteropts,
5312 + formatteropts,
5313 _('[-r REV]'))
5313 _('[-r REV]'))
5314 def manifest(ui, repo, node=None, rev=None, **opts):
5314 def manifest(ui, repo, node=None, rev=None, **opts):
5315 """output the current or given revision of the project manifest
5315 """output the current or given revision of the project manifest
5316
5316
5317 Print a list of version controlled files for the given revision.
5317 Print a list of version controlled files for the given revision.
5318 If no revision is given, the first parent of the working directory
5318 If no revision is given, the first parent of the working directory
5319 is used, or the null revision if no revision is checked out.
5319 is used, or the null revision if no revision is checked out.
5320
5320
5321 With -v, print file permissions, symlink and executable bits.
5321 With -v, print file permissions, symlink and executable bits.
5322 With --debug, print file revision hashes.
5322 With --debug, print file revision hashes.
5323
5323
5324 If option --all is specified, the list of all files from all revisions
5324 If option --all is specified, the list of all files from all revisions
5325 is printed. This includes deleted and renamed files.
5325 is printed. This includes deleted and renamed files.
5326
5326
5327 Returns 0 on success.
5327 Returns 0 on success.
5328 """
5328 """
5329
5329
5330 fm = ui.formatter('manifest', opts)
5330 fm = ui.formatter('manifest', opts)
5331
5331
5332 if opts.get('all'):
5332 if opts.get('all'):
5333 if rev or node:
5333 if rev or node:
5334 raise error.Abort(_("can't specify a revision with --all"))
5334 raise error.Abort(_("can't specify a revision with --all"))
5335
5335
5336 res = []
5336 res = []
5337 prefix = "data/"
5337 prefix = "data/"
5338 suffix = ".i"
5338 suffix = ".i"
5339 plen = len(prefix)
5339 plen = len(prefix)
5340 slen = len(suffix)
5340 slen = len(suffix)
5341 with repo.lock():
5341 with repo.lock():
5342 for fn, b, size in repo.store.datafiles():
5342 for fn, b, size in repo.store.datafiles():
5343 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5343 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5344 res.append(fn[plen:-slen])
5344 res.append(fn[plen:-slen])
5345 for f in res:
5345 for f in res:
5346 fm.startitem()
5346 fm.startitem()
5347 fm.write("path", '%s\n', f)
5347 fm.write("path", '%s\n', f)
5348 fm.end()
5348 fm.end()
5349 return
5349 return
5350
5350
5351 if rev and node:
5351 if rev and node:
5352 raise error.Abort(_("please specify just one revision"))
5352 raise error.Abort(_("please specify just one revision"))
5353
5353
5354 if not node:
5354 if not node:
5355 node = rev
5355 node = rev
5356
5356
5357 char = {'l': '@', 'x': '*', '': ''}
5357 char = {'l': '@', 'x': '*', '': ''}
5358 mode = {'l': '644', 'x': '755', '': '644'}
5358 mode = {'l': '644', 'x': '755', '': '644'}
5359 ctx = scmutil.revsingle(repo, node)
5359 ctx = scmutil.revsingle(repo, node)
5360 mf = ctx.manifest()
5360 mf = ctx.manifest()
5361 for f in ctx:
5361 for f in ctx:
5362 fm.startitem()
5362 fm.startitem()
5363 fl = ctx[f].flags()
5363 fl = ctx[f].flags()
5364 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5364 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5365 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5365 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5366 fm.write('path', '%s\n', f)
5366 fm.write('path', '%s\n', f)
5367 fm.end()
5367 fm.end()
5368
5368
5369 @command('^merge',
5369 @command('^merge',
5370 [('f', 'force', None,
5370 [('f', 'force', None,
5371 _('force a merge including outstanding changes (DEPRECATED)')),
5371 _('force a merge including outstanding changes (DEPRECATED)')),
5372 ('r', 'rev', '', _('revision to merge'), _('REV')),
5372 ('r', 'rev', '', _('revision to merge'), _('REV')),
5373 ('P', 'preview', None,
5373 ('P', 'preview', None,
5374 _('review revisions to merge (no merge is performed)'))
5374 _('review revisions to merge (no merge is performed)'))
5375 ] + mergetoolopts,
5375 ] + mergetoolopts,
5376 _('[-P] [[-r] REV]'))
5376 _('[-P] [[-r] REV]'))
5377 def merge(ui, repo, node=None, **opts):
5377 def merge(ui, repo, node=None, **opts):
5378 """merge another revision into working directory
5378 """merge another revision into working directory
5379
5379
5380 The current working directory is updated with all changes made in
5380 The current working directory is updated with all changes made in
5381 the requested revision since the last common predecessor revision.
5381 the requested revision since the last common predecessor revision.
5382
5382
5383 Files that changed between either parent are marked as changed for
5383 Files that changed between either parent are marked as changed for
5384 the next commit and a commit must be performed before any further
5384 the next commit and a commit must be performed before any further
5385 updates to the repository are allowed. The next commit will have
5385 updates to the repository are allowed. The next commit will have
5386 two parents.
5386 two parents.
5387
5387
5388 ``--tool`` can be used to specify the merge tool used for file
5388 ``--tool`` can be used to specify the merge tool used for file
5389 merges. It overrides the HGMERGE environment variable and your
5389 merges. It overrides the HGMERGE environment variable and your
5390 configuration files. See :hg:`help merge-tools` for options.
5390 configuration files. See :hg:`help merge-tools` for options.
5391
5391
5392 If no revision is specified, the working directory's parent is a
5392 If no revision is specified, the working directory's parent is a
5393 head revision, and the current branch contains exactly one other
5393 head revision, and the current branch contains exactly one other
5394 head, the other head is merged with by default. Otherwise, an
5394 head, the other head is merged with by default. Otherwise, an
5395 explicit revision with which to merge with must be provided.
5395 explicit revision with which to merge with must be provided.
5396
5396
5397 See :hg:`help resolve` for information on handling file conflicts.
5397 See :hg:`help resolve` for information on handling file conflicts.
5398
5398
5399 To undo an uncommitted merge, use :hg:`update --clean .` which
5399 To undo an uncommitted merge, use :hg:`update --clean .` which
5400 will check out a clean copy of the original merge parent, losing
5400 will check out a clean copy of the original merge parent, losing
5401 all changes.
5401 all changes.
5402
5402
5403 Returns 0 on success, 1 if there are unresolved files.
5403 Returns 0 on success, 1 if there are unresolved files.
5404 """
5404 """
5405
5405
5406 if opts.get('rev') and node:
5406 if opts.get('rev') and node:
5407 raise error.Abort(_("please specify just one revision"))
5407 raise error.Abort(_("please specify just one revision"))
5408 if not node:
5408 if not node:
5409 node = opts.get('rev')
5409 node = opts.get('rev')
5410
5410
5411 if node:
5411 if node:
5412 node = scmutil.revsingle(repo, node).node()
5412 node = scmutil.revsingle(repo, node).node()
5413
5413
5414 if not node:
5414 if not node:
5415 node = repo[destutil.destmerge(repo)].node()
5415 node = repo[destutil.destmerge(repo)].node()
5416
5416
5417 if opts.get('preview'):
5417 if opts.get('preview'):
5418 # find nodes that are ancestors of p2 but not of p1
5418 # find nodes that are ancestors of p2 but not of p1
5419 p1 = repo.lookup('.')
5419 p1 = repo.lookup('.')
5420 p2 = repo.lookup(node)
5420 p2 = repo.lookup(node)
5421 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5421 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5422
5422
5423 displayer = cmdutil.show_changeset(ui, repo, opts)
5423 displayer = cmdutil.show_changeset(ui, repo, opts)
5424 for node in nodes:
5424 for node in nodes:
5425 displayer.show(repo[node])
5425 displayer.show(repo[node])
5426 displayer.close()
5426 displayer.close()
5427 return 0
5427 return 0
5428
5428
5429 try:
5429 try:
5430 # ui.forcemerge is an internal variable, do not document
5430 # ui.forcemerge is an internal variable, do not document
5431 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5431 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5432 force = opts.get('force')
5432 force = opts.get('force')
5433 return hg.merge(repo, node, force=force, mergeforce=force)
5433 return hg.merge(repo, node, force=force, mergeforce=force)
5434 finally:
5434 finally:
5435 ui.setconfig('ui', 'forcemerge', '', 'merge')
5435 ui.setconfig('ui', 'forcemerge', '', 'merge')
5436
5436
5437 @command('outgoing|out',
5437 @command('outgoing|out',
5438 [('f', 'force', None, _('run even when the destination is unrelated')),
5438 [('f', 'force', None, _('run even when the destination is unrelated')),
5439 ('r', 'rev', [],
5439 ('r', 'rev', [],
5440 _('a changeset intended to be included in the destination'), _('REV')),
5440 _('a changeset intended to be included in the destination'), _('REV')),
5441 ('n', 'newest-first', None, _('show newest record first')),
5441 ('n', 'newest-first', None, _('show newest record first')),
5442 ('B', 'bookmarks', False, _('compare bookmarks')),
5442 ('B', 'bookmarks', False, _('compare bookmarks')),
5443 ('b', 'branch', [], _('a specific branch you would like to push'),
5443 ('b', 'branch', [], _('a specific branch you would like to push'),
5444 _('BRANCH')),
5444 _('BRANCH')),
5445 ] + logopts + remoteopts + subrepoopts,
5445 ] + logopts + remoteopts + subrepoopts,
5446 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5446 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5447 def outgoing(ui, repo, dest=None, **opts):
5447 def outgoing(ui, repo, dest=None, **opts):
5448 """show changesets not found in the destination
5448 """show changesets not found in the destination
5449
5449
5450 Show changesets not found in the specified destination repository
5450 Show changesets not found in the specified destination repository
5451 or the default push location. These are the changesets that would
5451 or the default push location. These are the changesets that would
5452 be pushed if a push was requested.
5452 be pushed if a push was requested.
5453
5453
5454 See pull for details of valid destination formats.
5454 See pull for details of valid destination formats.
5455
5455
5456 .. container:: verbose
5456 .. container:: verbose
5457
5457
5458 With -B/--bookmarks, the result of bookmark comparison between
5458 With -B/--bookmarks, the result of bookmark comparison between
5459 local and remote repositories is displayed. With -v/--verbose,
5459 local and remote repositories is displayed. With -v/--verbose,
5460 status is also displayed for each bookmark like below::
5460 status is also displayed for each bookmark like below::
5461
5461
5462 BM1 01234567890a added
5462 BM1 01234567890a added
5463 BM2 deleted
5463 BM2 deleted
5464 BM3 234567890abc advanced
5464 BM3 234567890abc advanced
5465 BM4 34567890abcd diverged
5465 BM4 34567890abcd diverged
5466 BM5 4567890abcde changed
5466 BM5 4567890abcde changed
5467
5467
5468 The action taken when pushing depends on the
5468 The action taken when pushing depends on the
5469 status of each bookmark:
5469 status of each bookmark:
5470
5470
5471 :``added``: push with ``-B`` will create it
5471 :``added``: push with ``-B`` will create it
5472 :``deleted``: push with ``-B`` will delete it
5472 :``deleted``: push with ``-B`` will delete it
5473 :``advanced``: push will update it
5473 :``advanced``: push will update it
5474 :``diverged``: push with ``-B`` will update it
5474 :``diverged``: push with ``-B`` will update it
5475 :``changed``: push with ``-B`` will update it
5475 :``changed``: push with ``-B`` will update it
5476
5476
5477 From the point of view of pushing behavior, bookmarks
5477 From the point of view of pushing behavior, bookmarks
5478 existing only in the remote repository are treated as
5478 existing only in the remote repository are treated as
5479 ``deleted``, even if it is in fact added remotely.
5479 ``deleted``, even if it is in fact added remotely.
5480
5480
5481 Returns 0 if there are outgoing changes, 1 otherwise.
5481 Returns 0 if there are outgoing changes, 1 otherwise.
5482 """
5482 """
5483 if opts.get('graph'):
5483 if opts.get('graph'):
5484 cmdutil.checkunsupportedgraphflags([], opts)
5484 cmdutil.checkunsupportedgraphflags([], opts)
5485 o, other = hg._outgoing(ui, repo, dest, opts)
5485 o, other = hg._outgoing(ui, repo, dest, opts)
5486 if not o:
5486 if not o:
5487 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5487 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5488 return
5488 return
5489
5489
5490 revdag = cmdutil.graphrevs(repo, o, opts)
5490 revdag = cmdutil.graphrevs(repo, o, opts)
5491 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5491 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5492 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5492 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5493 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5493 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5494 return 0
5494 return 0
5495
5495
5496 if opts.get('bookmarks'):
5496 if opts.get('bookmarks'):
5497 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5497 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5498 dest, branches = hg.parseurl(dest, opts.get('branch'))
5498 dest, branches = hg.parseurl(dest, opts.get('branch'))
5499 other = hg.peer(repo, opts, dest)
5499 other = hg.peer(repo, opts, dest)
5500 if 'bookmarks' not in other.listkeys('namespaces'):
5500 if 'bookmarks' not in other.listkeys('namespaces'):
5501 ui.warn(_("remote doesn't support bookmarks\n"))
5501 ui.warn(_("remote doesn't support bookmarks\n"))
5502 return 0
5502 return 0
5503 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5503 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5504 return bookmarks.outgoing(ui, repo, other)
5504 return bookmarks.outgoing(ui, repo, other)
5505
5505
5506 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5506 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5507 try:
5507 try:
5508 return hg.outgoing(ui, repo, dest, opts)
5508 return hg.outgoing(ui, repo, dest, opts)
5509 finally:
5509 finally:
5510 del repo._subtoppath
5510 del repo._subtoppath
5511
5511
5512 @command('parents',
5512 @command('parents',
5513 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5513 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5514 ] + templateopts,
5514 ] + templateopts,
5515 _('[-r REV] [FILE]'),
5515 _('[-r REV] [FILE]'),
5516 inferrepo=True)
5516 inferrepo=True)
5517 def parents(ui, repo, file_=None, **opts):
5517 def parents(ui, repo, file_=None, **opts):
5518 """show the parents of the working directory or revision (DEPRECATED)
5518 """show the parents of the working directory or revision (DEPRECATED)
5519
5519
5520 Print the working directory's parent revisions. If a revision is
5520 Print the working directory's parent revisions. If a revision is
5521 given via -r/--rev, the parent of that revision will be printed.
5521 given via -r/--rev, the parent of that revision will be printed.
5522 If a file argument is given, the revision in which the file was
5522 If a file argument is given, the revision in which the file was
5523 last changed (before the working directory revision or the
5523 last changed (before the working directory revision or the
5524 argument to --rev if given) is printed.
5524 argument to --rev if given) is printed.
5525
5525
5526 This command is equivalent to::
5526 This command is equivalent to::
5527
5527
5528 hg log -r "p1()+p2()" or
5528 hg log -r "p1()+p2()" or
5529 hg log -r "p1(REV)+p2(REV)" or
5529 hg log -r "p1(REV)+p2(REV)" or
5530 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5530 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5531 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5531 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5532
5532
5533 See :hg:`summary` and :hg:`help revsets` for related information.
5533 See :hg:`summary` and :hg:`help revsets` for related information.
5534
5534
5535 Returns 0 on success.
5535 Returns 0 on success.
5536 """
5536 """
5537
5537
5538 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5538 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5539
5539
5540 if file_:
5540 if file_:
5541 m = scmutil.match(ctx, (file_,), opts)
5541 m = scmutil.match(ctx, (file_,), opts)
5542 if m.anypats() or len(m.files()) != 1:
5542 if m.anypats() or len(m.files()) != 1:
5543 raise error.Abort(_('can only specify an explicit filename'))
5543 raise error.Abort(_('can only specify an explicit filename'))
5544 file_ = m.files()[0]
5544 file_ = m.files()[0]
5545 filenodes = []
5545 filenodes = []
5546 for cp in ctx.parents():
5546 for cp in ctx.parents():
5547 if not cp:
5547 if not cp:
5548 continue
5548 continue
5549 try:
5549 try:
5550 filenodes.append(cp.filenode(file_))
5550 filenodes.append(cp.filenode(file_))
5551 except error.LookupError:
5551 except error.LookupError:
5552 pass
5552 pass
5553 if not filenodes:
5553 if not filenodes:
5554 raise error.Abort(_("'%s' not found in manifest!") % file_)
5554 raise error.Abort(_("'%s' not found in manifest!") % file_)
5555 p = []
5555 p = []
5556 for fn in filenodes:
5556 for fn in filenodes:
5557 fctx = repo.filectx(file_, fileid=fn)
5557 fctx = repo.filectx(file_, fileid=fn)
5558 p.append(fctx.node())
5558 p.append(fctx.node())
5559 else:
5559 else:
5560 p = [cp.node() for cp in ctx.parents()]
5560 p = [cp.node() for cp in ctx.parents()]
5561
5561
5562 displayer = cmdutil.show_changeset(ui, repo, opts)
5562 displayer = cmdutil.show_changeset(ui, repo, opts)
5563 for n in p:
5563 for n in p:
5564 if n != nullid:
5564 if n != nullid:
5565 displayer.show(repo[n])
5565 displayer.show(repo[n])
5566 displayer.close()
5566 displayer.close()
5567
5567
5568 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5568 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5569 def paths(ui, repo, search=None, **opts):
5569 def paths(ui, repo, search=None, **opts):
5570 """show aliases for remote repositories
5570 """show aliases for remote repositories
5571
5571
5572 Show definition of symbolic path name NAME. If no name is given,
5572 Show definition of symbolic path name NAME. If no name is given,
5573 show definition of all available names.
5573 show definition of all available names.
5574
5574
5575 Option -q/--quiet suppresses all output when searching for NAME
5575 Option -q/--quiet suppresses all output when searching for NAME
5576 and shows only the path names when listing all definitions.
5576 and shows only the path names when listing all definitions.
5577
5577
5578 Path names are defined in the [paths] section of your
5578 Path names are defined in the [paths] section of your
5579 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5579 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5580 repository, ``.hg/hgrc`` is used, too.
5580 repository, ``.hg/hgrc`` is used, too.
5581
5581
5582 The path names ``default`` and ``default-push`` have a special
5582 The path names ``default`` and ``default-push`` have a special
5583 meaning. When performing a push or pull operation, they are used
5583 meaning. When performing a push or pull operation, they are used
5584 as fallbacks if no location is specified on the command-line.
5584 as fallbacks if no location is specified on the command-line.
5585 When ``default-push`` is set, it will be used for push and
5585 When ``default-push`` is set, it will be used for push and
5586 ``default`` will be used for pull; otherwise ``default`` is used
5586 ``default`` will be used for pull; otherwise ``default`` is used
5587 as the fallback for both. When cloning a repository, the clone
5587 as the fallback for both. When cloning a repository, the clone
5588 source is written as ``default`` in ``.hg/hgrc``.
5588 source is written as ``default`` in ``.hg/hgrc``.
5589
5589
5590 .. note::
5590 .. note::
5591
5591
5592 ``default`` and ``default-push`` apply to all inbound (e.g.
5592 ``default`` and ``default-push`` apply to all inbound (e.g.
5593 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5593 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5594 and :hg:`bundle`) operations.
5594 and :hg:`bundle`) operations.
5595
5595
5596 See :hg:`help urls` for more information.
5596 See :hg:`help urls` for more information.
5597
5597
5598 Returns 0 on success.
5598 Returns 0 on success.
5599 """
5599 """
5600 if search:
5600 if search:
5601 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5601 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5602 if name == search]
5602 if name == search]
5603 else:
5603 else:
5604 pathitems = sorted(ui.paths.iteritems())
5604 pathitems = sorted(ui.paths.iteritems())
5605
5605
5606 fm = ui.formatter('paths', opts)
5606 fm = ui.formatter('paths', opts)
5607 if fm:
5607 if fm:
5608 hidepassword = str
5608 hidepassword = str
5609 else:
5609 else:
5610 hidepassword = util.hidepassword
5610 hidepassword = util.hidepassword
5611 if ui.quiet:
5611 if ui.quiet:
5612 namefmt = '%s\n'
5612 namefmt = '%s\n'
5613 else:
5613 else:
5614 namefmt = '%s = '
5614 namefmt = '%s = '
5615 showsubopts = not search and not ui.quiet
5615 showsubopts = not search and not ui.quiet
5616
5616
5617 for name, path in pathitems:
5617 for name, path in pathitems:
5618 fm.startitem()
5618 fm.startitem()
5619 fm.condwrite(not search, 'name', namefmt, name)
5619 fm.condwrite(not search, 'name', namefmt, name)
5620 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5620 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5621 for subopt, value in sorted(path.suboptions.items()):
5621 for subopt, value in sorted(path.suboptions.items()):
5622 assert subopt not in ('name', 'url')
5622 assert subopt not in ('name', 'url')
5623 if showsubopts:
5623 if showsubopts:
5624 fm.plain('%s:%s = ' % (name, subopt))
5624 fm.plain('%s:%s = ' % (name, subopt))
5625 fm.condwrite(showsubopts, subopt, '%s\n', value)
5625 fm.condwrite(showsubopts, subopt, '%s\n', value)
5626
5626
5627 fm.end()
5627 fm.end()
5628
5628
5629 if search and not pathitems:
5629 if search and not pathitems:
5630 if not ui.quiet:
5630 if not ui.quiet:
5631 ui.warn(_("not found!\n"))
5631 ui.warn(_("not found!\n"))
5632 return 1
5632 return 1
5633 else:
5633 else:
5634 return 0
5634 return 0
5635
5635
5636 @command('phase',
5636 @command('phase',
5637 [('p', 'public', False, _('set changeset phase to public')),
5637 [('p', 'public', False, _('set changeset phase to public')),
5638 ('d', 'draft', False, _('set changeset phase to draft')),
5638 ('d', 'draft', False, _('set changeset phase to draft')),
5639 ('s', 'secret', False, _('set changeset phase to secret')),
5639 ('s', 'secret', False, _('set changeset phase to secret')),
5640 ('f', 'force', False, _('allow to move boundary backward')),
5640 ('f', 'force', False, _('allow to move boundary backward')),
5641 ('r', 'rev', [], _('target revision'), _('REV')),
5641 ('r', 'rev', [], _('target revision'), _('REV')),
5642 ],
5642 ],
5643 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5643 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5644 def phase(ui, repo, *revs, **opts):
5644 def phase(ui, repo, *revs, **opts):
5645 """set or show the current phase name
5645 """set or show the current phase name
5646
5646
5647 With no argument, show the phase name of the current revision(s).
5647 With no argument, show the phase name of the current revision(s).
5648
5648
5649 With one of -p/--public, -d/--draft or -s/--secret, change the
5649 With one of -p/--public, -d/--draft or -s/--secret, change the
5650 phase value of the specified revisions.
5650 phase value of the specified revisions.
5651
5651
5652 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5652 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5653 lower phase to an higher phase. Phases are ordered as follows::
5653 lower phase to an higher phase. Phases are ordered as follows::
5654
5654
5655 public < draft < secret
5655 public < draft < secret
5656
5656
5657 Returns 0 on success, 1 if some phases could not be changed.
5657 Returns 0 on success, 1 if some phases could not be changed.
5658
5658
5659 (For more information about the phases concept, see :hg:`help phases`.)
5659 (For more information about the phases concept, see :hg:`help phases`.)
5660 """
5660 """
5661 # search for a unique phase argument
5661 # search for a unique phase argument
5662 targetphase = None
5662 targetphase = None
5663 for idx, name in enumerate(phases.phasenames):
5663 for idx, name in enumerate(phases.phasenames):
5664 if opts[name]:
5664 if opts[name]:
5665 if targetphase is not None:
5665 if targetphase is not None:
5666 raise error.Abort(_('only one phase can be specified'))
5666 raise error.Abort(_('only one phase can be specified'))
5667 targetphase = idx
5667 targetphase = idx
5668
5668
5669 # look for specified revision
5669 # look for specified revision
5670 revs = list(revs)
5670 revs = list(revs)
5671 revs.extend(opts['rev'])
5671 revs.extend(opts['rev'])
5672 if not revs:
5672 if not revs:
5673 # display both parents as the second parent phase can influence
5673 # display both parents as the second parent phase can influence
5674 # the phase of a merge commit
5674 # the phase of a merge commit
5675 revs = [c.rev() for c in repo[None].parents()]
5675 revs = [c.rev() for c in repo[None].parents()]
5676
5676
5677 revs = scmutil.revrange(repo, revs)
5677 revs = scmutil.revrange(repo, revs)
5678
5678
5679 lock = None
5679 lock = None
5680 ret = 0
5680 ret = 0
5681 if targetphase is None:
5681 if targetphase is None:
5682 # display
5682 # display
5683 for r in revs:
5683 for r in revs:
5684 ctx = repo[r]
5684 ctx = repo[r]
5685 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5685 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5686 else:
5686 else:
5687 tr = None
5687 tr = None
5688 lock = repo.lock()
5688 lock = repo.lock()
5689 try:
5689 try:
5690 tr = repo.transaction("phase")
5690 tr = repo.transaction("phase")
5691 # set phase
5691 # set phase
5692 if not revs:
5692 if not revs:
5693 raise error.Abort(_('empty revision set'))
5693 raise error.Abort(_('empty revision set'))
5694 nodes = [repo[r].node() for r in revs]
5694 nodes = [repo[r].node() for r in revs]
5695 # moving revision from public to draft may hide them
5695 # moving revision from public to draft may hide them
5696 # We have to check result on an unfiltered repository
5696 # We have to check result on an unfiltered repository
5697 unfi = repo.unfiltered()
5697 unfi = repo.unfiltered()
5698 getphase = unfi._phasecache.phase
5698 getphase = unfi._phasecache.phase
5699 olddata = [getphase(unfi, r) for r in unfi]
5699 olddata = [getphase(unfi, r) for r in unfi]
5700 phases.advanceboundary(repo, tr, targetphase, nodes)
5700 phases.advanceboundary(repo, tr, targetphase, nodes)
5701 if opts['force']:
5701 if opts['force']:
5702 phases.retractboundary(repo, tr, targetphase, nodes)
5702 phases.retractboundary(repo, tr, targetphase, nodes)
5703 tr.close()
5703 tr.close()
5704 finally:
5704 finally:
5705 if tr is not None:
5705 if tr is not None:
5706 tr.release()
5706 tr.release()
5707 lock.release()
5707 lock.release()
5708 getphase = unfi._phasecache.phase
5708 getphase = unfi._phasecache.phase
5709 newdata = [getphase(unfi, r) for r in unfi]
5709 newdata = [getphase(unfi, r) for r in unfi]
5710 changes = sum(newdata[r] != olddata[r] for r in unfi)
5710 changes = sum(newdata[r] != olddata[r] for r in unfi)
5711 cl = unfi.changelog
5711 cl = unfi.changelog
5712 rejected = [n for n in nodes
5712 rejected = [n for n in nodes
5713 if newdata[cl.rev(n)] < targetphase]
5713 if newdata[cl.rev(n)] < targetphase]
5714 if rejected:
5714 if rejected:
5715 ui.warn(_('cannot move %i changesets to a higher '
5715 ui.warn(_('cannot move %i changesets to a higher '
5716 'phase, use --force\n') % len(rejected))
5716 'phase, use --force\n') % len(rejected))
5717 ret = 1
5717 ret = 1
5718 if changes:
5718 if changes:
5719 msg = _('phase changed for %i changesets\n') % changes
5719 msg = _('phase changed for %i changesets\n') % changes
5720 if ret:
5720 if ret:
5721 ui.status(msg)
5721 ui.status(msg)
5722 else:
5722 else:
5723 ui.note(msg)
5723 ui.note(msg)
5724 else:
5724 else:
5725 ui.warn(_('no phases changed\n'))
5725 ui.warn(_('no phases changed\n'))
5726 return ret
5726 return ret
5727
5727
5728 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5728 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5729 """Run after a changegroup has been added via pull/unbundle
5729 """Run after a changegroup has been added via pull/unbundle
5730
5730
5731 This takes arguments below:
5731 This takes arguments below:
5732
5732
5733 :modheads: change of heads by pull/unbundle
5733 :modheads: change of heads by pull/unbundle
5734 :optupdate: updating working directory is needed or not
5734 :optupdate: updating working directory is needed or not
5735 :checkout: update destination revision (or None to default destination)
5735 :checkout: update destination revision (or None to default destination)
5736 :brev: a name, which might be a bookmark to be activated after updating
5736 :brev: a name, which might be a bookmark to be activated after updating
5737 """
5737 """
5738 if modheads == 0:
5738 if modheads == 0:
5739 return
5739 return
5740 if optupdate:
5740 if optupdate:
5741 try:
5741 try:
5742 return hg.updatetotally(ui, repo, checkout, brev)
5742 return hg.updatetotally(ui, repo, checkout, brev)
5743 except error.UpdateAbort as inst:
5743 except error.UpdateAbort as inst:
5744 msg = _("not updating: %s") % str(inst)
5744 msg = _("not updating: %s") % str(inst)
5745 hint = inst.hint
5745 hint = inst.hint
5746 raise error.UpdateAbort(msg, hint=hint)
5746 raise error.UpdateAbort(msg, hint=hint)
5747 if modheads > 1:
5747 if modheads > 1:
5748 currentbranchheads = len(repo.branchheads())
5748 currentbranchheads = len(repo.branchheads())
5749 if currentbranchheads == modheads:
5749 if currentbranchheads == modheads:
5750 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5750 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5751 elif currentbranchheads > 1:
5751 elif currentbranchheads > 1:
5752 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5752 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5753 "merge)\n"))
5753 "merge)\n"))
5754 else:
5754 else:
5755 ui.status(_("(run 'hg heads' to see heads)\n"))
5755 ui.status(_("(run 'hg heads' to see heads)\n"))
5756 else:
5756 else:
5757 ui.status(_("(run 'hg update' to get a working copy)\n"))
5757 ui.status(_("(run 'hg update' to get a working copy)\n"))
5758
5758
5759 @command('^pull',
5759 @command('^pull',
5760 [('u', 'update', None,
5760 [('u', 'update', None,
5761 _('update to new branch head if changesets were pulled')),
5761 _('update to new branch head if changesets were pulled')),
5762 ('f', 'force', None, _('run even when remote repository is unrelated')),
5762 ('f', 'force', None, _('run even when remote repository is unrelated')),
5763 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5763 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5764 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5764 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5765 ('b', 'branch', [], _('a specific branch you would like to pull'),
5765 ('b', 'branch', [], _('a specific branch you would like to pull'),
5766 _('BRANCH')),
5766 _('BRANCH')),
5767 ] + remoteopts,
5767 ] + remoteopts,
5768 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5768 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5769 def pull(ui, repo, source="default", **opts):
5769 def pull(ui, repo, source="default", **opts):
5770 """pull changes from the specified source
5770 """pull changes from the specified source
5771
5771
5772 Pull changes from a remote repository to a local one.
5772 Pull changes from a remote repository to a local one.
5773
5773
5774 This finds all changes from the repository at the specified path
5774 This finds all changes from the repository at the specified path
5775 or URL and adds them to a local repository (the current one unless
5775 or URL and adds them to a local repository (the current one unless
5776 -R is specified). By default, this does not update the copy of the
5776 -R is specified). By default, this does not update the copy of the
5777 project in the working directory.
5777 project in the working directory.
5778
5778
5779 Use :hg:`incoming` if you want to see what would have been added
5779 Use :hg:`incoming` if you want to see what would have been added
5780 by a pull at the time you issued this command. If you then decide
5780 by a pull at the time you issued this command. If you then decide
5781 to add those changes to the repository, you should use :hg:`pull
5781 to add those changes to the repository, you should use :hg:`pull
5782 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5782 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5783
5783
5784 If SOURCE is omitted, the 'default' path will be used.
5784 If SOURCE is omitted, the 'default' path will be used.
5785 See :hg:`help urls` for more information.
5785 See :hg:`help urls` for more information.
5786
5786
5787 Specifying bookmark as ``.`` is equivalent to specifying the active
5788 bookmark's name.
5789
5787 Returns 0 on success, 1 if an update had unresolved files.
5790 Returns 0 on success, 1 if an update had unresolved files.
5788 """
5791 """
5789 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5792 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5790 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5793 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5791 other = hg.peer(repo, opts, source)
5794 other = hg.peer(repo, opts, source)
5792 try:
5795 try:
5793 revs, checkout = hg.addbranchrevs(repo, other, branches,
5796 revs, checkout = hg.addbranchrevs(repo, other, branches,
5794 opts.get('rev'))
5797 opts.get('rev'))
5795
5798
5796
5799
5797 pullopargs = {}
5800 pullopargs = {}
5798 if opts.get('bookmark'):
5801 if opts.get('bookmark'):
5799 if not revs:
5802 if not revs:
5800 revs = []
5803 revs = []
5801 # The list of bookmark used here is not the one used to actually
5804 # The list of bookmark used here is not the one used to actually
5802 # update the bookmark name. This can result in the revision pulled
5805 # update the bookmark name. This can result in the revision pulled
5803 # not ending up with the name of the bookmark because of a race
5806 # not ending up with the name of the bookmark because of a race
5804 # condition on the server. (See issue 4689 for details)
5807 # condition on the server. (See issue 4689 for details)
5805 remotebookmarks = other.listkeys('bookmarks')
5808 remotebookmarks = other.listkeys('bookmarks')
5806 pullopargs['remotebookmarks'] = remotebookmarks
5809 pullopargs['remotebookmarks'] = remotebookmarks
5807 for b in opts['bookmark']:
5810 for b in opts['bookmark']:
5808 b = repo._bookmarks.expandname(b)
5811 b = repo._bookmarks.expandname(b)
5809 if b not in remotebookmarks:
5812 if b not in remotebookmarks:
5810 raise error.Abort(_('remote bookmark %s not found!') % b)
5813 raise error.Abort(_('remote bookmark %s not found!') % b)
5811 revs.append(remotebookmarks[b])
5814 revs.append(remotebookmarks[b])
5812
5815
5813 if revs:
5816 if revs:
5814 try:
5817 try:
5815 # When 'rev' is a bookmark name, we cannot guarantee that it
5818 # When 'rev' is a bookmark name, we cannot guarantee that it
5816 # will be updated with that name because of a race condition
5819 # will be updated with that name because of a race condition
5817 # server side. (See issue 4689 for details)
5820 # server side. (See issue 4689 for details)
5818 oldrevs = revs
5821 oldrevs = revs
5819 revs = [] # actually, nodes
5822 revs = [] # actually, nodes
5820 for r in oldrevs:
5823 for r in oldrevs:
5821 node = other.lookup(r)
5824 node = other.lookup(r)
5822 revs.append(node)
5825 revs.append(node)
5823 if r == checkout:
5826 if r == checkout:
5824 checkout = node
5827 checkout = node
5825 except error.CapabilityError:
5828 except error.CapabilityError:
5826 err = _("other repository doesn't support revision lookup, "
5829 err = _("other repository doesn't support revision lookup, "
5827 "so a rev cannot be specified.")
5830 "so a rev cannot be specified.")
5828 raise error.Abort(err)
5831 raise error.Abort(err)
5829
5832
5830 pullopargs.update(opts.get('opargs', {}))
5833 pullopargs.update(opts.get('opargs', {}))
5831 modheads = exchange.pull(repo, other, heads=revs,
5834 modheads = exchange.pull(repo, other, heads=revs,
5832 force=opts.get('force'),
5835 force=opts.get('force'),
5833 bookmarks=opts.get('bookmark', ()),
5836 bookmarks=opts.get('bookmark', ()),
5834 opargs=pullopargs).cgresult
5837 opargs=pullopargs).cgresult
5835
5838
5836 # brev is a name, which might be a bookmark to be activated at
5839 # brev is a name, which might be a bookmark to be activated at
5837 # the end of the update. In other words, it is an explicit
5840 # the end of the update. In other words, it is an explicit
5838 # destination of the update
5841 # destination of the update
5839 brev = None
5842 brev = None
5840
5843
5841 if checkout:
5844 if checkout:
5842 checkout = str(repo.changelog.rev(checkout))
5845 checkout = str(repo.changelog.rev(checkout))
5843
5846
5844 # order below depends on implementation of
5847 # order below depends on implementation of
5845 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5848 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5846 # because 'checkout' is determined without it.
5849 # because 'checkout' is determined without it.
5847 if opts.get('rev'):
5850 if opts.get('rev'):
5848 brev = opts['rev'][0]
5851 brev = opts['rev'][0]
5849 elif opts.get('branch'):
5852 elif opts.get('branch'):
5850 brev = opts['branch'][0]
5853 brev = opts['branch'][0]
5851 else:
5854 else:
5852 brev = branches[0]
5855 brev = branches[0]
5853 repo._subtoppath = source
5856 repo._subtoppath = source
5854 try:
5857 try:
5855 ret = postincoming(ui, repo, modheads, opts.get('update'),
5858 ret = postincoming(ui, repo, modheads, opts.get('update'),
5856 checkout, brev)
5859 checkout, brev)
5857
5860
5858 finally:
5861 finally:
5859 del repo._subtoppath
5862 del repo._subtoppath
5860
5863
5861 finally:
5864 finally:
5862 other.close()
5865 other.close()
5863 return ret
5866 return ret
5864
5867
5865 @command('^push',
5868 @command('^push',
5866 [('f', 'force', None, _('force push')),
5869 [('f', 'force', None, _('force push')),
5867 ('r', 'rev', [],
5870 ('r', 'rev', [],
5868 _('a changeset intended to be included in the destination'),
5871 _('a changeset intended to be included in the destination'),
5869 _('REV')),
5872 _('REV')),
5870 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5873 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5871 ('b', 'branch', [],
5874 ('b', 'branch', [],
5872 _('a specific branch you would like to push'), _('BRANCH')),
5875 _('a specific branch you would like to push'), _('BRANCH')),
5873 ('', 'new-branch', False, _('allow pushing a new branch')),
5876 ('', 'new-branch', False, _('allow pushing a new branch')),
5874 ] + remoteopts,
5877 ] + remoteopts,
5875 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5878 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5876 def push(ui, repo, dest=None, **opts):
5879 def push(ui, repo, dest=None, **opts):
5877 """push changes to the specified destination
5880 """push changes to the specified destination
5878
5881
5879 Push changesets from the local repository to the specified
5882 Push changesets from the local repository to the specified
5880 destination.
5883 destination.
5881
5884
5882 This operation is symmetrical to pull: it is identical to a pull
5885 This operation is symmetrical to pull: it is identical to a pull
5883 in the destination repository from the current one.
5886 in the destination repository from the current one.
5884
5887
5885 By default, push will not allow creation of new heads at the
5888 By default, push will not allow creation of new heads at the
5886 destination, since multiple heads would make it unclear which head
5889 destination, since multiple heads would make it unclear which head
5887 to use. In this situation, it is recommended to pull and merge
5890 to use. In this situation, it is recommended to pull and merge
5888 before pushing.
5891 before pushing.
5889
5892
5890 Use --new-branch if you want to allow push to create a new named
5893 Use --new-branch if you want to allow push to create a new named
5891 branch that is not present at the destination. This allows you to
5894 branch that is not present at the destination. This allows you to
5892 only create a new branch without forcing other changes.
5895 only create a new branch without forcing other changes.
5893
5896
5894 .. note::
5897 .. note::
5895
5898
5896 Extra care should be taken with the -f/--force option,
5899 Extra care should be taken with the -f/--force option,
5897 which will push all new heads on all branches, an action which will
5900 which will push all new heads on all branches, an action which will
5898 almost always cause confusion for collaborators.
5901 almost always cause confusion for collaborators.
5899
5902
5900 If -r/--rev is used, the specified revision and all its ancestors
5903 If -r/--rev is used, the specified revision and all its ancestors
5901 will be pushed to the remote repository.
5904 will be pushed to the remote repository.
5902
5905
5903 If -B/--bookmark is used, the specified bookmarked revision, its
5906 If -B/--bookmark is used, the specified bookmarked revision, its
5904 ancestors, and the bookmark will be pushed to the remote
5907 ancestors, and the bookmark will be pushed to the remote
5905 repository. Specifying ``.`` is equivalent to specifying the active
5908 repository. Specifying ``.`` is equivalent to specifying the active
5906 bookmark's name.
5909 bookmark's name.
5907
5910
5908 Please see :hg:`help urls` for important details about ``ssh://``
5911 Please see :hg:`help urls` for important details about ``ssh://``
5909 URLs. If DESTINATION is omitted, a default path will be used.
5912 URLs. If DESTINATION is omitted, a default path will be used.
5910
5913
5911 Returns 0 if push was successful, 1 if nothing to push.
5914 Returns 0 if push was successful, 1 if nothing to push.
5912 """
5915 """
5913
5916
5914 if opts.get('bookmark'):
5917 if opts.get('bookmark'):
5915 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5918 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5916 for b in opts['bookmark']:
5919 for b in opts['bookmark']:
5917 # translate -B options to -r so changesets get pushed
5920 # translate -B options to -r so changesets get pushed
5918 b = repo._bookmarks.expandname(b)
5921 b = repo._bookmarks.expandname(b)
5919 if b in repo._bookmarks:
5922 if b in repo._bookmarks:
5920 opts.setdefault('rev', []).append(b)
5923 opts.setdefault('rev', []).append(b)
5921 else:
5924 else:
5922 # if we try to push a deleted bookmark, translate it to null
5925 # if we try to push a deleted bookmark, translate it to null
5923 # this lets simultaneous -r, -b options continue working
5926 # this lets simultaneous -r, -b options continue working
5924 opts.setdefault('rev', []).append("null")
5927 opts.setdefault('rev', []).append("null")
5925
5928
5926 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5929 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5927 if not path:
5930 if not path:
5928 raise error.Abort(_('default repository not configured!'),
5931 raise error.Abort(_('default repository not configured!'),
5929 hint=_('see the "path" section in "hg help config"'))
5932 hint=_('see the "path" section in "hg help config"'))
5930 dest = path.pushloc or path.loc
5933 dest = path.pushloc or path.loc
5931 branches = (path.branch, opts.get('branch') or [])
5934 branches = (path.branch, opts.get('branch') or [])
5932 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5935 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5933 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5936 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5934 other = hg.peer(repo, opts, dest)
5937 other = hg.peer(repo, opts, dest)
5935
5938
5936 if revs:
5939 if revs:
5937 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5940 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5938 if not revs:
5941 if not revs:
5939 raise error.Abort(_("specified revisions evaluate to an empty set"),
5942 raise error.Abort(_("specified revisions evaluate to an empty set"),
5940 hint=_("use different revision arguments"))
5943 hint=_("use different revision arguments"))
5941
5944
5942 repo._subtoppath = dest
5945 repo._subtoppath = dest
5943 try:
5946 try:
5944 # push subrepos depth-first for coherent ordering
5947 # push subrepos depth-first for coherent ordering
5945 c = repo['']
5948 c = repo['']
5946 subs = c.substate # only repos that are committed
5949 subs = c.substate # only repos that are committed
5947 for s in sorted(subs):
5950 for s in sorted(subs):
5948 result = c.sub(s).push(opts)
5951 result = c.sub(s).push(opts)
5949 if result == 0:
5952 if result == 0:
5950 return not result
5953 return not result
5951 finally:
5954 finally:
5952 del repo._subtoppath
5955 del repo._subtoppath
5953 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5956 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5954 newbranch=opts.get('new_branch'),
5957 newbranch=opts.get('new_branch'),
5955 bookmarks=opts.get('bookmark', ()),
5958 bookmarks=opts.get('bookmark', ()),
5956 opargs=opts.get('opargs'))
5959 opargs=opts.get('opargs'))
5957
5960
5958 result = not pushop.cgresult
5961 result = not pushop.cgresult
5959
5962
5960 if pushop.bkresult is not None:
5963 if pushop.bkresult is not None:
5961 if pushop.bkresult == 2:
5964 if pushop.bkresult == 2:
5962 result = 2
5965 result = 2
5963 elif not result and pushop.bkresult:
5966 elif not result and pushop.bkresult:
5964 result = 2
5967 result = 2
5965
5968
5966 return result
5969 return result
5967
5970
5968 @command('recover', [])
5971 @command('recover', [])
5969 def recover(ui, repo):
5972 def recover(ui, repo):
5970 """roll back an interrupted transaction
5973 """roll back an interrupted transaction
5971
5974
5972 Recover from an interrupted commit or pull.
5975 Recover from an interrupted commit or pull.
5973
5976
5974 This command tries to fix the repository status after an
5977 This command tries to fix the repository status after an
5975 interrupted operation. It should only be necessary when Mercurial
5978 interrupted operation. It should only be necessary when Mercurial
5976 suggests it.
5979 suggests it.
5977
5980
5978 Returns 0 if successful, 1 if nothing to recover or verify fails.
5981 Returns 0 if successful, 1 if nothing to recover or verify fails.
5979 """
5982 """
5980 if repo.recover():
5983 if repo.recover():
5981 return hg.verify(repo)
5984 return hg.verify(repo)
5982 return 1
5985 return 1
5983
5986
5984 @command('^remove|rm',
5987 @command('^remove|rm',
5985 [('A', 'after', None, _('record delete for missing files')),
5988 [('A', 'after', None, _('record delete for missing files')),
5986 ('f', 'force', None,
5989 ('f', 'force', None,
5987 _('forget added files, delete modified files')),
5990 _('forget added files, delete modified files')),
5988 ] + subrepoopts + walkopts,
5991 ] + subrepoopts + walkopts,
5989 _('[OPTION]... FILE...'),
5992 _('[OPTION]... FILE...'),
5990 inferrepo=True)
5993 inferrepo=True)
5991 def remove(ui, repo, *pats, **opts):
5994 def remove(ui, repo, *pats, **opts):
5992 """remove the specified files on the next commit
5995 """remove the specified files on the next commit
5993
5996
5994 Schedule the indicated files for removal from the current branch.
5997 Schedule the indicated files for removal from the current branch.
5995
5998
5996 This command schedules the files to be removed at the next commit.
5999 This command schedules the files to be removed at the next commit.
5997 To undo a remove before that, see :hg:`revert`. To undo added
6000 To undo a remove before that, see :hg:`revert`. To undo added
5998 files, see :hg:`forget`.
6001 files, see :hg:`forget`.
5999
6002
6000 .. container:: verbose
6003 .. container:: verbose
6001
6004
6002 -A/--after can be used to remove only files that have already
6005 -A/--after can be used to remove only files that have already
6003 been deleted, -f/--force can be used to force deletion, and -Af
6006 been deleted, -f/--force can be used to force deletion, and -Af
6004 can be used to remove files from the next revision without
6007 can be used to remove files from the next revision without
6005 deleting them from the working directory.
6008 deleting them from the working directory.
6006
6009
6007 The following table details the behavior of remove for different
6010 The following table details the behavior of remove for different
6008 file states (columns) and option combinations (rows). The file
6011 file states (columns) and option combinations (rows). The file
6009 states are Added [A], Clean [C], Modified [M] and Missing [!]
6012 states are Added [A], Clean [C], Modified [M] and Missing [!]
6010 (as reported by :hg:`status`). The actions are Warn, Remove
6013 (as reported by :hg:`status`). The actions are Warn, Remove
6011 (from branch) and Delete (from disk):
6014 (from branch) and Delete (from disk):
6012
6015
6013 ========= == == == ==
6016 ========= == == == ==
6014 opt/state A C M !
6017 opt/state A C M !
6015 ========= == == == ==
6018 ========= == == == ==
6016 none W RD W R
6019 none W RD W R
6017 -f R RD RD R
6020 -f R RD RD R
6018 -A W W W R
6021 -A W W W R
6019 -Af R R R R
6022 -Af R R R R
6020 ========= == == == ==
6023 ========= == == == ==
6021
6024
6022 .. note::
6025 .. note::
6023
6026
6024 :hg:`remove` never deletes files in Added [A] state from the
6027 :hg:`remove` never deletes files in Added [A] state from the
6025 working directory, not even if ``--force`` is specified.
6028 working directory, not even if ``--force`` is specified.
6026
6029
6027 Returns 0 on success, 1 if any warnings encountered.
6030 Returns 0 on success, 1 if any warnings encountered.
6028 """
6031 """
6029
6032
6030 after, force = opts.get('after'), opts.get('force')
6033 after, force = opts.get('after'), opts.get('force')
6031 if not pats and not after:
6034 if not pats and not after:
6032 raise error.Abort(_('no files specified'))
6035 raise error.Abort(_('no files specified'))
6033
6036
6034 m = scmutil.match(repo[None], pats, opts)
6037 m = scmutil.match(repo[None], pats, opts)
6035 subrepos = opts.get('subrepos')
6038 subrepos = opts.get('subrepos')
6036 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6039 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6037
6040
6038 @command('rename|move|mv',
6041 @command('rename|move|mv',
6039 [('A', 'after', None, _('record a rename that has already occurred')),
6042 [('A', 'after', None, _('record a rename that has already occurred')),
6040 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6043 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6041 ] + walkopts + dryrunopts,
6044 ] + walkopts + dryrunopts,
6042 _('[OPTION]... SOURCE... DEST'))
6045 _('[OPTION]... SOURCE... DEST'))
6043 def rename(ui, repo, *pats, **opts):
6046 def rename(ui, repo, *pats, **opts):
6044 """rename files; equivalent of copy + remove
6047 """rename files; equivalent of copy + remove
6045
6048
6046 Mark dest as copies of sources; mark sources for deletion. If dest
6049 Mark dest as copies of sources; mark sources for deletion. If dest
6047 is a directory, copies are put in that directory. If dest is a
6050 is a directory, copies are put in that directory. If dest is a
6048 file, there can only be one source.
6051 file, there can only be one source.
6049
6052
6050 By default, this command copies the contents of files as they
6053 By default, this command copies the contents of files as they
6051 exist in the working directory. If invoked with -A/--after, the
6054 exist in the working directory. If invoked with -A/--after, the
6052 operation is recorded, but no copying is performed.
6055 operation is recorded, but no copying is performed.
6053
6056
6054 This command takes effect at the next commit. To undo a rename
6057 This command takes effect at the next commit. To undo a rename
6055 before that, see :hg:`revert`.
6058 before that, see :hg:`revert`.
6056
6059
6057 Returns 0 on success, 1 if errors are encountered.
6060 Returns 0 on success, 1 if errors are encountered.
6058 """
6061 """
6059 with repo.wlock(False):
6062 with repo.wlock(False):
6060 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6063 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6061
6064
6062 @command('resolve',
6065 @command('resolve',
6063 [('a', 'all', None, _('select all unresolved files')),
6066 [('a', 'all', None, _('select all unresolved files')),
6064 ('l', 'list', None, _('list state of files needing merge')),
6067 ('l', 'list', None, _('list state of files needing merge')),
6065 ('m', 'mark', None, _('mark files as resolved')),
6068 ('m', 'mark', None, _('mark files as resolved')),
6066 ('u', 'unmark', None, _('mark files as unresolved')),
6069 ('u', 'unmark', None, _('mark files as unresolved')),
6067 ('n', 'no-status', None, _('hide status prefix'))]
6070 ('n', 'no-status', None, _('hide status prefix'))]
6068 + mergetoolopts + walkopts + formatteropts,
6071 + mergetoolopts + walkopts + formatteropts,
6069 _('[OPTION]... [FILE]...'),
6072 _('[OPTION]... [FILE]...'),
6070 inferrepo=True)
6073 inferrepo=True)
6071 def resolve(ui, repo, *pats, **opts):
6074 def resolve(ui, repo, *pats, **opts):
6072 """redo merges or set/view the merge status of files
6075 """redo merges or set/view the merge status of files
6073
6076
6074 Merges with unresolved conflicts are often the result of
6077 Merges with unresolved conflicts are often the result of
6075 non-interactive merging using the ``internal:merge`` configuration
6078 non-interactive merging using the ``internal:merge`` configuration
6076 setting, or a command-line merge tool like ``diff3``. The resolve
6079 setting, or a command-line merge tool like ``diff3``. The resolve
6077 command is used to manage the files involved in a merge, after
6080 command is used to manage the files involved in a merge, after
6078 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6081 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6079 working directory must have two parents). See :hg:`help
6082 working directory must have two parents). See :hg:`help
6080 merge-tools` for information on configuring merge tools.
6083 merge-tools` for information on configuring merge tools.
6081
6084
6082 The resolve command can be used in the following ways:
6085 The resolve command can be used in the following ways:
6083
6086
6084 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6087 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6085 files, discarding any previous merge attempts. Re-merging is not
6088 files, discarding any previous merge attempts. Re-merging is not
6086 performed for files already marked as resolved. Use ``--all/-a``
6089 performed for files already marked as resolved. Use ``--all/-a``
6087 to select all unresolved files. ``--tool`` can be used to specify
6090 to select all unresolved files. ``--tool`` can be used to specify
6088 the merge tool used for the given files. It overrides the HGMERGE
6091 the merge tool used for the given files. It overrides the HGMERGE
6089 environment variable and your configuration files. Previous file
6092 environment variable and your configuration files. Previous file
6090 contents are saved with a ``.orig`` suffix.
6093 contents are saved with a ``.orig`` suffix.
6091
6094
6092 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6095 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6093 (e.g. after having manually fixed-up the files). The default is
6096 (e.g. after having manually fixed-up the files). The default is
6094 to mark all unresolved files.
6097 to mark all unresolved files.
6095
6098
6096 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6099 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6097 default is to mark all resolved files.
6100 default is to mark all resolved files.
6098
6101
6099 - :hg:`resolve -l`: list files which had or still have conflicts.
6102 - :hg:`resolve -l`: list files which had or still have conflicts.
6100 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6103 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6101
6104
6102 .. note::
6105 .. note::
6103
6106
6104 Mercurial will not let you commit files with unresolved merge
6107 Mercurial will not let you commit files with unresolved merge
6105 conflicts. You must use :hg:`resolve -m ...` before you can
6108 conflicts. You must use :hg:`resolve -m ...` before you can
6106 commit after a conflicting merge.
6109 commit after a conflicting merge.
6107
6110
6108 Returns 0 on success, 1 if any files fail a resolve attempt.
6111 Returns 0 on success, 1 if any files fail a resolve attempt.
6109 """
6112 """
6110
6113
6111 flaglist = 'all mark unmark list no_status'.split()
6114 flaglist = 'all mark unmark list no_status'.split()
6112 all, mark, unmark, show, nostatus = \
6115 all, mark, unmark, show, nostatus = \
6113 [opts.get(o) for o in flaglist]
6116 [opts.get(o) for o in flaglist]
6114
6117
6115 if (show and (mark or unmark)) or (mark and unmark):
6118 if (show and (mark or unmark)) or (mark and unmark):
6116 raise error.Abort(_("too many options specified"))
6119 raise error.Abort(_("too many options specified"))
6117 if pats and all:
6120 if pats and all:
6118 raise error.Abort(_("can't specify --all and patterns"))
6121 raise error.Abort(_("can't specify --all and patterns"))
6119 if not (all or pats or show or mark or unmark):
6122 if not (all or pats or show or mark or unmark):
6120 raise error.Abort(_('no files or directories specified'),
6123 raise error.Abort(_('no files or directories specified'),
6121 hint=('use --all to re-merge all unresolved files'))
6124 hint=('use --all to re-merge all unresolved files'))
6122
6125
6123 if show:
6126 if show:
6124 fm = ui.formatter('resolve', opts)
6127 fm = ui.formatter('resolve', opts)
6125 ms = mergemod.mergestate.read(repo)
6128 ms = mergemod.mergestate.read(repo)
6126 m = scmutil.match(repo[None], pats, opts)
6129 m = scmutil.match(repo[None], pats, opts)
6127 for f in ms:
6130 for f in ms:
6128 if not m(f):
6131 if not m(f):
6129 continue
6132 continue
6130 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6133 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6131 'd': 'driverresolved'}[ms[f]]
6134 'd': 'driverresolved'}[ms[f]]
6132 fm.startitem()
6135 fm.startitem()
6133 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6136 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6134 fm.write('path', '%s\n', f, label=l)
6137 fm.write('path', '%s\n', f, label=l)
6135 fm.end()
6138 fm.end()
6136 return 0
6139 return 0
6137
6140
6138 with repo.wlock():
6141 with repo.wlock():
6139 ms = mergemod.mergestate.read(repo)
6142 ms = mergemod.mergestate.read(repo)
6140
6143
6141 if not (ms.active() or repo.dirstate.p2() != nullid):
6144 if not (ms.active() or repo.dirstate.p2() != nullid):
6142 raise error.Abort(
6145 raise error.Abort(
6143 _('resolve command not applicable when not merging'))
6146 _('resolve command not applicable when not merging'))
6144
6147
6145 wctx = repo[None]
6148 wctx = repo[None]
6146
6149
6147 if ms.mergedriver and ms.mdstate() == 'u':
6150 if ms.mergedriver and ms.mdstate() == 'u':
6148 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6151 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6149 ms.commit()
6152 ms.commit()
6150 # allow mark and unmark to go through
6153 # allow mark and unmark to go through
6151 if not mark and not unmark and not proceed:
6154 if not mark and not unmark and not proceed:
6152 return 1
6155 return 1
6153
6156
6154 m = scmutil.match(wctx, pats, opts)
6157 m = scmutil.match(wctx, pats, opts)
6155 ret = 0
6158 ret = 0
6156 didwork = False
6159 didwork = False
6157 runconclude = False
6160 runconclude = False
6158
6161
6159 tocomplete = []
6162 tocomplete = []
6160 for f in ms:
6163 for f in ms:
6161 if not m(f):
6164 if not m(f):
6162 continue
6165 continue
6163
6166
6164 didwork = True
6167 didwork = True
6165
6168
6166 # don't let driver-resolved files be marked, and run the conclude
6169 # don't let driver-resolved files be marked, and run the conclude
6167 # step if asked to resolve
6170 # step if asked to resolve
6168 if ms[f] == "d":
6171 if ms[f] == "d":
6169 exact = m.exact(f)
6172 exact = m.exact(f)
6170 if mark:
6173 if mark:
6171 if exact:
6174 if exact:
6172 ui.warn(_('not marking %s as it is driver-resolved\n')
6175 ui.warn(_('not marking %s as it is driver-resolved\n')
6173 % f)
6176 % f)
6174 elif unmark:
6177 elif unmark:
6175 if exact:
6178 if exact:
6176 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6179 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6177 % f)
6180 % f)
6178 else:
6181 else:
6179 runconclude = True
6182 runconclude = True
6180 continue
6183 continue
6181
6184
6182 if mark:
6185 if mark:
6183 ms.mark(f, "r")
6186 ms.mark(f, "r")
6184 elif unmark:
6187 elif unmark:
6185 ms.mark(f, "u")
6188 ms.mark(f, "u")
6186 else:
6189 else:
6187 # backup pre-resolve (merge uses .orig for its own purposes)
6190 # backup pre-resolve (merge uses .orig for its own purposes)
6188 a = repo.wjoin(f)
6191 a = repo.wjoin(f)
6189 try:
6192 try:
6190 util.copyfile(a, a + ".resolve")
6193 util.copyfile(a, a + ".resolve")
6191 except (IOError, OSError) as inst:
6194 except (IOError, OSError) as inst:
6192 if inst.errno != errno.ENOENT:
6195 if inst.errno != errno.ENOENT:
6193 raise
6196 raise
6194
6197
6195 try:
6198 try:
6196 # preresolve file
6199 # preresolve file
6197 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6200 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6198 'resolve')
6201 'resolve')
6199 complete, r = ms.preresolve(f, wctx)
6202 complete, r = ms.preresolve(f, wctx)
6200 if not complete:
6203 if not complete:
6201 tocomplete.append(f)
6204 tocomplete.append(f)
6202 elif r:
6205 elif r:
6203 ret = 1
6206 ret = 1
6204 finally:
6207 finally:
6205 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6208 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6206 ms.commit()
6209 ms.commit()
6207
6210
6208 # replace filemerge's .orig file with our resolve file, but only
6211 # replace filemerge's .orig file with our resolve file, but only
6209 # for merges that are complete
6212 # for merges that are complete
6210 if complete:
6213 if complete:
6211 try:
6214 try:
6212 util.rename(a + ".resolve",
6215 util.rename(a + ".resolve",
6213 scmutil.origpath(ui, repo, a))
6216 scmutil.origpath(ui, repo, a))
6214 except OSError as inst:
6217 except OSError as inst:
6215 if inst.errno != errno.ENOENT:
6218 if inst.errno != errno.ENOENT:
6216 raise
6219 raise
6217
6220
6218 for f in tocomplete:
6221 for f in tocomplete:
6219 try:
6222 try:
6220 # resolve file
6223 # resolve file
6221 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6224 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6222 'resolve')
6225 'resolve')
6223 r = ms.resolve(f, wctx)
6226 r = ms.resolve(f, wctx)
6224 if r:
6227 if r:
6225 ret = 1
6228 ret = 1
6226 finally:
6229 finally:
6227 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6230 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6228 ms.commit()
6231 ms.commit()
6229
6232
6230 # replace filemerge's .orig file with our resolve file
6233 # replace filemerge's .orig file with our resolve file
6231 a = repo.wjoin(f)
6234 a = repo.wjoin(f)
6232 try:
6235 try:
6233 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6236 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6234 except OSError as inst:
6237 except OSError as inst:
6235 if inst.errno != errno.ENOENT:
6238 if inst.errno != errno.ENOENT:
6236 raise
6239 raise
6237
6240
6238 ms.commit()
6241 ms.commit()
6239 ms.recordactions()
6242 ms.recordactions()
6240
6243
6241 if not didwork and pats:
6244 if not didwork and pats:
6242 hint = None
6245 hint = None
6243 if not any([p for p in pats if p.find(':') >= 0]):
6246 if not any([p for p in pats if p.find(':') >= 0]):
6244 pats = ['path:%s' % p for p in pats]
6247 pats = ['path:%s' % p for p in pats]
6245 m = scmutil.match(wctx, pats, opts)
6248 m = scmutil.match(wctx, pats, opts)
6246 for f in ms:
6249 for f in ms:
6247 if not m(f):
6250 if not m(f):
6248 continue
6251 continue
6249 flags = ''.join(['-%s ' % o[0] for o in flaglist
6252 flags = ''.join(['-%s ' % o[0] for o in flaglist
6250 if opts.get(o)])
6253 if opts.get(o)])
6251 hint = _("(try: hg resolve %s%s)\n") % (
6254 hint = _("(try: hg resolve %s%s)\n") % (
6252 flags,
6255 flags,
6253 ' '.join(pats))
6256 ' '.join(pats))
6254 break
6257 break
6255 ui.warn(_("arguments do not match paths that need resolving\n"))
6258 ui.warn(_("arguments do not match paths that need resolving\n"))
6256 if hint:
6259 if hint:
6257 ui.warn(hint)
6260 ui.warn(hint)
6258 elif ms.mergedriver and ms.mdstate() != 's':
6261 elif ms.mergedriver and ms.mdstate() != 's':
6259 # run conclude step when either a driver-resolved file is requested
6262 # run conclude step when either a driver-resolved file is requested
6260 # or there are no driver-resolved files
6263 # or there are no driver-resolved files
6261 # we can't use 'ret' to determine whether any files are unresolved
6264 # we can't use 'ret' to determine whether any files are unresolved
6262 # because we might not have tried to resolve some
6265 # because we might not have tried to resolve some
6263 if ((runconclude or not list(ms.driverresolved()))
6266 if ((runconclude or not list(ms.driverresolved()))
6264 and not list(ms.unresolved())):
6267 and not list(ms.unresolved())):
6265 proceed = mergemod.driverconclude(repo, ms, wctx)
6268 proceed = mergemod.driverconclude(repo, ms, wctx)
6266 ms.commit()
6269 ms.commit()
6267 if not proceed:
6270 if not proceed:
6268 return 1
6271 return 1
6269
6272
6270 # Nudge users into finishing an unfinished operation
6273 # Nudge users into finishing an unfinished operation
6271 unresolvedf = list(ms.unresolved())
6274 unresolvedf = list(ms.unresolved())
6272 driverresolvedf = list(ms.driverresolved())
6275 driverresolvedf = list(ms.driverresolved())
6273 if not unresolvedf and not driverresolvedf:
6276 if not unresolvedf and not driverresolvedf:
6274 ui.status(_('(no more unresolved files)\n'))
6277 ui.status(_('(no more unresolved files)\n'))
6275 cmdutil.checkafterresolved(repo)
6278 cmdutil.checkafterresolved(repo)
6276 elif not unresolvedf:
6279 elif not unresolvedf:
6277 ui.status(_('(no more unresolved files -- '
6280 ui.status(_('(no more unresolved files -- '
6278 'run "hg resolve --all" to conclude)\n'))
6281 'run "hg resolve --all" to conclude)\n'))
6279
6282
6280 return ret
6283 return ret
6281
6284
6282 @command('revert',
6285 @command('revert',
6283 [('a', 'all', None, _('revert all changes when no arguments given')),
6286 [('a', 'all', None, _('revert all changes when no arguments given')),
6284 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6287 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6285 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6288 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6286 ('C', 'no-backup', None, _('do not save backup copies of files')),
6289 ('C', 'no-backup', None, _('do not save backup copies of files')),
6287 ('i', 'interactive', None,
6290 ('i', 'interactive', None,
6288 _('interactively select the changes (EXPERIMENTAL)')),
6291 _('interactively select the changes (EXPERIMENTAL)')),
6289 ] + walkopts + dryrunopts,
6292 ] + walkopts + dryrunopts,
6290 _('[OPTION]... [-r REV] [NAME]...'))
6293 _('[OPTION]... [-r REV] [NAME]...'))
6291 def revert(ui, repo, *pats, **opts):
6294 def revert(ui, repo, *pats, **opts):
6292 """restore files to their checkout state
6295 """restore files to their checkout state
6293
6296
6294 .. note::
6297 .. note::
6295
6298
6296 To check out earlier revisions, you should use :hg:`update REV`.
6299 To check out earlier revisions, you should use :hg:`update REV`.
6297 To cancel an uncommitted merge (and lose your changes),
6300 To cancel an uncommitted merge (and lose your changes),
6298 use :hg:`update --clean .`.
6301 use :hg:`update --clean .`.
6299
6302
6300 With no revision specified, revert the specified files or directories
6303 With no revision specified, revert the specified files or directories
6301 to the contents they had in the parent of the working directory.
6304 to the contents they had in the parent of the working directory.
6302 This restores the contents of files to an unmodified
6305 This restores the contents of files to an unmodified
6303 state and unschedules adds, removes, copies, and renames. If the
6306 state and unschedules adds, removes, copies, and renames. If the
6304 working directory has two parents, you must explicitly specify a
6307 working directory has two parents, you must explicitly specify a
6305 revision.
6308 revision.
6306
6309
6307 Using the -r/--rev or -d/--date options, revert the given files or
6310 Using the -r/--rev or -d/--date options, revert the given files or
6308 directories to their states as of a specific revision. Because
6311 directories to their states as of a specific revision. Because
6309 revert does not change the working directory parents, this will
6312 revert does not change the working directory parents, this will
6310 cause these files to appear modified. This can be helpful to "back
6313 cause these files to appear modified. This can be helpful to "back
6311 out" some or all of an earlier change. See :hg:`backout` for a
6314 out" some or all of an earlier change. See :hg:`backout` for a
6312 related method.
6315 related method.
6313
6316
6314 Modified files are saved with a .orig suffix before reverting.
6317 Modified files are saved with a .orig suffix before reverting.
6315 To disable these backups, use --no-backup. It is possible to store
6318 To disable these backups, use --no-backup. It is possible to store
6316 the backup files in a custom directory relative to the root of the
6319 the backup files in a custom directory relative to the root of the
6317 repository by setting the ``ui.origbackuppath`` configuration
6320 repository by setting the ``ui.origbackuppath`` configuration
6318 option.
6321 option.
6319
6322
6320 See :hg:`help dates` for a list of formats valid for -d/--date.
6323 See :hg:`help dates` for a list of formats valid for -d/--date.
6321
6324
6322 See :hg:`help backout` for a way to reverse the effect of an
6325 See :hg:`help backout` for a way to reverse the effect of an
6323 earlier changeset.
6326 earlier changeset.
6324
6327
6325 Returns 0 on success.
6328 Returns 0 on success.
6326 """
6329 """
6327
6330
6328 if opts.get("date"):
6331 if opts.get("date"):
6329 if opts.get("rev"):
6332 if opts.get("rev"):
6330 raise error.Abort(_("you can't specify a revision and a date"))
6333 raise error.Abort(_("you can't specify a revision and a date"))
6331 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6334 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6332
6335
6333 parent, p2 = repo.dirstate.parents()
6336 parent, p2 = repo.dirstate.parents()
6334 if not opts.get('rev') and p2 != nullid:
6337 if not opts.get('rev') and p2 != nullid:
6335 # revert after merge is a trap for new users (issue2915)
6338 # revert after merge is a trap for new users (issue2915)
6336 raise error.Abort(_('uncommitted merge with no revision specified'),
6339 raise error.Abort(_('uncommitted merge with no revision specified'),
6337 hint=_("use 'hg update' or see 'hg help revert'"))
6340 hint=_("use 'hg update' or see 'hg help revert'"))
6338
6341
6339 ctx = scmutil.revsingle(repo, opts.get('rev'))
6342 ctx = scmutil.revsingle(repo, opts.get('rev'))
6340
6343
6341 if (not (pats or opts.get('include') or opts.get('exclude') or
6344 if (not (pats or opts.get('include') or opts.get('exclude') or
6342 opts.get('all') or opts.get('interactive'))):
6345 opts.get('all') or opts.get('interactive'))):
6343 msg = _("no files or directories specified")
6346 msg = _("no files or directories specified")
6344 if p2 != nullid:
6347 if p2 != nullid:
6345 hint = _("uncommitted merge, use --all to discard all changes,"
6348 hint = _("uncommitted merge, use --all to discard all changes,"
6346 " or 'hg update -C .' to abort the merge")
6349 " or 'hg update -C .' to abort the merge")
6347 raise error.Abort(msg, hint=hint)
6350 raise error.Abort(msg, hint=hint)
6348 dirty = any(repo.status())
6351 dirty = any(repo.status())
6349 node = ctx.node()
6352 node = ctx.node()
6350 if node != parent:
6353 if node != parent:
6351 if dirty:
6354 if dirty:
6352 hint = _("uncommitted changes, use --all to discard all"
6355 hint = _("uncommitted changes, use --all to discard all"
6353 " changes, or 'hg update %s' to update") % ctx.rev()
6356 " changes, or 'hg update %s' to update") % ctx.rev()
6354 else:
6357 else:
6355 hint = _("use --all to revert all files,"
6358 hint = _("use --all to revert all files,"
6356 " or 'hg update %s' to update") % ctx.rev()
6359 " or 'hg update %s' to update") % ctx.rev()
6357 elif dirty:
6360 elif dirty:
6358 hint = _("uncommitted changes, use --all to discard all changes")
6361 hint = _("uncommitted changes, use --all to discard all changes")
6359 else:
6362 else:
6360 hint = _("use --all to revert all files")
6363 hint = _("use --all to revert all files")
6361 raise error.Abort(msg, hint=hint)
6364 raise error.Abort(msg, hint=hint)
6362
6365
6363 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6366 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6364
6367
6365 @command('rollback', dryrunopts +
6368 @command('rollback', dryrunopts +
6366 [('f', 'force', False, _('ignore safety measures'))])
6369 [('f', 'force', False, _('ignore safety measures'))])
6367 def rollback(ui, repo, **opts):
6370 def rollback(ui, repo, **opts):
6368 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6371 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6369
6372
6370 Please use :hg:`commit --amend` instead of rollback to correct
6373 Please use :hg:`commit --amend` instead of rollback to correct
6371 mistakes in the last commit.
6374 mistakes in the last commit.
6372
6375
6373 This command should be used with care. There is only one level of
6376 This command should be used with care. There is only one level of
6374 rollback, and there is no way to undo a rollback. It will also
6377 rollback, and there is no way to undo a rollback. It will also
6375 restore the dirstate at the time of the last transaction, losing
6378 restore the dirstate at the time of the last transaction, losing
6376 any dirstate changes since that time. This command does not alter
6379 any dirstate changes since that time. This command does not alter
6377 the working directory.
6380 the working directory.
6378
6381
6379 Transactions are used to encapsulate the effects of all commands
6382 Transactions are used to encapsulate the effects of all commands
6380 that create new changesets or propagate existing changesets into a
6383 that create new changesets or propagate existing changesets into a
6381 repository.
6384 repository.
6382
6385
6383 .. container:: verbose
6386 .. container:: verbose
6384
6387
6385 For example, the following commands are transactional, and their
6388 For example, the following commands are transactional, and their
6386 effects can be rolled back:
6389 effects can be rolled back:
6387
6390
6388 - commit
6391 - commit
6389 - import
6392 - import
6390 - pull
6393 - pull
6391 - push (with this repository as the destination)
6394 - push (with this repository as the destination)
6392 - unbundle
6395 - unbundle
6393
6396
6394 To avoid permanent data loss, rollback will refuse to rollback a
6397 To avoid permanent data loss, rollback will refuse to rollback a
6395 commit transaction if it isn't checked out. Use --force to
6398 commit transaction if it isn't checked out. Use --force to
6396 override this protection.
6399 override this protection.
6397
6400
6398 The rollback command can be entirely disabled by setting the
6401 The rollback command can be entirely disabled by setting the
6399 ``ui.rollback`` configuration setting to false. If you're here
6402 ``ui.rollback`` configuration setting to false. If you're here
6400 because you want to use rollback and it's disabled, you can
6403 because you want to use rollback and it's disabled, you can
6401 re-enable the command by setting ``ui.rollback`` to true.
6404 re-enable the command by setting ``ui.rollback`` to true.
6402
6405
6403 This command is not intended for use on public repositories. Once
6406 This command is not intended for use on public repositories. Once
6404 changes are visible for pull by other users, rolling a transaction
6407 changes are visible for pull by other users, rolling a transaction
6405 back locally is ineffective (someone else may already have pulled
6408 back locally is ineffective (someone else may already have pulled
6406 the changes). Furthermore, a race is possible with readers of the
6409 the changes). Furthermore, a race is possible with readers of the
6407 repository; for example an in-progress pull from the repository
6410 repository; for example an in-progress pull from the repository
6408 may fail if a rollback is performed.
6411 may fail if a rollback is performed.
6409
6412
6410 Returns 0 on success, 1 if no rollback data is available.
6413 Returns 0 on success, 1 if no rollback data is available.
6411 """
6414 """
6412 if not ui.configbool('ui', 'rollback', True):
6415 if not ui.configbool('ui', 'rollback', True):
6413 raise error.Abort(_('rollback is disabled because it is unsafe'),
6416 raise error.Abort(_('rollback is disabled because it is unsafe'),
6414 hint=('see `hg help -v rollback` for information'))
6417 hint=('see `hg help -v rollback` for information'))
6415 return repo.rollback(dryrun=opts.get('dry_run'),
6418 return repo.rollback(dryrun=opts.get('dry_run'),
6416 force=opts.get('force'))
6419 force=opts.get('force'))
6417
6420
6418 @command('root', [])
6421 @command('root', [])
6419 def root(ui, repo):
6422 def root(ui, repo):
6420 """print the root (top) of the current working directory
6423 """print the root (top) of the current working directory
6421
6424
6422 Print the root directory of the current repository.
6425 Print the root directory of the current repository.
6423
6426
6424 Returns 0 on success.
6427 Returns 0 on success.
6425 """
6428 """
6426 ui.write(repo.root + "\n")
6429 ui.write(repo.root + "\n")
6427
6430
6428 @command('^serve',
6431 @command('^serve',
6429 [('A', 'accesslog', '', _('name of access log file to write to'),
6432 [('A', 'accesslog', '', _('name of access log file to write to'),
6430 _('FILE')),
6433 _('FILE')),
6431 ('d', 'daemon', None, _('run server in background')),
6434 ('d', 'daemon', None, _('run server in background')),
6432 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6435 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6433 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6436 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6434 # use string type, then we can check if something was passed
6437 # use string type, then we can check if something was passed
6435 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6438 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6436 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6439 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6437 _('ADDR')),
6440 _('ADDR')),
6438 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6441 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6439 _('PREFIX')),
6442 _('PREFIX')),
6440 ('n', 'name', '',
6443 ('n', 'name', '',
6441 _('name to show in web pages (default: working directory)'), _('NAME')),
6444 _('name to show in web pages (default: working directory)'), _('NAME')),
6442 ('', 'web-conf', '',
6445 ('', 'web-conf', '',
6443 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6446 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6444 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6447 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6445 _('FILE')),
6448 _('FILE')),
6446 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6449 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6447 ('', 'stdio', None, _('for remote clients')),
6450 ('', 'stdio', None, _('for remote clients')),
6448 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6451 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6449 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6452 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6450 ('', 'style', '', _('template style to use'), _('STYLE')),
6453 ('', 'style', '', _('template style to use'), _('STYLE')),
6451 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6454 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6452 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6455 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6453 _('[OPTION]...'),
6456 _('[OPTION]...'),
6454 optionalrepo=True)
6457 optionalrepo=True)
6455 def serve(ui, repo, **opts):
6458 def serve(ui, repo, **opts):
6456 """start stand-alone webserver
6459 """start stand-alone webserver
6457
6460
6458 Start a local HTTP repository browser and pull server. You can use
6461 Start a local HTTP repository browser and pull server. You can use
6459 this for ad-hoc sharing and browsing of repositories. It is
6462 this for ad-hoc sharing and browsing of repositories. It is
6460 recommended to use a real web server to serve a repository for
6463 recommended to use a real web server to serve a repository for
6461 longer periods of time.
6464 longer periods of time.
6462
6465
6463 Please note that the server does not implement access control.
6466 Please note that the server does not implement access control.
6464 This means that, by default, anybody can read from the server and
6467 This means that, by default, anybody can read from the server and
6465 nobody can write to it by default. Set the ``web.allow_push``
6468 nobody can write to it by default. Set the ``web.allow_push``
6466 option to ``*`` to allow everybody to push to the server. You
6469 option to ``*`` to allow everybody to push to the server. You
6467 should use a real web server if you need to authenticate users.
6470 should use a real web server if you need to authenticate users.
6468
6471
6469 By default, the server logs accesses to stdout and errors to
6472 By default, the server logs accesses to stdout and errors to
6470 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6473 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6471 files.
6474 files.
6472
6475
6473 To have the server choose a free port number to listen on, specify
6476 To have the server choose a free port number to listen on, specify
6474 a port number of 0; in this case, the server will print the port
6477 a port number of 0; in this case, the server will print the port
6475 number it uses.
6478 number it uses.
6476
6479
6477 Returns 0 on success.
6480 Returns 0 on success.
6478 """
6481 """
6479
6482
6480 if opts["stdio"] and opts["cmdserver"]:
6483 if opts["stdio"] and opts["cmdserver"]:
6481 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6484 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6482
6485
6483 if opts["stdio"]:
6486 if opts["stdio"]:
6484 if repo is None:
6487 if repo is None:
6485 raise error.RepoError(_("there is no Mercurial repository here"
6488 raise error.RepoError(_("there is no Mercurial repository here"
6486 " (.hg not found)"))
6489 " (.hg not found)"))
6487 s = sshserver.sshserver(ui, repo)
6490 s = sshserver.sshserver(ui, repo)
6488 s.serve_forever()
6491 s.serve_forever()
6489
6492
6490 if opts["cmdserver"]:
6493 if opts["cmdserver"]:
6491 service = commandserver.createservice(ui, repo, opts)
6494 service = commandserver.createservice(ui, repo, opts)
6492 else:
6495 else:
6493 service = hgweb.createservice(ui, repo, opts)
6496 service = hgweb.createservice(ui, repo, opts)
6494 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6497 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6495
6498
6496 @command('^status|st',
6499 @command('^status|st',
6497 [('A', 'all', None, _('show status of all files')),
6500 [('A', 'all', None, _('show status of all files')),
6498 ('m', 'modified', None, _('show only modified files')),
6501 ('m', 'modified', None, _('show only modified files')),
6499 ('a', 'added', None, _('show only added files')),
6502 ('a', 'added', None, _('show only added files')),
6500 ('r', 'removed', None, _('show only removed files')),
6503 ('r', 'removed', None, _('show only removed files')),
6501 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6504 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6502 ('c', 'clean', None, _('show only files without changes')),
6505 ('c', 'clean', None, _('show only files without changes')),
6503 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6506 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6504 ('i', 'ignored', None, _('show only ignored files')),
6507 ('i', 'ignored', None, _('show only ignored files')),
6505 ('n', 'no-status', None, _('hide status prefix')),
6508 ('n', 'no-status', None, _('hide status prefix')),
6506 ('C', 'copies', None, _('show source of copied files')),
6509 ('C', 'copies', None, _('show source of copied files')),
6507 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6510 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6508 ('', 'rev', [], _('show difference from revision'), _('REV')),
6511 ('', 'rev', [], _('show difference from revision'), _('REV')),
6509 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6512 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6510 ] + walkopts + subrepoopts + formatteropts,
6513 ] + walkopts + subrepoopts + formatteropts,
6511 _('[OPTION]... [FILE]...'),
6514 _('[OPTION]... [FILE]...'),
6512 inferrepo=True)
6515 inferrepo=True)
6513 def status(ui, repo, *pats, **opts):
6516 def status(ui, repo, *pats, **opts):
6514 """show changed files in the working directory
6517 """show changed files in the working directory
6515
6518
6516 Show status of files in the repository. If names are given, only
6519 Show status of files in the repository. If names are given, only
6517 files that match are shown. Files that are clean or ignored or
6520 files that match are shown. Files that are clean or ignored or
6518 the source of a copy/move operation, are not listed unless
6521 the source of a copy/move operation, are not listed unless
6519 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6522 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6520 Unless options described with "show only ..." are given, the
6523 Unless options described with "show only ..." are given, the
6521 options -mardu are used.
6524 options -mardu are used.
6522
6525
6523 Option -q/--quiet hides untracked (unknown and ignored) files
6526 Option -q/--quiet hides untracked (unknown and ignored) files
6524 unless explicitly requested with -u/--unknown or -i/--ignored.
6527 unless explicitly requested with -u/--unknown or -i/--ignored.
6525
6528
6526 .. note::
6529 .. note::
6527
6530
6528 :hg:`status` may appear to disagree with diff if permissions have
6531 :hg:`status` may appear to disagree with diff if permissions have
6529 changed or a merge has occurred. The standard diff format does
6532 changed or a merge has occurred. The standard diff format does
6530 not report permission changes and diff only reports changes
6533 not report permission changes and diff only reports changes
6531 relative to one merge parent.
6534 relative to one merge parent.
6532
6535
6533 If one revision is given, it is used as the base revision.
6536 If one revision is given, it is used as the base revision.
6534 If two revisions are given, the differences between them are
6537 If two revisions are given, the differences between them are
6535 shown. The --change option can also be used as a shortcut to list
6538 shown. The --change option can also be used as a shortcut to list
6536 the changed files of a revision from its first parent.
6539 the changed files of a revision from its first parent.
6537
6540
6538 The codes used to show the status of files are::
6541 The codes used to show the status of files are::
6539
6542
6540 M = modified
6543 M = modified
6541 A = added
6544 A = added
6542 R = removed
6545 R = removed
6543 C = clean
6546 C = clean
6544 ! = missing (deleted by non-hg command, but still tracked)
6547 ! = missing (deleted by non-hg command, but still tracked)
6545 ? = not tracked
6548 ? = not tracked
6546 I = ignored
6549 I = ignored
6547 = origin of the previous file (with --copies)
6550 = origin of the previous file (with --copies)
6548
6551
6549 .. container:: verbose
6552 .. container:: verbose
6550
6553
6551 Examples:
6554 Examples:
6552
6555
6553 - show changes in the working directory relative to a
6556 - show changes in the working directory relative to a
6554 changeset::
6557 changeset::
6555
6558
6556 hg status --rev 9353
6559 hg status --rev 9353
6557
6560
6558 - show changes in the working directory relative to the
6561 - show changes in the working directory relative to the
6559 current directory (see :hg:`help patterns` for more information)::
6562 current directory (see :hg:`help patterns` for more information)::
6560
6563
6561 hg status re:
6564 hg status re:
6562
6565
6563 - show all changes including copies in an existing changeset::
6566 - show all changes including copies in an existing changeset::
6564
6567
6565 hg status --copies --change 9353
6568 hg status --copies --change 9353
6566
6569
6567 - get a NUL separated list of added files, suitable for xargs::
6570 - get a NUL separated list of added files, suitable for xargs::
6568
6571
6569 hg status -an0
6572 hg status -an0
6570
6573
6571 Returns 0 on success.
6574 Returns 0 on success.
6572 """
6575 """
6573
6576
6574 revs = opts.get('rev')
6577 revs = opts.get('rev')
6575 change = opts.get('change')
6578 change = opts.get('change')
6576
6579
6577 if revs and change:
6580 if revs and change:
6578 msg = _('cannot specify --rev and --change at the same time')
6581 msg = _('cannot specify --rev and --change at the same time')
6579 raise error.Abort(msg)
6582 raise error.Abort(msg)
6580 elif change:
6583 elif change:
6581 node2 = scmutil.revsingle(repo, change, None).node()
6584 node2 = scmutil.revsingle(repo, change, None).node()
6582 node1 = repo[node2].p1().node()
6585 node1 = repo[node2].p1().node()
6583 else:
6586 else:
6584 node1, node2 = scmutil.revpair(repo, revs)
6587 node1, node2 = scmutil.revpair(repo, revs)
6585
6588
6586 if pats:
6589 if pats:
6587 cwd = repo.getcwd()
6590 cwd = repo.getcwd()
6588 else:
6591 else:
6589 cwd = ''
6592 cwd = ''
6590
6593
6591 if opts.get('print0'):
6594 if opts.get('print0'):
6592 end = '\0'
6595 end = '\0'
6593 else:
6596 else:
6594 end = '\n'
6597 end = '\n'
6595 copy = {}
6598 copy = {}
6596 states = 'modified added removed deleted unknown ignored clean'.split()
6599 states = 'modified added removed deleted unknown ignored clean'.split()
6597 show = [k for k in states if opts.get(k)]
6600 show = [k for k in states if opts.get(k)]
6598 if opts.get('all'):
6601 if opts.get('all'):
6599 show += ui.quiet and (states[:4] + ['clean']) or states
6602 show += ui.quiet and (states[:4] + ['clean']) or states
6600 if not show:
6603 if not show:
6601 if ui.quiet:
6604 if ui.quiet:
6602 show = states[:4]
6605 show = states[:4]
6603 else:
6606 else:
6604 show = states[:5]
6607 show = states[:5]
6605
6608
6606 m = scmutil.match(repo[node2], pats, opts)
6609 m = scmutil.match(repo[node2], pats, opts)
6607 stat = repo.status(node1, node2, m,
6610 stat = repo.status(node1, node2, m,
6608 'ignored' in show, 'clean' in show, 'unknown' in show,
6611 'ignored' in show, 'clean' in show, 'unknown' in show,
6609 opts.get('subrepos'))
6612 opts.get('subrepos'))
6610 changestates = zip(states, 'MAR!?IC', stat)
6613 changestates = zip(states, 'MAR!?IC', stat)
6611
6614
6612 if (opts.get('all') or opts.get('copies')
6615 if (opts.get('all') or opts.get('copies')
6613 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6616 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6614 copy = copies.pathcopies(repo[node1], repo[node2], m)
6617 copy = copies.pathcopies(repo[node1], repo[node2], m)
6615
6618
6616 fm = ui.formatter('status', opts)
6619 fm = ui.formatter('status', opts)
6617 fmt = '%s' + end
6620 fmt = '%s' + end
6618 showchar = not opts.get('no_status')
6621 showchar = not opts.get('no_status')
6619
6622
6620 for state, char, files in changestates:
6623 for state, char, files in changestates:
6621 if state in show:
6624 if state in show:
6622 label = 'status.' + state
6625 label = 'status.' + state
6623 for f in files:
6626 for f in files:
6624 fm.startitem()
6627 fm.startitem()
6625 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6628 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6626 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6629 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6627 if f in copy:
6630 if f in copy:
6628 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6631 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6629 label='status.copied')
6632 label='status.copied')
6630 fm.end()
6633 fm.end()
6631
6634
6632 @command('^summary|sum',
6635 @command('^summary|sum',
6633 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6636 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6634 def summary(ui, repo, **opts):
6637 def summary(ui, repo, **opts):
6635 """summarize working directory state
6638 """summarize working directory state
6636
6639
6637 This generates a brief summary of the working directory state,
6640 This generates a brief summary of the working directory state,
6638 including parents, branch, commit status, phase and available updates.
6641 including parents, branch, commit status, phase and available updates.
6639
6642
6640 With the --remote option, this will check the default paths for
6643 With the --remote option, this will check the default paths for
6641 incoming and outgoing changes. This can be time-consuming.
6644 incoming and outgoing changes. This can be time-consuming.
6642
6645
6643 Returns 0 on success.
6646 Returns 0 on success.
6644 """
6647 """
6645
6648
6646 ctx = repo[None]
6649 ctx = repo[None]
6647 parents = ctx.parents()
6650 parents = ctx.parents()
6648 pnode = parents[0].node()
6651 pnode = parents[0].node()
6649 marks = []
6652 marks = []
6650
6653
6651 ms = None
6654 ms = None
6652 try:
6655 try:
6653 ms = mergemod.mergestate.read(repo)
6656 ms = mergemod.mergestate.read(repo)
6654 except error.UnsupportedMergeRecords as e:
6657 except error.UnsupportedMergeRecords as e:
6655 s = ' '.join(e.recordtypes)
6658 s = ' '.join(e.recordtypes)
6656 ui.warn(
6659 ui.warn(
6657 _('warning: merge state has unsupported record types: %s\n') % s)
6660 _('warning: merge state has unsupported record types: %s\n') % s)
6658 unresolved = 0
6661 unresolved = 0
6659 else:
6662 else:
6660 unresolved = [f for f in ms if ms[f] == 'u']
6663 unresolved = [f for f in ms if ms[f] == 'u']
6661
6664
6662 for p in parents:
6665 for p in parents:
6663 # label with log.changeset (instead of log.parent) since this
6666 # label with log.changeset (instead of log.parent) since this
6664 # shows a working directory parent *changeset*:
6667 # shows a working directory parent *changeset*:
6665 # i18n: column positioning for "hg summary"
6668 # i18n: column positioning for "hg summary"
6666 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6669 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6667 label='log.changeset changeset.%s' % p.phasestr())
6670 label='log.changeset changeset.%s' % p.phasestr())
6668 ui.write(' '.join(p.tags()), label='log.tag')
6671 ui.write(' '.join(p.tags()), label='log.tag')
6669 if p.bookmarks():
6672 if p.bookmarks():
6670 marks.extend(p.bookmarks())
6673 marks.extend(p.bookmarks())
6671 if p.rev() == -1:
6674 if p.rev() == -1:
6672 if not len(repo):
6675 if not len(repo):
6673 ui.write(_(' (empty repository)'))
6676 ui.write(_(' (empty repository)'))
6674 else:
6677 else:
6675 ui.write(_(' (no revision checked out)'))
6678 ui.write(_(' (no revision checked out)'))
6676 ui.write('\n')
6679 ui.write('\n')
6677 if p.description():
6680 if p.description():
6678 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6681 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6679 label='log.summary')
6682 label='log.summary')
6680
6683
6681 branch = ctx.branch()
6684 branch = ctx.branch()
6682 bheads = repo.branchheads(branch)
6685 bheads = repo.branchheads(branch)
6683 # i18n: column positioning for "hg summary"
6686 # i18n: column positioning for "hg summary"
6684 m = _('branch: %s\n') % branch
6687 m = _('branch: %s\n') % branch
6685 if branch != 'default':
6688 if branch != 'default':
6686 ui.write(m, label='log.branch')
6689 ui.write(m, label='log.branch')
6687 else:
6690 else:
6688 ui.status(m, label='log.branch')
6691 ui.status(m, label='log.branch')
6689
6692
6690 if marks:
6693 if marks:
6691 active = repo._activebookmark
6694 active = repo._activebookmark
6692 # i18n: column positioning for "hg summary"
6695 # i18n: column positioning for "hg summary"
6693 ui.write(_('bookmarks:'), label='log.bookmark')
6696 ui.write(_('bookmarks:'), label='log.bookmark')
6694 if active is not None:
6697 if active is not None:
6695 if active in marks:
6698 if active in marks:
6696 ui.write(' *' + active, label=activebookmarklabel)
6699 ui.write(' *' + active, label=activebookmarklabel)
6697 marks.remove(active)
6700 marks.remove(active)
6698 else:
6701 else:
6699 ui.write(' [%s]' % active, label=activebookmarklabel)
6702 ui.write(' [%s]' % active, label=activebookmarklabel)
6700 for m in marks:
6703 for m in marks:
6701 ui.write(' ' + m, label='log.bookmark')
6704 ui.write(' ' + m, label='log.bookmark')
6702 ui.write('\n', label='log.bookmark')
6705 ui.write('\n', label='log.bookmark')
6703
6706
6704 status = repo.status(unknown=True)
6707 status = repo.status(unknown=True)
6705
6708
6706 c = repo.dirstate.copies()
6709 c = repo.dirstate.copies()
6707 copied, renamed = [], []
6710 copied, renamed = [], []
6708 for d, s in c.iteritems():
6711 for d, s in c.iteritems():
6709 if s in status.removed:
6712 if s in status.removed:
6710 status.removed.remove(s)
6713 status.removed.remove(s)
6711 renamed.append(d)
6714 renamed.append(d)
6712 else:
6715 else:
6713 copied.append(d)
6716 copied.append(d)
6714 if d in status.added:
6717 if d in status.added:
6715 status.added.remove(d)
6718 status.added.remove(d)
6716
6719
6717 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6720 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6718
6721
6719 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6722 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6720 (ui.label(_('%d added'), 'status.added'), status.added),
6723 (ui.label(_('%d added'), 'status.added'), status.added),
6721 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6724 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6722 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6725 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6723 (ui.label(_('%d copied'), 'status.copied'), copied),
6726 (ui.label(_('%d copied'), 'status.copied'), copied),
6724 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6727 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6725 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6728 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6726 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6729 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6727 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6730 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6728 t = []
6731 t = []
6729 for l, s in labels:
6732 for l, s in labels:
6730 if s:
6733 if s:
6731 t.append(l % len(s))
6734 t.append(l % len(s))
6732
6735
6733 t = ', '.join(t)
6736 t = ', '.join(t)
6734 cleanworkdir = False
6737 cleanworkdir = False
6735
6738
6736 if repo.vfs.exists('graftstate'):
6739 if repo.vfs.exists('graftstate'):
6737 t += _(' (graft in progress)')
6740 t += _(' (graft in progress)')
6738 if repo.vfs.exists('updatestate'):
6741 if repo.vfs.exists('updatestate'):
6739 t += _(' (interrupted update)')
6742 t += _(' (interrupted update)')
6740 elif len(parents) > 1:
6743 elif len(parents) > 1:
6741 t += _(' (merge)')
6744 t += _(' (merge)')
6742 elif branch != parents[0].branch():
6745 elif branch != parents[0].branch():
6743 t += _(' (new branch)')
6746 t += _(' (new branch)')
6744 elif (parents[0].closesbranch() and
6747 elif (parents[0].closesbranch() and
6745 pnode in repo.branchheads(branch, closed=True)):
6748 pnode in repo.branchheads(branch, closed=True)):
6746 t += _(' (head closed)')
6749 t += _(' (head closed)')
6747 elif not (status.modified or status.added or status.removed or renamed or
6750 elif not (status.modified or status.added or status.removed or renamed or
6748 copied or subs):
6751 copied or subs):
6749 t += _(' (clean)')
6752 t += _(' (clean)')
6750 cleanworkdir = True
6753 cleanworkdir = True
6751 elif pnode not in bheads:
6754 elif pnode not in bheads:
6752 t += _(' (new branch head)')
6755 t += _(' (new branch head)')
6753
6756
6754 if parents:
6757 if parents:
6755 pendingphase = max(p.phase() for p in parents)
6758 pendingphase = max(p.phase() for p in parents)
6756 else:
6759 else:
6757 pendingphase = phases.public
6760 pendingphase = phases.public
6758
6761
6759 if pendingphase > phases.newcommitphase(ui):
6762 if pendingphase > phases.newcommitphase(ui):
6760 t += ' (%s)' % phases.phasenames[pendingphase]
6763 t += ' (%s)' % phases.phasenames[pendingphase]
6761
6764
6762 if cleanworkdir:
6765 if cleanworkdir:
6763 # i18n: column positioning for "hg summary"
6766 # i18n: column positioning for "hg summary"
6764 ui.status(_('commit: %s\n') % t.strip())
6767 ui.status(_('commit: %s\n') % t.strip())
6765 else:
6768 else:
6766 # i18n: column positioning for "hg summary"
6769 # i18n: column positioning for "hg summary"
6767 ui.write(_('commit: %s\n') % t.strip())
6770 ui.write(_('commit: %s\n') % t.strip())
6768
6771
6769 # all ancestors of branch heads - all ancestors of parent = new csets
6772 # all ancestors of branch heads - all ancestors of parent = new csets
6770 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6773 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6771 bheads))
6774 bheads))
6772
6775
6773 if new == 0:
6776 if new == 0:
6774 # i18n: column positioning for "hg summary"
6777 # i18n: column positioning for "hg summary"
6775 ui.status(_('update: (current)\n'))
6778 ui.status(_('update: (current)\n'))
6776 elif pnode not in bheads:
6779 elif pnode not in bheads:
6777 # i18n: column positioning for "hg summary"
6780 # i18n: column positioning for "hg summary"
6778 ui.write(_('update: %d new changesets (update)\n') % new)
6781 ui.write(_('update: %d new changesets (update)\n') % new)
6779 else:
6782 else:
6780 # i18n: column positioning for "hg summary"
6783 # i18n: column positioning for "hg summary"
6781 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6784 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6782 (new, len(bheads)))
6785 (new, len(bheads)))
6783
6786
6784 t = []
6787 t = []
6785 draft = len(repo.revs('draft()'))
6788 draft = len(repo.revs('draft()'))
6786 if draft:
6789 if draft:
6787 t.append(_('%d draft') % draft)
6790 t.append(_('%d draft') % draft)
6788 secret = len(repo.revs('secret()'))
6791 secret = len(repo.revs('secret()'))
6789 if secret:
6792 if secret:
6790 t.append(_('%d secret') % secret)
6793 t.append(_('%d secret') % secret)
6791
6794
6792 if draft or secret:
6795 if draft or secret:
6793 ui.status(_('phases: %s\n') % ', '.join(t))
6796 ui.status(_('phases: %s\n') % ', '.join(t))
6794
6797
6795 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6798 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6796 for trouble in ("unstable", "divergent", "bumped"):
6799 for trouble in ("unstable", "divergent", "bumped"):
6797 numtrouble = len(repo.revs(trouble + "()"))
6800 numtrouble = len(repo.revs(trouble + "()"))
6798 # We write all the possibilities to ease translation
6801 # We write all the possibilities to ease translation
6799 troublemsg = {
6802 troublemsg = {
6800 "unstable": _("unstable: %d changesets"),
6803 "unstable": _("unstable: %d changesets"),
6801 "divergent": _("divergent: %d changesets"),
6804 "divergent": _("divergent: %d changesets"),
6802 "bumped": _("bumped: %d changesets"),
6805 "bumped": _("bumped: %d changesets"),
6803 }
6806 }
6804 if numtrouble > 0:
6807 if numtrouble > 0:
6805 ui.status(troublemsg[trouble] % numtrouble + "\n")
6808 ui.status(troublemsg[trouble] % numtrouble + "\n")
6806
6809
6807 cmdutil.summaryhooks(ui, repo)
6810 cmdutil.summaryhooks(ui, repo)
6808
6811
6809 if opts.get('remote'):
6812 if opts.get('remote'):
6810 needsincoming, needsoutgoing = True, True
6813 needsincoming, needsoutgoing = True, True
6811 else:
6814 else:
6812 needsincoming, needsoutgoing = False, False
6815 needsincoming, needsoutgoing = False, False
6813 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6816 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6814 if i:
6817 if i:
6815 needsincoming = True
6818 needsincoming = True
6816 if o:
6819 if o:
6817 needsoutgoing = True
6820 needsoutgoing = True
6818 if not needsincoming and not needsoutgoing:
6821 if not needsincoming and not needsoutgoing:
6819 return
6822 return
6820
6823
6821 def getincoming():
6824 def getincoming():
6822 source, branches = hg.parseurl(ui.expandpath('default'))
6825 source, branches = hg.parseurl(ui.expandpath('default'))
6823 sbranch = branches[0]
6826 sbranch = branches[0]
6824 try:
6827 try:
6825 other = hg.peer(repo, {}, source)
6828 other = hg.peer(repo, {}, source)
6826 except error.RepoError:
6829 except error.RepoError:
6827 if opts.get('remote'):
6830 if opts.get('remote'):
6828 raise
6831 raise
6829 return source, sbranch, None, None, None
6832 return source, sbranch, None, None, None
6830 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6833 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6831 if revs:
6834 if revs:
6832 revs = [other.lookup(rev) for rev in revs]
6835 revs = [other.lookup(rev) for rev in revs]
6833 ui.debug('comparing with %s\n' % util.hidepassword(source))
6836 ui.debug('comparing with %s\n' % util.hidepassword(source))
6834 repo.ui.pushbuffer()
6837 repo.ui.pushbuffer()
6835 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6838 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6836 repo.ui.popbuffer()
6839 repo.ui.popbuffer()
6837 return source, sbranch, other, commoninc, commoninc[1]
6840 return source, sbranch, other, commoninc, commoninc[1]
6838
6841
6839 if needsincoming:
6842 if needsincoming:
6840 source, sbranch, sother, commoninc, incoming = getincoming()
6843 source, sbranch, sother, commoninc, incoming = getincoming()
6841 else:
6844 else:
6842 source = sbranch = sother = commoninc = incoming = None
6845 source = sbranch = sother = commoninc = incoming = None
6843
6846
6844 def getoutgoing():
6847 def getoutgoing():
6845 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6848 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6846 dbranch = branches[0]
6849 dbranch = branches[0]
6847 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6850 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6848 if source != dest:
6851 if source != dest:
6849 try:
6852 try:
6850 dother = hg.peer(repo, {}, dest)
6853 dother = hg.peer(repo, {}, dest)
6851 except error.RepoError:
6854 except error.RepoError:
6852 if opts.get('remote'):
6855 if opts.get('remote'):
6853 raise
6856 raise
6854 return dest, dbranch, None, None
6857 return dest, dbranch, None, None
6855 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6858 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6856 elif sother is None:
6859 elif sother is None:
6857 # there is no explicit destination peer, but source one is invalid
6860 # there is no explicit destination peer, but source one is invalid
6858 return dest, dbranch, None, None
6861 return dest, dbranch, None, None
6859 else:
6862 else:
6860 dother = sother
6863 dother = sother
6861 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6864 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6862 common = None
6865 common = None
6863 else:
6866 else:
6864 common = commoninc
6867 common = commoninc
6865 if revs:
6868 if revs:
6866 revs = [repo.lookup(rev) for rev in revs]
6869 revs = [repo.lookup(rev) for rev in revs]
6867 repo.ui.pushbuffer()
6870 repo.ui.pushbuffer()
6868 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6871 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6869 commoninc=common)
6872 commoninc=common)
6870 repo.ui.popbuffer()
6873 repo.ui.popbuffer()
6871 return dest, dbranch, dother, outgoing
6874 return dest, dbranch, dother, outgoing
6872
6875
6873 if needsoutgoing:
6876 if needsoutgoing:
6874 dest, dbranch, dother, outgoing = getoutgoing()
6877 dest, dbranch, dother, outgoing = getoutgoing()
6875 else:
6878 else:
6876 dest = dbranch = dother = outgoing = None
6879 dest = dbranch = dother = outgoing = None
6877
6880
6878 if opts.get('remote'):
6881 if opts.get('remote'):
6879 t = []
6882 t = []
6880 if incoming:
6883 if incoming:
6881 t.append(_('1 or more incoming'))
6884 t.append(_('1 or more incoming'))
6882 o = outgoing.missing
6885 o = outgoing.missing
6883 if o:
6886 if o:
6884 t.append(_('%d outgoing') % len(o))
6887 t.append(_('%d outgoing') % len(o))
6885 other = dother or sother
6888 other = dother or sother
6886 if 'bookmarks' in other.listkeys('namespaces'):
6889 if 'bookmarks' in other.listkeys('namespaces'):
6887 counts = bookmarks.summary(repo, other)
6890 counts = bookmarks.summary(repo, other)
6888 if counts[0] > 0:
6891 if counts[0] > 0:
6889 t.append(_('%d incoming bookmarks') % counts[0])
6892 t.append(_('%d incoming bookmarks') % counts[0])
6890 if counts[1] > 0:
6893 if counts[1] > 0:
6891 t.append(_('%d outgoing bookmarks') % counts[1])
6894 t.append(_('%d outgoing bookmarks') % counts[1])
6892
6895
6893 if t:
6896 if t:
6894 # i18n: column positioning for "hg summary"
6897 # i18n: column positioning for "hg summary"
6895 ui.write(_('remote: %s\n') % (', '.join(t)))
6898 ui.write(_('remote: %s\n') % (', '.join(t)))
6896 else:
6899 else:
6897 # i18n: column positioning for "hg summary"
6900 # i18n: column positioning for "hg summary"
6898 ui.status(_('remote: (synced)\n'))
6901 ui.status(_('remote: (synced)\n'))
6899
6902
6900 cmdutil.summaryremotehooks(ui, repo, opts,
6903 cmdutil.summaryremotehooks(ui, repo, opts,
6901 ((source, sbranch, sother, commoninc),
6904 ((source, sbranch, sother, commoninc),
6902 (dest, dbranch, dother, outgoing)))
6905 (dest, dbranch, dother, outgoing)))
6903
6906
6904 @command('tag',
6907 @command('tag',
6905 [('f', 'force', None, _('force tag')),
6908 [('f', 'force', None, _('force tag')),
6906 ('l', 'local', None, _('make the tag local')),
6909 ('l', 'local', None, _('make the tag local')),
6907 ('r', 'rev', '', _('revision to tag'), _('REV')),
6910 ('r', 'rev', '', _('revision to tag'), _('REV')),
6908 ('', 'remove', None, _('remove a tag')),
6911 ('', 'remove', None, _('remove a tag')),
6909 # -l/--local is already there, commitopts cannot be used
6912 # -l/--local is already there, commitopts cannot be used
6910 ('e', 'edit', None, _('invoke editor on commit messages')),
6913 ('e', 'edit', None, _('invoke editor on commit messages')),
6911 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6914 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6912 ] + commitopts2,
6915 ] + commitopts2,
6913 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6916 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6914 def tag(ui, repo, name1, *names, **opts):
6917 def tag(ui, repo, name1, *names, **opts):
6915 """add one or more tags for the current or given revision
6918 """add one or more tags for the current or given revision
6916
6919
6917 Name a particular revision using <name>.
6920 Name a particular revision using <name>.
6918
6921
6919 Tags are used to name particular revisions of the repository and are
6922 Tags are used to name particular revisions of the repository and are
6920 very useful to compare different revisions, to go back to significant
6923 very useful to compare different revisions, to go back to significant
6921 earlier versions or to mark branch points as releases, etc. Changing
6924 earlier versions or to mark branch points as releases, etc. Changing
6922 an existing tag is normally disallowed; use -f/--force to override.
6925 an existing tag is normally disallowed; use -f/--force to override.
6923
6926
6924 If no revision is given, the parent of the working directory is
6927 If no revision is given, the parent of the working directory is
6925 used.
6928 used.
6926
6929
6927 To facilitate version control, distribution, and merging of tags,
6930 To facilitate version control, distribution, and merging of tags,
6928 they are stored as a file named ".hgtags" which is managed similarly
6931 they are stored as a file named ".hgtags" which is managed similarly
6929 to other project files and can be hand-edited if necessary. This
6932 to other project files and can be hand-edited if necessary. This
6930 also means that tagging creates a new commit. The file
6933 also means that tagging creates a new commit. The file
6931 ".hg/localtags" is used for local tags (not shared among
6934 ".hg/localtags" is used for local tags (not shared among
6932 repositories).
6935 repositories).
6933
6936
6934 Tag commits are usually made at the head of a branch. If the parent
6937 Tag commits are usually made at the head of a branch. If the parent
6935 of the working directory is not a branch head, :hg:`tag` aborts; use
6938 of the working directory is not a branch head, :hg:`tag` aborts; use
6936 -f/--force to force the tag commit to be based on a non-head
6939 -f/--force to force the tag commit to be based on a non-head
6937 changeset.
6940 changeset.
6938
6941
6939 See :hg:`help dates` for a list of formats valid for -d/--date.
6942 See :hg:`help dates` for a list of formats valid for -d/--date.
6940
6943
6941 Since tag names have priority over branch names during revision
6944 Since tag names have priority over branch names during revision
6942 lookup, using an existing branch name as a tag name is discouraged.
6945 lookup, using an existing branch name as a tag name is discouraged.
6943
6946
6944 Returns 0 on success.
6947 Returns 0 on success.
6945 """
6948 """
6946 wlock = lock = None
6949 wlock = lock = None
6947 try:
6950 try:
6948 wlock = repo.wlock()
6951 wlock = repo.wlock()
6949 lock = repo.lock()
6952 lock = repo.lock()
6950 rev_ = "."
6953 rev_ = "."
6951 names = [t.strip() for t in (name1,) + names]
6954 names = [t.strip() for t in (name1,) + names]
6952 if len(names) != len(set(names)):
6955 if len(names) != len(set(names)):
6953 raise error.Abort(_('tag names must be unique'))
6956 raise error.Abort(_('tag names must be unique'))
6954 for n in names:
6957 for n in names:
6955 scmutil.checknewlabel(repo, n, 'tag')
6958 scmutil.checknewlabel(repo, n, 'tag')
6956 if not n:
6959 if not n:
6957 raise error.Abort(_('tag names cannot consist entirely of '
6960 raise error.Abort(_('tag names cannot consist entirely of '
6958 'whitespace'))
6961 'whitespace'))
6959 if opts.get('rev') and opts.get('remove'):
6962 if opts.get('rev') and opts.get('remove'):
6960 raise error.Abort(_("--rev and --remove are incompatible"))
6963 raise error.Abort(_("--rev and --remove are incompatible"))
6961 if opts.get('rev'):
6964 if opts.get('rev'):
6962 rev_ = opts['rev']
6965 rev_ = opts['rev']
6963 message = opts.get('message')
6966 message = opts.get('message')
6964 if opts.get('remove'):
6967 if opts.get('remove'):
6965 if opts.get('local'):
6968 if opts.get('local'):
6966 expectedtype = 'local'
6969 expectedtype = 'local'
6967 else:
6970 else:
6968 expectedtype = 'global'
6971 expectedtype = 'global'
6969
6972
6970 for n in names:
6973 for n in names:
6971 if not repo.tagtype(n):
6974 if not repo.tagtype(n):
6972 raise error.Abort(_("tag '%s' does not exist") % n)
6975 raise error.Abort(_("tag '%s' does not exist") % n)
6973 if repo.tagtype(n) != expectedtype:
6976 if repo.tagtype(n) != expectedtype:
6974 if expectedtype == 'global':
6977 if expectedtype == 'global':
6975 raise error.Abort(_("tag '%s' is not a global tag") % n)
6978 raise error.Abort(_("tag '%s' is not a global tag") % n)
6976 else:
6979 else:
6977 raise error.Abort(_("tag '%s' is not a local tag") % n)
6980 raise error.Abort(_("tag '%s' is not a local tag") % n)
6978 rev_ = 'null'
6981 rev_ = 'null'
6979 if not message:
6982 if not message:
6980 # we don't translate commit messages
6983 # we don't translate commit messages
6981 message = 'Removed tag %s' % ', '.join(names)
6984 message = 'Removed tag %s' % ', '.join(names)
6982 elif not opts.get('force'):
6985 elif not opts.get('force'):
6983 for n in names:
6986 for n in names:
6984 if n in repo.tags():
6987 if n in repo.tags():
6985 raise error.Abort(_("tag '%s' already exists "
6988 raise error.Abort(_("tag '%s' already exists "
6986 "(use -f to force)") % n)
6989 "(use -f to force)") % n)
6987 if not opts.get('local'):
6990 if not opts.get('local'):
6988 p1, p2 = repo.dirstate.parents()
6991 p1, p2 = repo.dirstate.parents()
6989 if p2 != nullid:
6992 if p2 != nullid:
6990 raise error.Abort(_('uncommitted merge'))
6993 raise error.Abort(_('uncommitted merge'))
6991 bheads = repo.branchheads()
6994 bheads = repo.branchheads()
6992 if not opts.get('force') and bheads and p1 not in bheads:
6995 if not opts.get('force') and bheads and p1 not in bheads:
6993 raise error.Abort(_('not at a branch head (use -f to force)'))
6996 raise error.Abort(_('not at a branch head (use -f to force)'))
6994 r = scmutil.revsingle(repo, rev_).node()
6997 r = scmutil.revsingle(repo, rev_).node()
6995
6998
6996 if not message:
6999 if not message:
6997 # we don't translate commit messages
7000 # we don't translate commit messages
6998 message = ('Added tag %s for changeset %s' %
7001 message = ('Added tag %s for changeset %s' %
6999 (', '.join(names), short(r)))
7002 (', '.join(names), short(r)))
7000
7003
7001 date = opts.get('date')
7004 date = opts.get('date')
7002 if date:
7005 if date:
7003 date = util.parsedate(date)
7006 date = util.parsedate(date)
7004
7007
7005 if opts.get('remove'):
7008 if opts.get('remove'):
7006 editform = 'tag.remove'
7009 editform = 'tag.remove'
7007 else:
7010 else:
7008 editform = 'tag.add'
7011 editform = 'tag.add'
7009 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7012 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7010
7013
7011 # don't allow tagging the null rev
7014 # don't allow tagging the null rev
7012 if (not opts.get('remove') and
7015 if (not opts.get('remove') and
7013 scmutil.revsingle(repo, rev_).rev() == nullrev):
7016 scmutil.revsingle(repo, rev_).rev() == nullrev):
7014 raise error.Abort(_("cannot tag null revision"))
7017 raise error.Abort(_("cannot tag null revision"))
7015
7018
7016 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7019 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7017 editor=editor)
7020 editor=editor)
7018 finally:
7021 finally:
7019 release(lock, wlock)
7022 release(lock, wlock)
7020
7023
7021 @command('tags', formatteropts, '')
7024 @command('tags', formatteropts, '')
7022 def tags(ui, repo, **opts):
7025 def tags(ui, repo, **opts):
7023 """list repository tags
7026 """list repository tags
7024
7027
7025 This lists both regular and local tags. When the -v/--verbose
7028 This lists both regular and local tags. When the -v/--verbose
7026 switch is used, a third column "local" is printed for local tags.
7029 switch is used, a third column "local" is printed for local tags.
7027 When the -q/--quiet switch is used, only the tag name is printed.
7030 When the -q/--quiet switch is used, only the tag name is printed.
7028
7031
7029 Returns 0 on success.
7032 Returns 0 on success.
7030 """
7033 """
7031
7034
7032 fm = ui.formatter('tags', opts)
7035 fm = ui.formatter('tags', opts)
7033 hexfunc = fm.hexfunc
7036 hexfunc = fm.hexfunc
7034 tagtype = ""
7037 tagtype = ""
7035
7038
7036 for t, n in reversed(repo.tagslist()):
7039 for t, n in reversed(repo.tagslist()):
7037 hn = hexfunc(n)
7040 hn = hexfunc(n)
7038 label = 'tags.normal'
7041 label = 'tags.normal'
7039 tagtype = ''
7042 tagtype = ''
7040 if repo.tagtype(t) == 'local':
7043 if repo.tagtype(t) == 'local':
7041 label = 'tags.local'
7044 label = 'tags.local'
7042 tagtype = 'local'
7045 tagtype = 'local'
7043
7046
7044 fm.startitem()
7047 fm.startitem()
7045 fm.write('tag', '%s', t, label=label)
7048 fm.write('tag', '%s', t, label=label)
7046 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7049 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7047 fm.condwrite(not ui.quiet, 'rev node', fmt,
7050 fm.condwrite(not ui.quiet, 'rev node', fmt,
7048 repo.changelog.rev(n), hn, label=label)
7051 repo.changelog.rev(n), hn, label=label)
7049 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7052 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7050 tagtype, label=label)
7053 tagtype, label=label)
7051 fm.plain('\n')
7054 fm.plain('\n')
7052 fm.end()
7055 fm.end()
7053
7056
7054 @command('tip',
7057 @command('tip',
7055 [('p', 'patch', None, _('show patch')),
7058 [('p', 'patch', None, _('show patch')),
7056 ('g', 'git', None, _('use git extended diff format')),
7059 ('g', 'git', None, _('use git extended diff format')),
7057 ] + templateopts,
7060 ] + templateopts,
7058 _('[-p] [-g]'))
7061 _('[-p] [-g]'))
7059 def tip(ui, repo, **opts):
7062 def tip(ui, repo, **opts):
7060 """show the tip revision (DEPRECATED)
7063 """show the tip revision (DEPRECATED)
7061
7064
7062 The tip revision (usually just called the tip) is the changeset
7065 The tip revision (usually just called the tip) is the changeset
7063 most recently added to the repository (and therefore the most
7066 most recently added to the repository (and therefore the most
7064 recently changed head).
7067 recently changed head).
7065
7068
7066 If you have just made a commit, that commit will be the tip. If
7069 If you have just made a commit, that commit will be the tip. If
7067 you have just pulled changes from another repository, the tip of
7070 you have just pulled changes from another repository, the tip of
7068 that repository becomes the current tip. The "tip" tag is special
7071 that repository becomes the current tip. The "tip" tag is special
7069 and cannot be renamed or assigned to a different changeset.
7072 and cannot be renamed or assigned to a different changeset.
7070
7073
7071 This command is deprecated, please use :hg:`heads` instead.
7074 This command is deprecated, please use :hg:`heads` instead.
7072
7075
7073 Returns 0 on success.
7076 Returns 0 on success.
7074 """
7077 """
7075 displayer = cmdutil.show_changeset(ui, repo, opts)
7078 displayer = cmdutil.show_changeset(ui, repo, opts)
7076 displayer.show(repo['tip'])
7079 displayer.show(repo['tip'])
7077 displayer.close()
7080 displayer.close()
7078
7081
7079 @command('unbundle',
7082 @command('unbundle',
7080 [('u', 'update', None,
7083 [('u', 'update', None,
7081 _('update to new branch head if changesets were unbundled'))],
7084 _('update to new branch head if changesets were unbundled'))],
7082 _('[-u] FILE...'))
7085 _('[-u] FILE...'))
7083 def unbundle(ui, repo, fname1, *fnames, **opts):
7086 def unbundle(ui, repo, fname1, *fnames, **opts):
7084 """apply one or more changegroup files
7087 """apply one or more changegroup files
7085
7088
7086 Apply one or more compressed changegroup files generated by the
7089 Apply one or more compressed changegroup files generated by the
7087 bundle command.
7090 bundle command.
7088
7091
7089 Returns 0 on success, 1 if an update has unresolved files.
7092 Returns 0 on success, 1 if an update has unresolved files.
7090 """
7093 """
7091 fnames = (fname1,) + fnames
7094 fnames = (fname1,) + fnames
7092
7095
7093 with repo.lock():
7096 with repo.lock():
7094 for fname in fnames:
7097 for fname in fnames:
7095 f = hg.openpath(ui, fname)
7098 f = hg.openpath(ui, fname)
7096 gen = exchange.readbundle(ui, f, fname)
7099 gen = exchange.readbundle(ui, f, fname)
7097 if isinstance(gen, bundle2.unbundle20):
7100 if isinstance(gen, bundle2.unbundle20):
7098 tr = repo.transaction('unbundle')
7101 tr = repo.transaction('unbundle')
7099 try:
7102 try:
7100 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7103 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7101 url='bundle:' + fname)
7104 url='bundle:' + fname)
7102 tr.close()
7105 tr.close()
7103 except error.BundleUnknownFeatureError as exc:
7106 except error.BundleUnknownFeatureError as exc:
7104 raise error.Abort(_('%s: unknown bundle feature, %s')
7107 raise error.Abort(_('%s: unknown bundle feature, %s')
7105 % (fname, exc),
7108 % (fname, exc),
7106 hint=_("see https://mercurial-scm.org/"
7109 hint=_("see https://mercurial-scm.org/"
7107 "wiki/BundleFeature for more "
7110 "wiki/BundleFeature for more "
7108 "information"))
7111 "information"))
7109 finally:
7112 finally:
7110 if tr:
7113 if tr:
7111 tr.release()
7114 tr.release()
7112 changes = [r.get('return', 0)
7115 changes = [r.get('return', 0)
7113 for r in op.records['changegroup']]
7116 for r in op.records['changegroup']]
7114 modheads = changegroup.combineresults(changes)
7117 modheads = changegroup.combineresults(changes)
7115 elif isinstance(gen, streamclone.streamcloneapplier):
7118 elif isinstance(gen, streamclone.streamcloneapplier):
7116 raise error.Abort(
7119 raise error.Abort(
7117 _('packed bundles cannot be applied with '
7120 _('packed bundles cannot be applied with '
7118 '"hg unbundle"'),
7121 '"hg unbundle"'),
7119 hint=_('use "hg debugapplystreamclonebundle"'))
7122 hint=_('use "hg debugapplystreamclonebundle"'))
7120 else:
7123 else:
7121 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7124 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7122
7125
7123 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7126 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7124
7127
7125 @command('^update|up|checkout|co',
7128 @command('^update|up|checkout|co',
7126 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7129 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7127 ('c', 'check', None, _('require clean working directory')),
7130 ('c', 'check', None, _('require clean working directory')),
7128 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7131 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7129 ('r', 'rev', '', _('revision'), _('REV'))
7132 ('r', 'rev', '', _('revision'), _('REV'))
7130 ] + mergetoolopts,
7133 ] + mergetoolopts,
7131 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7134 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7132 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7135 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7133 tool=None):
7136 tool=None):
7134 """update working directory (or switch revisions)
7137 """update working directory (or switch revisions)
7135
7138
7136 Update the repository's working directory to the specified
7139 Update the repository's working directory to the specified
7137 changeset. If no changeset is specified, update to the tip of the
7140 changeset. If no changeset is specified, update to the tip of the
7138 current named branch and move the active bookmark (see :hg:`help
7141 current named branch and move the active bookmark (see :hg:`help
7139 bookmarks`).
7142 bookmarks`).
7140
7143
7141 Update sets the working directory's parent revision to the specified
7144 Update sets the working directory's parent revision to the specified
7142 changeset (see :hg:`help parents`).
7145 changeset (see :hg:`help parents`).
7143
7146
7144 If the changeset is not a descendant or ancestor of the working
7147 If the changeset is not a descendant or ancestor of the working
7145 directory's parent, the update is aborted. With the -c/--check
7148 directory's parent, the update is aborted. With the -c/--check
7146 option, the working directory is checked for uncommitted changes; if
7149 option, the working directory is checked for uncommitted changes; if
7147 none are found, the working directory is updated to the specified
7150 none are found, the working directory is updated to the specified
7148 changeset.
7151 changeset.
7149
7152
7150 .. container:: verbose
7153 .. container:: verbose
7151
7154
7152 The following rules apply when the working directory contains
7155 The following rules apply when the working directory contains
7153 uncommitted changes:
7156 uncommitted changes:
7154
7157
7155 1. If neither -c/--check nor -C/--clean is specified, and if
7158 1. If neither -c/--check nor -C/--clean is specified, and if
7156 the requested changeset is an ancestor or descendant of
7159 the requested changeset is an ancestor or descendant of
7157 the working directory's parent, the uncommitted changes
7160 the working directory's parent, the uncommitted changes
7158 are merged into the requested changeset and the merged
7161 are merged into the requested changeset and the merged
7159 result is left uncommitted. If the requested changeset is
7162 result is left uncommitted. If the requested changeset is
7160 not an ancestor or descendant (that is, it is on another
7163 not an ancestor or descendant (that is, it is on another
7161 branch), the update is aborted and the uncommitted changes
7164 branch), the update is aborted and the uncommitted changes
7162 are preserved.
7165 are preserved.
7163
7166
7164 2. With the -c/--check option, the update is aborted and the
7167 2. With the -c/--check option, the update is aborted and the
7165 uncommitted changes are preserved.
7168 uncommitted changes are preserved.
7166
7169
7167 3. With the -C/--clean option, uncommitted changes are discarded and
7170 3. With the -C/--clean option, uncommitted changes are discarded and
7168 the working directory is updated to the requested changeset.
7171 the working directory is updated to the requested changeset.
7169
7172
7170 To cancel an uncommitted merge (and lose your changes), use
7173 To cancel an uncommitted merge (and lose your changes), use
7171 :hg:`update --clean .`.
7174 :hg:`update --clean .`.
7172
7175
7173 Use null as the changeset to remove the working directory (like
7176 Use null as the changeset to remove the working directory (like
7174 :hg:`clone -U`).
7177 :hg:`clone -U`).
7175
7178
7176 If you want to revert just one file to an older revision, use
7179 If you want to revert just one file to an older revision, use
7177 :hg:`revert [-r REV] NAME`.
7180 :hg:`revert [-r REV] NAME`.
7178
7181
7179 See :hg:`help dates` for a list of formats valid for -d/--date.
7182 See :hg:`help dates` for a list of formats valid for -d/--date.
7180
7183
7181 Returns 0 on success, 1 if there are unresolved files.
7184 Returns 0 on success, 1 if there are unresolved files.
7182 """
7185 """
7183 if rev and node:
7186 if rev and node:
7184 raise error.Abort(_("please specify just one revision"))
7187 raise error.Abort(_("please specify just one revision"))
7185
7188
7186 if rev is None or rev == '':
7189 if rev is None or rev == '':
7187 rev = node
7190 rev = node
7188
7191
7189 if date and rev is not None:
7192 if date and rev is not None:
7190 raise error.Abort(_("you can't specify a revision and a date"))
7193 raise error.Abort(_("you can't specify a revision and a date"))
7191
7194
7192 if check and clean:
7195 if check and clean:
7193 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7196 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7194
7197
7195 with repo.wlock():
7198 with repo.wlock():
7196 cmdutil.clearunfinished(repo)
7199 cmdutil.clearunfinished(repo)
7197
7200
7198 if date:
7201 if date:
7199 rev = cmdutil.finddate(ui, repo, date)
7202 rev = cmdutil.finddate(ui, repo, date)
7200
7203
7201 # if we defined a bookmark, we have to remember the original name
7204 # if we defined a bookmark, we have to remember the original name
7202 brev = rev
7205 brev = rev
7203 rev = scmutil.revsingle(repo, rev, rev).rev()
7206 rev = scmutil.revsingle(repo, rev, rev).rev()
7204
7207
7205 if check:
7208 if check:
7206 cmdutil.bailifchanged(repo, merge=False)
7209 cmdutil.bailifchanged(repo, merge=False)
7207
7210
7208 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7211 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7209
7212
7210 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7213 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7211
7214
7212 @command('verify', [])
7215 @command('verify', [])
7213 def verify(ui, repo):
7216 def verify(ui, repo):
7214 """verify the integrity of the repository
7217 """verify the integrity of the repository
7215
7218
7216 Verify the integrity of the current repository.
7219 Verify the integrity of the current repository.
7217
7220
7218 This will perform an extensive check of the repository's
7221 This will perform an extensive check of the repository's
7219 integrity, validating the hashes and checksums of each entry in
7222 integrity, validating the hashes and checksums of each entry in
7220 the changelog, manifest, and tracked files, as well as the
7223 the changelog, manifest, and tracked files, as well as the
7221 integrity of their crosslinks and indices.
7224 integrity of their crosslinks and indices.
7222
7225
7223 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7226 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7224 for more information about recovery from corruption of the
7227 for more information about recovery from corruption of the
7225 repository.
7228 repository.
7226
7229
7227 Returns 0 on success, 1 if errors are encountered.
7230 Returns 0 on success, 1 if errors are encountered.
7228 """
7231 """
7229 return hg.verify(repo)
7232 return hg.verify(repo)
7230
7233
7231 @command('version', [], norepo=True)
7234 @command('version', [], norepo=True)
7232 def version_(ui):
7235 def version_(ui):
7233 """output version and copyright information"""
7236 """output version and copyright information"""
7234 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7237 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7235 % util.version())
7238 % util.version())
7236 ui.status(_(
7239 ui.status(_(
7237 "(see https://mercurial-scm.org for more information)\n"
7240 "(see https://mercurial-scm.org for more information)\n"
7238 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7241 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7239 "This is free software; see the source for copying conditions. "
7242 "This is free software; see the source for copying conditions. "
7240 "There is NO\nwarranty; "
7243 "There is NO\nwarranty; "
7241 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7244 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7242 ))
7245 ))
7243
7246
7244 ui.note(_("\nEnabled extensions:\n\n"))
7247 ui.note(_("\nEnabled extensions:\n\n"))
7245 if ui.verbose:
7248 if ui.verbose:
7246 # format names and versions into columns
7249 # format names and versions into columns
7247 names = []
7250 names = []
7248 vers = []
7251 vers = []
7249 place = []
7252 place = []
7250 for name, module in extensions.extensions():
7253 for name, module in extensions.extensions():
7251 names.append(name)
7254 names.append(name)
7252 vers.append(extensions.moduleversion(module))
7255 vers.append(extensions.moduleversion(module))
7253 if extensions.ismoduleinternal(module):
7256 if extensions.ismoduleinternal(module):
7254 place.append(_("internal"))
7257 place.append(_("internal"))
7255 else:
7258 else:
7256 place.append(_("external"))
7259 place.append(_("external"))
7257 if names:
7260 if names:
7258 maxnamelen = max(len(n) for n in names)
7261 maxnamelen = max(len(n) for n in names)
7259 for i, name in enumerate(names):
7262 for i, name in enumerate(names):
7260 ui.write(" %-*s %s %s\n" %
7263 ui.write(" %-*s %s %s\n" %
7261 (maxnamelen, name, place[i], vers[i]))
7264 (maxnamelen, name, place[i], vers[i]))
7262
7265
7263 def loadcmdtable(ui, name, cmdtable):
7266 def loadcmdtable(ui, name, cmdtable):
7264 """Load command functions from specified cmdtable
7267 """Load command functions from specified cmdtable
7265 """
7268 """
7266 overrides = [cmd for cmd in cmdtable if cmd in table]
7269 overrides = [cmd for cmd in cmdtable if cmd in table]
7267 if overrides:
7270 if overrides:
7268 ui.warn(_("extension '%s' overrides commands: %s\n")
7271 ui.warn(_("extension '%s' overrides commands: %s\n")
7269 % (name, " ".join(overrides)))
7272 % (name, " ".join(overrides)))
7270 table.update(cmdtable)
7273 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now