##// END OF EJS Templates
debuginstall: expose modulepolicy...
timeless -
r29266:b3a677c8 default
parent child Browse files
Show More
@@ -0,0 +1,40 b''
1 # policy.py - module policy logic for Mercurial.
2 #
3 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
4 #
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.
7
8 from __future__ import absolute_import
9
10 import os
11 import sys
12
13 # Rules for how modules can be loaded. Values are:
14 #
15 # c - require C extensions
16 # allow - allow pure Python implementation when C loading fails
17 # py - only load pure Python modules
18 #
19 # By default, require the C extensions for performance reasons.
20 policy = 'c'
21 try:
22 from . import __modulepolicy__
23 policy = __modulepolicy__.modulepolicy
24 except ImportError:
25 pass
26
27 # PyPy doesn't load C extensions.
28 #
29 # The canonical way to do this is to test platform.python_implementation().
30 # But we don't import platform and don't bloat for it here.
31 if '__pypy__' in sys.builtin_module_names:
32 policy = 'py'
33
34 # Our C extensions aren't yet compatible with Python 3. So use pure Python
35 # on Python 3 for now.
36 if sys.version_info[0] >= 3:
37 policy = 'py'
38
39 # Environment variable can always force settings.
40 policy = os.environ.get('HGMODULEPOLICY', policy)
@@ -1,152 +1,129 b''
1 # __init__.py - Startup and module loading logic for Mercurial.
1 # __init__.py - Startup and module loading logic for Mercurial.
2 #
2 #
3 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.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 imp
10 import imp
11 import os
11 import os
12 import sys
12 import sys
13 import zipimport
13 import zipimport
14
14
15 from . import (
16 policy
17 )
18
15 __all__ = []
19 __all__ = []
16
20
17 # Rules for how modules can be loaded. Values are:
21 modulepolicy = policy.policy
18 #
19 # c - require C extensions
20 # allow - allow pure Python implementation when C loading fails
21 # py - only load pure Python modules
22 #
23 # By default, require the C extensions for performance reasons.
24 modulepolicy = 'c'
25 try:
26 from . import __modulepolicy__
27 modulepolicy = __modulepolicy__.modulepolicy
28 except ImportError:
29 pass
30
31 # PyPy doesn't load C extensions.
32 #
33 # The canonical way to do this is to test platform.python_implementation().
34 # But we don't import platform and don't bloat for it here.
35 if '__pypy__' in sys.builtin_module_names:
36 modulepolicy = 'py'
37
38 # Our C extensions aren't yet compatible with Python 3. So use pure Python
39 # on Python 3 for now.
40 if sys.version_info[0] >= 3:
41 modulepolicy = 'py'
42
43 # Environment variable can always force settings.
44 modulepolicy = os.environ.get('HGMODULEPOLICY', modulepolicy)
45
22
46 # Modules that have both Python and C implementations. See also the
23 # Modules that have both Python and C implementations. See also the
47 # set of .py files under mercurial/pure/.
24 # set of .py files under mercurial/pure/.
48 _dualmodules = set([
25 _dualmodules = set([
49 'mercurial.base85',
26 'mercurial.base85',
50 'mercurial.bdiff',
27 'mercurial.bdiff',
51 'mercurial.diffhelpers',
28 'mercurial.diffhelpers',
52 'mercurial.mpatch',
29 'mercurial.mpatch',
53 'mercurial.osutil',
30 'mercurial.osutil',
54 'mercurial.parsers',
31 'mercurial.parsers',
55 ])
32 ])
56
33
57 class hgimporter(object):
34 class hgimporter(object):
58 """Object that conforms to import hook interface defined in PEP-302."""
35 """Object that conforms to import hook interface defined in PEP-302."""
59 def find_module(self, name, path=None):
36 def find_module(self, name, path=None):
60 # We only care about modules that have both C and pure implementations.
37 # We only care about modules that have both C and pure implementations.
61 if name in _dualmodules:
38 if name in _dualmodules:
62 return self
39 return self
63 return None
40 return None
64
41
65 def load_module(self, name):
42 def load_module(self, name):
66 mod = sys.modules.get(name, None)
43 mod = sys.modules.get(name, None)
67 if mod:
44 if mod:
68 return mod
45 return mod
69
46
70 mercurial = sys.modules['mercurial']
47 mercurial = sys.modules['mercurial']
71
48
72 # The zip importer behaves sufficiently differently from the default
49 # The zip importer behaves sufficiently differently from the default
73 # importer to warrant its own code path.
50 # importer to warrant its own code path.
74 loader = getattr(mercurial, '__loader__', None)
51 loader = getattr(mercurial, '__loader__', None)
75 if isinstance(loader, zipimport.zipimporter):
52 if isinstance(loader, zipimport.zipimporter):
76 def ziploader(*paths):
53 def ziploader(*paths):
77 """Obtain a zipimporter for a directory under the main zip."""
54 """Obtain a zipimporter for a directory under the main zip."""
78 path = os.path.join(loader.archive, *paths)
55 path = os.path.join(loader.archive, *paths)
79 zl = sys.path_importer_cache.get(path)
56 zl = sys.path_importer_cache.get(path)
80 if not zl:
57 if not zl:
81 zl = zipimport.zipimporter(path)
58 zl = zipimport.zipimporter(path)
82 return zl
59 return zl
83
60
84 try:
61 try:
85 if modulepolicy == 'py':
62 if modulepolicy == 'py':
86 raise ImportError()
63 raise ImportError()
87
64
88 zl = ziploader('mercurial')
65 zl = ziploader('mercurial')
89 mod = zl.load_module(name)
66 mod = zl.load_module(name)
90 # Unlike imp, ziploader doesn't expose module metadata that
67 # Unlike imp, ziploader doesn't expose module metadata that
91 # indicates the type of module. So just assume what we found
68 # indicates the type of module. So just assume what we found
92 # is OK (even though it could be a pure Python module).
69 # is OK (even though it could be a pure Python module).
93 except ImportError:
70 except ImportError:
94 if modulepolicy == 'c':
71 if modulepolicy == 'c':
95 raise
72 raise
96 zl = ziploader('mercurial', 'pure')
73 zl = ziploader('mercurial', 'pure')
97 mod = zl.load_module(name)
74 mod = zl.load_module(name)
98
75
99 sys.modules[name] = mod
76 sys.modules[name] = mod
100 return mod
77 return mod
101
78
102 # Unlike the default importer which searches special locations and
79 # Unlike the default importer which searches special locations and
103 # sys.path, we only look in the directory where "mercurial" was
80 # sys.path, we only look in the directory where "mercurial" was
104 # imported from.
81 # imported from.
105
82
106 # imp.find_module doesn't support submodules (modules with ".").
83 # imp.find_module doesn't support submodules (modules with ".").
107 # Instead you have to pass the parent package's __path__ attribute
84 # Instead you have to pass the parent package's __path__ attribute
108 # as the path argument.
85 # as the path argument.
109 stem = name.split('.')[-1]
86 stem = name.split('.')[-1]
110
87
111 try:
88 try:
112 if modulepolicy == 'py':
89 if modulepolicy == 'py':
113 raise ImportError()
90 raise ImportError()
114
91
115 modinfo = imp.find_module(stem, mercurial.__path__)
92 modinfo = imp.find_module(stem, mercurial.__path__)
116
93
117 # The Mercurial installer used to copy files from
94 # The Mercurial installer used to copy files from
118 # mercurial/pure/*.py to mercurial/*.py. Therefore, it's possible
95 # mercurial/pure/*.py to mercurial/*.py. Therefore, it's possible
119 # for some installations to have .py files under mercurial/*.
96 # for some installations to have .py files under mercurial/*.
120 # Loading Python modules when we expected C versions could result
97 # Loading Python modules when we expected C versions could result
121 # in a) poor performance b) loading a version from a previous
98 # in a) poor performance b) loading a version from a previous
122 # Mercurial version, potentially leading to incompatibility. Either
99 # Mercurial version, potentially leading to incompatibility. Either
123 # scenario is bad. So we verify that modules loaded from
100 # scenario is bad. So we verify that modules loaded from
124 # mercurial/* are C extensions. If the current policy allows the
101 # mercurial/* are C extensions. If the current policy allows the
125 # loading of .py modules, the module will be re-imported from
102 # loading of .py modules, the module will be re-imported from
126 # mercurial/pure/* below.
103 # mercurial/pure/* below.
127 if modinfo[2][2] != imp.C_EXTENSION:
104 if modinfo[2][2] != imp.C_EXTENSION:
128 raise ImportError('.py version of %s found where C '
105 raise ImportError('.py version of %s found where C '
129 'version should exist' % name)
106 'version should exist' % name)
130
107
131 except ImportError:
108 except ImportError:
132 if modulepolicy == 'c':
109 if modulepolicy == 'c':
133 raise
110 raise
134
111
135 # Could not load the C extension and pure Python is allowed. So
112 # Could not load the C extension and pure Python is allowed. So
136 # try to load them.
113 # try to load them.
137 from . import pure
114 from . import pure
138 modinfo = imp.find_module(stem, pure.__path__)
115 modinfo = imp.find_module(stem, pure.__path__)
139 if not modinfo:
116 if not modinfo:
140 raise ImportError('could not find mercurial module %s' %
117 raise ImportError('could not find mercurial module %s' %
141 name)
118 name)
142
119
143 mod = imp.load_module(name, *modinfo)
120 mod = imp.load_module(name, *modinfo)
144 sys.modules[name] = mod
121 sys.modules[name] = mod
145 return mod
122 return mod
146
123
147 # We automagically register our custom importer as a side-effect of loading.
124 # We automagically register our custom importer as a side-effect of loading.
148 # This is necessary to ensure that any entry points are able to import
125 # This is necessary to ensure that any entry points are able to import
149 # mercurial.* modules without having to perform this registration themselves.
126 # mercurial.* modules without having to perform this registration themselves.
150 if not any(isinstance(x, hgimporter) for x in sys.meta_path):
127 if not any(isinstance(x, hgimporter) for x in sys.meta_path):
151 # meta_path is used before any implicit finders and before sys.path.
128 # meta_path is used before any implicit finders and before sys.path.
152 sys.meta_path.insert(0, hgimporter())
129 sys.meta_path.insert(0, hgimporter())
@@ -1,7266 +1,7269 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import operator
12 import operator
13 import os
13 import os
14 import random
14 import random
15 import re
15 import re
16 import shlex
16 import shlex
17 import socket
17 import socket
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 import time
20 import time
21
21
22 from .i18n import _
22 from .i18n import _
23 from .node import (
23 from .node import (
24 bin,
24 bin,
25 hex,
25 hex,
26 nullhex,
26 nullhex,
27 nullid,
27 nullid,
28 nullrev,
28 nullrev,
29 short,
29 short,
30 )
30 )
31 from . import (
31 from . import (
32 archival,
32 archival,
33 bookmarks,
33 bookmarks,
34 bundle2,
34 bundle2,
35 changegroup,
35 changegroup,
36 cmdutil,
36 cmdutil,
37 commandserver,
37 commandserver,
38 context,
38 context,
39 copies,
39 copies,
40 dagparser,
40 dagparser,
41 dagutil,
41 dagutil,
42 destutil,
42 destutil,
43 discovery,
43 discovery,
44 encoding,
44 encoding,
45 error,
45 error,
46 exchange,
46 exchange,
47 extensions,
47 extensions,
48 fileset,
48 fileset,
49 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 pvec,
63 pvec,
63 repair,
64 repair,
64 revlog,
65 revlog,
65 revset,
66 revset,
66 scmutil,
67 scmutil,
67 setdiscovery,
68 setdiscovery,
68 simplemerge,
69 simplemerge,
69 sshserver,
70 sshserver,
70 streamclone,
71 streamclone,
71 templatekw,
72 templatekw,
72 templater,
73 templater,
73 treediscovery,
74 treediscovery,
74 ui as uimod,
75 ui as uimod,
75 util,
76 util,
76 )
77 )
77
78
78 release = lockmod.release
79 release = lockmod.release
79
80
80 table = {}
81 table = {}
81
82
82 command = cmdutil.command(table)
83 command = cmdutil.command(table)
83
84
84 # label constants
85 # label constants
85 # until 3.5, bookmarks.current was the advertised name, not
86 # until 3.5, bookmarks.current was the advertised name, not
86 # bookmarks.active, so we must use both to avoid breaking old
87 # bookmarks.active, so we must use both to avoid breaking old
87 # custom styles
88 # custom styles
88 activebookmarklabel = 'bookmarks.active bookmarks.current'
89 activebookmarklabel = 'bookmarks.active bookmarks.current'
89
90
90 # common command options
91 # common command options
91
92
92 globalopts = [
93 globalopts = [
93 ('R', 'repository', '',
94 ('R', 'repository', '',
94 _('repository root directory or name of overlay bundle file'),
95 _('repository root directory or name of overlay bundle file'),
95 _('REPO')),
96 _('REPO')),
96 ('', 'cwd', '',
97 ('', 'cwd', '',
97 _('change working directory'), _('DIR')),
98 _('change working directory'), _('DIR')),
98 ('y', 'noninteractive', None,
99 ('y', 'noninteractive', None,
99 _('do not prompt, automatically pick the first choice for all prompts')),
100 _('do not prompt, automatically pick the first choice for all prompts')),
100 ('q', 'quiet', None, _('suppress output')),
101 ('q', 'quiet', None, _('suppress output')),
101 ('v', 'verbose', None, _('enable additional output')),
102 ('v', 'verbose', None, _('enable additional output')),
102 ('', 'config', [],
103 ('', 'config', [],
103 _('set/override config option (use \'section.name=value\')'),
104 _('set/override config option (use \'section.name=value\')'),
104 _('CONFIG')),
105 _('CONFIG')),
105 ('', 'debug', None, _('enable debugging output')),
106 ('', 'debug', None, _('enable debugging output')),
106 ('', 'debugger', None, _('start debugger')),
107 ('', 'debugger', None, _('start debugger')),
107 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
108 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
108 _('ENCODE')),
109 _('ENCODE')),
109 ('', 'encodingmode', encoding.encodingmode,
110 ('', 'encodingmode', encoding.encodingmode,
110 _('set the charset encoding mode'), _('MODE')),
111 _('set the charset encoding mode'), _('MODE')),
111 ('', 'traceback', None, _('always print a traceback on exception')),
112 ('', 'traceback', None, _('always print a traceback on exception')),
112 ('', 'time', None, _('time how long the command takes')),
113 ('', 'time', None, _('time how long the command takes')),
113 ('', 'profile', None, _('print command execution profile')),
114 ('', 'profile', None, _('print command execution profile')),
114 ('', 'version', None, _('output version information and exit')),
115 ('', 'version', None, _('output version information and exit')),
115 ('h', 'help', None, _('display help and exit')),
116 ('h', 'help', None, _('display help and exit')),
116 ('', 'hidden', False, _('consider hidden changesets')),
117 ('', 'hidden', False, _('consider hidden changesets')),
117 ]
118 ]
118
119
119 dryrunopts = [('n', 'dry-run', None,
120 dryrunopts = [('n', 'dry-run', None,
120 _('do not perform actions, just print output'))]
121 _('do not perform actions, just print output'))]
121
122
122 remoteopts = [
123 remoteopts = [
123 ('e', 'ssh', '',
124 ('e', 'ssh', '',
124 _('specify ssh command to use'), _('CMD')),
125 _('specify ssh command to use'), _('CMD')),
125 ('', 'remotecmd', '',
126 ('', 'remotecmd', '',
126 _('specify hg command to run on the remote side'), _('CMD')),
127 _('specify hg command to run on the remote side'), _('CMD')),
127 ('', 'insecure', None,
128 ('', 'insecure', None,
128 _('do not verify server certificate (ignoring web.cacerts config)')),
129 _('do not verify server certificate (ignoring web.cacerts config)')),
129 ]
130 ]
130
131
131 walkopts = [
132 walkopts = [
132 ('I', 'include', [],
133 ('I', 'include', [],
133 _('include names matching the given patterns'), _('PATTERN')),
134 _('include names matching the given patterns'), _('PATTERN')),
134 ('X', 'exclude', [],
135 ('X', 'exclude', [],
135 _('exclude names matching the given patterns'), _('PATTERN')),
136 _('exclude names matching the given patterns'), _('PATTERN')),
136 ]
137 ]
137
138
138 commitopts = [
139 commitopts = [
139 ('m', 'message', '',
140 ('m', 'message', '',
140 _('use text as commit message'), _('TEXT')),
141 _('use text as commit message'), _('TEXT')),
141 ('l', 'logfile', '',
142 ('l', 'logfile', '',
142 _('read commit message from file'), _('FILE')),
143 _('read commit message from file'), _('FILE')),
143 ]
144 ]
144
145
145 commitopts2 = [
146 commitopts2 = [
146 ('d', 'date', '',
147 ('d', 'date', '',
147 _('record the specified date as commit date'), _('DATE')),
148 _('record the specified date as commit date'), _('DATE')),
148 ('u', 'user', '',
149 ('u', 'user', '',
149 _('record the specified user as committer'), _('USER')),
150 _('record the specified user as committer'), _('USER')),
150 ]
151 ]
151
152
152 # hidden for now
153 # hidden for now
153 formatteropts = [
154 formatteropts = [
154 ('T', 'template', '',
155 ('T', 'template', '',
155 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
156 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
156 ]
157 ]
157
158
158 templateopts = [
159 templateopts = [
159 ('', 'style', '',
160 ('', 'style', '',
160 _('display using template map file (DEPRECATED)'), _('STYLE')),
161 _('display using template map file (DEPRECATED)'), _('STYLE')),
161 ('T', 'template', '',
162 ('T', 'template', '',
162 _('display with template'), _('TEMPLATE')),
163 _('display with template'), _('TEMPLATE')),
163 ]
164 ]
164
165
165 logopts = [
166 logopts = [
166 ('p', 'patch', None, _('show patch')),
167 ('p', 'patch', None, _('show patch')),
167 ('g', 'git', None, _('use git extended diff format')),
168 ('g', 'git', None, _('use git extended diff format')),
168 ('l', 'limit', '',
169 ('l', 'limit', '',
169 _('limit number of changes displayed'), _('NUM')),
170 _('limit number of changes displayed'), _('NUM')),
170 ('M', 'no-merges', None, _('do not show merges')),
171 ('M', 'no-merges', None, _('do not show merges')),
171 ('', 'stat', None, _('output diffstat-style summary of changes')),
172 ('', 'stat', None, _('output diffstat-style summary of changes')),
172 ('G', 'graph', None, _("show the revision DAG")),
173 ('G', 'graph', None, _("show the revision DAG")),
173 ] + templateopts
174 ] + templateopts
174
175
175 diffopts = [
176 diffopts = [
176 ('a', 'text', None, _('treat all files as text')),
177 ('a', 'text', None, _('treat all files as text')),
177 ('g', 'git', None, _('use git extended diff format')),
178 ('g', 'git', None, _('use git extended diff format')),
178 ('', 'nodates', None, _('omit dates from diff headers'))
179 ('', 'nodates', None, _('omit dates from diff headers'))
179 ]
180 ]
180
181
181 diffwsopts = [
182 diffwsopts = [
182 ('w', 'ignore-all-space', None,
183 ('w', 'ignore-all-space', None,
183 _('ignore white space when comparing lines')),
184 _('ignore white space when comparing lines')),
184 ('b', 'ignore-space-change', None,
185 ('b', 'ignore-space-change', None,
185 _('ignore changes in the amount of white space')),
186 _('ignore changes in the amount of white space')),
186 ('B', 'ignore-blank-lines', None,
187 ('B', 'ignore-blank-lines', None,
187 _('ignore changes whose lines are all blank')),
188 _('ignore changes whose lines are all blank')),
188 ]
189 ]
189
190
190 diffopts2 = [
191 diffopts2 = [
191 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
192 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
192 ('p', 'show-function', None, _('show which function each change is in')),
193 ('p', 'show-function', None, _('show which function each change is in')),
193 ('', 'reverse', None, _('produce a diff that undoes the changes')),
194 ('', 'reverse', None, _('produce a diff that undoes the changes')),
194 ] + diffwsopts + [
195 ] + diffwsopts + [
195 ('U', 'unified', '',
196 ('U', 'unified', '',
196 _('number of lines of context to show'), _('NUM')),
197 _('number of lines of context to show'), _('NUM')),
197 ('', 'stat', None, _('output diffstat-style summary of changes')),
198 ('', 'stat', None, _('output diffstat-style summary of changes')),
198 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
199 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
199 ]
200 ]
200
201
201 mergetoolopts = [
202 mergetoolopts = [
202 ('t', 'tool', '', _('specify merge tool')),
203 ('t', 'tool', '', _('specify merge tool')),
203 ]
204 ]
204
205
205 similarityopts = [
206 similarityopts = [
206 ('s', 'similarity', '',
207 ('s', 'similarity', '',
207 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
208 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
208 ]
209 ]
209
210
210 subrepoopts = [
211 subrepoopts = [
211 ('S', 'subrepos', None,
212 ('S', 'subrepos', None,
212 _('recurse into subrepositories'))
213 _('recurse into subrepositories'))
213 ]
214 ]
214
215
215 debugrevlogopts = [
216 debugrevlogopts = [
216 ('c', 'changelog', False, _('open changelog')),
217 ('c', 'changelog', False, _('open changelog')),
217 ('m', 'manifest', False, _('open manifest')),
218 ('m', 'manifest', False, _('open manifest')),
218 ('', 'dir', False, _('open directory manifest')),
219 ('', 'dir', False, _('open directory manifest')),
219 ]
220 ]
220
221
221 # Commands start here, listed alphabetically
222 # Commands start here, listed alphabetically
222
223
223 @command('^add',
224 @command('^add',
224 walkopts + subrepoopts + dryrunopts,
225 walkopts + subrepoopts + dryrunopts,
225 _('[OPTION]... [FILE]...'),
226 _('[OPTION]... [FILE]...'),
226 inferrepo=True)
227 inferrepo=True)
227 def add(ui, repo, *pats, **opts):
228 def add(ui, repo, *pats, **opts):
228 """add the specified files on the next commit
229 """add the specified files on the next commit
229
230
230 Schedule files to be version controlled and added to the
231 Schedule files to be version controlled and added to the
231 repository.
232 repository.
232
233
233 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
234 undo an add before that, see :hg:`forget`.
235 undo an add before that, see :hg:`forget`.
235
236
236 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
237 files matching ``.hgignore``).
238 files matching ``.hgignore``).
238
239
239 .. container:: verbose
240 .. container:: verbose
240
241
241 Examples:
242 Examples:
242
243
243 - New (unknown) files are added
244 - New (unknown) files are added
244 automatically by :hg:`add`::
245 automatically by :hg:`add`::
245
246
246 $ ls
247 $ ls
247 foo.c
248 foo.c
248 $ hg status
249 $ hg status
249 ? foo.c
250 ? foo.c
250 $ hg add
251 $ hg add
251 adding foo.c
252 adding foo.c
252 $ hg status
253 $ hg status
253 A foo.c
254 A foo.c
254
255
255 - Specific files to be added can be specified::
256 - Specific files to be added can be specified::
256
257
257 $ ls
258 $ ls
258 bar.c foo.c
259 bar.c foo.c
259 $ hg status
260 $ hg status
260 ? bar.c
261 ? bar.c
261 ? foo.c
262 ? foo.c
262 $ hg add bar.c
263 $ hg add bar.c
263 $ hg status
264 $ hg status
264 A bar.c
265 A bar.c
265 ? foo.c
266 ? foo.c
266
267
267 Returns 0 if all files are successfully added.
268 Returns 0 if all files are successfully added.
268 """
269 """
269
270
270 m = scmutil.match(repo[None], pats, opts)
271 m = scmutil.match(repo[None], pats, opts)
271 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
272 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
272 return rejected and 1 or 0
273 return rejected and 1 or 0
273
274
274 @command('addremove',
275 @command('addremove',
275 similarityopts + subrepoopts + walkopts + dryrunopts,
276 similarityopts + subrepoopts + walkopts + dryrunopts,
276 _('[OPTION]... [FILE]...'),
277 _('[OPTION]... [FILE]...'),
277 inferrepo=True)
278 inferrepo=True)
278 def addremove(ui, repo, *pats, **opts):
279 def addremove(ui, repo, *pats, **opts):
279 """add all new files, delete all missing files
280 """add all new files, delete all missing files
280
281
281 Add all new files and remove all missing files from the
282 Add all new files and remove all missing files from the
282 repository.
283 repository.
283
284
284 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
285 the patterns in ``.hgignore``. As with add, these changes take
286 the patterns in ``.hgignore``. As with add, these changes take
286 effect at the next commit.
287 effect at the next commit.
287
288
288 Use the -s/--similarity option to detect renamed files. This
289 Use the -s/--similarity option to detect renamed files. This
289 option takes a percentage between 0 (disabled) and 100 (files must
290 option takes a percentage between 0 (disabled) and 100 (files must
290 be identical) as its parameter. With a parameter greater than 0,
291 be identical) as its parameter. With a parameter greater than 0,
291 this compares every removed file with every added file and records
292 this compares every removed file with every added file and records
292 those similar enough as renames. Detecting renamed files this way
293 those similar enough as renames. Detecting renamed files this way
293 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
294 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
295 not specified, -s/--similarity defaults to 100 and only renames of
296 not specified, -s/--similarity defaults to 100 and only renames of
296 identical files are detected.
297 identical files are detected.
297
298
298 .. container:: verbose
299 .. container:: verbose
299
300
300 Examples:
301 Examples:
301
302
302 - A number of files (bar.c and foo.c) are new,
303 - A number of files (bar.c and foo.c) are new,
303 while foobar.c has been removed (without using :hg:`remove`)
304 while foobar.c has been removed (without using :hg:`remove`)
304 from the repository::
305 from the repository::
305
306
306 $ ls
307 $ ls
307 bar.c foo.c
308 bar.c foo.c
308 $ hg status
309 $ hg status
309 ! foobar.c
310 ! foobar.c
310 ? bar.c
311 ? bar.c
311 ? foo.c
312 ? foo.c
312 $ hg addremove
313 $ hg addremove
313 adding bar.c
314 adding bar.c
314 adding foo.c
315 adding foo.c
315 removing foobar.c
316 removing foobar.c
316 $ hg status
317 $ hg status
317 A bar.c
318 A bar.c
318 A foo.c
319 A foo.c
319 R foobar.c
320 R foobar.c
320
321
321 - 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`.
322 Afterwards, it was edited slightly::
323 Afterwards, it was edited slightly::
323
324
324 $ ls
325 $ ls
325 foo.c
326 foo.c
326 $ hg status
327 $ hg status
327 ! foobar.c
328 ! foobar.c
328 ? foo.c
329 ? foo.c
329 $ hg addremove --similarity 90
330 $ hg addremove --similarity 90
330 removing foobar.c
331 removing foobar.c
331 adding foo.c
332 adding foo.c
332 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)
333 $ hg status -C
334 $ hg status -C
334 A foo.c
335 A foo.c
335 foobar.c
336 foobar.c
336 R foobar.c
337 R foobar.c
337
338
338 Returns 0 if all files are successfully added.
339 Returns 0 if all files are successfully added.
339 """
340 """
340 try:
341 try:
341 sim = float(opts.get('similarity') or 100)
342 sim = float(opts.get('similarity') or 100)
342 except ValueError:
343 except ValueError:
343 raise error.Abort(_('similarity must be a number'))
344 raise error.Abort(_('similarity must be a number'))
344 if sim < 0 or sim > 100:
345 if sim < 0 or sim > 100:
345 raise error.Abort(_('similarity must be between 0 and 100'))
346 raise error.Abort(_('similarity must be between 0 and 100'))
346 matcher = scmutil.match(repo[None], pats, opts)
347 matcher = scmutil.match(repo[None], pats, opts)
347 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
348 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
348
349
349 @command('^annotate|blame',
350 @command('^annotate|blame',
350 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
351 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
351 ('', 'follow', None,
352 ('', 'follow', None,
352 _('follow copies/renames and list the filename (DEPRECATED)')),
353 _('follow copies/renames and list the filename (DEPRECATED)')),
353 ('', 'no-follow', None, _("don't follow copies and renames")),
354 ('', 'no-follow', None, _("don't follow copies and renames")),
354 ('a', 'text', None, _('treat all files as text')),
355 ('a', 'text', None, _('treat all files as text')),
355 ('u', 'user', None, _('list the author (long with -v)')),
356 ('u', 'user', None, _('list the author (long with -v)')),
356 ('f', 'file', None, _('list the filename')),
357 ('f', 'file', None, _('list the filename')),
357 ('d', 'date', None, _('list the date (short with -q)')),
358 ('d', 'date', None, _('list the date (short with -q)')),
358 ('n', 'number', None, _('list the revision number (default)')),
359 ('n', 'number', None, _('list the revision number (default)')),
359 ('c', 'changeset', None, _('list the changeset')),
360 ('c', 'changeset', None, _('list the changeset')),
360 ('l', 'line-number', None, _('show line number at the first appearance'))
361 ('l', 'line-number', None, _('show line number at the first appearance'))
361 ] + diffwsopts + walkopts + formatteropts,
362 ] + diffwsopts + walkopts + formatteropts,
362 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
363 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
363 inferrepo=True)
364 inferrepo=True)
364 def annotate(ui, repo, *pats, **opts):
365 def annotate(ui, repo, *pats, **opts):
365 """show changeset information by line for each file
366 """show changeset information by line for each file
366
367
367 List changes in files, showing the revision id responsible for
368 List changes in files, showing the revision id responsible for
368 each line.
369 each line.
369
370
370 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
371 by whom.
372 by whom.
372
373
373 If you include --file, --user, or --date, the revision number is
374 If you include --file, --user, or --date, the revision number is
374 suppressed unless you also include --number.
375 suppressed unless you also include --number.
375
376
376 Without the -a/--text option, annotate will avoid processing files
377 Without the -a/--text option, annotate will avoid processing files
377 it detects as binary. With -a, annotate will annotate the file
378 it detects as binary. With -a, annotate will annotate the file
378 anyway, although the results will probably be neither useful
379 anyway, although the results will probably be neither useful
379 nor desirable.
380 nor desirable.
380
381
381 Returns 0 on success.
382 Returns 0 on success.
382 """
383 """
383 if not pats:
384 if not pats:
384 raise error.Abort(_('at least one filename or pattern is required'))
385 raise error.Abort(_('at least one filename or pattern is required'))
385
386
386 if opts.get('follow'):
387 if opts.get('follow'):
387 # --follow is deprecated and now just an alias for -f/--file
388 # --follow is deprecated and now just an alias for -f/--file
388 # to mimic the behavior of Mercurial before version 1.5
389 # to mimic the behavior of Mercurial before version 1.5
389 opts['file'] = True
390 opts['file'] = True
390
391
391 ctx = scmutil.revsingle(repo, opts.get('rev'))
392 ctx = scmutil.revsingle(repo, opts.get('rev'))
392
393
393 fm = ui.formatter('annotate', opts)
394 fm = ui.formatter('annotate', opts)
394 if ui.quiet:
395 if ui.quiet:
395 datefunc = util.shortdate
396 datefunc = util.shortdate
396 else:
397 else:
397 datefunc = util.datestr
398 datefunc = util.datestr
398 if ctx.rev() is None:
399 if ctx.rev() is None:
399 def hexfn(node):
400 def hexfn(node):
400 if node is None:
401 if node is None:
401 return None
402 return None
402 else:
403 else:
403 return fm.hexfunc(node)
404 return fm.hexfunc(node)
404 if opts.get('changeset'):
405 if opts.get('changeset'):
405 # omit "+" suffix which is appended to node hex
406 # omit "+" suffix which is appended to node hex
406 def formatrev(rev):
407 def formatrev(rev):
407 if rev is None:
408 if rev is None:
408 return '%d' % ctx.p1().rev()
409 return '%d' % ctx.p1().rev()
409 else:
410 else:
410 return '%d' % rev
411 return '%d' % rev
411 else:
412 else:
412 def formatrev(rev):
413 def formatrev(rev):
413 if rev is None:
414 if rev is None:
414 return '%d+' % ctx.p1().rev()
415 return '%d+' % ctx.p1().rev()
415 else:
416 else:
416 return '%d ' % rev
417 return '%d ' % rev
417 def formathex(hex):
418 def formathex(hex):
418 if hex is None:
419 if hex is None:
419 return '%s+' % fm.hexfunc(ctx.p1().node())
420 return '%s+' % fm.hexfunc(ctx.p1().node())
420 else:
421 else:
421 return '%s ' % hex
422 return '%s ' % hex
422 else:
423 else:
423 hexfn = fm.hexfunc
424 hexfn = fm.hexfunc
424 formatrev = formathex = str
425 formatrev = formathex = str
425
426
426 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
427 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
427 ('number', ' ', lambda x: x[0].rev(), formatrev),
428 ('number', ' ', lambda x: x[0].rev(), formatrev),
428 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
429 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
429 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
430 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
430 ('file', ' ', lambda x: x[0].path(), str),
431 ('file', ' ', lambda x: x[0].path(), str),
431 ('line_number', ':', lambda x: x[1], str),
432 ('line_number', ':', lambda x: x[1], str),
432 ]
433 ]
433 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
434 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
434
435
435 if (not opts.get('user') and not opts.get('changeset')
436 if (not opts.get('user') and not opts.get('changeset')
436 and not opts.get('date') and not opts.get('file')):
437 and not opts.get('date') and not opts.get('file')):
437 opts['number'] = True
438 opts['number'] = True
438
439
439 linenumber = opts.get('line_number') is not None
440 linenumber = opts.get('line_number') is not None
440 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')):
441 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'))
442
443
443 if fm:
444 if fm:
444 def makefunc(get, fmt):
445 def makefunc(get, fmt):
445 return get
446 return get
446 else:
447 else:
447 def makefunc(get, fmt):
448 def makefunc(get, fmt):
448 return lambda x: fmt(get(x))
449 return lambda x: fmt(get(x))
449 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
450 if opts.get(op)]
451 if opts.get(op)]
451 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
452 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
453 if opts.get(op))
454 if opts.get(op))
454
455
455 def bad(x, y):
456 def bad(x, y):
456 raise error.Abort("%s: %s" % (x, y))
457 raise error.Abort("%s: %s" % (x, y))
457
458
458 m = scmutil.match(ctx, pats, opts, badfn=bad)
459 m = scmutil.match(ctx, pats, opts, badfn=bad)
459
460
460 follow = not opts.get('no_follow')
461 follow = not opts.get('no_follow')
461 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
462 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
462 whitespace=True)
463 whitespace=True)
463 for abs in ctx.walk(m):
464 for abs in ctx.walk(m):
464 fctx = ctx[abs]
465 fctx = ctx[abs]
465 if not opts.get('text') and util.binary(fctx.data()):
466 if not opts.get('text') and util.binary(fctx.data()):
466 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))
467 continue
468 continue
468
469
469 lines = fctx.annotate(follow=follow, linenumber=linenumber,
470 lines = fctx.annotate(follow=follow, linenumber=linenumber,
470 diffopts=diffopts)
471 diffopts=diffopts)
471 formats = []
472 formats = []
472 pieces = []
473 pieces = []
473
474
474 for f, sep in funcmap:
475 for f, sep in funcmap:
475 l = [f(n) for n, dummy in lines]
476 l = [f(n) for n, dummy in lines]
476 if l:
477 if l:
477 if fm:
478 if fm:
478 formats.append(['%s' for x in l])
479 formats.append(['%s' for x in l])
479 else:
480 else:
480 sizes = [encoding.colwidth(x) for x in l]
481 sizes = [encoding.colwidth(x) for x in l]
481 ml = max(sizes)
482 ml = max(sizes)
482 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
483 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
483 pieces.append(l)
484 pieces.append(l)
484
485
485 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
486 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
486 fm.startitem()
487 fm.startitem()
487 fm.write(fields, "".join(f), *p)
488 fm.write(fields, "".join(f), *p)
488 fm.write('line', ": %s", l[1])
489 fm.write('line', ": %s", l[1])
489
490
490 if lines and not lines[-1][1].endswith('\n'):
491 if lines and not lines[-1][1].endswith('\n'):
491 fm.plain('\n')
492 fm.plain('\n')
492
493
493 fm.end()
494 fm.end()
494
495
495 @command('archive',
496 @command('archive',
496 [('', 'no-decode', None, _('do not pass files through decoders')),
497 [('', 'no-decode', None, _('do not pass files through decoders')),
497 ('p', 'prefix', '', _('directory prefix for files in archive'),
498 ('p', 'prefix', '', _('directory prefix for files in archive'),
498 _('PREFIX')),
499 _('PREFIX')),
499 ('r', 'rev', '', _('revision to distribute'), _('REV')),
500 ('r', 'rev', '', _('revision to distribute'), _('REV')),
500 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
501 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
501 ] + subrepoopts + walkopts,
502 ] + subrepoopts + walkopts,
502 _('[OPTION]... DEST'))
503 _('[OPTION]... DEST'))
503 def archive(ui, repo, dest, **opts):
504 def archive(ui, repo, dest, **opts):
504 '''create an unversioned archive of a repository revision
505 '''create an unversioned archive of a repository revision
505
506
506 By default, the revision used is the parent of the working
507 By default, the revision used is the parent of the working
507 directory; use -r/--rev to specify a different revision.
508 directory; use -r/--rev to specify a different revision.
508
509
509 The archive type is automatically detected based on file
510 The archive type is automatically detected based on file
510 extension (to override, use -t/--type).
511 extension (to override, use -t/--type).
511
512
512 .. container:: verbose
513 .. container:: verbose
513
514
514 Examples:
515 Examples:
515
516
516 - create a zip file containing the 1.0 release::
517 - create a zip file containing the 1.0 release::
517
518
518 hg archive -r 1.0 project-1.0.zip
519 hg archive -r 1.0 project-1.0.zip
519
520
520 - create a tarball excluding .hg files::
521 - create a tarball excluding .hg files::
521
522
522 hg archive project.tar.gz -X ".hg*"
523 hg archive project.tar.gz -X ".hg*"
523
524
524 Valid types are:
525 Valid types are:
525
526
526 :``files``: a directory full of files (default)
527 :``files``: a directory full of files (default)
527 :``tar``: tar archive, uncompressed
528 :``tar``: tar archive, uncompressed
528 :``tbz2``: tar archive, compressed using bzip2
529 :``tbz2``: tar archive, compressed using bzip2
529 :``tgz``: tar archive, compressed using gzip
530 :``tgz``: tar archive, compressed using gzip
530 :``uzip``: zip archive, uncompressed
531 :``uzip``: zip archive, uncompressed
531 :``zip``: zip archive, compressed using deflate
532 :``zip``: zip archive, compressed using deflate
532
533
533 The exact name of the destination archive or directory is given
534 The exact name of the destination archive or directory is given
534 using a format string; see :hg:`help export` for details.
535 using a format string; see :hg:`help export` for details.
535
536
536 Each member added to an archive file has a directory prefix
537 Each member added to an archive file has a directory prefix
537 prepended. Use -p/--prefix to specify a format string for the
538 prepended. Use -p/--prefix to specify a format string for the
538 prefix. The default is the basename of the archive, with suffixes
539 prefix. The default is the basename of the archive, with suffixes
539 removed.
540 removed.
540
541
541 Returns 0 on success.
542 Returns 0 on success.
542 '''
543 '''
543
544
544 ctx = scmutil.revsingle(repo, opts.get('rev'))
545 ctx = scmutil.revsingle(repo, opts.get('rev'))
545 if not ctx:
546 if not ctx:
546 raise error.Abort(_('no working directory: please specify a revision'))
547 raise error.Abort(_('no working directory: please specify a revision'))
547 node = ctx.node()
548 node = ctx.node()
548 dest = cmdutil.makefilename(repo, dest, node)
549 dest = cmdutil.makefilename(repo, dest, node)
549 if os.path.realpath(dest) == repo.root:
550 if os.path.realpath(dest) == repo.root:
550 raise error.Abort(_('repository root cannot be destination'))
551 raise error.Abort(_('repository root cannot be destination'))
551
552
552 kind = opts.get('type') or archival.guesskind(dest) or 'files'
553 kind = opts.get('type') or archival.guesskind(dest) or 'files'
553 prefix = opts.get('prefix')
554 prefix = opts.get('prefix')
554
555
555 if dest == '-':
556 if dest == '-':
556 if kind == 'files':
557 if kind == 'files':
557 raise error.Abort(_('cannot archive plain files to stdout'))
558 raise error.Abort(_('cannot archive plain files to stdout'))
558 dest = cmdutil.makefileobj(repo, dest)
559 dest = cmdutil.makefileobj(repo, dest)
559 if not prefix:
560 if not prefix:
560 prefix = os.path.basename(repo.root) + '-%h'
561 prefix = os.path.basename(repo.root) + '-%h'
561
562
562 prefix = cmdutil.makefilename(repo, prefix, node)
563 prefix = cmdutil.makefilename(repo, prefix, node)
563 matchfn = scmutil.match(ctx, [], opts)
564 matchfn = scmutil.match(ctx, [], opts)
564 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
565 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
565 matchfn, prefix, subrepos=opts.get('subrepos'))
566 matchfn, prefix, subrepos=opts.get('subrepos'))
566
567
567 @command('backout',
568 @command('backout',
568 [('', 'merge', None, _('merge with old dirstate parent after backout')),
569 [('', 'merge', None, _('merge with old dirstate parent after backout')),
569 ('', 'commit', None,
570 ('', 'commit', None,
570 _('commit if no conflicts were encountered (DEPRECATED)')),
571 _('commit if no conflicts were encountered (DEPRECATED)')),
571 ('', 'no-commit', None, _('do not commit')),
572 ('', 'no-commit', None, _('do not commit')),
572 ('', 'parent', '',
573 ('', 'parent', '',
573 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
574 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
574 ('r', 'rev', '', _('revision to backout'), _('REV')),
575 ('r', 'rev', '', _('revision to backout'), _('REV')),
575 ('e', 'edit', False, _('invoke editor on commit messages')),
576 ('e', 'edit', False, _('invoke editor on commit messages')),
576 ] + mergetoolopts + walkopts + commitopts + commitopts2,
577 ] + mergetoolopts + walkopts + commitopts + commitopts2,
577 _('[OPTION]... [-r] REV'))
578 _('[OPTION]... [-r] REV'))
578 def backout(ui, repo, node=None, rev=None, **opts):
579 def backout(ui, repo, node=None, rev=None, **opts):
579 '''reverse effect of earlier changeset
580 '''reverse effect of earlier changeset
580
581
581 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
582 current working directory. If no conflicts were encountered,
583 current working directory. If no conflicts were encountered,
583 it will be committed immediately.
584 it will be committed immediately.
584
585
585 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
586 is committed automatically (unless --no-commit is specified).
587 is committed automatically (unless --no-commit is specified).
587
588
588 .. note::
589 .. note::
589
590
590 :hg:`backout` cannot be used to fix either an unwanted or
591 :hg:`backout` cannot be used to fix either an unwanted or
591 incorrect merge.
592 incorrect merge.
592
593
593 .. container:: verbose
594 .. container:: verbose
594
595
595 Examples:
596 Examples:
596
597
597 - Reverse the effect of the parent of the working directory.
598 - Reverse the effect of the parent of the working directory.
598 This backout will be committed immediately::
599 This backout will be committed immediately::
599
600
600 hg backout -r .
601 hg backout -r .
601
602
602 - Reverse the effect of previous bad revision 23::
603 - Reverse the effect of previous bad revision 23::
603
604
604 hg backout -r 23
605 hg backout -r 23
605
606
606 - Reverse the effect of previous bad revision 23 and
607 - Reverse the effect of previous bad revision 23 and
607 leave changes uncommitted::
608 leave changes uncommitted::
608
609
609 hg backout -r 23 --no-commit
610 hg backout -r 23 --no-commit
610 hg commit -m "Backout revision 23"
611 hg commit -m "Backout revision 23"
611
612
612 By default, the pending changeset will have one parent,
613 By default, the pending changeset will have one parent,
613 maintaining a linear history. With --merge, the pending
614 maintaining a linear history. With --merge, the pending
614 changeset will instead have two parents: the old parent of the
615 changeset will instead have two parents: the old parent of the
615 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.
616
617
617 Before version 1.7, the behavior without --merge was equivalent
618 Before version 1.7, the behavior without --merge was equivalent
618 to specifying --merge followed by :hg:`update --clean .` to
619 to specifying --merge followed by :hg:`update --clean .` to
619 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
620 merged separately.
621 merged separately.
621
622
622 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.
623
624
624 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
625 of another revision.
626 of another revision.
626
627
627 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
628 files.
629 files.
629 '''
630 '''
630 wlock = lock = None
631 wlock = lock = None
631 try:
632 try:
632 wlock = repo.wlock()
633 wlock = repo.wlock()
633 lock = repo.lock()
634 lock = repo.lock()
634 return _dobackout(ui, repo, node, rev, **opts)
635 return _dobackout(ui, repo, node, rev, **opts)
635 finally:
636 finally:
636 release(lock, wlock)
637 release(lock, wlock)
637
638
638 def _dobackout(ui, repo, node=None, rev=None, **opts):
639 def _dobackout(ui, repo, node=None, rev=None, **opts):
639 if opts.get('commit') and opts.get('no_commit'):
640 if opts.get('commit') and opts.get('no_commit'):
640 raise error.Abort(_("cannot use --commit with --no-commit"))
641 raise error.Abort(_("cannot use --commit with --no-commit"))
641 if opts.get('merge') and opts.get('no_commit'):
642 if opts.get('merge') and opts.get('no_commit'):
642 raise error.Abort(_("cannot use --merge with --no-commit"))
643 raise error.Abort(_("cannot use --merge with --no-commit"))
643
644
644 if rev and node:
645 if rev and node:
645 raise error.Abort(_("please specify just one revision"))
646 raise error.Abort(_("please specify just one revision"))
646
647
647 if not rev:
648 if not rev:
648 rev = node
649 rev = node
649
650
650 if not rev:
651 if not rev:
651 raise error.Abort(_("please specify a revision to backout"))
652 raise error.Abort(_("please specify a revision to backout"))
652
653
653 date = opts.get('date')
654 date = opts.get('date')
654 if date:
655 if date:
655 opts['date'] = util.parsedate(date)
656 opts['date'] = util.parsedate(date)
656
657
657 cmdutil.checkunfinished(repo)
658 cmdutil.checkunfinished(repo)
658 cmdutil.bailifchanged(repo)
659 cmdutil.bailifchanged(repo)
659 node = scmutil.revsingle(repo, rev).node()
660 node = scmutil.revsingle(repo, rev).node()
660
661
661 op1, op2 = repo.dirstate.parents()
662 op1, op2 = repo.dirstate.parents()
662 if not repo.changelog.isancestor(node, op1):
663 if not repo.changelog.isancestor(node, op1):
663 raise error.Abort(_('cannot backout change that is not an ancestor'))
664 raise error.Abort(_('cannot backout change that is not an ancestor'))
664
665
665 p1, p2 = repo.changelog.parents(node)
666 p1, p2 = repo.changelog.parents(node)
666 if p1 == nullid:
667 if p1 == nullid:
667 raise error.Abort(_('cannot backout a change with no parents'))
668 raise error.Abort(_('cannot backout a change with no parents'))
668 if p2 != nullid:
669 if p2 != nullid:
669 if not opts.get('parent'):
670 if not opts.get('parent'):
670 raise error.Abort(_('cannot backout a merge changeset'))
671 raise error.Abort(_('cannot backout a merge changeset'))
671 p = repo.lookup(opts['parent'])
672 p = repo.lookup(opts['parent'])
672 if p not in (p1, p2):
673 if p not in (p1, p2):
673 raise error.Abort(_('%s is not a parent of %s') %
674 raise error.Abort(_('%s is not a parent of %s') %
674 (short(p), short(node)))
675 (short(p), short(node)))
675 parent = p
676 parent = p
676 else:
677 else:
677 if opts.get('parent'):
678 if opts.get('parent'):
678 raise error.Abort(_('cannot use --parent on non-merge changeset'))
679 raise error.Abort(_('cannot use --parent on non-merge changeset'))
679 parent = p1
680 parent = p1
680
681
681 # the backout should appear on the same branch
682 # the backout should appear on the same branch
682 branch = repo.dirstate.branch()
683 branch = repo.dirstate.branch()
683 bheads = repo.branchheads(branch)
684 bheads = repo.branchheads(branch)
684 rctx = scmutil.revsingle(repo, hex(parent))
685 rctx = scmutil.revsingle(repo, hex(parent))
685 if not opts.get('merge') and op1 != node:
686 if not opts.get('merge') and op1 != node:
686 dsguard = cmdutil.dirstateguard(repo, 'backout')
687 dsguard = cmdutil.dirstateguard(repo, 'backout')
687 try:
688 try:
688 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
689 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
689 'backout')
690 'backout')
690 stats = mergemod.update(repo, parent, True, True, node, False)
691 stats = mergemod.update(repo, parent, True, True, node, False)
691 repo.setparents(op1, op2)
692 repo.setparents(op1, op2)
692 dsguard.close()
693 dsguard.close()
693 hg._showstats(repo, stats)
694 hg._showstats(repo, stats)
694 if stats[3]:
695 if stats[3]:
695 repo.ui.status(_("use 'hg resolve' to retry unresolved "
696 repo.ui.status(_("use 'hg resolve' to retry unresolved "
696 "file merges\n"))
697 "file merges\n"))
697 return 1
698 return 1
698 finally:
699 finally:
699 ui.setconfig('ui', 'forcemerge', '', '')
700 ui.setconfig('ui', 'forcemerge', '', '')
700 lockmod.release(dsguard)
701 lockmod.release(dsguard)
701 else:
702 else:
702 hg.clean(repo, node, show_stats=False)
703 hg.clean(repo, node, show_stats=False)
703 repo.dirstate.setbranch(branch)
704 repo.dirstate.setbranch(branch)
704 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
705 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
705
706
706 if opts.get('no_commit'):
707 if opts.get('no_commit'):
707 msg = _("changeset %s backed out, "
708 msg = _("changeset %s backed out, "
708 "don't forget to commit.\n")
709 "don't forget to commit.\n")
709 ui.status(msg % short(node))
710 ui.status(msg % short(node))
710 return 0
711 return 0
711
712
712 def commitfunc(ui, repo, message, match, opts):
713 def commitfunc(ui, repo, message, match, opts):
713 editform = 'backout'
714 editform = 'backout'
714 e = cmdutil.getcommiteditor(editform=editform, **opts)
715 e = cmdutil.getcommiteditor(editform=editform, **opts)
715 if not message:
716 if not message:
716 # we don't translate commit messages
717 # we don't translate commit messages
717 message = "Backed out changeset %s" % short(node)
718 message = "Backed out changeset %s" % short(node)
718 e = cmdutil.getcommiteditor(edit=True, editform=editform)
719 e = cmdutil.getcommiteditor(edit=True, editform=editform)
719 return repo.commit(message, opts.get('user'), opts.get('date'),
720 return repo.commit(message, opts.get('user'), opts.get('date'),
720 match, editor=e)
721 match, editor=e)
721 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
722 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
722 if not newnode:
723 if not newnode:
723 ui.status(_("nothing changed\n"))
724 ui.status(_("nothing changed\n"))
724 return 1
725 return 1
725 cmdutil.commitstatus(repo, newnode, branch, bheads)
726 cmdutil.commitstatus(repo, newnode, branch, bheads)
726
727
727 def nice(node):
728 def nice(node):
728 return '%d:%s' % (repo.changelog.rev(node), short(node))
729 return '%d:%s' % (repo.changelog.rev(node), short(node))
729 ui.status(_('changeset %s backs out changeset %s\n') %
730 ui.status(_('changeset %s backs out changeset %s\n') %
730 (nice(repo.changelog.tip()), nice(node)))
731 (nice(repo.changelog.tip()), nice(node)))
731 if opts.get('merge') and op1 != node:
732 if opts.get('merge') and op1 != node:
732 hg.clean(repo, op1, show_stats=False)
733 hg.clean(repo, op1, show_stats=False)
733 ui.status(_('merging with changeset %s\n')
734 ui.status(_('merging with changeset %s\n')
734 % nice(repo.changelog.tip()))
735 % nice(repo.changelog.tip()))
735 try:
736 try:
736 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
737 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
737 'backout')
738 'backout')
738 return hg.merge(repo, hex(repo.changelog.tip()))
739 return hg.merge(repo, hex(repo.changelog.tip()))
739 finally:
740 finally:
740 ui.setconfig('ui', 'forcemerge', '', '')
741 ui.setconfig('ui', 'forcemerge', '', '')
741 return 0
742 return 0
742
743
743 @command('bisect',
744 @command('bisect',
744 [('r', 'reset', False, _('reset bisect state')),
745 [('r', 'reset', False, _('reset bisect state')),
745 ('g', 'good', False, _('mark changeset good')),
746 ('g', 'good', False, _('mark changeset good')),
746 ('b', 'bad', False, _('mark changeset bad')),
747 ('b', 'bad', False, _('mark changeset bad')),
747 ('s', 'skip', False, _('skip testing changeset')),
748 ('s', 'skip', False, _('skip testing changeset')),
748 ('e', 'extend', False, _('extend the bisect range')),
749 ('e', 'extend', False, _('extend the bisect range')),
749 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
750 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
750 ('U', 'noupdate', False, _('do not update to target'))],
751 ('U', 'noupdate', False, _('do not update to target'))],
751 _("[-gbsr] [-U] [-c CMD] [REV]"))
752 _("[-gbsr] [-U] [-c CMD] [REV]"))
752 def bisect(ui, repo, rev=None, extra=None, command=None,
753 def bisect(ui, repo, rev=None, extra=None, command=None,
753 reset=None, good=None, bad=None, skip=None, extend=None,
754 reset=None, good=None, bad=None, skip=None, extend=None,
754 noupdate=None):
755 noupdate=None):
755 """subdivision search of changesets
756 """subdivision search of changesets
756
757
757 This command helps to find changesets which introduce problems. To
758 This command helps to find changesets which introduce problems. To
758 use, mark the earliest changeset you know exhibits the problem as
759 use, mark the earliest changeset you know exhibits the problem as
759 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
760 as good. Bisect will update your working directory to a revision
761 as good. Bisect will update your working directory to a revision
761 for testing (unless the -U/--noupdate option is specified). Once
762 for testing (unless the -U/--noupdate option is specified). Once
762 you have performed tests, mark the working directory as good or
763 you have performed tests, mark the working directory as good or
763 bad, and bisect will either update to another candidate changeset
764 bad, and bisect will either update to another candidate changeset
764 or announce that it has found the bad revision.
765 or announce that it has found the bad revision.
765
766
766 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
767 revision as good or bad without checking it out first.
768 revision as good or bad without checking it out first.
768
769
769 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.
770 The environment variable HG_NODE will contain the ID of the
771 The environment variable HG_NODE will contain the ID of the
771 changeset being tested. The exit status of the command will be
772 changeset being tested. The exit status of the command will be
772 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
773 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
774 bisection, and any other non-zero exit status means the revision
775 bisection, and any other non-zero exit status means the revision
775 is bad.
776 is bad.
776
777
777 .. container:: verbose
778 .. container:: verbose
778
779
779 Some examples:
780 Some examples:
780
781
781 - 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::
782
783
783 hg bisect --bad 34
784 hg bisect --bad 34
784 hg bisect --good 12
785 hg bisect --good 12
785
786
786 - advance the current bisection by marking current revision as good or
787 - advance the current bisection by marking current revision as good or
787 bad::
788 bad::
788
789
789 hg bisect --good
790 hg bisect --good
790 hg bisect --bad
791 hg bisect --bad
791
792
792 - 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
793 that revision is not usable because of another issue)::
794 that revision is not usable because of another issue)::
794
795
795 hg bisect --skip
796 hg bisect --skip
796 hg bisect --skip 23
797 hg bisect --skip 23
797
798
798 - skip all revisions that do not touch directories ``foo`` or ``bar``::
799 - skip all revisions that do not touch directories ``foo`` or ``bar``::
799
800
800 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
801 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
801
802
802 - forget the current bisection::
803 - forget the current bisection::
803
804
804 hg bisect --reset
805 hg bisect --reset
805
806
806 - use 'make && make tests' to automatically find the first broken
807 - use 'make && make tests' to automatically find the first broken
807 revision::
808 revision::
808
809
809 hg bisect --reset
810 hg bisect --reset
810 hg bisect --bad 34
811 hg bisect --bad 34
811 hg bisect --good 12
812 hg bisect --good 12
812 hg bisect --command "make && make tests"
813 hg bisect --command "make && make tests"
813
814
814 - see all changesets whose states are already known in the current
815 - see all changesets whose states are already known in the current
815 bisection::
816 bisection::
816
817
817 hg log -r "bisect(pruned)"
818 hg log -r "bisect(pruned)"
818
819
819 - see the changeset currently being bisected (especially useful
820 - see the changeset currently being bisected (especially useful
820 if running with -U/--noupdate)::
821 if running with -U/--noupdate)::
821
822
822 hg log -r "bisect(current)"
823 hg log -r "bisect(current)"
823
824
824 - see all changesets that took part in the current bisection::
825 - see all changesets that took part in the current bisection::
825
826
826 hg log -r "bisect(range)"
827 hg log -r "bisect(range)"
827
828
828 - you can even get a nice graph::
829 - you can even get a nice graph::
829
830
830 hg log --graph -r "bisect(range)"
831 hg log --graph -r "bisect(range)"
831
832
832 See :hg:`help revsets` for more about the `bisect()` keyword.
833 See :hg:`help revsets` for more about the `bisect()` keyword.
833
834
834 Returns 0 on success.
835 Returns 0 on success.
835 """
836 """
836 def extendbisectrange(nodes, good):
837 def extendbisectrange(nodes, good):
837 # bisect is incomplete when it ends on a merge node and
838 # bisect is incomplete when it ends on a merge node and
838 # one of the parent was not checked.
839 # one of the parent was not checked.
839 parents = repo[nodes[0]].parents()
840 parents = repo[nodes[0]].parents()
840 if len(parents) > 1:
841 if len(parents) > 1:
841 if good:
842 if good:
842 side = state['bad']
843 side = state['bad']
843 else:
844 else:
844 side = state['good']
845 side = state['good']
845 num = len(set(i.node() for i in parents) & set(side))
846 num = len(set(i.node() for i in parents) & set(side))
846 if num == 1:
847 if num == 1:
847 return parents[0].ancestor(parents[1])
848 return parents[0].ancestor(parents[1])
848 return None
849 return None
849
850
850 def print_result(nodes, good):
851 def print_result(nodes, good):
851 displayer = cmdutil.show_changeset(ui, repo, {})
852 displayer = cmdutil.show_changeset(ui, repo, {})
852 if len(nodes) == 1:
853 if len(nodes) == 1:
853 # narrowed it down to a single revision
854 # narrowed it down to a single revision
854 if good:
855 if good:
855 ui.write(_("The first good revision is:\n"))
856 ui.write(_("The first good revision is:\n"))
856 else:
857 else:
857 ui.write(_("The first bad revision is:\n"))
858 ui.write(_("The first bad revision is:\n"))
858 displayer.show(repo[nodes[0]])
859 displayer.show(repo[nodes[0]])
859 extendnode = extendbisectrange(nodes, good)
860 extendnode = extendbisectrange(nodes, good)
860 if extendnode is not None:
861 if extendnode is not None:
861 ui.write(_('Not all ancestors of this changeset have been'
862 ui.write(_('Not all ancestors of this changeset have been'
862 ' checked.\nUse bisect --extend to continue the '
863 ' checked.\nUse bisect --extend to continue the '
863 'bisection from\nthe common ancestor, %s.\n')
864 'bisection from\nthe common ancestor, %s.\n')
864 % extendnode)
865 % extendnode)
865 else:
866 else:
866 # multiple possible revisions
867 # multiple possible revisions
867 if good:
868 if good:
868 ui.write(_("Due to skipped revisions, the first "
869 ui.write(_("Due to skipped revisions, the first "
869 "good revision could be any of:\n"))
870 "good revision could be any of:\n"))
870 else:
871 else:
871 ui.write(_("Due to skipped revisions, the first "
872 ui.write(_("Due to skipped revisions, the first "
872 "bad revision could be any of:\n"))
873 "bad revision could be any of:\n"))
873 for n in nodes:
874 for n in nodes:
874 displayer.show(repo[n])
875 displayer.show(repo[n])
875 displayer.close()
876 displayer.close()
876
877
877 def check_state(state, interactive=True):
878 def check_state(state, interactive=True):
878 if not state['good'] or not state['bad']:
879 if not state['good'] or not state['bad']:
879 if (good or bad or skip or reset) and interactive:
880 if (good or bad or skip or reset) and interactive:
880 return
881 return
881 if not state['good']:
882 if not state['good']:
882 raise error.Abort(_('cannot bisect (no known good revisions)'))
883 raise error.Abort(_('cannot bisect (no known good revisions)'))
883 else:
884 else:
884 raise error.Abort(_('cannot bisect (no known bad revisions)'))
885 raise error.Abort(_('cannot bisect (no known bad revisions)'))
885 return True
886 return True
886
887
887 # backward compatibility
888 # backward compatibility
888 if rev in "good bad reset init".split():
889 if rev in "good bad reset init".split():
889 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
890 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
890 cmd, rev, extra = rev, extra, None
891 cmd, rev, extra = rev, extra, None
891 if cmd == "good":
892 if cmd == "good":
892 good = True
893 good = True
893 elif cmd == "bad":
894 elif cmd == "bad":
894 bad = True
895 bad = True
895 else:
896 else:
896 reset = True
897 reset = True
897 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
898 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
898 raise error.Abort(_('incompatible arguments'))
899 raise error.Abort(_('incompatible arguments'))
899
900
900 cmdutil.checkunfinished(repo)
901 cmdutil.checkunfinished(repo)
901
902
902 if reset:
903 if reset:
903 p = repo.join("bisect.state")
904 p = repo.join("bisect.state")
904 if os.path.exists(p):
905 if os.path.exists(p):
905 os.unlink(p)
906 os.unlink(p)
906 return
907 return
907
908
908 state = hbisect.load_state(repo)
909 state = hbisect.load_state(repo)
909
910
910 if command:
911 if command:
911 changesets = 1
912 changesets = 1
912 if noupdate:
913 if noupdate:
913 try:
914 try:
914 node = state['current'][0]
915 node = state['current'][0]
915 except LookupError:
916 except LookupError:
916 raise error.Abort(_('current bisect revision is unknown - '
917 raise error.Abort(_('current bisect revision is unknown - '
917 'start a new bisect to fix'))
918 'start a new bisect to fix'))
918 else:
919 else:
919 node, p2 = repo.dirstate.parents()
920 node, p2 = repo.dirstate.parents()
920 if p2 != nullid:
921 if p2 != nullid:
921 raise error.Abort(_('current bisect revision is a merge'))
922 raise error.Abort(_('current bisect revision is a merge'))
922 try:
923 try:
923 while changesets:
924 while changesets:
924 # update state
925 # update state
925 state['current'] = [node]
926 state['current'] = [node]
926 hbisect.save_state(repo, state)
927 hbisect.save_state(repo, state)
927 status = ui.system(command, environ={'HG_NODE': hex(node)})
928 status = ui.system(command, environ={'HG_NODE': hex(node)})
928 if status == 125:
929 if status == 125:
929 transition = "skip"
930 transition = "skip"
930 elif status == 0:
931 elif status == 0:
931 transition = "good"
932 transition = "good"
932 # status < 0 means process was killed
933 # status < 0 means process was killed
933 elif status == 127:
934 elif status == 127:
934 raise error.Abort(_("failed to execute %s") % command)
935 raise error.Abort(_("failed to execute %s") % command)
935 elif status < 0:
936 elif status < 0:
936 raise error.Abort(_("%s killed") % command)
937 raise error.Abort(_("%s killed") % command)
937 else:
938 else:
938 transition = "bad"
939 transition = "bad"
939 ctx = scmutil.revsingle(repo, rev, node)
940 ctx = scmutil.revsingle(repo, rev, node)
940 rev = None # clear for future iterations
941 rev = None # clear for future iterations
941 state[transition].append(ctx.node())
942 state[transition].append(ctx.node())
942 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
943 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
943 check_state(state, interactive=False)
944 check_state(state, interactive=False)
944 # bisect
945 # bisect
945 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
946 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
946 # update to next check
947 # update to next check
947 node = nodes[0]
948 node = nodes[0]
948 if not noupdate:
949 if not noupdate:
949 cmdutil.bailifchanged(repo)
950 cmdutil.bailifchanged(repo)
950 hg.clean(repo, node, show_stats=False)
951 hg.clean(repo, node, show_stats=False)
951 finally:
952 finally:
952 state['current'] = [node]
953 state['current'] = [node]
953 hbisect.save_state(repo, state)
954 hbisect.save_state(repo, state)
954 print_result(nodes, bgood)
955 print_result(nodes, bgood)
955 return
956 return
956
957
957 # update state
958 # update state
958
959
959 if rev:
960 if rev:
960 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
961 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
961 else:
962 else:
962 nodes = [repo.lookup('.')]
963 nodes = [repo.lookup('.')]
963
964
964 if good or bad or skip:
965 if good or bad or skip:
965 if good:
966 if good:
966 state['good'] += nodes
967 state['good'] += nodes
967 elif bad:
968 elif bad:
968 state['bad'] += nodes
969 state['bad'] += nodes
969 elif skip:
970 elif skip:
970 state['skip'] += nodes
971 state['skip'] += nodes
971 hbisect.save_state(repo, state)
972 hbisect.save_state(repo, state)
972
973
973 if not check_state(state):
974 if not check_state(state):
974 return
975 return
975
976
976 # actually bisect
977 # actually bisect
977 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
978 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
978 if extend:
979 if extend:
979 if not changesets:
980 if not changesets:
980 extendnode = extendbisectrange(nodes, good)
981 extendnode = extendbisectrange(nodes, good)
981 if extendnode is not None:
982 if extendnode is not None:
982 ui.write(_("Extending search to changeset %d:%s\n")
983 ui.write(_("Extending search to changeset %d:%s\n")
983 % (extendnode.rev(), extendnode))
984 % (extendnode.rev(), extendnode))
984 state['current'] = [extendnode.node()]
985 state['current'] = [extendnode.node()]
985 hbisect.save_state(repo, state)
986 hbisect.save_state(repo, state)
986 if noupdate:
987 if noupdate:
987 return
988 return
988 cmdutil.bailifchanged(repo)
989 cmdutil.bailifchanged(repo)
989 return hg.clean(repo, extendnode.node())
990 return hg.clean(repo, extendnode.node())
990 raise error.Abort(_("nothing to extend"))
991 raise error.Abort(_("nothing to extend"))
991
992
992 if changesets == 0:
993 if changesets == 0:
993 print_result(nodes, good)
994 print_result(nodes, good)
994 else:
995 else:
995 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
996 node = nodes[0]
997 node = nodes[0]
997 # compute the approximate number of remaining tests
998 # compute the approximate number of remaining tests
998 tests, size = 0, 2
999 tests, size = 0, 2
999 while size <= changesets:
1000 while size <= changesets:
1000 tests, size = tests + 1, size * 2
1001 tests, size = tests + 1, size * 2
1001 rev = repo.changelog.rev(node)
1002 rev = repo.changelog.rev(node)
1002 ui.write(_("Testing changeset %d:%s "
1003 ui.write(_("Testing changeset %d:%s "
1003 "(%d changesets remaining, ~%d tests)\n")
1004 "(%d changesets remaining, ~%d tests)\n")
1004 % (rev, short(node), changesets, tests))
1005 % (rev, short(node), changesets, tests))
1005 state['current'] = [node]
1006 state['current'] = [node]
1006 hbisect.save_state(repo, state)
1007 hbisect.save_state(repo, state)
1007 if not noupdate:
1008 if not noupdate:
1008 cmdutil.bailifchanged(repo)
1009 cmdutil.bailifchanged(repo)
1009 return hg.clean(repo, node)
1010 return hg.clean(repo, node)
1010
1011
1011 @command('bookmarks|bookmark',
1012 @command('bookmarks|bookmark',
1012 [('f', 'force', False, _('force')),
1013 [('f', 'force', False, _('force')),
1013 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1014 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1014 ('d', 'delete', False, _('delete a given bookmark')),
1015 ('d', 'delete', False, _('delete a given bookmark')),
1015 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1016 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1016 ('i', 'inactive', False, _('mark a bookmark inactive')),
1017 ('i', 'inactive', False, _('mark a bookmark inactive')),
1017 ] + formatteropts,
1018 ] + formatteropts,
1018 _('hg bookmarks [OPTIONS]... [NAME]...'))
1019 _('hg bookmarks [OPTIONS]... [NAME]...'))
1019 def bookmark(ui, repo, *names, **opts):
1020 def bookmark(ui, repo, *names, **opts):
1020 '''create a new bookmark or list existing bookmarks
1021 '''create a new bookmark or list existing bookmarks
1021
1022
1022 Bookmarks are labels on changesets to help track lines of development.
1023 Bookmarks are labels on changesets to help track lines of development.
1023 Bookmarks are unversioned and can be moved, renamed and deleted.
1024 Bookmarks are unversioned and can be moved, renamed and deleted.
1024 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.
1025
1026
1026 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'.
1027 The active bookmark is indicated with a '*'.
1028 The active bookmark is indicated with a '*'.
1028 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.
1029 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.
1030 Updating away from a bookmark will cause it to be deactivated.
1031 Updating away from a bookmark will cause it to be deactivated.
1031
1032
1032 Bookmarks can be pushed and pulled between repositories (see
1033 Bookmarks can be pushed and pulled between repositories (see
1033 :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
1034 diverged, a new 'divergent bookmark' of the form 'name@path' will
1035 diverged, a new 'divergent bookmark' of the form 'name@path' will
1035 be created. Using :hg:`merge` will resolve the divergence.
1036 be created. Using :hg:`merge` will resolve the divergence.
1036
1037
1037 A bookmark named '@' has the special property that :hg:`clone` will
1038 A bookmark named '@' has the special property that :hg:`clone` will
1038 check it out by default if it exists.
1039 check it out by default if it exists.
1039
1040
1040 .. container:: verbose
1041 .. container:: verbose
1041
1042
1042 Examples:
1043 Examples:
1043
1044
1044 - create an active bookmark for a new line of development::
1045 - create an active bookmark for a new line of development::
1045
1046
1046 hg book new-feature
1047 hg book new-feature
1047
1048
1048 - create an inactive bookmark as a place marker::
1049 - create an inactive bookmark as a place marker::
1049
1050
1050 hg book -i reviewed
1051 hg book -i reviewed
1051
1052
1052 - create an inactive bookmark on another changeset::
1053 - create an inactive bookmark on another changeset::
1053
1054
1054 hg book -r .^ tested
1055 hg book -r .^ tested
1055
1056
1056 - rename bookmark turkey to dinner::
1057 - rename bookmark turkey to dinner::
1057
1058
1058 hg book -m turkey dinner
1059 hg book -m turkey dinner
1059
1060
1060 - move the '@' bookmark from another branch::
1061 - move the '@' bookmark from another branch::
1061
1062
1062 hg book -f @
1063 hg book -f @
1063 '''
1064 '''
1064 force = opts.get('force')
1065 force = opts.get('force')
1065 rev = opts.get('rev')
1066 rev = opts.get('rev')
1066 delete = opts.get('delete')
1067 delete = opts.get('delete')
1067 rename = opts.get('rename')
1068 rename = opts.get('rename')
1068 inactive = opts.get('inactive')
1069 inactive = opts.get('inactive')
1069
1070
1070 def checkformat(mark):
1071 def checkformat(mark):
1071 mark = mark.strip()
1072 mark = mark.strip()
1072 if not mark:
1073 if not mark:
1073 raise error.Abort(_("bookmark names cannot consist entirely of "
1074 raise error.Abort(_("bookmark names cannot consist entirely of "
1074 "whitespace"))
1075 "whitespace"))
1075 scmutil.checknewlabel(repo, mark, 'bookmark')
1076 scmutil.checknewlabel(repo, mark, 'bookmark')
1076 return mark
1077 return mark
1077
1078
1078 def checkconflict(repo, mark, cur, force=False, target=None):
1079 def checkconflict(repo, mark, cur, force=False, target=None):
1079 if mark in marks and not force:
1080 if mark in marks and not force:
1080 if target:
1081 if target:
1081 if marks[mark] == target and target == cur:
1082 if marks[mark] == target and target == cur:
1082 # re-activating a bookmark
1083 # re-activating a bookmark
1083 return
1084 return
1084 anc = repo.changelog.ancestors([repo[target].rev()])
1085 anc = repo.changelog.ancestors([repo[target].rev()])
1085 bmctx = repo[marks[mark]]
1086 bmctx = repo[marks[mark]]
1086 divs = [repo[b].node() for b in marks
1087 divs = [repo[b].node() for b in marks
1087 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1088 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1088
1089
1089 # allow resolving a single divergent bookmark even if moving
1090 # allow resolving a single divergent bookmark even if moving
1090 # the bookmark across branches when a revision is specified
1091 # the bookmark across branches when a revision is specified
1091 # that contains a divergent bookmark
1092 # that contains a divergent bookmark
1092 if bmctx.rev() not in anc and target in divs:
1093 if bmctx.rev() not in anc and target in divs:
1093 bookmarks.deletedivergent(repo, [target], mark)
1094 bookmarks.deletedivergent(repo, [target], mark)
1094 return
1095 return
1095
1096
1096 deletefrom = [b for b in divs
1097 deletefrom = [b for b in divs
1097 if repo[b].rev() in anc or b == target]
1098 if repo[b].rev() in anc or b == target]
1098 bookmarks.deletedivergent(repo, deletefrom, mark)
1099 bookmarks.deletedivergent(repo, deletefrom, mark)
1099 if bookmarks.validdest(repo, bmctx, repo[target]):
1100 if bookmarks.validdest(repo, bmctx, repo[target]):
1100 ui.status(_("moving bookmark '%s' forward from %s\n") %
1101 ui.status(_("moving bookmark '%s' forward from %s\n") %
1101 (mark, short(bmctx.node())))
1102 (mark, short(bmctx.node())))
1102 return
1103 return
1103 raise error.Abort(_("bookmark '%s' already exists "
1104 raise error.Abort(_("bookmark '%s' already exists "
1104 "(use -f to force)") % mark)
1105 "(use -f to force)") % mark)
1105 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1106 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1106 and not force):
1107 and not force):
1107 raise error.Abort(
1108 raise error.Abort(
1108 _("a bookmark cannot have the name of an existing branch"))
1109 _("a bookmark cannot have the name of an existing branch"))
1109
1110
1110 if delete and rename:
1111 if delete and rename:
1111 raise error.Abort(_("--delete and --rename are incompatible"))
1112 raise error.Abort(_("--delete and --rename are incompatible"))
1112 if delete and rev:
1113 if delete and rev:
1113 raise error.Abort(_("--rev is incompatible with --delete"))
1114 raise error.Abort(_("--rev is incompatible with --delete"))
1114 if rename and rev:
1115 if rename and rev:
1115 raise error.Abort(_("--rev is incompatible with --rename"))
1116 raise error.Abort(_("--rev is incompatible with --rename"))
1116 if not names and (delete or rev):
1117 if not names and (delete or rev):
1117 raise error.Abort(_("bookmark name required"))
1118 raise error.Abort(_("bookmark name required"))
1118
1119
1119 if delete or rename or names or inactive:
1120 if delete or rename or names or inactive:
1120 wlock = lock = tr = None
1121 wlock = lock = tr = None
1121 try:
1122 try:
1122 wlock = repo.wlock()
1123 wlock = repo.wlock()
1123 lock = repo.lock()
1124 lock = repo.lock()
1124 cur = repo.changectx('.').node()
1125 cur = repo.changectx('.').node()
1125 marks = repo._bookmarks
1126 marks = repo._bookmarks
1126 if delete:
1127 if delete:
1127 tr = repo.transaction('bookmark')
1128 tr = repo.transaction('bookmark')
1128 for mark in names:
1129 for mark in names:
1129 if mark not in marks:
1130 if mark not in marks:
1130 raise error.Abort(_("bookmark '%s' does not exist") %
1131 raise error.Abort(_("bookmark '%s' does not exist") %
1131 mark)
1132 mark)
1132 if mark == repo._activebookmark:
1133 if mark == repo._activebookmark:
1133 bookmarks.deactivate(repo)
1134 bookmarks.deactivate(repo)
1134 del marks[mark]
1135 del marks[mark]
1135
1136
1136 elif rename:
1137 elif rename:
1137 tr = repo.transaction('bookmark')
1138 tr = repo.transaction('bookmark')
1138 if not names:
1139 if not names:
1139 raise error.Abort(_("new bookmark name required"))
1140 raise error.Abort(_("new bookmark name required"))
1140 elif len(names) > 1:
1141 elif len(names) > 1:
1141 raise error.Abort(_("only one new bookmark name allowed"))
1142 raise error.Abort(_("only one new bookmark name allowed"))
1142 mark = checkformat(names[0])
1143 mark = checkformat(names[0])
1143 if rename not in marks:
1144 if rename not in marks:
1144 raise error.Abort(_("bookmark '%s' does not exist")
1145 raise error.Abort(_("bookmark '%s' does not exist")
1145 % rename)
1146 % rename)
1146 checkconflict(repo, mark, cur, force)
1147 checkconflict(repo, mark, cur, force)
1147 marks[mark] = marks[rename]
1148 marks[mark] = marks[rename]
1148 if repo._activebookmark == rename and not inactive:
1149 if repo._activebookmark == rename and not inactive:
1149 bookmarks.activate(repo, mark)
1150 bookmarks.activate(repo, mark)
1150 del marks[rename]
1151 del marks[rename]
1151 elif names:
1152 elif names:
1152 tr = repo.transaction('bookmark')
1153 tr = repo.transaction('bookmark')
1153 newact = None
1154 newact = None
1154 for mark in names:
1155 for mark in names:
1155 mark = checkformat(mark)
1156 mark = checkformat(mark)
1156 if newact is None:
1157 if newact is None:
1157 newact = mark
1158 newact = mark
1158 if inactive and mark == repo._activebookmark:
1159 if inactive and mark == repo._activebookmark:
1159 bookmarks.deactivate(repo)
1160 bookmarks.deactivate(repo)
1160 return
1161 return
1161 tgt = cur
1162 tgt = cur
1162 if rev:
1163 if rev:
1163 tgt = scmutil.revsingle(repo, rev).node()
1164 tgt = scmutil.revsingle(repo, rev).node()
1164 checkconflict(repo, mark, cur, force, tgt)
1165 checkconflict(repo, mark, cur, force, tgt)
1165 marks[mark] = tgt
1166 marks[mark] = tgt
1166 if not inactive and cur == marks[newact] and not rev:
1167 if not inactive and cur == marks[newact] and not rev:
1167 bookmarks.activate(repo, newact)
1168 bookmarks.activate(repo, newact)
1168 elif cur != tgt and newact == repo._activebookmark:
1169 elif cur != tgt and newact == repo._activebookmark:
1169 bookmarks.deactivate(repo)
1170 bookmarks.deactivate(repo)
1170 elif inactive:
1171 elif inactive:
1171 if len(marks) == 0:
1172 if len(marks) == 0:
1172 ui.status(_("no bookmarks set\n"))
1173 ui.status(_("no bookmarks set\n"))
1173 elif not repo._activebookmark:
1174 elif not repo._activebookmark:
1174 ui.status(_("no active bookmark\n"))
1175 ui.status(_("no active bookmark\n"))
1175 else:
1176 else:
1176 bookmarks.deactivate(repo)
1177 bookmarks.deactivate(repo)
1177 if tr is not None:
1178 if tr is not None:
1178 marks.recordchange(tr)
1179 marks.recordchange(tr)
1179 tr.close()
1180 tr.close()
1180 finally:
1181 finally:
1181 lockmod.release(tr, lock, wlock)
1182 lockmod.release(tr, lock, wlock)
1182 else: # show bookmarks
1183 else: # show bookmarks
1183 fm = ui.formatter('bookmarks', opts)
1184 fm = ui.formatter('bookmarks', opts)
1184 hexfn = fm.hexfunc
1185 hexfn = fm.hexfunc
1185 marks = repo._bookmarks
1186 marks = repo._bookmarks
1186 if len(marks) == 0 and not fm:
1187 if len(marks) == 0 and not fm:
1187 ui.status(_("no bookmarks set\n"))
1188 ui.status(_("no bookmarks set\n"))
1188 for bmark, n in sorted(marks.iteritems()):
1189 for bmark, n in sorted(marks.iteritems()):
1189 active = repo._activebookmark
1190 active = repo._activebookmark
1190 if bmark == active:
1191 if bmark == active:
1191 prefix, label = '*', activebookmarklabel
1192 prefix, label = '*', activebookmarklabel
1192 else:
1193 else:
1193 prefix, label = ' ', ''
1194 prefix, label = ' ', ''
1194
1195
1195 fm.startitem()
1196 fm.startitem()
1196 if not ui.quiet:
1197 if not ui.quiet:
1197 fm.plain(' %s ' % prefix, label=label)
1198 fm.plain(' %s ' % prefix, label=label)
1198 fm.write('bookmark', '%s', bmark, label=label)
1199 fm.write('bookmark', '%s', bmark, label=label)
1199 pad = " " * (25 - encoding.colwidth(bmark))
1200 pad = " " * (25 - encoding.colwidth(bmark))
1200 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1201 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1201 repo.changelog.rev(n), hexfn(n), label=label)
1202 repo.changelog.rev(n), hexfn(n), label=label)
1202 fm.data(active=(bmark == active))
1203 fm.data(active=(bmark == active))
1203 fm.plain('\n')
1204 fm.plain('\n')
1204 fm.end()
1205 fm.end()
1205
1206
1206 @command('branch',
1207 @command('branch',
1207 [('f', 'force', None,
1208 [('f', 'force', None,
1208 _('set branch name even if it shadows an existing branch')),
1209 _('set branch name even if it shadows an existing branch')),
1209 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1210 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1210 _('[-fC] [NAME]'))
1211 _('[-fC] [NAME]'))
1211 def branch(ui, repo, label=None, **opts):
1212 def branch(ui, repo, label=None, **opts):
1212 """set or show the current branch name
1213 """set or show the current branch name
1213
1214
1214 .. note::
1215 .. note::
1215
1216
1216 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
1217 light-weight bookmark instead. See :hg:`help glossary` for more
1218 light-weight bookmark instead. See :hg:`help glossary` for more
1218 information about named branches and bookmarks.
1219 information about named branches and bookmarks.
1219
1220
1220 With no argument, show the current branch name. With one argument,
1221 With no argument, show the current branch name. With one argument,
1221 set the working directory branch name (the branch will not exist
1222 set the working directory branch name (the branch will not exist
1222 in the repository until the next commit). Standard practice
1223 in the repository until the next commit). Standard practice
1223 recommends that primary development take place on the 'default'
1224 recommends that primary development take place on the 'default'
1224 branch.
1225 branch.
1225
1226
1226 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
1227 branch name that already exists.
1228 branch name that already exists.
1228
1229
1229 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
1230 the parent of the working directory, negating a previous branch
1231 the parent of the working directory, negating a previous branch
1231 change.
1232 change.
1232
1233
1233 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
1234 :hg:`commit --close-branch` to mark this branch head as closed.
1235 :hg:`commit --close-branch` to mark this branch head as closed.
1235 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
1236 considered closed.
1237 considered closed.
1237
1238
1238 Returns 0 on success.
1239 Returns 0 on success.
1239 """
1240 """
1240 if label:
1241 if label:
1241 label = label.strip()
1242 label = label.strip()
1242
1243
1243 if not opts.get('clean') and not label:
1244 if not opts.get('clean') and not label:
1244 ui.write("%s\n" % repo.dirstate.branch())
1245 ui.write("%s\n" % repo.dirstate.branch())
1245 return
1246 return
1246
1247
1247 with repo.wlock():
1248 with repo.wlock():
1248 if opts.get('clean'):
1249 if opts.get('clean'):
1249 label = repo[None].p1().branch()
1250 label = repo[None].p1().branch()
1250 repo.dirstate.setbranch(label)
1251 repo.dirstate.setbranch(label)
1251 ui.status(_('reset working directory to branch %s\n') % label)
1252 ui.status(_('reset working directory to branch %s\n') % label)
1252 elif label:
1253 elif label:
1253 if not opts.get('force') and label in repo.branchmap():
1254 if not opts.get('force') and label in repo.branchmap():
1254 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()]:
1255 raise error.Abort(_('a branch of the same name already'
1256 raise error.Abort(_('a branch of the same name already'
1256 ' exists'),
1257 ' exists'),
1257 # i18n: "it" refers to an existing branch
1258 # i18n: "it" refers to an existing branch
1258 hint=_("use 'hg update' to switch to it"))
1259 hint=_("use 'hg update' to switch to it"))
1259 scmutil.checknewlabel(repo, label, 'branch')
1260 scmutil.checknewlabel(repo, label, 'branch')
1260 repo.dirstate.setbranch(label)
1261 repo.dirstate.setbranch(label)
1261 ui.status(_('marked working directory as branch %s\n') % label)
1262 ui.status(_('marked working directory as branch %s\n') % label)
1262
1263
1263 # find any open named branches aside from default
1264 # find any open named branches aside from default
1264 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1265 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1265 if n != "default" and not c]
1266 if n != "default" and not c]
1266 if not others:
1267 if not others:
1267 ui.status(_('(branches are permanent and global, '
1268 ui.status(_('(branches are permanent and global, '
1268 'did you want a bookmark?)\n'))
1269 'did you want a bookmark?)\n'))
1269
1270
1270 @command('branches',
1271 @command('branches',
1271 [('a', 'active', False,
1272 [('a', 'active', False,
1272 _('show only branches that have unmerged heads (DEPRECATED)')),
1273 _('show only branches that have unmerged heads (DEPRECATED)')),
1273 ('c', 'closed', False, _('show normal and closed branches')),
1274 ('c', 'closed', False, _('show normal and closed branches')),
1274 ] + formatteropts,
1275 ] + formatteropts,
1275 _('[-c]'))
1276 _('[-c]'))
1276 def branches(ui, repo, active=False, closed=False, **opts):
1277 def branches(ui, repo, active=False, closed=False, **opts):
1277 """list repository named branches
1278 """list repository named branches
1278
1279
1279 List the repository's named branches, indicating which ones are
1280 List the repository's named branches, indicating which ones are
1280 inactive. If -c/--closed is specified, also list branches which have
1281 inactive. If -c/--closed is specified, also list branches which have
1281 been marked closed (see :hg:`commit --close-branch`).
1282 been marked closed (see :hg:`commit --close-branch`).
1282
1283
1283 Use the command :hg:`update` to switch to an existing branch.
1284 Use the command :hg:`update` to switch to an existing branch.
1284
1285
1285 Returns 0.
1286 Returns 0.
1286 """
1287 """
1287
1288
1288 fm = ui.formatter('branches', opts)
1289 fm = ui.formatter('branches', opts)
1289 hexfunc = fm.hexfunc
1290 hexfunc = fm.hexfunc
1290
1291
1291 allheads = set(repo.heads())
1292 allheads = set(repo.heads())
1292 branches = []
1293 branches = []
1293 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1294 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1294 isactive = not isclosed and bool(set(heads) & allheads)
1295 isactive = not isclosed and bool(set(heads) & allheads)
1295 branches.append((tag, repo[tip], isactive, not isclosed))
1296 branches.append((tag, repo[tip], isactive, not isclosed))
1296 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]),
1297 reverse=True)
1298 reverse=True)
1298
1299
1299 for tag, ctx, isactive, isopen in branches:
1300 for tag, ctx, isactive, isopen in branches:
1300 if active and not isactive:
1301 if active and not isactive:
1301 continue
1302 continue
1302 if isactive:
1303 if isactive:
1303 label = 'branches.active'
1304 label = 'branches.active'
1304 notice = ''
1305 notice = ''
1305 elif not isopen:
1306 elif not isopen:
1306 if not closed:
1307 if not closed:
1307 continue
1308 continue
1308 label = 'branches.closed'
1309 label = 'branches.closed'
1309 notice = _(' (closed)')
1310 notice = _(' (closed)')
1310 else:
1311 else:
1311 label = 'branches.inactive'
1312 label = 'branches.inactive'
1312 notice = _(' (inactive)')
1313 notice = _(' (inactive)')
1313 current = (tag == repo.dirstate.branch())
1314 current = (tag == repo.dirstate.branch())
1314 if current:
1315 if current:
1315 label = 'branches.current'
1316 label = 'branches.current'
1316
1317
1317 fm.startitem()
1318 fm.startitem()
1318 fm.write('branch', '%s', tag, label=label)
1319 fm.write('branch', '%s', tag, label=label)
1319 rev = ctx.rev()
1320 rev = ctx.rev()
1320 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1321 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1321 fmt = ' ' * padsize + ' %d:%s'
1322 fmt = ' ' * padsize + ' %d:%s'
1322 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()),
1323 label='log.changeset changeset.%s' % ctx.phasestr())
1324 label='log.changeset changeset.%s' % ctx.phasestr())
1324 fm.data(active=isactive, closed=not isopen, current=current)
1325 fm.data(active=isactive, closed=not isopen, current=current)
1325 if not ui.quiet:
1326 if not ui.quiet:
1326 fm.plain(notice)
1327 fm.plain(notice)
1327 fm.plain('\n')
1328 fm.plain('\n')
1328 fm.end()
1329 fm.end()
1329
1330
1330 @command('bundle',
1331 @command('bundle',
1331 [('f', 'force', None, _('run even when the destination is unrelated')),
1332 [('f', 'force', None, _('run even when the destination is unrelated')),
1332 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1333 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1333 _('REV')),
1334 _('REV')),
1334 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1335 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1335 _('BRANCH')),
1336 _('BRANCH')),
1336 ('', 'base', [],
1337 ('', 'base', [],
1337 _('a base changeset assumed to be available at the destination'),
1338 _('a base changeset assumed to be available at the destination'),
1338 _('REV')),
1339 _('REV')),
1339 ('a', 'all', None, _('bundle all changesets in the repository')),
1340 ('a', 'all', None, _('bundle all changesets in the repository')),
1340 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1341 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1341 ] + remoteopts,
1342 ] + remoteopts,
1342 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1343 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1343 def bundle(ui, repo, fname, dest=None, **opts):
1344 def bundle(ui, repo, fname, dest=None, **opts):
1344 """create a changegroup file
1345 """create a changegroup file
1345
1346
1346 Generate a changegroup file collecting changesets to be added
1347 Generate a changegroup file collecting changesets to be added
1347 to a repository.
1348 to a repository.
1348
1349
1349 To create a bundle containing all changesets, use -a/--all
1350 To create a bundle containing all changesets, use -a/--all
1350 (or --base null). Otherwise, hg assumes the destination will have
1351 (or --base null). Otherwise, hg assumes the destination will have
1351 all the nodes you specify with --base parameters. Otherwise, hg
1352 all the nodes you specify with --base parameters. Otherwise, hg
1352 will assume the repository has all the nodes in destination, or
1353 will assume the repository has all the nodes in destination, or
1353 default-push/default if no destination is specified.
1354 default-push/default if no destination is specified.
1354
1355
1355 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
1356 specify a compression, a bundle version or both using a dash
1357 specify a compression, a bundle version or both using a dash
1357 (comp-version). The available compression methods are: none, bzip2,
1358 (comp-version). The available compression methods are: none, bzip2,
1358 and gzip (by default, bundles are compressed using bzip2). The
1359 and gzip (by default, bundles are compressed using bzip2). The
1359 available formats are: v1, v2 (default to most suitable).
1360 available formats are: v1, v2 (default to most suitable).
1360
1361
1361 The bundle file can then be transferred using conventional means
1362 The bundle file can then be transferred using conventional means
1362 and applied to another repository with the unbundle or pull
1363 and applied to another repository with the unbundle or pull
1363 command. This is useful when direct push and pull are not
1364 command. This is useful when direct push and pull are not
1364 available or when exporting an entire repository is undesirable.
1365 available or when exporting an entire repository is undesirable.
1365
1366
1366 Applying bundles preserves all changeset contents including
1367 Applying bundles preserves all changeset contents including
1367 permissions, copy/rename information, and revision history.
1368 permissions, copy/rename information, and revision history.
1368
1369
1369 Returns 0 on success, 1 if no changes found.
1370 Returns 0 on success, 1 if no changes found.
1370 """
1371 """
1371 revs = None
1372 revs = None
1372 if 'rev' in opts:
1373 if 'rev' in opts:
1373 revstrings = opts['rev']
1374 revstrings = opts['rev']
1374 revs = scmutil.revrange(repo, revstrings)
1375 revs = scmutil.revrange(repo, revstrings)
1375 if revstrings and not revs:
1376 if revstrings and not revs:
1376 raise error.Abort(_('no commits to bundle'))
1377 raise error.Abort(_('no commits to bundle'))
1377
1378
1378 bundletype = opts.get('type', 'bzip2').lower()
1379 bundletype = opts.get('type', 'bzip2').lower()
1379 try:
1380 try:
1380 bcompression, cgversion, params = exchange.parsebundlespec(
1381 bcompression, cgversion, params = exchange.parsebundlespec(
1381 repo, bundletype, strict=False)
1382 repo, bundletype, strict=False)
1382 except error.UnsupportedBundleSpecification as e:
1383 except error.UnsupportedBundleSpecification as e:
1383 raise error.Abort(str(e),
1384 raise error.Abort(str(e),
1384 hint=_('see "hg help bundle" for supported '
1385 hint=_('see "hg help bundle" for supported '
1385 'values for --type'))
1386 'values for --type'))
1386
1387
1387 # Packed bundles are a pseudo bundle format for now.
1388 # Packed bundles are a pseudo bundle format for now.
1388 if cgversion == 's1':
1389 if cgversion == 's1':
1389 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1390 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1390 hint=_("use 'hg debugcreatestreamclonebundle'"))
1391 hint=_("use 'hg debugcreatestreamclonebundle'"))
1391
1392
1392 if opts.get('all'):
1393 if opts.get('all'):
1393 if dest:
1394 if dest:
1394 raise error.Abort(_("--all is incompatible with specifying "
1395 raise error.Abort(_("--all is incompatible with specifying "
1395 "a destination"))
1396 "a destination"))
1396 if opts.get('base'):
1397 if opts.get('base'):
1397 ui.warn(_("ignoring --base because --all was specified\n"))
1398 ui.warn(_("ignoring --base because --all was specified\n"))
1398 base = ['null']
1399 base = ['null']
1399 else:
1400 else:
1400 base = scmutil.revrange(repo, opts.get('base'))
1401 base = scmutil.revrange(repo, opts.get('base'))
1401 # TODO: get desired bundlecaps from command line.
1402 # TODO: get desired bundlecaps from command line.
1402 bundlecaps = None
1403 bundlecaps = None
1403 if cgversion not in changegroup.supportedoutgoingversions(repo):
1404 if cgversion not in changegroup.supportedoutgoingversions(repo):
1404 raise error.Abort(_("repository does not support bundle version %s") %
1405 raise error.Abort(_("repository does not support bundle version %s") %
1405 cgversion)
1406 cgversion)
1406
1407
1407 if base:
1408 if base:
1408 if dest:
1409 if dest:
1409 raise error.Abort(_("--base is incompatible with specifying "
1410 raise error.Abort(_("--base is incompatible with specifying "
1410 "a destination"))
1411 "a destination"))
1411 common = [repo.lookup(rev) for rev in base]
1412 common = [repo.lookup(rev) for rev in base]
1412 heads = revs and map(repo.lookup, revs) or revs
1413 heads = revs and map(repo.lookup, revs) or revs
1413 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1414 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1414 common=common, bundlecaps=bundlecaps,
1415 common=common, bundlecaps=bundlecaps,
1415 version=cgversion)
1416 version=cgversion)
1416 outgoing = None
1417 outgoing = None
1417 else:
1418 else:
1418 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1419 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1419 dest, branches = hg.parseurl(dest, opts.get('branch'))
1420 dest, branches = hg.parseurl(dest, opts.get('branch'))
1420 other = hg.peer(repo, opts, dest)
1421 other = hg.peer(repo, opts, dest)
1421 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1422 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1422 heads = revs and map(repo.lookup, revs) or revs
1423 heads = revs and map(repo.lookup, revs) or revs
1423 outgoing = discovery.findcommonoutgoing(repo, other,
1424 outgoing = discovery.findcommonoutgoing(repo, other,
1424 onlyheads=heads,
1425 onlyheads=heads,
1425 force=opts.get('force'),
1426 force=opts.get('force'),
1426 portable=True)
1427 portable=True)
1427 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1428 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1428 bundlecaps, version=cgversion)
1429 bundlecaps, version=cgversion)
1429 if not cg:
1430 if not cg:
1430 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1431 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1431 return 1
1432 return 1
1432
1433
1433 if cgversion == '01': #bundle1
1434 if cgversion == '01': #bundle1
1434 if bcompression is None:
1435 if bcompression is None:
1435 bcompression = 'UN'
1436 bcompression = 'UN'
1436 bversion = 'HG10' + bcompression
1437 bversion = 'HG10' + bcompression
1437 bcompression = None
1438 bcompression = None
1438 else:
1439 else:
1439 assert cgversion == '02'
1440 assert cgversion == '02'
1440 bversion = 'HG20'
1441 bversion = 'HG20'
1441
1442
1442 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1443 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1443
1444
1444 @command('cat',
1445 @command('cat',
1445 [('o', 'output', '',
1446 [('o', 'output', '',
1446 _('print output to file with formatted name'), _('FORMAT')),
1447 _('print output to file with formatted name'), _('FORMAT')),
1447 ('r', 'rev', '', _('print the given revision'), _('REV')),
1448 ('r', 'rev', '', _('print the given revision'), _('REV')),
1448 ('', 'decode', None, _('apply any matching decode filter')),
1449 ('', 'decode', None, _('apply any matching decode filter')),
1449 ] + walkopts,
1450 ] + walkopts,
1450 _('[OPTION]... FILE...'),
1451 _('[OPTION]... FILE...'),
1451 inferrepo=True)
1452 inferrepo=True)
1452 def cat(ui, repo, file1, *pats, **opts):
1453 def cat(ui, repo, file1, *pats, **opts):
1453 """output the current or given revision of files
1454 """output the current or given revision of files
1454
1455
1455 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
1456 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.
1457
1458
1458 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
1459 given using a format string. The formatting rules as follows:
1460 given using a format string. The formatting rules as follows:
1460
1461
1461 :``%%``: literal "%" character
1462 :``%%``: literal "%" character
1462 :``%s``: basename of file being printed
1463 :``%s``: basename of file being printed
1463 :``%d``: dirname of file being printed, or '.' if in repository root
1464 :``%d``: dirname of file being printed, or '.' if in repository root
1464 :``%p``: root-relative path name of file being printed
1465 :``%p``: root-relative path name of file being printed
1465 :``%H``: changeset hash (40 hexadecimal digits)
1466 :``%H``: changeset hash (40 hexadecimal digits)
1466 :``%R``: changeset revision number
1467 :``%R``: changeset revision number
1467 :``%h``: short-form changeset hash (12 hexadecimal digits)
1468 :``%h``: short-form changeset hash (12 hexadecimal digits)
1468 :``%r``: zero-padded changeset revision number
1469 :``%r``: zero-padded changeset revision number
1469 :``%b``: basename of the exporting repository
1470 :``%b``: basename of the exporting repository
1470
1471
1471 Returns 0 on success.
1472 Returns 0 on success.
1472 """
1473 """
1473 ctx = scmutil.revsingle(repo, opts.get('rev'))
1474 ctx = scmutil.revsingle(repo, opts.get('rev'))
1474 m = scmutil.match(ctx, (file1,) + pats, opts)
1475 m = scmutil.match(ctx, (file1,) + pats, opts)
1475
1476
1476 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1477 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1477
1478
1478 @command('^clone',
1479 @command('^clone',
1479 [('U', 'noupdate', None, _('the clone will include an empty working '
1480 [('U', 'noupdate', None, _('the clone will include an empty working '
1480 'directory (only a repository)')),
1481 'directory (only a repository)')),
1481 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1482 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1482 _('REV')),
1483 _('REV')),
1483 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1484 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1484 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1485 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1485 ('', 'pull', None, _('use pull protocol to copy metadata')),
1486 ('', 'pull', None, _('use pull protocol to copy metadata')),
1486 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1487 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1487 ] + remoteopts,
1488 ] + remoteopts,
1488 _('[OPTION]... SOURCE [DEST]'),
1489 _('[OPTION]... SOURCE [DEST]'),
1489 norepo=True)
1490 norepo=True)
1490 def clone(ui, source, dest=None, **opts):
1491 def clone(ui, source, dest=None, **opts):
1491 """make a copy of an existing repository
1492 """make a copy of an existing repository
1492
1493
1493 Create a copy of an existing repository in a new directory.
1494 Create a copy of an existing repository in a new directory.
1494
1495
1495 If no destination directory name is specified, it defaults to the
1496 If no destination directory name is specified, it defaults to the
1496 basename of the source.
1497 basename of the source.
1497
1498
1498 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
1499 ``.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.
1500
1501
1501 Only local paths and ``ssh://`` URLs are supported as
1502 Only local paths and ``ssh://`` URLs are supported as
1502 destinations. For ``ssh://`` destinations, no working directory or
1503 destinations. For ``ssh://`` destinations, no working directory or
1503 ``.hg/hgrc`` will be created on the remote side.
1504 ``.hg/hgrc`` will be created on the remote side.
1504
1505
1505 If the source repository has a bookmark called '@' set, that
1506 If the source repository has a bookmark called '@' set, that
1506 revision will be checked out in the new repository by default.
1507 revision will be checked out in the new repository by default.
1507
1508
1508 To check out a particular version, use -u/--update, or
1509 To check out a particular version, use -u/--update, or
1509 -U/--noupdate to create a clone with no working directory.
1510 -U/--noupdate to create a clone with no working directory.
1510
1511
1511 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
1512 identifiers with -r/--rev or branches with -b/--branch. The
1513 identifiers with -r/--rev or branches with -b/--branch. The
1513 resulting clone will contain only the specified changesets and
1514 resulting clone will contain only the specified changesets and
1514 their ancestors. These options (or 'clone src#rev dest') imply
1515 their ancestors. These options (or 'clone src#rev dest') imply
1515 --pull, even for local source repositories.
1516 --pull, even for local source repositories.
1516
1517
1517 .. note::
1518 .. note::
1518
1519
1519 Specifying a tag will include the tagged changeset but not the
1520 Specifying a tag will include the tagged changeset but not the
1520 changeset containing the tag.
1521 changeset containing the tag.
1521
1522
1522 .. container:: verbose
1523 .. container:: verbose
1523
1524
1524 For efficiency, hardlinks are used for cloning whenever the
1525 For efficiency, hardlinks are used for cloning whenever the
1525 source and destination are on the same filesystem (note this
1526 source and destination are on the same filesystem (note this
1526 applies only to the repository data, not to the working
1527 applies only to the repository data, not to the working
1527 directory). Some filesystems, such as AFS, implement hardlinking
1528 directory). Some filesystems, such as AFS, implement hardlinking
1528 incorrectly, but do not report errors. In these cases, use the
1529 incorrectly, but do not report errors. In these cases, use the
1529 --pull option to avoid hardlinking.
1530 --pull option to avoid hardlinking.
1530
1531
1531 In some cases, you can clone repositories and the working
1532 In some cases, you can clone repositories and the working
1532 directory using full hardlinks with ::
1533 directory using full hardlinks with ::
1533
1534
1534 $ cp -al REPO REPOCLONE
1535 $ cp -al REPO REPOCLONE
1535
1536
1536 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
1537 operation is not atomic (making sure REPO is not modified during
1538 operation is not atomic (making sure REPO is not modified during
1538 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
1539 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1540 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1540 so). Also, this is not compatible with certain extensions that
1541 so). Also, this is not compatible with certain extensions that
1541 place their metadata under the .hg directory, such as mq.
1542 place their metadata under the .hg directory, such as mq.
1542
1543
1543 Mercurial will update the working directory to the first applicable
1544 Mercurial will update the working directory to the first applicable
1544 revision from this list:
1545 revision from this list:
1545
1546
1546 a) null if -U or the source repository has no changesets
1547 a) null if -U or the source repository has no changesets
1547 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
1548 the source repository's working directory
1549 the source repository's working directory
1549 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
1550 latest head of that branch)
1551 latest head of that branch)
1551 d) the changeset specified with -r
1552 d) the changeset specified with -r
1552 e) the tipmost head specified with -b
1553 e) the tipmost head specified with -b
1553 f) the tipmost head specified with the url#branch source syntax
1554 f) the tipmost head specified with the url#branch source syntax
1554 g) the revision marked with the '@' bookmark, if present
1555 g) the revision marked with the '@' bookmark, if present
1555 h) the tipmost head of the default branch
1556 h) the tipmost head of the default branch
1556 i) tip
1557 i) tip
1557
1558
1558 When cloning from servers that support it, Mercurial may fetch
1559 When cloning from servers that support it, Mercurial may fetch
1559 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,
1560 hooks operating on incoming changesets and changegroups may fire twice,
1561 hooks operating on incoming changesets and changegroups may fire twice,
1561 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
1562 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
1563 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
1564 change in future releases. See :hg:`help -e clonebundles` for more.
1565 change in future releases. See :hg:`help -e clonebundles` for more.
1565
1566
1566 Examples:
1567 Examples:
1567
1568
1568 - clone a remote repository to a new directory named hg/::
1569 - clone a remote repository to a new directory named hg/::
1569
1570
1570 hg clone http://selenic.com/hg
1571 hg clone http://selenic.com/hg
1571
1572
1572 - create a lightweight local clone::
1573 - create a lightweight local clone::
1573
1574
1574 hg clone project/ project-feature/
1575 hg clone project/ project-feature/
1575
1576
1576 - 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)::
1577
1578
1578 hg clone ssh://user@server//home/projects/alpha/
1579 hg clone ssh://user@server//home/projects/alpha/
1579
1580
1580 - 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
1581 specified version::
1582 specified version::
1582
1583
1583 hg clone --uncompressed http://server/repo -u 1.5
1584 hg clone --uncompressed http://server/repo -u 1.5
1584
1585
1585 - create a repository without changesets after a particular revision::
1586 - create a repository without changesets after a particular revision::
1586
1587
1587 hg clone -r 04e544 experimental/ good/
1588 hg clone -r 04e544 experimental/ good/
1588
1589
1589 - clone (and track) a particular named branch::
1590 - clone (and track) a particular named branch::
1590
1591
1591 hg clone http://selenic.com/hg#stable
1592 hg clone http://selenic.com/hg#stable
1592
1593
1593 See :hg:`help urls` for details on specifying URLs.
1594 See :hg:`help urls` for details on specifying URLs.
1594
1595
1595 Returns 0 on success.
1596 Returns 0 on success.
1596 """
1597 """
1597 if opts.get('noupdate') and opts.get('updaterev'):
1598 if opts.get('noupdate') and opts.get('updaterev'):
1598 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1599 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1599
1600
1600 r = hg.clone(ui, opts, source, dest,
1601 r = hg.clone(ui, opts, source, dest,
1601 pull=opts.get('pull'),
1602 pull=opts.get('pull'),
1602 stream=opts.get('uncompressed'),
1603 stream=opts.get('uncompressed'),
1603 rev=opts.get('rev'),
1604 rev=opts.get('rev'),
1604 update=opts.get('updaterev') or not opts.get('noupdate'),
1605 update=opts.get('updaterev') or not opts.get('noupdate'),
1605 branch=opts.get('branch'),
1606 branch=opts.get('branch'),
1606 shareopts=opts.get('shareopts'))
1607 shareopts=opts.get('shareopts'))
1607
1608
1608 return r is None
1609 return r is None
1609
1610
1610 @command('^commit|ci',
1611 @command('^commit|ci',
1611 [('A', 'addremove', None,
1612 [('A', 'addremove', None,
1612 _('mark new/missing files as added/removed before committing')),
1613 _('mark new/missing files as added/removed before committing')),
1613 ('', 'close-branch', None,
1614 ('', 'close-branch', None,
1614 _('mark a branch head as closed')),
1615 _('mark a branch head as closed')),
1615 ('', 'amend', None, _('amend the parent of the working directory')),
1616 ('', 'amend', None, _('amend the parent of the working directory')),
1616 ('s', 'secret', None, _('use the secret phase for committing')),
1617 ('s', 'secret', None, _('use the secret phase for committing')),
1617 ('e', 'edit', None, _('invoke editor on commit messages')),
1618 ('e', 'edit', None, _('invoke editor on commit messages')),
1618 ('i', 'interactive', None, _('use interactive mode')),
1619 ('i', 'interactive', None, _('use interactive mode')),
1619 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1620 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1620 _('[OPTION]... [FILE]...'),
1621 _('[OPTION]... [FILE]...'),
1621 inferrepo=True)
1622 inferrepo=True)
1622 def commit(ui, repo, *pats, **opts):
1623 def commit(ui, repo, *pats, **opts):
1623 """commit the specified files or all outstanding changes
1624 """commit the specified files or all outstanding changes
1624
1625
1625 Commit changes to the given files into the repository. Unlike a
1626 Commit changes to the given files into the repository. Unlike a
1626 centralized SCM, this operation is a local operation. See
1627 centralized SCM, this operation is a local operation. See
1627 :hg:`push` for a way to actively distribute your changes.
1628 :hg:`push` for a way to actively distribute your changes.
1628
1629
1629 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`
1630 will be committed.
1631 will be committed.
1631
1632
1632 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
1633 filenames or -I/-X filters.
1634 filenames or -I/-X filters.
1634
1635
1635 If no commit message is specified, Mercurial starts your
1636 If no commit message is specified, Mercurial starts your
1636 configured editor where you can enter a message. In case your
1637 configured editor where you can enter a message. In case your
1637 commit fails, you will find a backup of your message in
1638 commit fails, you will find a backup of your message in
1638 ``.hg/last-message.txt``.
1639 ``.hg/last-message.txt``.
1639
1640
1640 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
1641 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
1642 will be considered closed and no longer listed.
1643 will be considered closed and no longer listed.
1643
1644
1644 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
1645 working directory with a new commit that contains the changes
1646 working directory with a new commit that contains the changes
1646 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`,
1647 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
1648 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1649 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1649 on how to restore it).
1650 on how to restore it).
1650
1651
1651 Message, user and date are taken from the amended commit unless
1652 Message, user and date are taken from the amended commit unless
1652 specified. When a message isn't specified on the command line,
1653 specified. When a message isn't specified on the command line,
1653 the editor will open with the message of the amended commit.
1654 the editor will open with the message of the amended commit.
1654
1655
1655 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`)
1656 or changesets that have children.
1657 or changesets that have children.
1657
1658
1658 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.
1659
1660
1660 Returns 0 on success, 1 if nothing changed.
1661 Returns 0 on success, 1 if nothing changed.
1661
1662
1662 .. container:: verbose
1663 .. container:: verbose
1663
1664
1664 Examples:
1665 Examples:
1665
1666
1666 - commit all files ending in .py::
1667 - commit all files ending in .py::
1667
1668
1668 hg commit --include "set:**.py"
1669 hg commit --include "set:**.py"
1669
1670
1670 - commit all non-binary files::
1671 - commit all non-binary files::
1671
1672
1672 hg commit --exclude "set:binary()"
1673 hg commit --exclude "set:binary()"
1673
1674
1674 - amend the current commit and set the date to now::
1675 - amend the current commit and set the date to now::
1675
1676
1676 hg commit --amend --date now
1677 hg commit --amend --date now
1677 """
1678 """
1678 wlock = lock = None
1679 wlock = lock = None
1679 try:
1680 try:
1680 wlock = repo.wlock()
1681 wlock = repo.wlock()
1681 lock = repo.lock()
1682 lock = repo.lock()
1682 return _docommit(ui, repo, *pats, **opts)
1683 return _docommit(ui, repo, *pats, **opts)
1683 finally:
1684 finally:
1684 release(lock, wlock)
1685 release(lock, wlock)
1685
1686
1686 def _docommit(ui, repo, *pats, **opts):
1687 def _docommit(ui, repo, *pats, **opts):
1687 if opts.get('interactive'):
1688 if opts.get('interactive'):
1688 opts.pop('interactive')
1689 opts.pop('interactive')
1689 cmdutil.dorecord(ui, repo, commit, None, False,
1690 cmdutil.dorecord(ui, repo, commit, None, False,
1690 cmdutil.recordfilter, *pats, **opts)
1691 cmdutil.recordfilter, *pats, **opts)
1691 return
1692 return
1692
1693
1693 if opts.get('subrepos'):
1694 if opts.get('subrepos'):
1694 if opts.get('amend'):
1695 if opts.get('amend'):
1695 raise error.Abort(_('cannot amend with --subrepos'))
1696 raise error.Abort(_('cannot amend with --subrepos'))
1696 # Let --subrepos on the command line override config setting.
1697 # Let --subrepos on the command line override config setting.
1697 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1698 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1698
1699
1699 cmdutil.checkunfinished(repo, commit=True)
1700 cmdutil.checkunfinished(repo, commit=True)
1700
1701
1701 branch = repo[None].branch()
1702 branch = repo[None].branch()
1702 bheads = repo.branchheads(branch)
1703 bheads = repo.branchheads(branch)
1703
1704
1704 extra = {}
1705 extra = {}
1705 if opts.get('close_branch'):
1706 if opts.get('close_branch'):
1706 extra['close'] = 1
1707 extra['close'] = 1
1707
1708
1708 if not bheads:
1709 if not bheads:
1709 raise error.Abort(_('can only close branch heads'))
1710 raise error.Abort(_('can only close branch heads'))
1710 elif opts.get('amend'):
1711 elif opts.get('amend'):
1711 if repo[None].parents()[0].p1().branch() != branch and \
1712 if repo[None].parents()[0].p1().branch() != branch and \
1712 repo[None].parents()[0].p2().branch() != branch:
1713 repo[None].parents()[0].p2().branch() != branch:
1713 raise error.Abort(_('can only close branch heads'))
1714 raise error.Abort(_('can only close branch heads'))
1714
1715
1715 if opts.get('amend'):
1716 if opts.get('amend'):
1716 if ui.configbool('ui', 'commitsubrepos'):
1717 if ui.configbool('ui', 'commitsubrepos'):
1717 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1718 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1718
1719
1719 old = repo['.']
1720 old = repo['.']
1720 if not old.mutable():
1721 if not old.mutable():
1721 raise error.Abort(_('cannot amend public changesets'))
1722 raise error.Abort(_('cannot amend public changesets'))
1722 if len(repo[None].parents()) > 1:
1723 if len(repo[None].parents()) > 1:
1723 raise error.Abort(_('cannot amend while merging'))
1724 raise error.Abort(_('cannot amend while merging'))
1724 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1725 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1725 if not allowunstable and old.children():
1726 if not allowunstable and old.children():
1726 raise error.Abort(_('cannot amend changeset with children'))
1727 raise error.Abort(_('cannot amend changeset with children'))
1727
1728
1728 # Currently histedit gets confused if an amend happens while histedit
1729 # Currently histedit gets confused if an amend happens while histedit
1729 # is in progress. Since we have a checkunfinished command, we are
1730 # is in progress. Since we have a checkunfinished command, we are
1730 # temporarily honoring it.
1731 # temporarily honoring it.
1731 #
1732 #
1732 # Note: eventually this guard will be removed. Please do not expect
1733 # Note: eventually this guard will be removed. Please do not expect
1733 # this behavior to remain.
1734 # this behavior to remain.
1734 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1735 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1735 cmdutil.checkunfinished(repo)
1736 cmdutil.checkunfinished(repo)
1736
1737
1737 # commitfunc is used only for temporary amend commit by cmdutil.amend
1738 # commitfunc is used only for temporary amend commit by cmdutil.amend
1738 def commitfunc(ui, repo, message, match, opts):
1739 def commitfunc(ui, repo, message, match, opts):
1739 return repo.commit(message,
1740 return repo.commit(message,
1740 opts.get('user') or old.user(),
1741 opts.get('user') or old.user(),
1741 opts.get('date') or old.date(),
1742 opts.get('date') or old.date(),
1742 match,
1743 match,
1743 extra=extra)
1744 extra=extra)
1744
1745
1745 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1746 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1746 if node == old.node():
1747 if node == old.node():
1747 ui.status(_("nothing changed\n"))
1748 ui.status(_("nothing changed\n"))
1748 return 1
1749 return 1
1749 else:
1750 else:
1750 def commitfunc(ui, repo, message, match, opts):
1751 def commitfunc(ui, repo, message, match, opts):
1751 backup = ui.backupconfig('phases', 'new-commit')
1752 backup = ui.backupconfig('phases', 'new-commit')
1752 baseui = repo.baseui
1753 baseui = repo.baseui
1753 basebackup = baseui.backupconfig('phases', 'new-commit')
1754 basebackup = baseui.backupconfig('phases', 'new-commit')
1754 try:
1755 try:
1755 if opts.get('secret'):
1756 if opts.get('secret'):
1756 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1757 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1757 # Propagate to subrepos
1758 # Propagate to subrepos
1758 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1759 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1759
1760
1760 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1761 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1761 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1762 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1762 return repo.commit(message, opts.get('user'), opts.get('date'),
1763 return repo.commit(message, opts.get('user'), opts.get('date'),
1763 match,
1764 match,
1764 editor=editor,
1765 editor=editor,
1765 extra=extra)
1766 extra=extra)
1766 finally:
1767 finally:
1767 ui.restoreconfig(backup)
1768 ui.restoreconfig(backup)
1768 repo.baseui.restoreconfig(basebackup)
1769 repo.baseui.restoreconfig(basebackup)
1769
1770
1770
1771
1771 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1772 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1772
1773
1773 if not node:
1774 if not node:
1774 stat = cmdutil.postcommitstatus(repo, pats, opts)
1775 stat = cmdutil.postcommitstatus(repo, pats, opts)
1775 if stat[3]:
1776 if stat[3]:
1776 ui.status(_("nothing changed (%d missing files, see "
1777 ui.status(_("nothing changed (%d missing files, see "
1777 "'hg status')\n") % len(stat[3]))
1778 "'hg status')\n") % len(stat[3]))
1778 else:
1779 else:
1779 ui.status(_("nothing changed\n"))
1780 ui.status(_("nothing changed\n"))
1780 return 1
1781 return 1
1781
1782
1782 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1783 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1783
1784
1784 @command('config|showconfig|debugconfig',
1785 @command('config|showconfig|debugconfig',
1785 [('u', 'untrusted', None, _('show untrusted configuration options')),
1786 [('u', 'untrusted', None, _('show untrusted configuration options')),
1786 ('e', 'edit', None, _('edit user config')),
1787 ('e', 'edit', None, _('edit user config')),
1787 ('l', 'local', None, _('edit repository config')),
1788 ('l', 'local', None, _('edit repository config')),
1788 ('g', 'global', None, _('edit global config'))],
1789 ('g', 'global', None, _('edit global config'))],
1789 _('[-u] [NAME]...'),
1790 _('[-u] [NAME]...'),
1790 optionalrepo=True)
1791 optionalrepo=True)
1791 def config(ui, repo, *values, **opts):
1792 def config(ui, repo, *values, **opts):
1792 """show combined config settings from all hgrc files
1793 """show combined config settings from all hgrc files
1793
1794
1794 With no arguments, print names and values of all config items.
1795 With no arguments, print names and values of all config items.
1795
1796
1796 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
1797 of that config item.
1798 of that config item.
1798
1799
1799 With multiple arguments, print names and values of all config
1800 With multiple arguments, print names and values of all config
1800 items with matching section names.
1801 items with matching section names.
1801
1802
1802 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
1803 --global, edit the system-wide config file. With --local, edit the
1804 --global, edit the system-wide config file. With --local, edit the
1804 repository-level config file.
1805 repository-level config file.
1805
1806
1806 With --debug, the source (filename and line number) is printed
1807 With --debug, the source (filename and line number) is printed
1807 for each config item.
1808 for each config item.
1808
1809
1809 See :hg:`help config` for more information about config files.
1810 See :hg:`help config` for more information about config files.
1810
1811
1811 Returns 0 on success, 1 if NAME does not exist.
1812 Returns 0 on success, 1 if NAME does not exist.
1812
1813
1813 """
1814 """
1814
1815
1815 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'):
1816 if opts.get('local') and opts.get('global'):
1817 if opts.get('local') and opts.get('global'):
1817 raise error.Abort(_("can't use --local and --global together"))
1818 raise error.Abort(_("can't use --local and --global together"))
1818
1819
1819 if opts.get('local'):
1820 if opts.get('local'):
1820 if not repo:
1821 if not repo:
1821 raise error.Abort(_("can't use --local outside a repository"))
1822 raise error.Abort(_("can't use --local outside a repository"))
1822 paths = [repo.join('hgrc')]
1823 paths = [repo.join('hgrc')]
1823 elif opts.get('global'):
1824 elif opts.get('global'):
1824 paths = scmutil.systemrcpath()
1825 paths = scmutil.systemrcpath()
1825 else:
1826 else:
1826 paths = scmutil.userrcpath()
1827 paths = scmutil.userrcpath()
1827
1828
1828 for f in paths:
1829 for f in paths:
1829 if os.path.exists(f):
1830 if os.path.exists(f):
1830 break
1831 break
1831 else:
1832 else:
1832 if opts.get('global'):
1833 if opts.get('global'):
1833 samplehgrc = uimod.samplehgrcs['global']
1834 samplehgrc = uimod.samplehgrcs['global']
1834 elif opts.get('local'):
1835 elif opts.get('local'):
1835 samplehgrc = uimod.samplehgrcs['local']
1836 samplehgrc = uimod.samplehgrcs['local']
1836 else:
1837 else:
1837 samplehgrc = uimod.samplehgrcs['user']
1838 samplehgrc = uimod.samplehgrcs['user']
1838
1839
1839 f = paths[0]
1840 f = paths[0]
1840 fp = open(f, "w")
1841 fp = open(f, "w")
1841 fp.write(samplehgrc)
1842 fp.write(samplehgrc)
1842 fp.close()
1843 fp.close()
1843
1844
1844 editor = ui.geteditor()
1845 editor = ui.geteditor()
1845 ui.system("%s \"%s\"" % (editor, f),
1846 ui.system("%s \"%s\"" % (editor, f),
1846 onerr=error.Abort, errprefix=_("edit failed"))
1847 onerr=error.Abort, errprefix=_("edit failed"))
1847 return
1848 return
1848
1849
1849 for f in scmutil.rcpath():
1850 for f in scmutil.rcpath():
1850 ui.debug('read config from: %s\n' % f)
1851 ui.debug('read config from: %s\n' % f)
1851 untrusted = bool(opts.get('untrusted'))
1852 untrusted = bool(opts.get('untrusted'))
1852 if values:
1853 if values:
1853 sections = [v for v in values if '.' not in v]
1854 sections = [v for v in values if '.' not in v]
1854 items = [v for v in values if '.' in v]
1855 items = [v for v in values if '.' in v]
1855 if len(items) > 1 or items and sections:
1856 if len(items) > 1 or items and sections:
1856 raise error.Abort(_('only one config item permitted'))
1857 raise error.Abort(_('only one config item permitted'))
1857 matched = False
1858 matched = False
1858 for section, name, value in ui.walkconfig(untrusted=untrusted):
1859 for section, name, value in ui.walkconfig(untrusted=untrusted):
1859 value = str(value).replace('\n', '\\n')
1860 value = str(value).replace('\n', '\\n')
1860 sectname = section + '.' + name
1861 sectname = section + '.' + name
1861 if values:
1862 if values:
1862 for v in values:
1863 for v in values:
1863 if v == section:
1864 if v == section:
1864 ui.debug('%s: ' %
1865 ui.debug('%s: ' %
1865 ui.configsource(section, name, untrusted))
1866 ui.configsource(section, name, untrusted))
1866 ui.write('%s=%s\n' % (sectname, value))
1867 ui.write('%s=%s\n' % (sectname, value))
1867 matched = True
1868 matched = True
1868 elif v == sectname:
1869 elif v == sectname:
1869 ui.debug('%s: ' %
1870 ui.debug('%s: ' %
1870 ui.configsource(section, name, untrusted))
1871 ui.configsource(section, name, untrusted))
1871 ui.write(value, '\n')
1872 ui.write(value, '\n')
1872 matched = True
1873 matched = True
1873 else:
1874 else:
1874 ui.debug('%s: ' %
1875 ui.debug('%s: ' %
1875 ui.configsource(section, name, untrusted))
1876 ui.configsource(section, name, untrusted))
1876 ui.write('%s=%s\n' % (sectname, value))
1877 ui.write('%s=%s\n' % (sectname, value))
1877 matched = True
1878 matched = True
1878 if matched:
1879 if matched:
1879 return 0
1880 return 0
1880 return 1
1881 return 1
1881
1882
1882 @command('copy|cp',
1883 @command('copy|cp',
1883 [('A', 'after', None, _('record a copy that has already occurred')),
1884 [('A', 'after', None, _('record a copy that has already occurred')),
1884 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1885 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1885 ] + walkopts + dryrunopts,
1886 ] + walkopts + dryrunopts,
1886 _('[OPTION]... [SOURCE]... DEST'))
1887 _('[OPTION]... [SOURCE]... DEST'))
1887 def copy(ui, repo, *pats, **opts):
1888 def copy(ui, repo, *pats, **opts):
1888 """mark files as copied for the next commit
1889 """mark files as copied for the next commit
1889
1890
1890 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
1891 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,
1892 the source must be a single file.
1893 the source must be a single file.
1893
1894
1894 By default, this command copies the contents of files as they
1895 By default, this command copies the contents of files as they
1895 exist in the working directory. If invoked with -A/--after, the
1896 exist in the working directory. If invoked with -A/--after, the
1896 operation is recorded, but no copying is performed.
1897 operation is recorded, but no copying is performed.
1897
1898
1898 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
1899 before that, see :hg:`revert`.
1900 before that, see :hg:`revert`.
1900
1901
1901 Returns 0 on success, 1 if errors are encountered.
1902 Returns 0 on success, 1 if errors are encountered.
1902 """
1903 """
1903 with repo.wlock(False):
1904 with repo.wlock(False):
1904 return cmdutil.copy(ui, repo, pats, opts)
1905 return cmdutil.copy(ui, repo, pats, opts)
1905
1906
1906 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1907 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1907 def debugancestor(ui, repo, *args):
1908 def debugancestor(ui, repo, *args):
1908 """find the ancestor revision of two revisions in a given index"""
1909 """find the ancestor revision of two revisions in a given index"""
1909 if len(args) == 3:
1910 if len(args) == 3:
1910 index, rev1, rev2 = args
1911 index, rev1, rev2 = args
1911 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1912 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1912 lookup = r.lookup
1913 lookup = r.lookup
1913 elif len(args) == 2:
1914 elif len(args) == 2:
1914 if not repo:
1915 if not repo:
1915 raise error.Abort(_("there is no Mercurial repository here "
1916 raise error.Abort(_("there is no Mercurial repository here "
1916 "(.hg not found)"))
1917 "(.hg not found)"))
1917 rev1, rev2 = args
1918 rev1, rev2 = args
1918 r = repo.changelog
1919 r = repo.changelog
1919 lookup = repo.lookup
1920 lookup = repo.lookup
1920 else:
1921 else:
1921 raise error.Abort(_('either two or three arguments required'))
1922 raise error.Abort(_('either two or three arguments required'))
1922 a = r.ancestor(lookup(rev1), lookup(rev2))
1923 a = r.ancestor(lookup(rev1), lookup(rev2))
1923 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1924 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1924
1925
1925 @command('debugbuilddag',
1926 @command('debugbuilddag',
1926 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1927 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1927 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1928 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1928 ('n', 'new-file', None, _('add new file at each rev'))],
1929 ('n', 'new-file', None, _('add new file at each rev'))],
1929 _('[OPTION]... [TEXT]'))
1930 _('[OPTION]... [TEXT]'))
1930 def debugbuilddag(ui, repo, text=None,
1931 def debugbuilddag(ui, repo, text=None,
1931 mergeable_file=False,
1932 mergeable_file=False,
1932 overwritten_file=False,
1933 overwritten_file=False,
1933 new_file=False):
1934 new_file=False):
1934 """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
1935
1936
1936 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
1937 command line.
1938 command line.
1938
1939
1939 Elements:
1940 Elements:
1940
1941
1941 - "+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
1942 - "." is a single node based on the current default parent
1943 - "." is a single node based on the current default parent
1943 - "$" resets the default parent to null (implied at the start);
1944 - "$" resets the default parent to null (implied at the start);
1944 otherwise the default parent is always the last node created
1945 otherwise the default parent is always the last node created
1945 - "<p" sets the default parent to the backref p
1946 - "<p" sets the default parent to the backref p
1946 - "*p" is a fork at parent p, which is a backref
1947 - "*p" is a fork at parent p, which is a backref
1947 - "*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
1948 - "/p2" is a merge of the preceding node and p2
1949 - "/p2" is a merge of the preceding node and p2
1949 - ":tag" defines a local tag for the preceding node
1950 - ":tag" defines a local tag for the preceding node
1950 - "@branch" sets the named branch for subsequent nodes
1951 - "@branch" sets the named branch for subsequent nodes
1951 - "#...\\n" is a comment up to the end of the line
1952 - "#...\\n" is a comment up to the end of the line
1952
1953
1953 Whitespace between the above elements is ignored.
1954 Whitespace between the above elements is ignored.
1954
1955
1955 A backref is either
1956 A backref is either
1956
1957
1957 - 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
1958 node, or
1959 node, or
1959 - 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
1960 - empty to denote the default parent.
1961 - empty to denote the default parent.
1961
1962
1962 All string valued-elements are either strictly alphanumeric, or must
1963 All string valued-elements are either strictly alphanumeric, or must
1963 be enclosed in double quotes ("..."), with "\\" as escape character.
1964 be enclosed in double quotes ("..."), with "\\" as escape character.
1964 """
1965 """
1965
1966
1966 if text is None:
1967 if text is None:
1967 ui.status(_("reading DAG from stdin\n"))
1968 ui.status(_("reading DAG from stdin\n"))
1968 text = ui.fin.read()
1969 text = ui.fin.read()
1969
1970
1970 cl = repo.changelog
1971 cl = repo.changelog
1971 if len(cl) > 0:
1972 if len(cl) > 0:
1972 raise error.Abort(_('repository is not empty'))
1973 raise error.Abort(_('repository is not empty'))
1973
1974
1974 # determine number of revs in DAG
1975 # determine number of revs in DAG
1975 total = 0
1976 total = 0
1976 for type, data in dagparser.parsedag(text):
1977 for type, data in dagparser.parsedag(text):
1977 if type == 'n':
1978 if type == 'n':
1978 total += 1
1979 total += 1
1979
1980
1980 if mergeable_file:
1981 if mergeable_file:
1981 linesperrev = 2
1982 linesperrev = 2
1982 # make a file with k lines per rev
1983 # make a file with k lines per rev
1983 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1984 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1984 initialmergedlines.append("")
1985 initialmergedlines.append("")
1985
1986
1986 tags = []
1987 tags = []
1987
1988
1988 lock = tr = None
1989 lock = tr = None
1989 try:
1990 try:
1990 lock = repo.lock()
1991 lock = repo.lock()
1991 tr = repo.transaction("builddag")
1992 tr = repo.transaction("builddag")
1992
1993
1993 at = -1
1994 at = -1
1994 atbranch = 'default'
1995 atbranch = 'default'
1995 nodeids = []
1996 nodeids = []
1996 id = 0
1997 id = 0
1997 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1998 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1998 for type, data in dagparser.parsedag(text):
1999 for type, data in dagparser.parsedag(text):
1999 if type == 'n':
2000 if type == 'n':
2000 ui.note(('node %s\n' % str(data)))
2001 ui.note(('node %s\n' % str(data)))
2001 id, ps = data
2002 id, ps = data
2002
2003
2003 files = []
2004 files = []
2004 fctxs = {}
2005 fctxs = {}
2005
2006
2006 p2 = None
2007 p2 = None
2007 if mergeable_file:
2008 if mergeable_file:
2008 fn = "mf"
2009 fn = "mf"
2009 p1 = repo[ps[0]]
2010 p1 = repo[ps[0]]
2010 if len(ps) > 1:
2011 if len(ps) > 1:
2011 p2 = repo[ps[1]]
2012 p2 = repo[ps[1]]
2012 pa = p1.ancestor(p2)
2013 pa = p1.ancestor(p2)
2013 base, local, other = [x[fn].data() for x in (pa, p1,
2014 base, local, other = [x[fn].data() for x in (pa, p1,
2014 p2)]
2015 p2)]
2015 m3 = simplemerge.Merge3Text(base, local, other)
2016 m3 = simplemerge.Merge3Text(base, local, other)
2016 ml = [l.strip() for l in m3.merge_lines()]
2017 ml = [l.strip() for l in m3.merge_lines()]
2017 ml.append("")
2018 ml.append("")
2018 elif at > 0:
2019 elif at > 0:
2019 ml = p1[fn].data().split("\n")
2020 ml = p1[fn].data().split("\n")
2020 else:
2021 else:
2021 ml = initialmergedlines
2022 ml = initialmergedlines
2022 ml[id * linesperrev] += " r%i" % id
2023 ml[id * linesperrev] += " r%i" % id
2023 mergedtext = "\n".join(ml)
2024 mergedtext = "\n".join(ml)
2024 files.append(fn)
2025 files.append(fn)
2025 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2026 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2026
2027
2027 if overwritten_file:
2028 if overwritten_file:
2028 fn = "of"
2029 fn = "of"
2029 files.append(fn)
2030 files.append(fn)
2030 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2031 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2031
2032
2032 if new_file:
2033 if new_file:
2033 fn = "nf%i" % id
2034 fn = "nf%i" % id
2034 files.append(fn)
2035 files.append(fn)
2035 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2036 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2036 if len(ps) > 1:
2037 if len(ps) > 1:
2037 if not p2:
2038 if not p2:
2038 p2 = repo[ps[1]]
2039 p2 = repo[ps[1]]
2039 for fn in p2:
2040 for fn in p2:
2040 if fn.startswith("nf"):
2041 if fn.startswith("nf"):
2041 files.append(fn)
2042 files.append(fn)
2042 fctxs[fn] = p2[fn]
2043 fctxs[fn] = p2[fn]
2043
2044
2044 def fctxfn(repo, cx, path):
2045 def fctxfn(repo, cx, path):
2045 return fctxs.get(path)
2046 return fctxs.get(path)
2046
2047
2047 if len(ps) == 0 or ps[0] < 0:
2048 if len(ps) == 0 or ps[0] < 0:
2048 pars = [None, None]
2049 pars = [None, None]
2049 elif len(ps) == 1:
2050 elif len(ps) == 1:
2050 pars = [nodeids[ps[0]], None]
2051 pars = [nodeids[ps[0]], None]
2051 else:
2052 else:
2052 pars = [nodeids[p] for p in ps]
2053 pars = [nodeids[p] for p in ps]
2053 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2054 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2054 date=(id, 0),
2055 date=(id, 0),
2055 user="debugbuilddag",
2056 user="debugbuilddag",
2056 extra={'branch': atbranch})
2057 extra={'branch': atbranch})
2057 nodeid = repo.commitctx(cx)
2058 nodeid = repo.commitctx(cx)
2058 nodeids.append(nodeid)
2059 nodeids.append(nodeid)
2059 at = id
2060 at = id
2060 elif type == 'l':
2061 elif type == 'l':
2061 id, name = data
2062 id, name = data
2062 ui.note(('tag %s\n' % name))
2063 ui.note(('tag %s\n' % name))
2063 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2064 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2064 elif type == 'a':
2065 elif type == 'a':
2065 ui.note(('branch %s\n' % data))
2066 ui.note(('branch %s\n' % data))
2066 atbranch = data
2067 atbranch = data
2067 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2068 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2068 tr.close()
2069 tr.close()
2069
2070
2070 if tags:
2071 if tags:
2071 repo.vfs.write("localtags", "".join(tags))
2072 repo.vfs.write("localtags", "".join(tags))
2072 finally:
2073 finally:
2073 ui.progress(_('building'), None)
2074 ui.progress(_('building'), None)
2074 release(tr, lock)
2075 release(tr, lock)
2075
2076
2076 @command('debugbundle',
2077 @command('debugbundle',
2077 [('a', 'all', None, _('show all details')),
2078 [('a', 'all', None, _('show all details')),
2078 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2079 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2079 _('FILE'),
2080 _('FILE'),
2080 norepo=True)
2081 norepo=True)
2081 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2082 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2082 """lists the contents of a bundle"""
2083 """lists the contents of a bundle"""
2083 with hg.openpath(ui, bundlepath) as f:
2084 with hg.openpath(ui, bundlepath) as f:
2084 if spec:
2085 if spec:
2085 spec = exchange.getbundlespec(ui, f)
2086 spec = exchange.getbundlespec(ui, f)
2086 ui.write('%s\n' % spec)
2087 ui.write('%s\n' % spec)
2087 return
2088 return
2088
2089
2089 gen = exchange.readbundle(ui, f, bundlepath)
2090 gen = exchange.readbundle(ui, f, bundlepath)
2090 if isinstance(gen, bundle2.unbundle20):
2091 if isinstance(gen, bundle2.unbundle20):
2091 return _debugbundle2(ui, gen, all=all, **opts)
2092 return _debugbundle2(ui, gen, all=all, **opts)
2092 _debugchangegroup(ui, gen, all=all, **opts)
2093 _debugchangegroup(ui, gen, all=all, **opts)
2093
2094
2094 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2095 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
2095 indent_string = ' ' * indent
2096 indent_string = ' ' * indent
2096 if all:
2097 if all:
2097 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"
2098 % indent_string)
2099 % indent_string)
2099
2100
2100 def showchunks(named):
2101 def showchunks(named):
2101 ui.write("\n%s%s\n" % (indent_string, named))
2102 ui.write("\n%s%s\n" % (indent_string, named))
2102 chain = None
2103 chain = None
2103 while True:
2104 while True:
2104 chunkdata = gen.deltachunk(chain)
2105 chunkdata = gen.deltachunk(chain)
2105 if not chunkdata:
2106 if not chunkdata:
2106 break
2107 break
2107 node = chunkdata['node']
2108 node = chunkdata['node']
2108 p1 = chunkdata['p1']
2109 p1 = chunkdata['p1']
2109 p2 = chunkdata['p2']
2110 p2 = chunkdata['p2']
2110 cs = chunkdata['cs']
2111 cs = chunkdata['cs']
2111 deltabase = chunkdata['deltabase']
2112 deltabase = chunkdata['deltabase']
2112 delta = chunkdata['delta']
2113 delta = chunkdata['delta']
2113 ui.write("%s%s %s %s %s %s %s\n" %
2114 ui.write("%s%s %s %s %s %s %s\n" %
2114 (indent_string, hex(node), hex(p1), hex(p2),
2115 (indent_string, hex(node), hex(p1), hex(p2),
2115 hex(cs), hex(deltabase), len(delta)))
2116 hex(cs), hex(deltabase), len(delta)))
2116 chain = node
2117 chain = node
2117
2118
2118 chunkdata = gen.changelogheader()
2119 chunkdata = gen.changelogheader()
2119 showchunks("changelog")
2120 showchunks("changelog")
2120 chunkdata = gen.manifestheader()
2121 chunkdata = gen.manifestheader()
2121 showchunks("manifest")
2122 showchunks("manifest")
2122 while True:
2123 while True:
2123 chunkdata = gen.filelogheader()
2124 chunkdata = gen.filelogheader()
2124 if not chunkdata:
2125 if not chunkdata:
2125 break
2126 break
2126 fname = chunkdata['filename']
2127 fname = chunkdata['filename']
2127 showchunks(fname)
2128 showchunks(fname)
2128 else:
2129 else:
2129 if isinstance(gen, bundle2.unbundle20):
2130 if isinstance(gen, bundle2.unbundle20):
2130 raise error.Abort(_('use debugbundle2 for this file'))
2131 raise error.Abort(_('use debugbundle2 for this file'))
2131 chunkdata = gen.changelogheader()
2132 chunkdata = gen.changelogheader()
2132 chain = None
2133 chain = None
2133 while True:
2134 while True:
2134 chunkdata = gen.deltachunk(chain)
2135 chunkdata = gen.deltachunk(chain)
2135 if not chunkdata:
2136 if not chunkdata:
2136 break
2137 break
2137 node = chunkdata['node']
2138 node = chunkdata['node']
2138 ui.write("%s%s\n" % (indent_string, hex(node)))
2139 ui.write("%s%s\n" % (indent_string, hex(node)))
2139 chain = node
2140 chain = node
2140
2141
2141 def _debugbundle2(ui, gen, all=None, **opts):
2142 def _debugbundle2(ui, gen, all=None, **opts):
2142 """lists the contents of a bundle2"""
2143 """lists the contents of a bundle2"""
2143 if not isinstance(gen, bundle2.unbundle20):
2144 if not isinstance(gen, bundle2.unbundle20):
2144 raise error.Abort(_('not a bundle2 file'))
2145 raise error.Abort(_('not a bundle2 file'))
2145 ui.write(('Stream params: %s\n' % repr(gen.params)))
2146 ui.write(('Stream params: %s\n' % repr(gen.params)))
2146 for part in gen.iterparts():
2147 for part in gen.iterparts():
2147 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2148 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2148 if part.type == 'changegroup':
2149 if part.type == 'changegroup':
2149 version = part.params.get('version', '01')
2150 version = part.params.get('version', '01')
2150 cg = changegroup.getunbundler(version, part, 'UN')
2151 cg = changegroup.getunbundler(version, part, 'UN')
2151 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2152 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
2152
2153
2153 @command('debugcreatestreamclonebundle', [], 'FILE')
2154 @command('debugcreatestreamclonebundle', [], 'FILE')
2154 def debugcreatestreamclonebundle(ui, repo, fname):
2155 def debugcreatestreamclonebundle(ui, repo, fname):
2155 """create a stream clone bundle file
2156 """create a stream clone bundle file
2156
2157
2157 Stream bundles are special bundles that are essentially archives of
2158 Stream bundles are special bundles that are essentially archives of
2158 revlog files. They are commonly used for cloning very quickly.
2159 revlog files. They are commonly used for cloning very quickly.
2159 """
2160 """
2160 requirements, gen = streamclone.generatebundlev1(repo)
2161 requirements, gen = streamclone.generatebundlev1(repo)
2161 changegroup.writechunks(ui, gen, fname)
2162 changegroup.writechunks(ui, gen, fname)
2162
2163
2163 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2164 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2164
2165
2165 @command('debugapplystreamclonebundle', [], 'FILE')
2166 @command('debugapplystreamclonebundle', [], 'FILE')
2166 def debugapplystreamclonebundle(ui, repo, fname):
2167 def debugapplystreamclonebundle(ui, repo, fname):
2167 """apply a stream clone bundle file"""
2168 """apply a stream clone bundle file"""
2168 f = hg.openpath(ui, fname)
2169 f = hg.openpath(ui, fname)
2169 gen = exchange.readbundle(ui, f, fname)
2170 gen = exchange.readbundle(ui, f, fname)
2170 gen.apply(repo)
2171 gen.apply(repo)
2171
2172
2172 @command('debugcheckstate', [], '')
2173 @command('debugcheckstate', [], '')
2173 def debugcheckstate(ui, repo):
2174 def debugcheckstate(ui, repo):
2174 """validate the correctness of the current dirstate"""
2175 """validate the correctness of the current dirstate"""
2175 parent1, parent2 = repo.dirstate.parents()
2176 parent1, parent2 = repo.dirstate.parents()
2176 m1 = repo[parent1].manifest()
2177 m1 = repo[parent1].manifest()
2177 m2 = repo[parent2].manifest()
2178 m2 = repo[parent2].manifest()
2178 errors = 0
2179 errors = 0
2179 for f in repo.dirstate:
2180 for f in repo.dirstate:
2180 state = repo.dirstate[f]
2181 state = repo.dirstate[f]
2181 if state in "nr" and f not in m1:
2182 if state in "nr" and f not in m1:
2182 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))
2183 errors += 1
2184 errors += 1
2184 if state in "a" and f in m1:
2185 if state in "a" and f in m1:
2185 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))
2186 errors += 1
2187 errors += 1
2187 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:
2188 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") %
2189 (f, state))
2190 (f, state))
2190 errors += 1
2191 errors += 1
2191 for f in m1:
2192 for f in m1:
2192 state = repo.dirstate[f]
2193 state = repo.dirstate[f]
2193 if state not in "nrm":
2194 if state not in "nrm":
2194 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))
2195 errors += 1
2196 errors += 1
2196 if errors:
2197 if errors:
2197 error = _(".hg/dirstate inconsistent with current parent's manifest")
2198 error = _(".hg/dirstate inconsistent with current parent's manifest")
2198 raise error.Abort(error)
2199 raise error.Abort(error)
2199
2200
2200 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2201 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2201 def debugcommands(ui, cmd='', *args):
2202 def debugcommands(ui, cmd='', *args):
2202 """list all available commands and options"""
2203 """list all available commands and options"""
2203 for cmd, vals in sorted(table.iteritems()):
2204 for cmd, vals in sorted(table.iteritems()):
2204 cmd = cmd.split('|')[0].strip('^')
2205 cmd = cmd.split('|')[0].strip('^')
2205 opts = ', '.join([i[1] for i in vals[1]])
2206 opts = ', '.join([i[1] for i in vals[1]])
2206 ui.write('%s: %s\n' % (cmd, opts))
2207 ui.write('%s: %s\n' % (cmd, opts))
2207
2208
2208 @command('debugcomplete',
2209 @command('debugcomplete',
2209 [('o', 'options', None, _('show the command options'))],
2210 [('o', 'options', None, _('show the command options'))],
2210 _('[-o] CMD'),
2211 _('[-o] CMD'),
2211 norepo=True)
2212 norepo=True)
2212 def debugcomplete(ui, cmd='', **opts):
2213 def debugcomplete(ui, cmd='', **opts):
2213 """returns the completion list associated with the given command"""
2214 """returns the completion list associated with the given command"""
2214
2215
2215 if opts.get('options'):
2216 if opts.get('options'):
2216 options = []
2217 options = []
2217 otables = [globalopts]
2218 otables = [globalopts]
2218 if cmd:
2219 if cmd:
2219 aliases, entry = cmdutil.findcmd(cmd, table, False)
2220 aliases, entry = cmdutil.findcmd(cmd, table, False)
2220 otables.append(entry[1])
2221 otables.append(entry[1])
2221 for t in otables:
2222 for t in otables:
2222 for o in t:
2223 for o in t:
2223 if "(DEPRECATED)" in o[3]:
2224 if "(DEPRECATED)" in o[3]:
2224 continue
2225 continue
2225 if o[0]:
2226 if o[0]:
2226 options.append('-%s' % o[0])
2227 options.append('-%s' % o[0])
2227 options.append('--%s' % o[1])
2228 options.append('--%s' % o[1])
2228 ui.write("%s\n" % "\n".join(options))
2229 ui.write("%s\n" % "\n".join(options))
2229 return
2230 return
2230
2231
2231 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2232 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2232 if ui.verbose:
2233 if ui.verbose:
2233 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2234 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2234 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2235 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2235
2236
2236 @command('debugdag',
2237 @command('debugdag',
2237 [('t', 'tags', None, _('use tags as labels')),
2238 [('t', 'tags', None, _('use tags as labels')),
2238 ('b', 'branches', None, _('annotate with branch names')),
2239 ('b', 'branches', None, _('annotate with branch names')),
2239 ('', 'dots', None, _('use dots for runs')),
2240 ('', 'dots', None, _('use dots for runs')),
2240 ('s', 'spaces', None, _('separate elements by spaces'))],
2241 ('s', 'spaces', None, _('separate elements by spaces'))],
2241 _('[OPTION]... [FILE [REV]...]'),
2242 _('[OPTION]... [FILE [REV]...]'),
2242 optionalrepo=True)
2243 optionalrepo=True)
2243 def debugdag(ui, repo, file_=None, *revs, **opts):
2244 def debugdag(ui, repo, file_=None, *revs, **opts):
2244 """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
2245
2246
2246 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
2247 revision numbers, they get labeled in the output as rN.
2248 revision numbers, they get labeled in the output as rN.
2248
2249
2249 Otherwise, the changelog DAG of the current repo is emitted.
2250 Otherwise, the changelog DAG of the current repo is emitted.
2250 """
2251 """
2251 spaces = opts.get('spaces')
2252 spaces = opts.get('spaces')
2252 dots = opts.get('dots')
2253 dots = opts.get('dots')
2253 if file_:
2254 if file_:
2254 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2255 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2255 revs = set((int(r) for r in revs))
2256 revs = set((int(r) for r in revs))
2256 def events():
2257 def events():
2257 for r in rlog:
2258 for r in rlog:
2258 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2259 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2259 if p != -1))
2260 if p != -1))
2260 if r in revs:
2261 if r in revs:
2261 yield 'l', (r, "r%i" % r)
2262 yield 'l', (r, "r%i" % r)
2262 elif repo:
2263 elif repo:
2263 cl = repo.changelog
2264 cl = repo.changelog
2264 tags = opts.get('tags')
2265 tags = opts.get('tags')
2265 branches = opts.get('branches')
2266 branches = opts.get('branches')
2266 if tags:
2267 if tags:
2267 labels = {}
2268 labels = {}
2268 for l, n in repo.tags().items():
2269 for l, n in repo.tags().items():
2269 labels.setdefault(cl.rev(n), []).append(l)
2270 labels.setdefault(cl.rev(n), []).append(l)
2270 def events():
2271 def events():
2271 b = "default"
2272 b = "default"
2272 for r in cl:
2273 for r in cl:
2273 if branches:
2274 if branches:
2274 newb = cl.read(cl.node(r))[5]['branch']
2275 newb = cl.read(cl.node(r))[5]['branch']
2275 if newb != b:
2276 if newb != b:
2276 yield 'a', newb
2277 yield 'a', newb
2277 b = newb
2278 b = newb
2278 yield 'n', (r, list(p for p in cl.parentrevs(r)
2279 yield 'n', (r, list(p for p in cl.parentrevs(r)
2279 if p != -1))
2280 if p != -1))
2280 if tags:
2281 if tags:
2281 ls = labels.get(r)
2282 ls = labels.get(r)
2282 if ls:
2283 if ls:
2283 for l in ls:
2284 for l in ls:
2284 yield 'l', (r, l)
2285 yield 'l', (r, l)
2285 else:
2286 else:
2286 raise error.Abort(_('need repo for changelog dag'))
2287 raise error.Abort(_('need repo for changelog dag'))
2287
2288
2288 for line in dagparser.dagtextlines(events(),
2289 for line in dagparser.dagtextlines(events(),
2289 addspaces=spaces,
2290 addspaces=spaces,
2290 wraplabels=True,
2291 wraplabels=True,
2291 wrapannotations=True,
2292 wrapannotations=True,
2292 wrapnonlinear=dots,
2293 wrapnonlinear=dots,
2293 usedots=dots,
2294 usedots=dots,
2294 maxlinewidth=70):
2295 maxlinewidth=70):
2295 ui.write(line)
2296 ui.write(line)
2296 ui.write("\n")
2297 ui.write("\n")
2297
2298
2298 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2299 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2299 def debugdata(ui, repo, file_, rev=None, **opts):
2300 def debugdata(ui, repo, file_, rev=None, **opts):
2300 """dump the contents of a data file revision"""
2301 """dump the contents of a data file revision"""
2301 if opts.get('changelog') or opts.get('manifest'):
2302 if opts.get('changelog') or opts.get('manifest'):
2302 file_, rev = None, file_
2303 file_, rev = None, file_
2303 elif rev is None:
2304 elif rev is None:
2304 raise error.CommandError('debugdata', _('invalid arguments'))
2305 raise error.CommandError('debugdata', _('invalid arguments'))
2305 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2306 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2306 try:
2307 try:
2307 ui.write(r.revision(r.lookup(rev)))
2308 ui.write(r.revision(r.lookup(rev)))
2308 except KeyError:
2309 except KeyError:
2309 raise error.Abort(_('invalid revision identifier %s') % rev)
2310 raise error.Abort(_('invalid revision identifier %s') % rev)
2310
2311
2311 @command('debugdate',
2312 @command('debugdate',
2312 [('e', 'extended', None, _('try extended date formats'))],
2313 [('e', 'extended', None, _('try extended date formats'))],
2313 _('[-e] DATE [RANGE]'),
2314 _('[-e] DATE [RANGE]'),
2314 norepo=True, optionalrepo=True)
2315 norepo=True, optionalrepo=True)
2315 def debugdate(ui, date, range=None, **opts):
2316 def debugdate(ui, date, range=None, **opts):
2316 """parse and display a date"""
2317 """parse and display a date"""
2317 if opts["extended"]:
2318 if opts["extended"]:
2318 d = util.parsedate(date, util.extendeddateformats)
2319 d = util.parsedate(date, util.extendeddateformats)
2319 else:
2320 else:
2320 d = util.parsedate(date)
2321 d = util.parsedate(date)
2321 ui.write(("internal: %s %s\n") % d)
2322 ui.write(("internal: %s %s\n") % d)
2322 ui.write(("standard: %s\n") % util.datestr(d))
2323 ui.write(("standard: %s\n") % util.datestr(d))
2323 if range:
2324 if range:
2324 m = util.matchdate(range)
2325 m = util.matchdate(range)
2325 ui.write(("match: %s\n") % m(d[0]))
2326 ui.write(("match: %s\n") % m(d[0]))
2326
2327
2327 @command('debugdiscovery',
2328 @command('debugdiscovery',
2328 [('', 'old', None, _('use old-style discovery')),
2329 [('', 'old', None, _('use old-style discovery')),
2329 ('', 'nonheads', None,
2330 ('', 'nonheads', None,
2330 _('use old-style discovery with non-heads included')),
2331 _('use old-style discovery with non-heads included')),
2331 ] + remoteopts,
2332 ] + remoteopts,
2332 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2333 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2333 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2334 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2334 """runs the changeset discovery protocol in isolation"""
2335 """runs the changeset discovery protocol in isolation"""
2335 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2336 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2336 opts.get('branch'))
2337 opts.get('branch'))
2337 remote = hg.peer(repo, opts, remoteurl)
2338 remote = hg.peer(repo, opts, remoteurl)
2338 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2339 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2339
2340
2340 # make sure tests are repeatable
2341 # make sure tests are repeatable
2341 random.seed(12323)
2342 random.seed(12323)
2342
2343
2343 def doit(localheads, remoteheads, remote=remote):
2344 def doit(localheads, remoteheads, remote=remote):
2344 if opts.get('old'):
2345 if opts.get('old'):
2345 if localheads:
2346 if localheads:
2346 raise error.Abort('cannot use localheads with old style '
2347 raise error.Abort('cannot use localheads with old style '
2347 'discovery')
2348 'discovery')
2348 if not util.safehasattr(remote, 'branches'):
2349 if not util.safehasattr(remote, 'branches'):
2349 # enable in-client legacy support
2350 # enable in-client legacy support
2350 remote = localrepo.locallegacypeer(remote.local())
2351 remote = localrepo.locallegacypeer(remote.local())
2351 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2352 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2352 force=True)
2353 force=True)
2353 common = set(common)
2354 common = set(common)
2354 if not opts.get('nonheads'):
2355 if not opts.get('nonheads'):
2355 ui.write(("unpruned common: %s\n") %
2356 ui.write(("unpruned common: %s\n") %
2356 " ".join(sorted(short(n) for n in common)))
2357 " ".join(sorted(short(n) for n in common)))
2357 dag = dagutil.revlogdag(repo.changelog)
2358 dag = dagutil.revlogdag(repo.changelog)
2358 all = dag.ancestorset(dag.internalizeall(common))
2359 all = dag.ancestorset(dag.internalizeall(common))
2359 common = dag.externalizeall(dag.headsetofconnecteds(all))
2360 common = dag.externalizeall(dag.headsetofconnecteds(all))
2360 else:
2361 else:
2361 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2362 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2362 common = set(common)
2363 common = set(common)
2363 rheads = set(hds)
2364 rheads = set(hds)
2364 lheads = set(repo.heads())
2365 lheads = set(repo.heads())
2365 ui.write(("common heads: %s\n") %
2366 ui.write(("common heads: %s\n") %
2366 " ".join(sorted(short(n) for n in common)))
2367 " ".join(sorted(short(n) for n in common)))
2367 if lheads <= common:
2368 if lheads <= common:
2368 ui.write(("local is subset\n"))
2369 ui.write(("local is subset\n"))
2369 elif rheads <= common:
2370 elif rheads <= common:
2370 ui.write(("remote is subset\n"))
2371 ui.write(("remote is subset\n"))
2371
2372
2372 serverlogs = opts.get('serverlog')
2373 serverlogs = opts.get('serverlog')
2373 if serverlogs:
2374 if serverlogs:
2374 for filename in serverlogs:
2375 for filename in serverlogs:
2375 with open(filename, 'r') as logfile:
2376 with open(filename, 'r') as logfile:
2376 line = logfile.readline()
2377 line = logfile.readline()
2377 while line:
2378 while line:
2378 parts = line.strip().split(';')
2379 parts = line.strip().split(';')
2379 op = parts[1]
2380 op = parts[1]
2380 if op == 'cg':
2381 if op == 'cg':
2381 pass
2382 pass
2382 elif op == 'cgss':
2383 elif op == 'cgss':
2383 doit(parts[2].split(' '), parts[3].split(' '))
2384 doit(parts[2].split(' '), parts[3].split(' '))
2384 elif op == 'unb':
2385 elif op == 'unb':
2385 doit(parts[3].split(' '), parts[2].split(' '))
2386 doit(parts[3].split(' '), parts[2].split(' '))
2386 line = logfile.readline()
2387 line = logfile.readline()
2387 else:
2388 else:
2388 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2389 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2389 opts.get('remote_head'))
2390 opts.get('remote_head'))
2390 localrevs = opts.get('local_head')
2391 localrevs = opts.get('local_head')
2391 doit(localrevs, remoterevs)
2392 doit(localrevs, remoterevs)
2392
2393
2393 @command('debugextensions', formatteropts, [], norepo=True)
2394 @command('debugextensions', formatteropts, [], norepo=True)
2394 def debugextensions(ui, **opts):
2395 def debugextensions(ui, **opts):
2395 '''show information about active extensions'''
2396 '''show information about active extensions'''
2396 exts = extensions.extensions(ui)
2397 exts = extensions.extensions(ui)
2397 fm = ui.formatter('debugextensions', opts)
2398 fm = ui.formatter('debugextensions', opts)
2398 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2399 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2399 extsource = extmod.__file__
2400 extsource = extmod.__file__
2400 exttestedwith = getattr(extmod, 'testedwith', None)
2401 exttestedwith = getattr(extmod, 'testedwith', None)
2401 if exttestedwith is not None:
2402 if exttestedwith is not None:
2402 exttestedwith = exttestedwith.split()
2403 exttestedwith = exttestedwith.split()
2403 extbuglink = getattr(extmod, 'buglink', None)
2404 extbuglink = getattr(extmod, 'buglink', None)
2404
2405
2405 fm.startitem()
2406 fm.startitem()
2406
2407
2407 if ui.quiet or ui.verbose:
2408 if ui.quiet or ui.verbose:
2408 fm.write('name', '%s\n', extname)
2409 fm.write('name', '%s\n', extname)
2409 else:
2410 else:
2410 fm.write('name', '%s', extname)
2411 fm.write('name', '%s', extname)
2411 if not exttestedwith:
2412 if not exttestedwith:
2412 fm.plain(_(' (untested!)\n'))
2413 fm.plain(_(' (untested!)\n'))
2413 else:
2414 else:
2414 if exttestedwith == ['internal'] or \
2415 if exttestedwith == ['internal'] or \
2415 util.version() in exttestedwith:
2416 util.version() in exttestedwith:
2416 fm.plain('\n')
2417 fm.plain('\n')
2417 else:
2418 else:
2418 lasttestedversion = exttestedwith[-1]
2419 lasttestedversion = exttestedwith[-1]
2419 fm.plain(' (%s!)\n' % lasttestedversion)
2420 fm.plain(' (%s!)\n' % lasttestedversion)
2420
2421
2421 fm.condwrite(ui.verbose and extsource, 'source',
2422 fm.condwrite(ui.verbose and extsource, 'source',
2422 _(' location: %s\n'), extsource or "")
2423 _(' location: %s\n'), extsource or "")
2423
2424
2424 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2425 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2425 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2426 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2426
2427
2427 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2428 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2428 _(' bug reporting: %s\n'), extbuglink or "")
2429 _(' bug reporting: %s\n'), extbuglink or "")
2429
2430
2430 fm.end()
2431 fm.end()
2431
2432
2432 @command('debugfileset',
2433 @command('debugfileset',
2433 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2434 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2434 _('[-r REV] FILESPEC'))
2435 _('[-r REV] FILESPEC'))
2435 def debugfileset(ui, repo, expr, **opts):
2436 def debugfileset(ui, repo, expr, **opts):
2436 '''parse and apply a fileset specification'''
2437 '''parse and apply a fileset specification'''
2437 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2438 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2438 if ui.verbose:
2439 if ui.verbose:
2439 tree = fileset.parse(expr)
2440 tree = fileset.parse(expr)
2440 ui.note(fileset.prettyformat(tree), "\n")
2441 ui.note(fileset.prettyformat(tree), "\n")
2441
2442
2442 for f in ctx.getfileset(expr):
2443 for f in ctx.getfileset(expr):
2443 ui.write("%s\n" % f)
2444 ui.write("%s\n" % f)
2444
2445
2445 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2446 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2446 def debugfsinfo(ui, path="."):
2447 def debugfsinfo(ui, path="."):
2447 """show information detected about current filesystem"""
2448 """show information detected about current filesystem"""
2448 util.writefile('.debugfsinfo', '')
2449 util.writefile('.debugfsinfo', '')
2449 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'))
2450 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'))
2451 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'))
2452 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2453 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2453 and 'yes' or 'no'))
2454 and 'yes' or 'no'))
2454 os.unlink('.debugfsinfo')
2455 os.unlink('.debugfsinfo')
2455
2456
2456 @command('debuggetbundle',
2457 @command('debuggetbundle',
2457 [('H', 'head', [], _('id of head node'), _('ID')),
2458 [('H', 'head', [], _('id of head node'), _('ID')),
2458 ('C', 'common', [], _('id of common node'), _('ID')),
2459 ('C', 'common', [], _('id of common node'), _('ID')),
2459 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2460 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2460 _('REPO FILE [-H|-C ID]...'),
2461 _('REPO FILE [-H|-C ID]...'),
2461 norepo=True)
2462 norepo=True)
2462 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2463 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2463 """retrieves a bundle from a repo
2464 """retrieves a bundle from a repo
2464
2465
2465 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
2466 given file.
2467 given file.
2467 """
2468 """
2468 repo = hg.peer(ui, opts, repopath)
2469 repo = hg.peer(ui, opts, repopath)
2469 if not repo.capable('getbundle'):
2470 if not repo.capable('getbundle'):
2470 raise error.Abort("getbundle() not supported by target repository")
2471 raise error.Abort("getbundle() not supported by target repository")
2471 args = {}
2472 args = {}
2472 if common:
2473 if common:
2473 args['common'] = [bin(s) for s in common]
2474 args['common'] = [bin(s) for s in common]
2474 if head:
2475 if head:
2475 args['heads'] = [bin(s) for s in head]
2476 args['heads'] = [bin(s) for s in head]
2476 # TODO: get desired bundlecaps from command line.
2477 # TODO: get desired bundlecaps from command line.
2477 args['bundlecaps'] = None
2478 args['bundlecaps'] = None
2478 bundle = repo.getbundle('debug', **args)
2479 bundle = repo.getbundle('debug', **args)
2479
2480
2480 bundletype = opts.get('type', 'bzip2').lower()
2481 bundletype = opts.get('type', 'bzip2').lower()
2481 btypes = {'none': 'HG10UN',
2482 btypes = {'none': 'HG10UN',
2482 'bzip2': 'HG10BZ',
2483 'bzip2': 'HG10BZ',
2483 'gzip': 'HG10GZ',
2484 'gzip': 'HG10GZ',
2484 'bundle2': 'HG20'}
2485 'bundle2': 'HG20'}
2485 bundletype = btypes.get(bundletype)
2486 bundletype = btypes.get(bundletype)
2486 if bundletype not in bundle2.bundletypes:
2487 if bundletype not in bundle2.bundletypes:
2487 raise error.Abort(_('unknown bundle type specified with --type'))
2488 raise error.Abort(_('unknown bundle type specified with --type'))
2488 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2489 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2489
2490
2490 @command('debugignore', [], '[FILE]')
2491 @command('debugignore', [], '[FILE]')
2491 def debugignore(ui, repo, *files, **opts):
2492 def debugignore(ui, repo, *files, **opts):
2492 """display the combined ignore pattern and information about ignored files
2493 """display the combined ignore pattern and information about ignored files
2493
2494
2494 With no argument display the combined ignore pattern.
2495 With no argument display the combined ignore pattern.
2495
2496
2496 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
2497 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.
2498 """
2499 """
2499 ignore = repo.dirstate._ignore
2500 ignore = repo.dirstate._ignore
2500 if not files:
2501 if not files:
2501 # Show all the patterns
2502 # Show all the patterns
2502 includepat = getattr(ignore, 'includepat', None)
2503 includepat = getattr(ignore, 'includepat', None)
2503 if includepat is not None:
2504 if includepat is not None:
2504 ui.write("%s\n" % includepat)
2505 ui.write("%s\n" % includepat)
2505 else:
2506 else:
2506 raise error.Abort(_("no ignore patterns found"))
2507 raise error.Abort(_("no ignore patterns found"))
2507 else:
2508 else:
2508 for f in files:
2509 for f in files:
2509 nf = util.normpath(f)
2510 nf = util.normpath(f)
2510 ignored = None
2511 ignored = None
2511 ignoredata = None
2512 ignoredata = None
2512 if nf != '.':
2513 if nf != '.':
2513 if ignore(nf):
2514 if ignore(nf):
2514 ignored = nf
2515 ignored = nf
2515 ignoredata = repo.dirstate._ignorefileandline(nf)
2516 ignoredata = repo.dirstate._ignorefileandline(nf)
2516 else:
2517 else:
2517 for p in util.finddirs(nf):
2518 for p in util.finddirs(nf):
2518 if ignore(p):
2519 if ignore(p):
2519 ignored = p
2520 ignored = p
2520 ignoredata = repo.dirstate._ignorefileandline(p)
2521 ignoredata = repo.dirstate._ignorefileandline(p)
2521 break
2522 break
2522 if ignored:
2523 if ignored:
2523 if ignored == nf:
2524 if ignored == nf:
2524 ui.write(_("%s is ignored\n") % f)
2525 ui.write(_("%s is ignored\n") % f)
2525 else:
2526 else:
2526 ui.write(_("%s is ignored because of "
2527 ui.write(_("%s is ignored because of "
2527 "containing folder %s\n")
2528 "containing folder %s\n")
2528 % (f, ignored))
2529 % (f, ignored))
2529 ignorefile, lineno, line = ignoredata
2530 ignorefile, lineno, line = ignoredata
2530 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2531 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
2531 % (ignorefile, lineno, line))
2532 % (ignorefile, lineno, line))
2532 else:
2533 else:
2533 ui.write(_("%s is not ignored\n") % f)
2534 ui.write(_("%s is not ignored\n") % f)
2534
2535
2535 @command('debugindex', debugrevlogopts +
2536 @command('debugindex', debugrevlogopts +
2536 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2537 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2537 _('[-f FORMAT] -c|-m|FILE'),
2538 _('[-f FORMAT] -c|-m|FILE'),
2538 optionalrepo=True)
2539 optionalrepo=True)
2539 def debugindex(ui, repo, file_=None, **opts):
2540 def debugindex(ui, repo, file_=None, **opts):
2540 """dump the contents of an index file"""
2541 """dump the contents of an index file"""
2541 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2542 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2542 format = opts.get('format', 0)
2543 format = opts.get('format', 0)
2543 if format not in (0, 1):
2544 if format not in (0, 1):
2544 raise error.Abort(_("unknown format %d") % format)
2545 raise error.Abort(_("unknown format %d") % format)
2545
2546
2546 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2547 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2547 if generaldelta:
2548 if generaldelta:
2548 basehdr = ' delta'
2549 basehdr = ' delta'
2549 else:
2550 else:
2550 basehdr = ' base'
2551 basehdr = ' base'
2551
2552
2552 if ui.debugflag:
2553 if ui.debugflag:
2553 shortfn = hex
2554 shortfn = hex
2554 else:
2555 else:
2555 shortfn = short
2556 shortfn = short
2556
2557
2557 # 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
2558 idlen = 12
2559 idlen = 12
2559 for i in r:
2560 for i in r:
2560 idlen = len(shortfn(r.node(i)))
2561 idlen = len(shortfn(r.node(i)))
2561 break
2562 break
2562
2563
2563 if format == 0:
2564 if format == 0:
2564 ui.write(" rev offset length " + basehdr + " linkrev"
2565 ui.write(" rev offset length " + basehdr + " linkrev"
2565 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2566 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2566 elif format == 1:
2567 elif format == 1:
2567 ui.write(" rev flag offset length"
2568 ui.write(" rev flag offset length"
2568 " size " + basehdr + " link p1 p2"
2569 " size " + basehdr + " link p1 p2"
2569 " %s\n" % "nodeid".rjust(idlen))
2570 " %s\n" % "nodeid".rjust(idlen))
2570
2571
2571 for i in r:
2572 for i in r:
2572 node = r.node(i)
2573 node = r.node(i)
2573 if generaldelta:
2574 if generaldelta:
2574 base = r.deltaparent(i)
2575 base = r.deltaparent(i)
2575 else:
2576 else:
2576 base = r.chainbase(i)
2577 base = r.chainbase(i)
2577 if format == 0:
2578 if format == 0:
2578 try:
2579 try:
2579 pp = r.parents(node)
2580 pp = r.parents(node)
2580 except Exception:
2581 except Exception:
2581 pp = [nullid, nullid]
2582 pp = [nullid, nullid]
2582 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2583 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2583 i, r.start(i), r.length(i), base, r.linkrev(i),
2584 i, r.start(i), r.length(i), base, r.linkrev(i),
2584 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2585 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2585 elif format == 1:
2586 elif format == 1:
2586 pr = r.parentrevs(i)
2587 pr = r.parentrevs(i)
2587 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" % (
2588 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),
2589 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2590 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2590
2591
2591 @command('debugindexdot', debugrevlogopts,
2592 @command('debugindexdot', debugrevlogopts,
2592 _('-c|-m|FILE'), optionalrepo=True)
2593 _('-c|-m|FILE'), optionalrepo=True)
2593 def debugindexdot(ui, repo, file_=None, **opts):
2594 def debugindexdot(ui, repo, file_=None, **opts):
2594 """dump an index DAG as a graphviz dot file"""
2595 """dump an index DAG as a graphviz dot file"""
2595 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2596 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2596 ui.write(("digraph G {\n"))
2597 ui.write(("digraph G {\n"))
2597 for i in r:
2598 for i in r:
2598 node = r.node(i)
2599 node = r.node(i)
2599 pp = r.parents(node)
2600 pp = r.parents(node)
2600 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2601 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2601 if pp[1] != nullid:
2602 if pp[1] != nullid:
2602 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2603 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2603 ui.write("}\n")
2604 ui.write("}\n")
2604
2605
2605 @command('debugdeltachain',
2606 @command('debugdeltachain',
2606 debugrevlogopts + formatteropts,
2607 debugrevlogopts + formatteropts,
2607 _('-c|-m|FILE'),
2608 _('-c|-m|FILE'),
2608 optionalrepo=True)
2609 optionalrepo=True)
2609 def debugdeltachain(ui, repo, file_=None, **opts):
2610 def debugdeltachain(ui, repo, file_=None, **opts):
2610 """dump information about delta chains in a revlog
2611 """dump information about delta chains in a revlog
2611
2612
2612 Output can be templatized. Available template keywords are:
2613 Output can be templatized. Available template keywords are:
2613
2614
2614 rev revision number
2615 rev revision number
2615 chainid delta chain identifier (numbered by unique base)
2616 chainid delta chain identifier (numbered by unique base)
2616 chainlen delta chain length to this revision
2617 chainlen delta chain length to this revision
2617 prevrev previous revision in delta chain
2618 prevrev previous revision in delta chain
2618 deltatype role of delta / how it was computed
2619 deltatype role of delta / how it was computed
2619 compsize compressed size of revision
2620 compsize compressed size of revision
2620 uncompsize uncompressed size of revision
2621 uncompsize uncompressed size of revision
2621 chainsize total size of compressed revisions in chain
2622 chainsize total size of compressed revisions in chain
2622 chainratio total chain size divided by uncompressed revision size
2623 chainratio total chain size divided by uncompressed revision size
2623 (new delta chains typically start at ratio 2.00)
2624 (new delta chains typically start at ratio 2.00)
2624 lindist linear distance from base revision in delta chain to end
2625 lindist linear distance from base revision in delta chain to end
2625 of this revision
2626 of this revision
2626 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
2627 base of delta chain to end of this revision; a measurement
2628 base of delta chain to end of this revision; a measurement
2628 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
2629 the delta chain for this revision
2630 the delta chain for this revision
2630 extraratio extradist divided by chainsize; another representation of
2631 extraratio extradist divided by chainsize; another representation of
2631 how much unrelated data is needed to load this delta chain
2632 how much unrelated data is needed to load this delta chain
2632 """
2633 """
2633 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2634 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2634 index = r.index
2635 index = r.index
2635 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2636 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2636
2637
2637 def revinfo(rev):
2638 def revinfo(rev):
2638 e = index[rev]
2639 e = index[rev]
2639 compsize = e[1]
2640 compsize = e[1]
2640 uncompsize = e[2]
2641 uncompsize = e[2]
2641 chainsize = 0
2642 chainsize = 0
2642
2643
2643 if generaldelta:
2644 if generaldelta:
2644 if e[3] == e[5]:
2645 if e[3] == e[5]:
2645 deltatype = 'p1'
2646 deltatype = 'p1'
2646 elif e[3] == e[6]:
2647 elif e[3] == e[6]:
2647 deltatype = 'p2'
2648 deltatype = 'p2'
2648 elif e[3] == rev - 1:
2649 elif e[3] == rev - 1:
2649 deltatype = 'prev'
2650 deltatype = 'prev'
2650 elif e[3] == rev:
2651 elif e[3] == rev:
2651 deltatype = 'base'
2652 deltatype = 'base'
2652 else:
2653 else:
2653 deltatype = 'other'
2654 deltatype = 'other'
2654 else:
2655 else:
2655 if e[3] == rev:
2656 if e[3] == rev:
2656 deltatype = 'base'
2657 deltatype = 'base'
2657 else:
2658 else:
2658 deltatype = 'prev'
2659 deltatype = 'prev'
2659
2660
2660 chain = r._deltachain(rev)[0]
2661 chain = r._deltachain(rev)[0]
2661 for iterrev in chain:
2662 for iterrev in chain:
2662 e = index[iterrev]
2663 e = index[iterrev]
2663 chainsize += e[1]
2664 chainsize += e[1]
2664
2665
2665 return compsize, uncompsize, deltatype, chain, chainsize
2666 return compsize, uncompsize, deltatype, chain, chainsize
2666
2667
2667 fm = ui.formatter('debugdeltachain', opts)
2668 fm = ui.formatter('debugdeltachain', opts)
2668
2669
2669 fm.plain(' rev chain# chainlen prev delta '
2670 fm.plain(' rev chain# chainlen prev delta '
2670 'size rawsize chainsize ratio lindist extradist '
2671 'size rawsize chainsize ratio lindist extradist '
2671 'extraratio\n')
2672 'extraratio\n')
2672
2673
2673 chainbases = {}
2674 chainbases = {}
2674 for rev in r:
2675 for rev in r:
2675 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2676 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2676 chainbase = chain[0]
2677 chainbase = chain[0]
2677 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2678 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2678 basestart = r.start(chainbase)
2679 basestart = r.start(chainbase)
2679 revstart = r.start(rev)
2680 revstart = r.start(rev)
2680 lineardist = revstart + comp - basestart
2681 lineardist = revstart + comp - basestart
2681 extradist = lineardist - chainsize
2682 extradist = lineardist - chainsize
2682 try:
2683 try:
2683 prevrev = chain[-2]
2684 prevrev = chain[-2]
2684 except IndexError:
2685 except IndexError:
2685 prevrev = -1
2686 prevrev = -1
2686
2687
2687 chainratio = float(chainsize) / float(uncomp)
2688 chainratio = float(chainsize) / float(uncomp)
2688 extraratio = float(extradist) / float(chainsize)
2689 extraratio = float(extradist) / float(chainsize)
2689
2690
2690 fm.startitem()
2691 fm.startitem()
2691 fm.write('rev chainid chainlen prevrev deltatype compsize '
2692 fm.write('rev chainid chainlen prevrev deltatype compsize '
2692 'uncompsize chainsize chainratio lindist extradist '
2693 'uncompsize chainsize chainratio lindist extradist '
2693 'extraratio',
2694 'extraratio',
2694 '%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',
2695 rev, chainid, len(chain), prevrev, deltatype, comp,
2696 rev, chainid, len(chain), prevrev, deltatype, comp,
2696 uncomp, chainsize, chainratio, lineardist, extradist,
2697 uncomp, chainsize, chainratio, lineardist, extradist,
2697 extraratio,
2698 extraratio,
2698 rev=rev, chainid=chainid, chainlen=len(chain),
2699 rev=rev, chainid=chainid, chainlen=len(chain),
2699 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2700 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2700 uncompsize=uncomp, chainsize=chainsize,
2701 uncompsize=uncomp, chainsize=chainsize,
2701 chainratio=chainratio, lindist=lineardist,
2702 chainratio=chainratio, lindist=lineardist,
2702 extradist=extradist, extraratio=extraratio)
2703 extradist=extradist, extraratio=extraratio)
2703
2704
2704 fm.end()
2705 fm.end()
2705
2706
2706 @command('debuginstall', [] + formatteropts, '', norepo=True)
2707 @command('debuginstall', [] + formatteropts, '', norepo=True)
2707 def debuginstall(ui, **opts):
2708 def debuginstall(ui, **opts):
2708 '''test Mercurial installation
2709 '''test Mercurial installation
2709
2710
2710 Returns 0 on success.
2711 Returns 0 on success.
2711 '''
2712 '''
2712
2713
2713 def writetemp(contents):
2714 def writetemp(contents):
2714 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2715 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2715 f = os.fdopen(fd, "wb")
2716 f = os.fdopen(fd, "wb")
2716 f.write(contents)
2717 f.write(contents)
2717 f.close()
2718 f.close()
2718 return name
2719 return name
2719
2720
2720 problems = 0
2721 problems = 0
2721
2722
2722 fm = ui.formatter('debuginstall', opts)
2723 fm = ui.formatter('debuginstall', opts)
2723 fm.startitem()
2724 fm.startitem()
2724
2725
2725 # encoding
2726 # encoding
2726 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2727 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2727 err = None
2728 err = None
2728 try:
2729 try:
2729 encoding.fromlocal("test")
2730 encoding.fromlocal("test")
2730 except error.Abort as inst:
2731 except error.Abort as inst:
2731 err = inst
2732 err = inst
2732 problems += 1
2733 problems += 1
2733 fm.condwrite(err, 'encodingerror', _(" %s\n"
2734 fm.condwrite(err, 'encodingerror', _(" %s\n"
2734 " (check that your locale is properly set)\n"), err)
2735 " (check that your locale is properly set)\n"), err)
2735
2736
2736 # Python
2737 # Python
2737 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2738 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2738 sys.executable)
2739 sys.executable)
2739 fm.write('pythonver', _("checking Python version (%s)\n"),
2740 fm.write('pythonver', _("checking Python version (%s)\n"),
2740 ("%s.%s.%s" % sys.version_info[:3]))
2741 ("%s.%s.%s" % sys.version_info[:3]))
2741 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2742 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2742 os.path.dirname(os.__file__))
2743 os.path.dirname(os.__file__))
2743
2744
2744 # hg version
2745 # hg version
2745 hgver = util.version()
2746 hgver = util.version()
2746 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2747 fm.write('hgver', _("checking Mercurial version (%s)\n"),
2747 hgver.split('+')[0])
2748 hgver.split('+')[0])
2748 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2749 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
2749 '+'.join(hgver.split('+')[1:]))
2750 '+'.join(hgver.split('+')[1:]))
2750
2751
2751 # compiled modules
2752 # compiled modules
2753 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
2754 policy.policy)
2752 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2755 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2753 os.path.dirname(__file__))
2756 os.path.dirname(__file__))
2754
2757
2755 err = None
2758 err = None
2756 try:
2759 try:
2757 from . import (
2760 from . import (
2758 base85,
2761 base85,
2759 bdiff,
2762 bdiff,
2760 mpatch,
2763 mpatch,
2761 osutil,
2764 osutil,
2762 )
2765 )
2763 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2766 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2764 except Exception as inst:
2767 except Exception as inst:
2765 err = inst
2768 err = inst
2766 problems += 1
2769 problems += 1
2767 fm.condwrite(err, 'extensionserror', " %s\n", err)
2770 fm.condwrite(err, 'extensionserror', " %s\n", err)
2768
2771
2769 # templates
2772 # templates
2770 p = templater.templatepaths()
2773 p = templater.templatepaths()
2771 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2774 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2772 fm.condwrite(not p, '', _(" no template directories found\n"))
2775 fm.condwrite(not p, '', _(" no template directories found\n"))
2773 if p:
2776 if p:
2774 m = templater.templatepath("map-cmdline.default")
2777 m = templater.templatepath("map-cmdline.default")
2775 if m:
2778 if m:
2776 # template found, check if it is working
2779 # template found, check if it is working
2777 err = None
2780 err = None
2778 try:
2781 try:
2779 templater.templater.frommapfile(m)
2782 templater.templater.frommapfile(m)
2780 except Exception as inst:
2783 except Exception as inst:
2781 err = inst
2784 err = inst
2782 p = None
2785 p = None
2783 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2786 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2784 else:
2787 else:
2785 p = None
2788 p = None
2786 fm.condwrite(p, 'defaulttemplate',
2789 fm.condwrite(p, 'defaulttemplate',
2787 _("checking default template (%s)\n"), m)
2790 _("checking default template (%s)\n"), m)
2788 fm.condwrite(not m, 'defaulttemplatenotfound',
2791 fm.condwrite(not m, 'defaulttemplatenotfound',
2789 _(" template '%s' not found\n"), "default")
2792 _(" template '%s' not found\n"), "default")
2790 if not p:
2793 if not p:
2791 problems += 1
2794 problems += 1
2792 fm.condwrite(not p, '',
2795 fm.condwrite(not p, '',
2793 _(" (templates seem to have been installed incorrectly)\n"))
2796 _(" (templates seem to have been installed incorrectly)\n"))
2794
2797
2795 # editor
2798 # editor
2796 editor = ui.geteditor()
2799 editor = ui.geteditor()
2797 editor = util.expandpath(editor)
2800 editor = util.expandpath(editor)
2798 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2801 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2799 cmdpath = util.findexe(shlex.split(editor)[0])
2802 cmdpath = util.findexe(shlex.split(editor)[0])
2800 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2803 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2801 _(" 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"
2802 " (specify a commit editor in your configuration"
2805 " (specify a commit editor in your configuration"
2803 " file)\n"), not cmdpath and editor == 'vi' and editor)
2806 " file)\n"), not cmdpath and editor == 'vi' and editor)
2804 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2807 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2805 _(" Can't find editor '%s' in PATH\n"
2808 _(" Can't find editor '%s' in PATH\n"
2806 " (specify a commit editor in your configuration"
2809 " (specify a commit editor in your configuration"
2807 " file)\n"), not cmdpath and editor)
2810 " file)\n"), not cmdpath and editor)
2808 if not cmdpath and editor != 'vi':
2811 if not cmdpath and editor != 'vi':
2809 problems += 1
2812 problems += 1
2810
2813
2811 # check username
2814 # check username
2812 username = None
2815 username = None
2813 err = None
2816 err = None
2814 try:
2817 try:
2815 username = ui.username()
2818 username = ui.username()
2816 except error.Abort as e:
2819 except error.Abort as e:
2817 err = e
2820 err = e
2818 problems += 1
2821 problems += 1
2819
2822
2820 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2823 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2821 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2824 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2822 " (specify a username in your configuration file)\n"), err)
2825 " (specify a username in your configuration file)\n"), err)
2823
2826
2824 fm.condwrite(not problems, '',
2827 fm.condwrite(not problems, '',
2825 _("no problems detected\n"))
2828 _("no problems detected\n"))
2826 if not problems:
2829 if not problems:
2827 fm.data(problems=problems)
2830 fm.data(problems=problems)
2828 fm.condwrite(problems, 'problems',
2831 fm.condwrite(problems, 'problems',
2829 _("%s problems detected,"
2832 _("%s problems detected,"
2830 " please check your install!\n"), problems)
2833 " please check your install!\n"), problems)
2831 fm.end()
2834 fm.end()
2832
2835
2833 return problems
2836 return problems
2834
2837
2835 @command('debugknown', [], _('REPO ID...'), norepo=True)
2838 @command('debugknown', [], _('REPO ID...'), norepo=True)
2836 def debugknown(ui, repopath, *ids, **opts):
2839 def debugknown(ui, repopath, *ids, **opts):
2837 """test whether node ids are known to a repo
2840 """test whether node ids are known to a repo
2838
2841
2839 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
2840 and 1s indicating unknown/known.
2843 and 1s indicating unknown/known.
2841 """
2844 """
2842 repo = hg.peer(ui, opts, repopath)
2845 repo = hg.peer(ui, opts, repopath)
2843 if not repo.capable('known'):
2846 if not repo.capable('known'):
2844 raise error.Abort("known() not supported by target repository")
2847 raise error.Abort("known() not supported by target repository")
2845 flags = repo.known([bin(s) for s in ids])
2848 flags = repo.known([bin(s) for s in ids])
2846 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])))
2847
2850
2848 @command('debuglabelcomplete', [], _('LABEL...'))
2851 @command('debuglabelcomplete', [], _('LABEL...'))
2849 def debuglabelcomplete(ui, repo, *args):
2852 def debuglabelcomplete(ui, repo, *args):
2850 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2853 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2851 debugnamecomplete(ui, repo, *args)
2854 debugnamecomplete(ui, repo, *args)
2852
2855
2853 @command('debugmergestate', [], '')
2856 @command('debugmergestate', [], '')
2854 def debugmergestate(ui, repo, *args):
2857 def debugmergestate(ui, repo, *args):
2855 """print merge state
2858 """print merge state
2856
2859
2857 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
2858 was chosen."""
2861 was chosen."""
2859 def _hashornull(h):
2862 def _hashornull(h):
2860 if h == nullhex:
2863 if h == nullhex:
2861 return 'null'
2864 return 'null'
2862 else:
2865 else:
2863 return h
2866 return h
2864
2867
2865 def printrecords(version):
2868 def printrecords(version):
2866 ui.write(('* version %s records\n') % version)
2869 ui.write(('* version %s records\n') % version)
2867 if version == 1:
2870 if version == 1:
2868 records = v1records
2871 records = v1records
2869 else:
2872 else:
2870 records = v2records
2873 records = v2records
2871
2874
2872 for rtype, record in records:
2875 for rtype, record in records:
2873 # pretty print some record types
2876 # pretty print some record types
2874 if rtype == 'L':
2877 if rtype == 'L':
2875 ui.write(('local: %s\n') % record)
2878 ui.write(('local: %s\n') % record)
2876 elif rtype == 'O':
2879 elif rtype == 'O':
2877 ui.write(('other: %s\n') % record)
2880 ui.write(('other: %s\n') % record)
2878 elif rtype == 'm':
2881 elif rtype == 'm':
2879 driver, mdstate = record.split('\0', 1)
2882 driver, mdstate = record.split('\0', 1)
2880 ui.write(('merge driver: %s (state "%s")\n')
2883 ui.write(('merge driver: %s (state "%s")\n')
2881 % (driver, mdstate))
2884 % (driver, mdstate))
2882 elif rtype in 'FDC':
2885 elif rtype in 'FDC':
2883 r = record.split('\0')
2886 r = record.split('\0')
2884 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2887 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2885 if version == 1:
2888 if version == 1:
2886 onode = 'not stored in v1 format'
2889 onode = 'not stored in v1 format'
2887 flags = r[7]
2890 flags = r[7]
2888 else:
2891 else:
2889 onode, flags = r[7:9]
2892 onode, flags = r[7:9]
2890 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')
2891 % (f, rtype, state, _hashornull(hash)))
2894 % (f, rtype, state, _hashornull(hash)))
2892 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2895 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2893 ui.write((' ancestor path: %s (node %s)\n')
2896 ui.write((' ancestor path: %s (node %s)\n')
2894 % (afile, _hashornull(anode)))
2897 % (afile, _hashornull(anode)))
2895 ui.write((' other path: %s (node %s)\n')
2898 ui.write((' other path: %s (node %s)\n')
2896 % (ofile, _hashornull(onode)))
2899 % (ofile, _hashornull(onode)))
2897 elif rtype == 'f':
2900 elif rtype == 'f':
2898 filename, rawextras = record.split('\0', 1)
2901 filename, rawextras = record.split('\0', 1)
2899 extras = rawextras.split('\0')
2902 extras = rawextras.split('\0')
2900 i = 0
2903 i = 0
2901 extrastrings = []
2904 extrastrings = []
2902 while i < len(extras):
2905 while i < len(extras):
2903 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2906 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2904 i += 2
2907 i += 2
2905
2908
2906 ui.write(('file extras: %s (%s)\n')
2909 ui.write(('file extras: %s (%s)\n')
2907 % (filename, ', '.join(extrastrings)))
2910 % (filename, ', '.join(extrastrings)))
2908 elif rtype == 'l':
2911 elif rtype == 'l':
2909 labels = record.split('\0', 2)
2912 labels = record.split('\0', 2)
2910 labels = [l for l in labels if len(l) > 0]
2913 labels = [l for l in labels if len(l) > 0]
2911 ui.write(('labels:\n'))
2914 ui.write(('labels:\n'))
2912 ui.write((' local: %s\n' % labels[0]))
2915 ui.write((' local: %s\n' % labels[0]))
2913 ui.write((' other: %s\n' % labels[1]))
2916 ui.write((' other: %s\n' % labels[1]))
2914 if len(labels) > 2:
2917 if len(labels) > 2:
2915 ui.write((' base: %s\n' % labels[2]))
2918 ui.write((' base: %s\n' % labels[2]))
2916 else:
2919 else:
2917 ui.write(('unrecognized entry: %s\t%s\n')
2920 ui.write(('unrecognized entry: %s\t%s\n')
2918 % (rtype, record.replace('\0', '\t')))
2921 % (rtype, record.replace('\0', '\t')))
2919
2922
2920 # Avoid mergestate.read() since it may raise an exception for unsupported
2923 # Avoid mergestate.read() since it may raise an exception for unsupported
2921 # 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
2922 # command is pretty low-level.
2925 # command is pretty low-level.
2923 ms = mergemod.mergestate(repo)
2926 ms = mergemod.mergestate(repo)
2924
2927
2925 # sort so that reasonable information is on top
2928 # sort so that reasonable information is on top
2926 v1records = ms._readrecordsv1()
2929 v1records = ms._readrecordsv1()
2927 v2records = ms._readrecordsv2()
2930 v2records = ms._readrecordsv2()
2928 order = 'LOml'
2931 order = 'LOml'
2929 def key(r):
2932 def key(r):
2930 idx = order.find(r[0])
2933 idx = order.find(r[0])
2931 if idx == -1:
2934 if idx == -1:
2932 return (1, r[1])
2935 return (1, r[1])
2933 else:
2936 else:
2934 return (0, idx)
2937 return (0, idx)
2935 v1records.sort(key=key)
2938 v1records.sort(key=key)
2936 v2records.sort(key=key)
2939 v2records.sort(key=key)
2937
2940
2938 if not v1records and not v2records:
2941 if not v1records and not v2records:
2939 ui.write(('no merge state found\n'))
2942 ui.write(('no merge state found\n'))
2940 elif not v2records:
2943 elif not v2records:
2941 ui.note(('no version 2 merge state\n'))
2944 ui.note(('no version 2 merge state\n'))
2942 printrecords(1)
2945 printrecords(1)
2943 elif ms._v1v2match(v1records, v2records):
2946 elif ms._v1v2match(v1records, v2records):
2944 ui.note(('v1 and v2 states match: using v2\n'))
2947 ui.note(('v1 and v2 states match: using v2\n'))
2945 printrecords(2)
2948 printrecords(2)
2946 else:
2949 else:
2947 ui.note(('v1 and v2 states mismatch: using v1\n'))
2950 ui.note(('v1 and v2 states mismatch: using v1\n'))
2948 printrecords(1)
2951 printrecords(1)
2949 if ui.verbose:
2952 if ui.verbose:
2950 printrecords(2)
2953 printrecords(2)
2951
2954
2952 @command('debugnamecomplete', [], _('NAME...'))
2955 @command('debugnamecomplete', [], _('NAME...'))
2953 def debugnamecomplete(ui, repo, *args):
2956 def debugnamecomplete(ui, repo, *args):
2954 '''complete "names" - tags, open branch names, bookmark names'''
2957 '''complete "names" - tags, open branch names, bookmark names'''
2955
2958
2956 names = set()
2959 names = set()
2957 # since we previously only listed open branches, we will handle that
2960 # since we previously only listed open branches, we will handle that
2958 # specially (after this for loop)
2961 # specially (after this for loop)
2959 for name, ns in repo.names.iteritems():
2962 for name, ns in repo.names.iteritems():
2960 if name != 'branches':
2963 if name != 'branches':
2961 names.update(ns.listnames(repo))
2964 names.update(ns.listnames(repo))
2962 names.update(tag for (tag, heads, tip, closed)
2965 names.update(tag for (tag, heads, tip, closed)
2963 in repo.branchmap().iterbranches() if not closed)
2966 in repo.branchmap().iterbranches() if not closed)
2964 completions = set()
2967 completions = set()
2965 if not args:
2968 if not args:
2966 args = ['']
2969 args = ['']
2967 for a in args:
2970 for a in args:
2968 completions.update(n for n in names if n.startswith(a))
2971 completions.update(n for n in names if n.startswith(a))
2969 ui.write('\n'.join(sorted(completions)))
2972 ui.write('\n'.join(sorted(completions)))
2970 ui.write('\n')
2973 ui.write('\n')
2971
2974
2972 @command('debuglocks',
2975 @command('debuglocks',
2973 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2976 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2974 ('W', 'force-wlock', None,
2977 ('W', 'force-wlock', None,
2975 _('free the working state lock (DANGEROUS)'))],
2978 _('free the working state lock (DANGEROUS)'))],
2976 _('[OPTION]...'))
2979 _('[OPTION]...'))
2977 def debuglocks(ui, repo, **opts):
2980 def debuglocks(ui, repo, **opts):
2978 """show or modify state of locks
2981 """show or modify state of locks
2979
2982
2980 By default, this command will show which locks are held. This
2983 By default, this command will show which locks are held. This
2981 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
2982 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
2983 running if it's not local.
2986 running if it's not local.
2984
2987
2985 Locks protect the integrity of Mercurial's data, so should be
2988 Locks protect the integrity of Mercurial's data, so should be
2986 treated with care. System crashes or other interruptions may cause
2989 treated with care. System crashes or other interruptions may cause
2987 locks to not be properly released, though Mercurial will usually
2990 locks to not be properly released, though Mercurial will usually
2988 detect and remove such stale locks automatically.
2991 detect and remove such stale locks automatically.
2989
2992
2990 However, detecting stale locks may not always be possible (for
2993 However, detecting stale locks may not always be possible (for
2991 instance, on a shared filesystem). Removing locks may also be
2994 instance, on a shared filesystem). Removing locks may also be
2992 blocked by filesystem permissions.
2995 blocked by filesystem permissions.
2993
2996
2994 Returns 0 if no locks are held.
2997 Returns 0 if no locks are held.
2995
2998
2996 """
2999 """
2997
3000
2998 if opts.get('force_lock'):
3001 if opts.get('force_lock'):
2999 repo.svfs.unlink('lock')
3002 repo.svfs.unlink('lock')
3000 if opts.get('force_wlock'):
3003 if opts.get('force_wlock'):
3001 repo.vfs.unlink('wlock')
3004 repo.vfs.unlink('wlock')
3002 if opts.get('force_lock') or opts.get('force_lock'):
3005 if opts.get('force_lock') or opts.get('force_lock'):
3003 return 0
3006 return 0
3004
3007
3005 now = time.time()
3008 now = time.time()
3006 held = 0
3009 held = 0
3007
3010
3008 def report(vfs, name, method):
3011 def report(vfs, name, method):
3009 # this causes stale locks to get reaped for more accurate reporting
3012 # this causes stale locks to get reaped for more accurate reporting
3010 try:
3013 try:
3011 l = method(False)
3014 l = method(False)
3012 except error.LockHeld:
3015 except error.LockHeld:
3013 l = None
3016 l = None
3014
3017
3015 if l:
3018 if l:
3016 l.release()
3019 l.release()
3017 else:
3020 else:
3018 try:
3021 try:
3019 stat = vfs.lstat(name)
3022 stat = vfs.lstat(name)
3020 age = now - stat.st_mtime
3023 age = now - stat.st_mtime
3021 user = util.username(stat.st_uid)
3024 user = util.username(stat.st_uid)
3022 locker = vfs.readlock(name)
3025 locker = vfs.readlock(name)
3023 if ":" in locker:
3026 if ":" in locker:
3024 host, pid = locker.split(':')
3027 host, pid = locker.split(':')
3025 if host == socket.gethostname():
3028 if host == socket.gethostname():
3026 locker = 'user %s, process %s' % (user, pid)
3029 locker = 'user %s, process %s' % (user, pid)
3027 else:
3030 else:
3028 locker = 'user %s, process %s, host %s' \
3031 locker = 'user %s, process %s, host %s' \
3029 % (user, pid, host)
3032 % (user, pid, host)
3030 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3033 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3031 return 1
3034 return 1
3032 except OSError as e:
3035 except OSError as e:
3033 if e.errno != errno.ENOENT:
3036 if e.errno != errno.ENOENT:
3034 raise
3037 raise
3035
3038
3036 ui.write("%-6s free\n" % (name + ":"))
3039 ui.write("%-6s free\n" % (name + ":"))
3037 return 0
3040 return 0
3038
3041
3039 held += report(repo.svfs, "lock", repo.lock)
3042 held += report(repo.svfs, "lock", repo.lock)
3040 held += report(repo.vfs, "wlock", repo.wlock)
3043 held += report(repo.vfs, "wlock", repo.wlock)
3041
3044
3042 return held
3045 return held
3043
3046
3044 @command('debugobsolete',
3047 @command('debugobsolete',
3045 [('', 'flags', 0, _('markers flag')),
3048 [('', 'flags', 0, _('markers flag')),
3046 ('', 'record-parents', False,
3049 ('', 'record-parents', False,
3047 _('record parent information for the precursor')),
3050 _('record parent information for the precursor')),
3048 ('r', 'rev', [], _('display markers relevant to REV')),
3051 ('r', 'rev', [], _('display markers relevant to REV')),
3049 ('', 'index', False, _('display index of the marker')),
3052 ('', 'index', False, _('display index of the marker')),
3050 ('', 'delete', [], _('delete markers specified by indices')),
3053 ('', 'delete', [], _('delete markers specified by indices')),
3051 ] + commitopts2,
3054 ] + commitopts2,
3052 _('[OBSOLETED [REPLACEMENT ...]]'))
3055 _('[OBSOLETED [REPLACEMENT ...]]'))
3053 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3056 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3054 """create arbitrary obsolete marker
3057 """create arbitrary obsolete marker
3055
3058
3056 With no arguments, displays the list of obsolescence markers."""
3059 With no arguments, displays the list of obsolescence markers."""
3057
3060
3058 def parsenodeid(s):
3061 def parsenodeid(s):
3059 try:
3062 try:
3060 # We do not use revsingle/revrange functions here to accept
3063 # We do not use revsingle/revrange functions here to accept
3061 # arbitrary node identifiers, possibly not present in the
3064 # arbitrary node identifiers, possibly not present in the
3062 # local repository.
3065 # local repository.
3063 n = bin(s)
3066 n = bin(s)
3064 if len(n) != len(nullid):
3067 if len(n) != len(nullid):
3065 raise TypeError()
3068 raise TypeError()
3066 return n
3069 return n
3067 except TypeError:
3070 except TypeError:
3068 raise error.Abort('changeset references must be full hexadecimal '
3071 raise error.Abort('changeset references must be full hexadecimal '
3069 'node identifiers')
3072 'node identifiers')
3070
3073
3071 if opts.get('delete'):
3074 if opts.get('delete'):
3072 indices = []
3075 indices = []
3073 for v in opts.get('delete'):
3076 for v in opts.get('delete'):
3074 try:
3077 try:
3075 indices.append(int(v))
3078 indices.append(int(v))
3076 except ValueError:
3079 except ValueError:
3077 raise error.Abort(_('invalid index value: %r') % v,
3080 raise error.Abort(_('invalid index value: %r') % v,
3078 hint=_('use integers for indices'))
3081 hint=_('use integers for indices'))
3079
3082
3080 if repo.currenttransaction():
3083 if repo.currenttransaction():
3081 raise error.Abort(_('cannot delete obsmarkers in the middle '
3084 raise error.Abort(_('cannot delete obsmarkers in the middle '
3082 'of transaction.'))
3085 'of transaction.'))
3083
3086
3084 with repo.lock():
3087 with repo.lock():
3085 n = repair.deleteobsmarkers(repo.obsstore, indices)
3088 n = repair.deleteobsmarkers(repo.obsstore, indices)
3086 ui.write(_('deleted %i obsolescense markers\n') % n)
3089 ui.write(_('deleted %i obsolescense markers\n') % n)
3087
3090
3088 return
3091 return
3089
3092
3090 if precursor is not None:
3093 if precursor is not None:
3091 if opts['rev']:
3094 if opts['rev']:
3092 raise error.Abort('cannot select revision when creating marker')
3095 raise error.Abort('cannot select revision when creating marker')
3093 metadata = {}
3096 metadata = {}
3094 metadata['user'] = opts['user'] or ui.username()
3097 metadata['user'] = opts['user'] or ui.username()
3095 succs = tuple(parsenodeid(succ) for succ in successors)
3098 succs = tuple(parsenodeid(succ) for succ in successors)
3096 l = repo.lock()
3099 l = repo.lock()
3097 try:
3100 try:
3098 tr = repo.transaction('debugobsolete')
3101 tr = repo.transaction('debugobsolete')
3099 try:
3102 try:
3100 date = opts.get('date')
3103 date = opts.get('date')
3101 if date:
3104 if date:
3102 date = util.parsedate(date)
3105 date = util.parsedate(date)
3103 else:
3106 else:
3104 date = None
3107 date = None
3105 prec = parsenodeid(precursor)
3108 prec = parsenodeid(precursor)
3106 parents = None
3109 parents = None
3107 if opts['record_parents']:
3110 if opts['record_parents']:
3108 if prec not in repo.unfiltered():
3111 if prec not in repo.unfiltered():
3109 raise error.Abort('cannot used --record-parents on '
3112 raise error.Abort('cannot used --record-parents on '
3110 'unknown changesets')
3113 'unknown changesets')
3111 parents = repo.unfiltered()[prec].parents()
3114 parents = repo.unfiltered()[prec].parents()
3112 parents = tuple(p.node() for p in parents)
3115 parents = tuple(p.node() for p in parents)
3113 repo.obsstore.create(tr, prec, succs, opts['flags'],
3116 repo.obsstore.create(tr, prec, succs, opts['flags'],
3114 parents=parents, date=date,
3117 parents=parents, date=date,
3115 metadata=metadata)
3118 metadata=metadata)
3116 tr.close()
3119 tr.close()
3117 except ValueError as exc:
3120 except ValueError as exc:
3118 raise error.Abort(_('bad obsmarker input: %s') % exc)
3121 raise error.Abort(_('bad obsmarker input: %s') % exc)
3119 finally:
3122 finally:
3120 tr.release()
3123 tr.release()
3121 finally:
3124 finally:
3122 l.release()
3125 l.release()
3123 else:
3126 else:
3124 if opts['rev']:
3127 if opts['rev']:
3125 revs = scmutil.revrange(repo, opts['rev'])
3128 revs = scmutil.revrange(repo, opts['rev'])
3126 nodes = [repo[r].node() for r in revs]
3129 nodes = [repo[r].node() for r in revs]
3127 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3130 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3128 markers.sort(key=lambda x: x._data)
3131 markers.sort(key=lambda x: x._data)
3129 else:
3132 else:
3130 markers = obsolete.getmarkers(repo)
3133 markers = obsolete.getmarkers(repo)
3131
3134
3132 markerstoiter = markers
3135 markerstoiter = markers
3133 isrelevant = lambda m: True
3136 isrelevant = lambda m: True
3134 if opts.get('rev') and opts.get('index'):
3137 if opts.get('rev') and opts.get('index'):
3135 markerstoiter = obsolete.getmarkers(repo)
3138 markerstoiter = obsolete.getmarkers(repo)
3136 markerset = set(markers)
3139 markerset = set(markers)
3137 isrelevant = lambda m: m in markerset
3140 isrelevant = lambda m: m in markerset
3138
3141
3139 for i, m in enumerate(markerstoiter):
3142 for i, m in enumerate(markerstoiter):
3140 if not isrelevant(m):
3143 if not isrelevant(m):
3141 # marker can be irrelevant when we're iterating over a set
3144 # marker can be irrelevant when we're iterating over a set
3142 # of markers (markerstoiter) which is bigger than the set
3145 # of markers (markerstoiter) which is bigger than the set
3143 # of markers we want to display (markers)
3146 # of markers we want to display (markers)
3144 # this can happen if both --index and --rev options are
3147 # this can happen if both --index and --rev options are
3145 # 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
3146 # to get the correct indices, but only display the ones that
3149 # to get the correct indices, but only display the ones that
3147 # are relevant to --rev value
3150 # are relevant to --rev value
3148 continue
3151 continue
3149 ind = i if opts.get('index') else None
3152 ind = i if opts.get('index') else None
3150 cmdutil.showmarker(ui, m, index=ind)
3153 cmdutil.showmarker(ui, m, index=ind)
3151
3154
3152 @command('debugpathcomplete',
3155 @command('debugpathcomplete',
3153 [('f', 'full', None, _('complete an entire path')),
3156 [('f', 'full', None, _('complete an entire path')),
3154 ('n', 'normal', None, _('show only normal files')),
3157 ('n', 'normal', None, _('show only normal files')),
3155 ('a', 'added', None, _('show only added files')),
3158 ('a', 'added', None, _('show only added files')),
3156 ('r', 'removed', None, _('show only removed files'))],
3159 ('r', 'removed', None, _('show only removed files'))],
3157 _('FILESPEC...'))
3160 _('FILESPEC...'))
3158 def debugpathcomplete(ui, repo, *specs, **opts):
3161 def debugpathcomplete(ui, repo, *specs, **opts):
3159 '''complete part or all of a tracked path
3162 '''complete part or all of a tracked path
3160
3163
3161 This command supports shells that offer path name completion. It
3164 This command supports shells that offer path name completion. It
3162 currently completes only files already known to the dirstate.
3165 currently completes only files already known to the dirstate.
3163
3166
3164 Completion extends only to the next path segment unless
3167 Completion extends only to the next path segment unless
3165 --full is specified, in which case entire paths are used.'''
3168 --full is specified, in which case entire paths are used.'''
3166
3169
3167 def complete(path, acceptable):
3170 def complete(path, acceptable):
3168 dirstate = repo.dirstate
3171 dirstate = repo.dirstate
3169 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3172 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3170 rootdir = repo.root + os.sep
3173 rootdir = repo.root + os.sep
3171 if spec != repo.root and not spec.startswith(rootdir):
3174 if spec != repo.root and not spec.startswith(rootdir):
3172 return [], []
3175 return [], []
3173 if os.path.isdir(spec):
3176 if os.path.isdir(spec):
3174 spec += '/'
3177 spec += '/'
3175 spec = spec[len(rootdir):]
3178 spec = spec[len(rootdir):]
3176 fixpaths = os.sep != '/'
3179 fixpaths = os.sep != '/'
3177 if fixpaths:
3180 if fixpaths:
3178 spec = spec.replace(os.sep, '/')
3181 spec = spec.replace(os.sep, '/')
3179 speclen = len(spec)
3182 speclen = len(spec)
3180 fullpaths = opts['full']
3183 fullpaths = opts['full']
3181 files, dirs = set(), set()
3184 files, dirs = set(), set()
3182 adddir, addfile = dirs.add, files.add
3185 adddir, addfile = dirs.add, files.add
3183 for f, st in dirstate.iteritems():
3186 for f, st in dirstate.iteritems():
3184 if f.startswith(spec) and st[0] in acceptable:
3187 if f.startswith(spec) and st[0] in acceptable:
3185 if fixpaths:
3188 if fixpaths:
3186 f = f.replace('/', os.sep)
3189 f = f.replace('/', os.sep)
3187 if fullpaths:
3190 if fullpaths:
3188 addfile(f)
3191 addfile(f)
3189 continue
3192 continue
3190 s = f.find(os.sep, speclen)
3193 s = f.find(os.sep, speclen)
3191 if s >= 0:
3194 if s >= 0:
3192 adddir(f[:s])
3195 adddir(f[:s])
3193 else:
3196 else:
3194 addfile(f)
3197 addfile(f)
3195 return files, dirs
3198 return files, dirs
3196
3199
3197 acceptable = ''
3200 acceptable = ''
3198 if opts['normal']:
3201 if opts['normal']:
3199 acceptable += 'nm'
3202 acceptable += 'nm'
3200 if opts['added']:
3203 if opts['added']:
3201 acceptable += 'a'
3204 acceptable += 'a'
3202 if opts['removed']:
3205 if opts['removed']:
3203 acceptable += 'r'
3206 acceptable += 'r'
3204 cwd = repo.getcwd()
3207 cwd = repo.getcwd()
3205 if not specs:
3208 if not specs:
3206 specs = ['.']
3209 specs = ['.']
3207
3210
3208 files, dirs = set(), set()
3211 files, dirs = set(), set()
3209 for spec in specs:
3212 for spec in specs:
3210 f, d = complete(spec, acceptable or 'nmar')
3213 f, d = complete(spec, acceptable or 'nmar')
3211 files.update(f)
3214 files.update(f)
3212 dirs.update(d)
3215 dirs.update(d)
3213 files.update(dirs)
3216 files.update(dirs)
3214 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)))
3215 ui.write('\n')
3218 ui.write('\n')
3216
3219
3217 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3220 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3218 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3221 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3219 '''access the pushkey key/value protocol
3222 '''access the pushkey key/value protocol
3220
3223
3221 With two args, list the keys in the given namespace.
3224 With two args, list the keys in the given namespace.
3222
3225
3223 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.
3224 Reports success or failure.
3227 Reports success or failure.
3225 '''
3228 '''
3226
3229
3227 target = hg.peer(ui, {}, repopath)
3230 target = hg.peer(ui, {}, repopath)
3228 if keyinfo:
3231 if keyinfo:
3229 key, old, new = keyinfo
3232 key, old, new = keyinfo
3230 r = target.pushkey(namespace, key, old, new)
3233 r = target.pushkey(namespace, key, old, new)
3231 ui.status(str(r) + '\n')
3234 ui.status(str(r) + '\n')
3232 return not r
3235 return not r
3233 else:
3236 else:
3234 for k, v in sorted(target.listkeys(namespace).iteritems()):
3237 for k, v in sorted(target.listkeys(namespace).iteritems()):
3235 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3238 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3236 v.encode('string-escape')))
3239 v.encode('string-escape')))
3237
3240
3238 @command('debugpvec', [], _('A B'))
3241 @command('debugpvec', [], _('A B'))
3239 def debugpvec(ui, repo, a, b=None):
3242 def debugpvec(ui, repo, a, b=None):
3240 ca = scmutil.revsingle(repo, a)
3243 ca = scmutil.revsingle(repo, a)
3241 cb = scmutil.revsingle(repo, b)
3244 cb = scmutil.revsingle(repo, b)
3242 pa = pvec.ctxpvec(ca)
3245 pa = pvec.ctxpvec(ca)
3243 pb = pvec.ctxpvec(cb)
3246 pb = pvec.ctxpvec(cb)
3244 if pa == pb:
3247 if pa == pb:
3245 rel = "="
3248 rel = "="
3246 elif pa > pb:
3249 elif pa > pb:
3247 rel = ">"
3250 rel = ">"
3248 elif pa < pb:
3251 elif pa < pb:
3249 rel = "<"
3252 rel = "<"
3250 elif pa | pb:
3253 elif pa | pb:
3251 rel = "|"
3254 rel = "|"
3252 ui.write(_("a: %s\n") % pa)
3255 ui.write(_("a: %s\n") % pa)
3253 ui.write(_("b: %s\n") % pb)
3256 ui.write(_("b: %s\n") % pb)
3254 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))
3255 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3258 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3256 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3259 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3257 pa.distance(pb), rel))
3260 pa.distance(pb), rel))
3258
3261
3259 @command('debugrebuilddirstate|debugrebuildstate',
3262 @command('debugrebuilddirstate|debugrebuildstate',
3260 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3263 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3261 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3264 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3262 'the working copy parent')),
3265 'the working copy parent')),
3263 ],
3266 ],
3264 _('[-r REV]'))
3267 _('[-r REV]'))
3265 def debugrebuilddirstate(ui, repo, rev, **opts):
3268 def debugrebuilddirstate(ui, repo, rev, **opts):
3266 """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
3267
3270
3268 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.
3269
3272
3270 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.
3271 The actual working directory content or existing dirstate
3274 The actual working directory content or existing dirstate
3272 information such as adds or removes is not considered.
3275 information such as adds or removes is not considered.
3273
3276
3274 ``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
3275 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
3276 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
3277 modified files that are in the working copy parent.
3280 modified files that are in the working copy parent.
3278
3281
3279 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
3280 check the actual file content.
3283 check the actual file content.
3281 """
3284 """
3282 ctx = scmutil.revsingle(repo, rev)
3285 ctx = scmutil.revsingle(repo, rev)
3283 with repo.wlock():
3286 with repo.wlock():
3284 dirstate = repo.dirstate
3287 dirstate = repo.dirstate
3285 changedfiles = None
3288 changedfiles = None
3286 # See command doc for what minimal does.
3289 # See command doc for what minimal does.
3287 if opts.get('minimal'):
3290 if opts.get('minimal'):
3288 manifestfiles = set(ctx.manifest().keys())
3291 manifestfiles = set(ctx.manifest().keys())
3289 dirstatefiles = set(dirstate)
3292 dirstatefiles = set(dirstate)
3290 manifestonly = manifestfiles - dirstatefiles
3293 manifestonly = manifestfiles - dirstatefiles
3291 dsonly = dirstatefiles - manifestfiles
3294 dsonly = dirstatefiles - manifestfiles
3292 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3295 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3293 changedfiles = manifestonly | dsnotadded
3296 changedfiles = manifestonly | dsnotadded
3294
3297
3295 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3298 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3296
3299
3297 @command('debugrebuildfncache', [], '')
3300 @command('debugrebuildfncache', [], '')
3298 def debugrebuildfncache(ui, repo):
3301 def debugrebuildfncache(ui, repo):
3299 """rebuild the fncache file"""
3302 """rebuild the fncache file"""
3300 repair.rebuildfncache(ui, repo)
3303 repair.rebuildfncache(ui, repo)
3301
3304
3302 @command('debugrename',
3305 @command('debugrename',
3303 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3306 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3304 _('[-r REV] FILE'))
3307 _('[-r REV] FILE'))
3305 def debugrename(ui, repo, file1, *pats, **opts):
3308 def debugrename(ui, repo, file1, *pats, **opts):
3306 """dump rename information"""
3309 """dump rename information"""
3307
3310
3308 ctx = scmutil.revsingle(repo, opts.get('rev'))
3311 ctx = scmutil.revsingle(repo, opts.get('rev'))
3309 m = scmutil.match(ctx, (file1,) + pats, opts)
3312 m = scmutil.match(ctx, (file1,) + pats, opts)
3310 for abs in ctx.walk(m):
3313 for abs in ctx.walk(m):
3311 fctx = ctx[abs]
3314 fctx = ctx[abs]
3312 o = fctx.filelog().renamed(fctx.filenode())
3315 o = fctx.filelog().renamed(fctx.filenode())
3313 rel = m.rel(abs)
3316 rel = m.rel(abs)
3314 if o:
3317 if o:
3315 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])))
3316 else:
3319 else:
3317 ui.write(_("%s not renamed\n") % rel)
3320 ui.write(_("%s not renamed\n") % rel)
3318
3321
3319 @command('debugrevlog', debugrevlogopts +
3322 @command('debugrevlog', debugrevlogopts +
3320 [('d', 'dump', False, _('dump index data'))],
3323 [('d', 'dump', False, _('dump index data'))],
3321 _('-c|-m|FILE'),
3324 _('-c|-m|FILE'),
3322 optionalrepo=True)
3325 optionalrepo=True)
3323 def debugrevlog(ui, repo, file_=None, **opts):
3326 def debugrevlog(ui, repo, file_=None, **opts):
3324 """show data and statistics about a revlog"""
3327 """show data and statistics about a revlog"""
3325 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3328 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3326
3329
3327 if opts.get("dump"):
3330 if opts.get("dump"):
3328 numrevs = len(r)
3331 numrevs = len(r)
3329 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3332 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3330 " rawsize totalsize compression heads chainlen\n")
3333 " rawsize totalsize compression heads chainlen\n")
3331 ts = 0
3334 ts = 0
3332 heads = set()
3335 heads = set()
3333
3336
3334 for rev in xrange(numrevs):
3337 for rev in xrange(numrevs):
3335 dbase = r.deltaparent(rev)
3338 dbase = r.deltaparent(rev)
3336 if dbase == -1:
3339 if dbase == -1:
3337 dbase = rev
3340 dbase = rev
3338 cbase = r.chainbase(rev)
3341 cbase = r.chainbase(rev)
3339 clen = r.chainlen(rev)
3342 clen = r.chainlen(rev)
3340 p1, p2 = r.parentrevs(rev)
3343 p1, p2 = r.parentrevs(rev)
3341 rs = r.rawsize(rev)
3344 rs = r.rawsize(rev)
3342 ts = ts + rs
3345 ts = ts + rs
3343 heads -= set(r.parentrevs(rev))
3346 heads -= set(r.parentrevs(rev))
3344 heads.add(rev)
3347 heads.add(rev)
3345 try:
3348 try:
3346 compression = ts / r.end(rev)
3349 compression = ts / r.end(rev)
3347 except ZeroDivisionError:
3350 except ZeroDivisionError:
3348 compression = 0
3351 compression = 0
3349 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 "
3350 "%11d %5d %8d\n" %
3353 "%11d %5d %8d\n" %
3351 (rev, p1, p2, r.start(rev), r.end(rev),
3354 (rev, p1, p2, r.start(rev), r.end(rev),
3352 r.start(dbase), r.start(cbase),
3355 r.start(dbase), r.start(cbase),
3353 r.start(p1), r.start(p2),
3356 r.start(p1), r.start(p2),
3354 rs, ts, compression, len(heads), clen))
3357 rs, ts, compression, len(heads), clen))
3355 return 0
3358 return 0
3356
3359
3357 v = r.version
3360 v = r.version
3358 format = v & 0xFFFF
3361 format = v & 0xFFFF
3359 flags = []
3362 flags = []
3360 gdelta = False
3363 gdelta = False
3361 if v & revlog.REVLOGNGINLINEDATA:
3364 if v & revlog.REVLOGNGINLINEDATA:
3362 flags.append('inline')
3365 flags.append('inline')
3363 if v & revlog.REVLOGGENERALDELTA:
3366 if v & revlog.REVLOGGENERALDELTA:
3364 gdelta = True
3367 gdelta = True
3365 flags.append('generaldelta')
3368 flags.append('generaldelta')
3366 if not flags:
3369 if not flags:
3367 flags = ['(none)']
3370 flags = ['(none)']
3368
3371
3369 nummerges = 0
3372 nummerges = 0
3370 numfull = 0
3373 numfull = 0
3371 numprev = 0
3374 numprev = 0
3372 nump1 = 0
3375 nump1 = 0
3373 nump2 = 0
3376 nump2 = 0
3374 numother = 0
3377 numother = 0
3375 nump1prev = 0
3378 nump1prev = 0
3376 nump2prev = 0
3379 nump2prev = 0
3377 chainlengths = []
3380 chainlengths = []
3378
3381
3379 datasize = [None, 0, 0L]
3382 datasize = [None, 0, 0L]
3380 fullsize = [None, 0, 0L]
3383 fullsize = [None, 0, 0L]
3381 deltasize = [None, 0, 0L]
3384 deltasize = [None, 0, 0L]
3382
3385
3383 def addsize(size, l):
3386 def addsize(size, l):
3384 if l[0] is None or size < l[0]:
3387 if l[0] is None or size < l[0]:
3385 l[0] = size
3388 l[0] = size
3386 if size > l[1]:
3389 if size > l[1]:
3387 l[1] = size
3390 l[1] = size
3388 l[2] += size
3391 l[2] += size
3389
3392
3390 numrevs = len(r)
3393 numrevs = len(r)
3391 for rev in xrange(numrevs):
3394 for rev in xrange(numrevs):
3392 p1, p2 = r.parentrevs(rev)
3395 p1, p2 = r.parentrevs(rev)
3393 delta = r.deltaparent(rev)
3396 delta = r.deltaparent(rev)
3394 if format > 0:
3397 if format > 0:
3395 addsize(r.rawsize(rev), datasize)
3398 addsize(r.rawsize(rev), datasize)
3396 if p2 != nullrev:
3399 if p2 != nullrev:
3397 nummerges += 1
3400 nummerges += 1
3398 size = r.length(rev)
3401 size = r.length(rev)
3399 if delta == nullrev:
3402 if delta == nullrev:
3400 chainlengths.append(0)
3403 chainlengths.append(0)
3401 numfull += 1
3404 numfull += 1
3402 addsize(size, fullsize)
3405 addsize(size, fullsize)
3403 else:
3406 else:
3404 chainlengths.append(chainlengths[delta] + 1)
3407 chainlengths.append(chainlengths[delta] + 1)
3405 addsize(size, deltasize)
3408 addsize(size, deltasize)
3406 if delta == rev - 1:
3409 if delta == rev - 1:
3407 numprev += 1
3410 numprev += 1
3408 if delta == p1:
3411 if delta == p1:
3409 nump1prev += 1
3412 nump1prev += 1
3410 elif delta == p2:
3413 elif delta == p2:
3411 nump2prev += 1
3414 nump2prev += 1
3412 elif delta == p1:
3415 elif delta == p1:
3413 nump1 += 1
3416 nump1 += 1
3414 elif delta == p2:
3417 elif delta == p2:
3415 nump2 += 1
3418 nump2 += 1
3416 elif delta != nullrev:
3419 elif delta != nullrev:
3417 numother += 1
3420 numother += 1
3418
3421
3419 # Adjust size min value for empty cases
3422 # Adjust size min value for empty cases
3420 for size in (datasize, fullsize, deltasize):
3423 for size in (datasize, fullsize, deltasize):
3421 if size[0] is None:
3424 if size[0] is None:
3422 size[0] = 0
3425 size[0] = 0
3423
3426
3424 numdeltas = numrevs - numfull
3427 numdeltas = numrevs - numfull
3425 numoprev = numprev - nump1prev - nump2prev
3428 numoprev = numprev - nump1prev - nump2prev
3426 totalrawsize = datasize[2]
3429 totalrawsize = datasize[2]
3427 datasize[2] /= numrevs
3430 datasize[2] /= numrevs
3428 fulltotal = fullsize[2]
3431 fulltotal = fullsize[2]
3429 fullsize[2] /= numfull
3432 fullsize[2] /= numfull
3430 deltatotal = deltasize[2]
3433 deltatotal = deltasize[2]
3431 if numrevs - numfull > 0:
3434 if numrevs - numfull > 0:
3432 deltasize[2] /= numrevs - numfull
3435 deltasize[2] /= numrevs - numfull
3433 totalsize = fulltotal + deltatotal
3436 totalsize = fulltotal + deltatotal
3434 avgchainlen = sum(chainlengths) / numrevs
3437 avgchainlen = sum(chainlengths) / numrevs
3435 maxchainlen = max(chainlengths)
3438 maxchainlen = max(chainlengths)
3436 compratio = 1
3439 compratio = 1
3437 if totalsize:
3440 if totalsize:
3438 compratio = totalrawsize / totalsize
3441 compratio = totalrawsize / totalsize
3439
3442
3440 basedfmtstr = '%%%dd\n'
3443 basedfmtstr = '%%%dd\n'
3441 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3444 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3442
3445
3443 def dfmtstr(max):
3446 def dfmtstr(max):
3444 return basedfmtstr % len(str(max))
3447 return basedfmtstr % len(str(max))
3445 def pcfmtstr(max, padding=0):
3448 def pcfmtstr(max, padding=0):
3446 return basepcfmtstr % (len(str(max)), ' ' * padding)
3449 return basepcfmtstr % (len(str(max)), ' ' * padding)
3447
3450
3448 def pcfmt(value, total):
3451 def pcfmt(value, total):
3449 if total:
3452 if total:
3450 return (value, 100 * float(value) / total)
3453 return (value, 100 * float(value) / total)
3451 else:
3454 else:
3452 return value, 100.0
3455 return value, 100.0
3453
3456
3454 ui.write(('format : %d\n') % format)
3457 ui.write(('format : %d\n') % format)
3455 ui.write(('flags : %s\n') % ', '.join(flags))
3458 ui.write(('flags : %s\n') % ', '.join(flags))
3456
3459
3457 ui.write('\n')
3460 ui.write('\n')
3458 fmt = pcfmtstr(totalsize)
3461 fmt = pcfmtstr(totalsize)
3459 fmt2 = dfmtstr(totalsize)
3462 fmt2 = dfmtstr(totalsize)
3460 ui.write(('revisions : ') + fmt2 % numrevs)
3463 ui.write(('revisions : ') + fmt2 % numrevs)
3461 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3464 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3462 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3465 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3463 ui.write(('revisions : ') + fmt2 % numrevs)
3466 ui.write(('revisions : ') + fmt2 % numrevs)
3464 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3467 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3465 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3468 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3466 ui.write(('revision size : ') + fmt2 % totalsize)
3469 ui.write(('revision size : ') + fmt2 % totalsize)
3467 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3470 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3468 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3471 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3469
3472
3470 ui.write('\n')
3473 ui.write('\n')
3471 fmt = dfmtstr(max(avgchainlen, compratio))
3474 fmt = dfmtstr(max(avgchainlen, compratio))
3472 ui.write(('avg chain length : ') + fmt % avgchainlen)
3475 ui.write(('avg chain length : ') + fmt % avgchainlen)
3473 ui.write(('max chain length : ') + fmt % maxchainlen)
3476 ui.write(('max chain length : ') + fmt % maxchainlen)
3474 ui.write(('compression ratio : ') + fmt % compratio)
3477 ui.write(('compression ratio : ') + fmt % compratio)
3475
3478
3476 if format > 0:
3479 if format > 0:
3477 ui.write('\n')
3480 ui.write('\n')
3478 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')
3479 % tuple(datasize))
3482 % tuple(datasize))
3480 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')
3481 % tuple(fullsize))
3484 % tuple(fullsize))
3482 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3485 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3483 % tuple(deltasize))
3486 % tuple(deltasize))
3484
3487
3485 if numdeltas > 0:
3488 if numdeltas > 0:
3486 ui.write('\n')
3489 ui.write('\n')
3487 fmt = pcfmtstr(numdeltas)
3490 fmt = pcfmtstr(numdeltas)
3488 fmt2 = pcfmtstr(numdeltas, 4)
3491 fmt2 = pcfmtstr(numdeltas, 4)
3489 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3492 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3490 if numprev > 0:
3493 if numprev > 0:
3491 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3494 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3492 numprev))
3495 numprev))
3493 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3496 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3494 numprev))
3497 numprev))
3495 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3498 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3496 numprev))
3499 numprev))
3497 if gdelta:
3500 if gdelta:
3498 ui.write(('deltas against p1 : ')
3501 ui.write(('deltas against p1 : ')
3499 + fmt % pcfmt(nump1, numdeltas))
3502 + fmt % pcfmt(nump1, numdeltas))
3500 ui.write(('deltas against p2 : ')
3503 ui.write(('deltas against p2 : ')
3501 + fmt % pcfmt(nump2, numdeltas))
3504 + fmt % pcfmt(nump2, numdeltas))
3502 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3505 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3503 numdeltas))
3506 numdeltas))
3504
3507
3505 @command('debugrevspec',
3508 @command('debugrevspec',
3506 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3509 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3507 ('REVSPEC'))
3510 ('REVSPEC'))
3508 def debugrevspec(ui, repo, expr, **opts):
3511 def debugrevspec(ui, repo, expr, **opts):
3509 """parse and apply a revision specification
3512 """parse and apply a revision specification
3510
3513
3511 Use --verbose to print the parsed tree before and after aliases
3514 Use --verbose to print the parsed tree before and after aliases
3512 expansion.
3515 expansion.
3513 """
3516 """
3514 if ui.verbose:
3517 if ui.verbose:
3515 tree = revset.parse(expr, lookup=repo.__contains__)
3518 tree = revset.parse(expr, lookup=repo.__contains__)
3516 ui.note(revset.prettyformat(tree), "\n")
3519 ui.note(revset.prettyformat(tree), "\n")
3517 newtree = revset.expandaliases(ui, tree)
3520 newtree = revset.expandaliases(ui, tree)
3518 if newtree != tree:
3521 if newtree != tree:
3519 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3522 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3520 tree = newtree
3523 tree = newtree
3521 newtree = revset.foldconcat(tree)
3524 newtree = revset.foldconcat(tree)
3522 if newtree != tree:
3525 if newtree != tree:
3523 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3526 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3524 if opts["optimize"]:
3527 if opts["optimize"]:
3525 optimizedtree = revset.optimize(newtree)
3528 optimizedtree = revset.optimize(newtree)
3526 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3529 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3527 func = revset.match(ui, expr, repo)
3530 func = revset.match(ui, expr, repo)
3528 revs = func(repo)
3531 revs = func(repo)
3529 if ui.verbose:
3532 if ui.verbose:
3530 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3533 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3531 for c in revs:
3534 for c in revs:
3532 ui.write("%s\n" % c)
3535 ui.write("%s\n" % c)
3533
3536
3534 @command('debugsetparents', [], _('REV1 [REV2]'))
3537 @command('debugsetparents', [], _('REV1 [REV2]'))
3535 def debugsetparents(ui, repo, rev1, rev2=None):
3538 def debugsetparents(ui, repo, rev1, rev2=None):
3536 """manually set the parents of the current working directory
3539 """manually set the parents of the current working directory
3537
3540
3538 This is useful for writing repository conversion tools, but should
3541 This is useful for writing repository conversion tools, but should
3539 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
3540 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
3541 command.
3544 command.
3542
3545
3543 Returns 0 on success.
3546 Returns 0 on success.
3544 """
3547 """
3545
3548
3546 r1 = scmutil.revsingle(repo, rev1).node()
3549 r1 = scmutil.revsingle(repo, rev1).node()
3547 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3550 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3548
3551
3549 with repo.wlock():
3552 with repo.wlock():
3550 repo.setparents(r1, r2)
3553 repo.setparents(r1, r2)
3551
3554
3552 @command('debugdirstate|debugstate',
3555 @command('debugdirstate|debugstate',
3553 [('', 'nodates', None, _('do not display the saved mtime')),
3556 [('', 'nodates', None, _('do not display the saved mtime')),
3554 ('', 'datesort', None, _('sort by saved mtime'))],
3557 ('', 'datesort', None, _('sort by saved mtime'))],
3555 _('[OPTION]...'))
3558 _('[OPTION]...'))
3556 def debugstate(ui, repo, **opts):
3559 def debugstate(ui, repo, **opts):
3557 """show the contents of the current dirstate"""
3560 """show the contents of the current dirstate"""
3558
3561
3559 nodates = opts.get('nodates')
3562 nodates = opts.get('nodates')
3560 datesort = opts.get('datesort')
3563 datesort = opts.get('datesort')
3561
3564
3562 timestr = ""
3565 timestr = ""
3563 if datesort:
3566 if datesort:
3564 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
3565 else:
3568 else:
3566 keyfunc = None # sort by filename
3569 keyfunc = None # sort by filename
3567 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3570 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3568 if ent[3] == -1:
3571 if ent[3] == -1:
3569 timestr = 'unset '
3572 timestr = 'unset '
3570 elif nodates:
3573 elif nodates:
3571 timestr = 'set '
3574 timestr = 'set '
3572 else:
3575 else:
3573 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3576 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3574 time.localtime(ent[3]))
3577 time.localtime(ent[3]))
3575 if ent[1] & 0o20000:
3578 if ent[1] & 0o20000:
3576 mode = 'lnk'
3579 mode = 'lnk'
3577 else:
3580 else:
3578 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3581 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3579 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_))
3580 for f in repo.dirstate.copies():
3583 for f in repo.dirstate.copies():
3581 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3584 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3582
3585
3583 @command('debugsub',
3586 @command('debugsub',
3584 [('r', 'rev', '',
3587 [('r', 'rev', '',
3585 _('revision to check'), _('REV'))],
3588 _('revision to check'), _('REV'))],
3586 _('[-r REV] [REV]'))
3589 _('[-r REV] [REV]'))
3587 def debugsub(ui, repo, rev=None):
3590 def debugsub(ui, repo, rev=None):
3588 ctx = scmutil.revsingle(repo, rev, None)
3591 ctx = scmutil.revsingle(repo, rev, None)
3589 for k, v in sorted(ctx.substate.items()):
3592 for k, v in sorted(ctx.substate.items()):
3590 ui.write(('path %s\n') % k)
3593 ui.write(('path %s\n') % k)
3591 ui.write((' source %s\n') % v[0])
3594 ui.write((' source %s\n') % v[0])
3592 ui.write((' revision %s\n') % v[1])
3595 ui.write((' revision %s\n') % v[1])
3593
3596
3594 @command('debugsuccessorssets',
3597 @command('debugsuccessorssets',
3595 [],
3598 [],
3596 _('[REV]'))
3599 _('[REV]'))
3597 def debugsuccessorssets(ui, repo, *revs):
3600 def debugsuccessorssets(ui, repo, *revs):
3598 """show set of successors for revision
3601 """show set of successors for revision
3599
3602
3600 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
3601 succeed A. It contains non-obsolete changesets only.
3604 succeed A. It contains non-obsolete changesets only.
3602
3605
3603 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
3604 successor (changeset A replaced by A').
3607 successor (changeset A replaced by A').
3605
3608
3606 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".
3607 Such changesets have no successors sets at all.
3610 Such changesets have no successors sets at all.
3608
3611
3609 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
3610 more than one successor.
3613 more than one successor.
3611
3614
3612 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
3613 "divergent". Such changesets have multiple successor sets (each of which
3616 "divergent". Such changesets have multiple successor sets (each of which
3614 may also be split, i.e. have multiple successors).
3617 may also be split, i.e. have multiple successors).
3615
3618
3616 Results are displayed as follows::
3619 Results are displayed as follows::
3617
3620
3618 <rev1>
3621 <rev1>
3619 <successors-1A>
3622 <successors-1A>
3620 <rev2>
3623 <rev2>
3621 <successors-2A>
3624 <successors-2A>
3622 <successors-2B1> <successors-2B2> <successors-2B3>
3625 <successors-2B1> <successors-2B2> <successors-2B3>
3623
3626
3624 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
3625 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
3626 been split).
3629 been split).
3627 """
3630 """
3628 # passed to successorssets caching computation from one call to another
3631 # passed to successorssets caching computation from one call to another
3629 cache = {}
3632 cache = {}
3630 ctx2str = str
3633 ctx2str = str
3631 node2str = short
3634 node2str = short
3632 if ui.debug():
3635 if ui.debug():
3633 def ctx2str(ctx):
3636 def ctx2str(ctx):
3634 return ctx.hex()
3637 return ctx.hex()
3635 node2str = hex
3638 node2str = hex
3636 for rev in scmutil.revrange(repo, revs):
3639 for rev in scmutil.revrange(repo, revs):
3637 ctx = repo[rev]
3640 ctx = repo[rev]
3638 ui.write('%s\n'% ctx2str(ctx))
3641 ui.write('%s\n'% ctx2str(ctx))
3639 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3642 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3640 if succsset:
3643 if succsset:
3641 ui.write(' ')
3644 ui.write(' ')
3642 ui.write(node2str(succsset[0]))
3645 ui.write(node2str(succsset[0]))
3643 for node in succsset[1:]:
3646 for node in succsset[1:]:
3644 ui.write(' ')
3647 ui.write(' ')
3645 ui.write(node2str(node))
3648 ui.write(node2str(node))
3646 ui.write('\n')
3649 ui.write('\n')
3647
3650
3648 @command('debugtemplate',
3651 @command('debugtemplate',
3649 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3652 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3650 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3653 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3651 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3654 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3652 optionalrepo=True)
3655 optionalrepo=True)
3653 def debugtemplate(ui, repo, tmpl, **opts):
3656 def debugtemplate(ui, repo, tmpl, **opts):
3654 """parse and apply a template
3657 """parse and apply a template
3655
3658
3656 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
3657 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
3658 template.
3661 template.
3659
3662
3660 Use --verbose to print the parsed tree.
3663 Use --verbose to print the parsed tree.
3661 """
3664 """
3662 revs = None
3665 revs = None
3663 if opts['rev']:
3666 if opts['rev']:
3664 if repo is None:
3667 if repo is None:
3665 raise error.RepoError(_('there is no Mercurial repository here '
3668 raise error.RepoError(_('there is no Mercurial repository here '
3666 '(.hg not found)'))
3669 '(.hg not found)'))
3667 revs = scmutil.revrange(repo, opts['rev'])
3670 revs = scmutil.revrange(repo, opts['rev'])
3668
3671
3669 props = {}
3672 props = {}
3670 for d in opts['define']:
3673 for d in opts['define']:
3671 try:
3674 try:
3672 k, v = (e.strip() for e in d.split('=', 1))
3675 k, v = (e.strip() for e in d.split('=', 1))
3673 if not k:
3676 if not k:
3674 raise ValueError
3677 raise ValueError
3675 props[k] = v
3678 props[k] = v
3676 except ValueError:
3679 except ValueError:
3677 raise error.Abort(_('malformed keyword definition: %s') % d)
3680 raise error.Abort(_('malformed keyword definition: %s') % d)
3678
3681
3679 if ui.verbose:
3682 if ui.verbose:
3680 aliases = ui.configitems('templatealias')
3683 aliases = ui.configitems('templatealias')
3681 tree = templater.parse(tmpl)
3684 tree = templater.parse(tmpl)
3682 ui.note(templater.prettyformat(tree), '\n')
3685 ui.note(templater.prettyformat(tree), '\n')
3683 newtree = templater.expandaliases(tree, aliases)
3686 newtree = templater.expandaliases(tree, aliases)
3684 if newtree != tree:
3687 if newtree != tree:
3685 ui.note("* expanded:\n", templater.prettyformat(newtree), '\n')
3688 ui.note("* expanded:\n", templater.prettyformat(newtree), '\n')
3686
3689
3687 mapfile = None
3690 mapfile = None
3688 if revs is None:
3691 if revs is None:
3689 k = 'debugtemplate'
3692 k = 'debugtemplate'
3690 t = formatter.maketemplater(ui, k, tmpl)
3693 t = formatter.maketemplater(ui, k, tmpl)
3691 ui.write(templater.stringify(t(k, **props)))
3694 ui.write(templater.stringify(t(k, **props)))
3692 else:
3695 else:
3693 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3696 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3694 mapfile, buffered=False)
3697 mapfile, buffered=False)
3695 for r in revs:
3698 for r in revs:
3696 displayer.show(repo[r], **props)
3699 displayer.show(repo[r], **props)
3697 displayer.close()
3700 displayer.close()
3698
3701
3699 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3702 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3700 def debugwalk(ui, repo, *pats, **opts):
3703 def debugwalk(ui, repo, *pats, **opts):
3701 """show how files match on given patterns"""
3704 """show how files match on given patterns"""
3702 m = scmutil.match(repo[None], pats, opts)
3705 m = scmutil.match(repo[None], pats, opts)
3703 items = list(repo.walk(m))
3706 items = list(repo.walk(m))
3704 if not items:
3707 if not items:
3705 return
3708 return
3706 f = lambda fn: fn
3709 f = lambda fn: fn
3707 if ui.configbool('ui', 'slash') and os.sep != '/':
3710 if ui.configbool('ui', 'slash') and os.sep != '/':
3708 f = lambda fn: util.normpath(fn)
3711 f = lambda fn: util.normpath(fn)
3709 fmt = 'f %%-%ds %%-%ds %%s' % (
3712 fmt = 'f %%-%ds %%-%ds %%s' % (
3710 max([len(abs) for abs in items]),
3713 max([len(abs) for abs in items]),
3711 max([len(m.rel(abs)) for abs in items]))
3714 max([len(m.rel(abs)) for abs in items]))
3712 for abs in items:
3715 for abs in items:
3713 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 '')
3714 ui.write("%s\n" % line.rstrip())
3717 ui.write("%s\n" % line.rstrip())
3715
3718
3716 @command('debugwireargs',
3719 @command('debugwireargs',
3717 [('', 'three', '', 'three'),
3720 [('', 'three', '', 'three'),
3718 ('', 'four', '', 'four'),
3721 ('', 'four', '', 'four'),
3719 ('', 'five', '', 'five'),
3722 ('', 'five', '', 'five'),
3720 ] + remoteopts,
3723 ] + remoteopts,
3721 _('REPO [OPTIONS]... [ONE [TWO]]'),
3724 _('REPO [OPTIONS]... [ONE [TWO]]'),
3722 norepo=True)
3725 norepo=True)
3723 def debugwireargs(ui, repopath, *vals, **opts):
3726 def debugwireargs(ui, repopath, *vals, **opts):
3724 repo = hg.peer(ui, opts, repopath)
3727 repo = hg.peer(ui, opts, repopath)
3725 for opt in remoteopts:
3728 for opt in remoteopts:
3726 del opts[opt[1]]
3729 del opts[opt[1]]
3727 args = {}
3730 args = {}
3728 for k, v in opts.iteritems():
3731 for k, v in opts.iteritems():
3729 if v:
3732 if v:
3730 args[k] = v
3733 args[k] = v
3731 # 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
3732 res1 = repo.debugwireargs(*vals, **args)
3735 res1 = repo.debugwireargs(*vals, **args)
3733 res2 = repo.debugwireargs(*vals, **args)
3736 res2 = repo.debugwireargs(*vals, **args)
3734 ui.write("%s\n" % res1)
3737 ui.write("%s\n" % res1)
3735 if res1 != res2:
3738 if res1 != res2:
3736 ui.warn("%s\n" % res2)
3739 ui.warn("%s\n" % res2)
3737
3740
3738 @command('^diff',
3741 @command('^diff',
3739 [('r', 'rev', [], _('revision'), _('REV')),
3742 [('r', 'rev', [], _('revision'), _('REV')),
3740 ('c', 'change', '', _('change made by revision'), _('REV'))
3743 ('c', 'change', '', _('change made by revision'), _('REV'))
3741 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3744 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3742 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3745 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3743 inferrepo=True)
3746 inferrepo=True)
3744 def diff(ui, repo, *pats, **opts):
3747 def diff(ui, repo, *pats, **opts):
3745 """diff repository (or selected files)
3748 """diff repository (or selected files)
3746
3749
3747 Show differences between revisions for the specified files.
3750 Show differences between revisions for the specified files.
3748
3751
3749 Differences between files are shown using the unified diff format.
3752 Differences between files are shown using the unified diff format.
3750
3753
3751 .. note::
3754 .. note::
3752
3755
3753 :hg:`diff` may generate unexpected results for merges, as it will
3756 :hg:`diff` may generate unexpected results for merges, as it will
3754 default to comparing against the working directory's first
3757 default to comparing against the working directory's first
3755 parent changeset if no revisions are specified.
3758 parent changeset if no revisions are specified.
3756
3759
3757 When two revision arguments are given, then changes are shown
3760 When two revision arguments are given, then changes are shown
3758 between those revisions. If only one revision is specified then
3761 between those revisions. If only one revision is specified then
3759 that revision is compared to the working directory, and, when no
3762 that revision is compared to the working directory, and, when no
3760 revisions are specified, the working directory files are compared
3763 revisions are specified, the working directory files are compared
3761 to its first parent.
3764 to its first parent.
3762
3765
3763 Alternatively you can specify -c/--change with a revision to see
3766 Alternatively you can specify -c/--change with a revision to see
3764 the changes in that changeset relative to its first parent.
3767 the changes in that changeset relative to its first parent.
3765
3768
3766 Without the -a/--text option, diff will avoid generating diffs of
3769 Without the -a/--text option, diff will avoid generating diffs of
3767 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
3768 anyway, probably with undesirable results.
3771 anyway, probably with undesirable results.
3769
3772
3770 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
3771 format. For more information, read :hg:`help diffs`.
3774 format. For more information, read :hg:`help diffs`.
3772
3775
3773 .. container:: verbose
3776 .. container:: verbose
3774
3777
3775 Examples:
3778 Examples:
3776
3779
3777 - compare a file in the current working directory to its parent::
3780 - compare a file in the current working directory to its parent::
3778
3781
3779 hg diff foo.c
3782 hg diff foo.c
3780
3783
3781 - compare two historical versions of a directory, with rename info::
3784 - compare two historical versions of a directory, with rename info::
3782
3785
3783 hg diff --git -r 1.0:1.2 lib/
3786 hg diff --git -r 1.0:1.2 lib/
3784
3787
3785 - get change stats relative to the last change on some date::
3788 - get change stats relative to the last change on some date::
3786
3789
3787 hg diff --stat -r "date('may 2')"
3790 hg diff --stat -r "date('may 2')"
3788
3791
3789 - diff all newly-added files that contain a keyword::
3792 - diff all newly-added files that contain a keyword::
3790
3793
3791 hg diff "set:added() and grep(GNU)"
3794 hg diff "set:added() and grep(GNU)"
3792
3795
3793 - compare a revision and its parents::
3796 - compare a revision and its parents::
3794
3797
3795 hg diff -c 9353 # compare against first parent
3798 hg diff -c 9353 # compare against first parent
3796 hg diff -r 9353^:9353 # same using revset syntax
3799 hg diff -r 9353^:9353 # same using revset syntax
3797 hg diff -r 9353^2:9353 # compare against the second parent
3800 hg diff -r 9353^2:9353 # compare against the second parent
3798
3801
3799 Returns 0 on success.
3802 Returns 0 on success.
3800 """
3803 """
3801
3804
3802 revs = opts.get('rev')
3805 revs = opts.get('rev')
3803 change = opts.get('change')
3806 change = opts.get('change')
3804 stat = opts.get('stat')
3807 stat = opts.get('stat')
3805 reverse = opts.get('reverse')
3808 reverse = opts.get('reverse')
3806
3809
3807 if revs and change:
3810 if revs and change:
3808 msg = _('cannot specify --rev and --change at the same time')
3811 msg = _('cannot specify --rev and --change at the same time')
3809 raise error.Abort(msg)
3812 raise error.Abort(msg)
3810 elif change:
3813 elif change:
3811 node2 = scmutil.revsingle(repo, change, None).node()
3814 node2 = scmutil.revsingle(repo, change, None).node()
3812 node1 = repo[node2].p1().node()
3815 node1 = repo[node2].p1().node()
3813 else:
3816 else:
3814 node1, node2 = scmutil.revpair(repo, revs)
3817 node1, node2 = scmutil.revpair(repo, revs)
3815
3818
3816 if reverse:
3819 if reverse:
3817 node1, node2 = node2, node1
3820 node1, node2 = node2, node1
3818
3821
3819 diffopts = patch.diffallopts(ui, opts)
3822 diffopts = patch.diffallopts(ui, opts)
3820 m = scmutil.match(repo[node2], pats, opts)
3823 m = scmutil.match(repo[node2], pats, opts)
3821 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3824 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3822 listsubrepos=opts.get('subrepos'),
3825 listsubrepos=opts.get('subrepos'),
3823 root=opts.get('root'))
3826 root=opts.get('root'))
3824
3827
3825 @command('^export',
3828 @command('^export',
3826 [('o', 'output', '',
3829 [('o', 'output', '',
3827 _('print output to file with formatted name'), _('FORMAT')),
3830 _('print output to file with formatted name'), _('FORMAT')),
3828 ('', 'switch-parent', None, _('diff against the second parent')),
3831 ('', 'switch-parent', None, _('diff against the second parent')),
3829 ('r', 'rev', [], _('revisions to export'), _('REV')),
3832 ('r', 'rev', [], _('revisions to export'), _('REV')),
3830 ] + diffopts,
3833 ] + diffopts,
3831 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3834 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3832 def export(ui, repo, *changesets, **opts):
3835 def export(ui, repo, *changesets, **opts):
3833 """dump the header and diffs for one or more changesets
3836 """dump the header and diffs for one or more changesets
3834
3837
3835 Print the changeset header and diffs for one or more revisions.
3838 Print the changeset header and diffs for one or more revisions.
3836 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.
3837
3840
3838 The information shown in the changeset header is: author, date,
3841 The information shown in the changeset header is: author, date,
3839 branch name (if non-default), changeset hash, parent(s) and commit
3842 branch name (if non-default), changeset hash, parent(s) and commit
3840 comment.
3843 comment.
3841
3844
3842 .. note::
3845 .. note::
3843
3846
3844 :hg:`export` may generate unexpected diff output for merge
3847 :hg:`export` may generate unexpected diff output for merge
3845 changesets, as it will compare the merge changeset against its
3848 changesets, as it will compare the merge changeset against its
3846 first parent only.
3849 first parent only.
3847
3850
3848 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
3849 given using a format string. The formatting rules are as follows:
3852 given using a format string. The formatting rules are as follows:
3850
3853
3851 :``%%``: literal "%" character
3854 :``%%``: literal "%" character
3852 :``%H``: changeset hash (40 hexadecimal digits)
3855 :``%H``: changeset hash (40 hexadecimal digits)
3853 :``%N``: number of patches being generated
3856 :``%N``: number of patches being generated
3854 :``%R``: changeset revision number
3857 :``%R``: changeset revision number
3855 :``%b``: basename of the exporting repository
3858 :``%b``: basename of the exporting repository
3856 :``%h``: short-form changeset hash (12 hexadecimal digits)
3859 :``%h``: short-form changeset hash (12 hexadecimal digits)
3857 :``%m``: first line of the commit message (only alphanumeric characters)
3860 :``%m``: first line of the commit message (only alphanumeric characters)
3858 :``%n``: zero-padded sequence number, starting at 1
3861 :``%n``: zero-padded sequence number, starting at 1
3859 :``%r``: zero-padded changeset revision number
3862 :``%r``: zero-padded changeset revision number
3860
3863
3861 Without the -a/--text option, export will avoid generating diffs
3864 Without the -a/--text option, export will avoid generating diffs
3862 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
3863 diff anyway, probably with undesirable results.
3866 diff anyway, probably with undesirable results.
3864
3867
3865 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
3866 format. See :hg:`help diffs` for more information.
3869 format. See :hg:`help diffs` for more information.
3867
3870
3868 With the --switch-parent option, the diff will be against the
3871 With the --switch-parent option, the diff will be against the
3869 second parent. It can be useful to review a merge.
3872 second parent. It can be useful to review a merge.
3870
3873
3871 .. container:: verbose
3874 .. container:: verbose
3872
3875
3873 Examples:
3876 Examples:
3874
3877
3875 - use export and import to transplant a bugfix to the current
3878 - use export and import to transplant a bugfix to the current
3876 branch::
3879 branch::
3877
3880
3878 hg export -r 9353 | hg import -
3881 hg export -r 9353 | hg import -
3879
3882
3880 - export all the changesets between two revisions to a file with
3883 - export all the changesets between two revisions to a file with
3881 rename information::
3884 rename information::
3882
3885
3883 hg export --git -r 123:150 > changes.txt
3886 hg export --git -r 123:150 > changes.txt
3884
3887
3885 - split outgoing changes into a series of patches with
3888 - split outgoing changes into a series of patches with
3886 descriptive names::
3889 descriptive names::
3887
3890
3888 hg export -r "outgoing()" -o "%n-%m.patch"
3891 hg export -r "outgoing()" -o "%n-%m.patch"
3889
3892
3890 Returns 0 on success.
3893 Returns 0 on success.
3891 """
3894 """
3892 changesets += tuple(opts.get('rev', []))
3895 changesets += tuple(opts.get('rev', []))
3893 if not changesets:
3896 if not changesets:
3894 changesets = ['.']
3897 changesets = ['.']
3895 revs = scmutil.revrange(repo, changesets)
3898 revs = scmutil.revrange(repo, changesets)
3896 if not revs:
3899 if not revs:
3897 raise error.Abort(_("export requires at least one changeset"))
3900 raise error.Abort(_("export requires at least one changeset"))
3898 if len(revs) > 1:
3901 if len(revs) > 1:
3899 ui.note(_('exporting patches:\n'))
3902 ui.note(_('exporting patches:\n'))
3900 else:
3903 else:
3901 ui.note(_('exporting patch:\n'))
3904 ui.note(_('exporting patch:\n'))
3902 cmdutil.export(repo, revs, template=opts.get('output'),
3905 cmdutil.export(repo, revs, template=opts.get('output'),
3903 switch_parent=opts.get('switch_parent'),
3906 switch_parent=opts.get('switch_parent'),
3904 opts=patch.diffallopts(ui, opts))
3907 opts=patch.diffallopts(ui, opts))
3905
3908
3906 @command('files',
3909 @command('files',
3907 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3910 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3908 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3911 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3909 ] + walkopts + formatteropts + subrepoopts,
3912 ] + walkopts + formatteropts + subrepoopts,
3910 _('[OPTION]... [PATTERN]...'))
3913 _('[OPTION]... [PATTERN]...'))
3911 def files(ui, repo, *pats, **opts):
3914 def files(ui, repo, *pats, **opts):
3912 """list tracked files
3915 """list tracked files
3913
3916
3914 Print files under Mercurial control in the working directory or
3917 Print files under Mercurial control in the working directory or
3915 specified revision whose names match the given patterns (excluding
3918 specified revision whose names match the given patterns (excluding
3916 removed files).
3919 removed files).
3917
3920
3918 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
3919 of all files under Mercurial control in the working directory.
3922 of all files under Mercurial control in the working directory.
3920
3923
3921 .. container:: verbose
3924 .. container:: verbose
3922
3925
3923 Examples:
3926 Examples:
3924
3927
3925 - list all files under the current directory::
3928 - list all files under the current directory::
3926
3929
3927 hg files .
3930 hg files .
3928
3931
3929 - shows sizes and flags for current revision::
3932 - shows sizes and flags for current revision::
3930
3933
3931 hg files -vr .
3934 hg files -vr .
3932
3935
3933 - list all files named README::
3936 - list all files named README::
3934
3937
3935 hg files -I "**/README"
3938 hg files -I "**/README"
3936
3939
3937 - list all binary files::
3940 - list all binary files::
3938
3941
3939 hg files "set:binary()"
3942 hg files "set:binary()"
3940
3943
3941 - find files containing a regular expression::
3944 - find files containing a regular expression::
3942
3945
3943 hg files "set:grep('bob')"
3946 hg files "set:grep('bob')"
3944
3947
3945 - search tracked file contents with xargs and grep::
3948 - search tracked file contents with xargs and grep::
3946
3949
3947 hg files -0 | xargs -0 grep foo
3950 hg files -0 | xargs -0 grep foo
3948
3951
3949 See :hg:`help patterns` and :hg:`help filesets` for more information
3952 See :hg:`help patterns` and :hg:`help filesets` for more information
3950 on specifying file patterns.
3953 on specifying file patterns.
3951
3954
3952 Returns 0 if a match is found, 1 otherwise.
3955 Returns 0 if a match is found, 1 otherwise.
3953
3956
3954 """
3957 """
3955 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3958 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3956
3959
3957 end = '\n'
3960 end = '\n'
3958 if opts.get('print0'):
3961 if opts.get('print0'):
3959 end = '\0'
3962 end = '\0'
3960 fm = ui.formatter('files', opts)
3963 fm = ui.formatter('files', opts)
3961 fmt = '%s' + end
3964 fmt = '%s' + end
3962
3965
3963 m = scmutil.match(ctx, pats, opts)
3966 m = scmutil.match(ctx, pats, opts)
3964 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3967 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3965
3968
3966 fm.end()
3969 fm.end()
3967
3970
3968 return ret
3971 return ret
3969
3972
3970 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3973 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3971 def forget(ui, repo, *pats, **opts):
3974 def forget(ui, repo, *pats, **opts):
3972 """forget the specified files on the next commit
3975 """forget the specified files on the next commit
3973
3976
3974 Mark the specified files so they will no longer be tracked
3977 Mark the specified files so they will no longer be tracked
3975 after the next commit.
3978 after the next commit.
3976
3979
3977 This only removes files from the current branch, not from the
3980 This only removes files from the current branch, not from the
3978 entire project history, and it does not delete them from the
3981 entire project history, and it does not delete them from the
3979 working directory.
3982 working directory.
3980
3983
3981 To delete the file from the working directory, see :hg:`remove`.
3984 To delete the file from the working directory, see :hg:`remove`.
3982
3985
3983 To undo a forget before the next commit, see :hg:`add`.
3986 To undo a forget before the next commit, see :hg:`add`.
3984
3987
3985 .. container:: verbose
3988 .. container:: verbose
3986
3989
3987 Examples:
3990 Examples:
3988
3991
3989 - forget newly-added binary files::
3992 - forget newly-added binary files::
3990
3993
3991 hg forget "set:added() and binary()"
3994 hg forget "set:added() and binary()"
3992
3995
3993 - forget files that would be excluded by .hgignore::
3996 - forget files that would be excluded by .hgignore::
3994
3997
3995 hg forget "set:hgignore()"
3998 hg forget "set:hgignore()"
3996
3999
3997 Returns 0 on success.
4000 Returns 0 on success.
3998 """
4001 """
3999
4002
4000 if not pats:
4003 if not pats:
4001 raise error.Abort(_('no files specified'))
4004 raise error.Abort(_('no files specified'))
4002
4005
4003 m = scmutil.match(repo[None], pats, opts)
4006 m = scmutil.match(repo[None], pats, opts)
4004 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4007 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
4005 return rejected and 1 or 0
4008 return rejected and 1 or 0
4006
4009
4007 @command(
4010 @command(
4008 'graft',
4011 'graft',
4009 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4012 [('r', 'rev', [], _('revisions to graft'), _('REV')),
4010 ('c', 'continue', False, _('resume interrupted graft')),
4013 ('c', 'continue', False, _('resume interrupted graft')),
4011 ('e', 'edit', False, _('invoke editor on commit messages')),
4014 ('e', 'edit', False, _('invoke editor on commit messages')),
4012 ('', 'log', None, _('append graft info to log message')),
4015 ('', 'log', None, _('append graft info to log message')),
4013 ('f', 'force', False, _('force graft')),
4016 ('f', 'force', False, _('force graft')),
4014 ('D', 'currentdate', False,
4017 ('D', 'currentdate', False,
4015 _('record the current date as commit date')),
4018 _('record the current date as commit date')),
4016 ('U', 'currentuser', False,
4019 ('U', 'currentuser', False,
4017 _('record the current user as committer'), _('DATE'))]
4020 _('record the current user as committer'), _('DATE'))]
4018 + commitopts2 + mergetoolopts + dryrunopts,
4021 + commitopts2 + mergetoolopts + dryrunopts,
4019 _('[OPTION]... [-r REV]... REV...'))
4022 _('[OPTION]... [-r REV]... REV...'))
4020 def graft(ui, repo, *revs, **opts):
4023 def graft(ui, repo, *revs, **opts):
4021 '''copy changes from other branches onto the current branch
4024 '''copy changes from other branches onto the current branch
4022
4025
4023 This command uses Mercurial's merge logic to copy individual
4026 This command uses Mercurial's merge logic to copy individual
4024 changes from other branches without merging branches in the
4027 changes from other branches without merging branches in the
4025 history graph. This is sometimes known as 'backporting' or
4028 history graph. This is sometimes known as 'backporting' or
4026 'cherry-picking'. By default, graft will copy user, date, and
4029 'cherry-picking'. By default, graft will copy user, date, and
4027 description from the source changesets.
4030 description from the source changesets.
4028
4031
4029 Changesets that are ancestors of the current revision, that have
4032 Changesets that are ancestors of the current revision, that have
4030 already been grafted, or that are merges will be skipped.
4033 already been grafted, or that are merges will be skipped.
4031
4034
4032 If --log is specified, log messages will have a comment appended
4035 If --log is specified, log messages will have a comment appended
4033 of the form::
4036 of the form::
4034
4037
4035 (grafted from CHANGESETHASH)
4038 (grafted from CHANGESETHASH)
4036
4039
4037 If --force is specified, revisions will be grafted even if they
4040 If --force is specified, revisions will be grafted even if they
4038 are already ancestors of or have been grafted to the destination.
4041 are already ancestors of or have been grafted to the destination.
4039 This is useful when the revisions have since been backed out.
4042 This is useful when the revisions have since been backed out.
4040
4043
4041 If a graft merge results in conflicts, the graft process is
4044 If a graft merge results in conflicts, the graft process is
4042 interrupted so that the current merge can be manually resolved.
4045 interrupted so that the current merge can be manually resolved.
4043 Once all conflicts are addressed, the graft process can be
4046 Once all conflicts are addressed, the graft process can be
4044 continued with the -c/--continue option.
4047 continued with the -c/--continue option.
4045
4048
4046 .. note::
4049 .. note::
4047
4050
4048 The -c/--continue option does not reapply earlier options, except
4051 The -c/--continue option does not reapply earlier options, except
4049 for --force.
4052 for --force.
4050
4053
4051 .. container:: verbose
4054 .. container:: verbose
4052
4055
4053 Examples:
4056 Examples:
4054
4057
4055 - 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::
4056
4059
4057 hg update stable
4060 hg update stable
4058 hg graft --edit 9393
4061 hg graft --edit 9393
4059
4062
4060 - graft a range of changesets with one exception, updating dates::
4063 - graft a range of changesets with one exception, updating dates::
4061
4064
4062 hg graft -D "2085::2093 and not 2091"
4065 hg graft -D "2085::2093 and not 2091"
4063
4066
4064 - continue a graft after resolving conflicts::
4067 - continue a graft after resolving conflicts::
4065
4068
4066 hg graft -c
4069 hg graft -c
4067
4070
4068 - show the source of a grafted changeset::
4071 - show the source of a grafted changeset::
4069
4072
4070 hg log --debug -r .
4073 hg log --debug -r .
4071
4074
4072 - show revisions sorted by date::
4075 - show revisions sorted by date::
4073
4076
4074 hg log -r "sort(all(), date)"
4077 hg log -r "sort(all(), date)"
4075
4078
4076 See :hg:`help revisions` and :hg:`help revsets` for more about
4079 See :hg:`help revisions` and :hg:`help revsets` for more about
4077 specifying revisions.
4080 specifying revisions.
4078
4081
4079 Returns 0 on successful completion.
4082 Returns 0 on successful completion.
4080 '''
4083 '''
4081 with repo.wlock():
4084 with repo.wlock():
4082 return _dograft(ui, repo, *revs, **opts)
4085 return _dograft(ui, repo, *revs, **opts)
4083
4086
4084 def _dograft(ui, repo, *revs, **opts):
4087 def _dograft(ui, repo, *revs, **opts):
4085 if revs and opts['rev']:
4088 if revs and opts['rev']:
4086 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4089 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4087 'revision ordering!\n'))
4090 'revision ordering!\n'))
4088
4091
4089 revs = list(revs)
4092 revs = list(revs)
4090 revs.extend(opts['rev'])
4093 revs.extend(opts['rev'])
4091
4094
4092 if not opts.get('user') and opts.get('currentuser'):
4095 if not opts.get('user') and opts.get('currentuser'):
4093 opts['user'] = ui.username()
4096 opts['user'] = ui.username()
4094 if not opts.get('date') and opts.get('currentdate'):
4097 if not opts.get('date') and opts.get('currentdate'):
4095 opts['date'] = "%d %d" % util.makedate()
4098 opts['date'] = "%d %d" % util.makedate()
4096
4099
4097 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4100 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4098
4101
4099 cont = False
4102 cont = False
4100 if opts['continue']:
4103 if opts['continue']:
4101 cont = True
4104 cont = True
4102 if revs:
4105 if revs:
4103 raise error.Abort(_("can't specify --continue and revisions"))
4106 raise error.Abort(_("can't specify --continue and revisions"))
4104 # read in unfinished revisions
4107 # read in unfinished revisions
4105 try:
4108 try:
4106 nodes = repo.vfs.read('graftstate').splitlines()
4109 nodes = repo.vfs.read('graftstate').splitlines()
4107 revs = [repo[node].rev() for node in nodes]
4110 revs = [repo[node].rev() for node in nodes]
4108 except IOError as inst:
4111 except IOError as inst:
4109 if inst.errno != errno.ENOENT:
4112 if inst.errno != errno.ENOENT:
4110 raise
4113 raise
4111 cmdutil.wrongtooltocontinue(repo, _('graft'))
4114 cmdutil.wrongtooltocontinue(repo, _('graft'))
4112 else:
4115 else:
4113 cmdutil.checkunfinished(repo)
4116 cmdutil.checkunfinished(repo)
4114 cmdutil.bailifchanged(repo)
4117 cmdutil.bailifchanged(repo)
4115 if not revs:
4118 if not revs:
4116 raise error.Abort(_('no revisions specified'))
4119 raise error.Abort(_('no revisions specified'))
4117 revs = scmutil.revrange(repo, revs)
4120 revs = scmutil.revrange(repo, revs)
4118
4121
4119 skipped = set()
4122 skipped = set()
4120 # check for merges
4123 # check for merges
4121 for rev in repo.revs('%ld and merge()', revs):
4124 for rev in repo.revs('%ld and merge()', revs):
4122 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4125 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4123 skipped.add(rev)
4126 skipped.add(rev)
4124 revs = [r for r in revs if r not in skipped]
4127 revs = [r for r in revs if r not in skipped]
4125 if not revs:
4128 if not revs:
4126 return -1
4129 return -1
4127
4130
4128 # 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
4129 # --continues. That's because without --force, any revisions we decided to
4132 # --continues. That's because without --force, any revisions we decided to
4130 # 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
4131 # 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
4132 # 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
4133 # already, they'd have been in the graftstate.
4136 # already, they'd have been in the graftstate.
4134 if not (cont or opts.get('force')):
4137 if not (cont or opts.get('force')):
4135 # check for ancestors of dest branch
4138 # check for ancestors of dest branch
4136 crev = repo['.'].rev()
4139 crev = repo['.'].rev()
4137 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4140 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4138 # 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.
4139 # XXX make this lazy in the future
4142 # XXX make this lazy in the future
4140 revs = list(revs)
4143 revs = list(revs)
4141 # don't mutate while iterating, create a copy
4144 # don't mutate while iterating, create a copy
4142 for rev in list(revs):
4145 for rev in list(revs):
4143 if rev in ancestors:
4146 if rev in ancestors:
4144 ui.warn(_('skipping ancestor revision %d:%s\n') %
4147 ui.warn(_('skipping ancestor revision %d:%s\n') %
4145 (rev, repo[rev]))
4148 (rev, repo[rev]))
4146 # XXX remove on list is slow
4149 # XXX remove on list is slow
4147 revs.remove(rev)
4150 revs.remove(rev)
4148 if not revs:
4151 if not revs:
4149 return -1
4152 return -1
4150
4153
4151 # analyze revs for earlier grafts
4154 # analyze revs for earlier grafts
4152 ids = {}
4155 ids = {}
4153 for ctx in repo.set("%ld", revs):
4156 for ctx in repo.set("%ld", revs):
4154 ids[ctx.hex()] = ctx.rev()
4157 ids[ctx.hex()] = ctx.rev()
4155 n = ctx.extra().get('source')
4158 n = ctx.extra().get('source')
4156 if n:
4159 if n:
4157 ids[n] = ctx.rev()
4160 ids[n] = ctx.rev()
4158
4161
4159 # check ancestors for earlier grafts
4162 # check ancestors for earlier grafts
4160 ui.debug('scanning for duplicate grafts\n')
4163 ui.debug('scanning for duplicate grafts\n')
4161
4164
4162 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4165 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4163 ctx = repo[rev]
4166 ctx = repo[rev]
4164 n = ctx.extra().get('source')
4167 n = ctx.extra().get('source')
4165 if n in ids:
4168 if n in ids:
4166 try:
4169 try:
4167 r = repo[n].rev()
4170 r = repo[n].rev()
4168 except error.RepoLookupError:
4171 except error.RepoLookupError:
4169 r = None
4172 r = None
4170 if r in revs:
4173 if r in revs:
4171 ui.warn(_('skipping revision %d:%s '
4174 ui.warn(_('skipping revision %d:%s '
4172 '(already grafted to %d:%s)\n')
4175 '(already grafted to %d:%s)\n')
4173 % (r, repo[r], rev, ctx))
4176 % (r, repo[r], rev, ctx))
4174 revs.remove(r)
4177 revs.remove(r)
4175 elif ids[n] in revs:
4178 elif ids[n] in revs:
4176 if r is None:
4179 if r is None:
4177 ui.warn(_('skipping already grafted revision %d:%s '
4180 ui.warn(_('skipping already grafted revision %d:%s '
4178 '(%d:%s also has unknown origin %s)\n')
4181 '(%d:%s also has unknown origin %s)\n')
4179 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4182 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4180 else:
4183 else:
4181 ui.warn(_('skipping already grafted revision %d:%s '
4184 ui.warn(_('skipping already grafted revision %d:%s '
4182 '(%d:%s also has origin %d:%s)\n')
4185 '(%d:%s also has origin %d:%s)\n')
4183 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4186 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4184 revs.remove(ids[n])
4187 revs.remove(ids[n])
4185 elif ctx.hex() in ids:
4188 elif ctx.hex() in ids:
4186 r = ids[ctx.hex()]
4189 r = ids[ctx.hex()]
4187 ui.warn(_('skipping already grafted revision %d:%s '
4190 ui.warn(_('skipping already grafted revision %d:%s '
4188 '(was grafted from %d:%s)\n') %
4191 '(was grafted from %d:%s)\n') %
4189 (r, repo[r], rev, ctx))
4192 (r, repo[r], rev, ctx))
4190 revs.remove(r)
4193 revs.remove(r)
4191 if not revs:
4194 if not revs:
4192 return -1
4195 return -1
4193
4196
4194 for pos, ctx in enumerate(repo.set("%ld", revs)):
4197 for pos, ctx in enumerate(repo.set("%ld", revs)):
4195 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4198 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4196 ctx.description().split('\n', 1)[0])
4199 ctx.description().split('\n', 1)[0])
4197 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4200 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4198 if names:
4201 if names:
4199 desc += ' (%s)' % ' '.join(names)
4202 desc += ' (%s)' % ' '.join(names)
4200 ui.status(_('grafting %s\n') % desc)
4203 ui.status(_('grafting %s\n') % desc)
4201 if opts.get('dry_run'):
4204 if opts.get('dry_run'):
4202 continue
4205 continue
4203
4206
4204 source = ctx.extra().get('source')
4207 source = ctx.extra().get('source')
4205 extra = {}
4208 extra = {}
4206 if source:
4209 if source:
4207 extra['source'] = source
4210 extra['source'] = source
4208 extra['intermediate-source'] = ctx.hex()
4211 extra['intermediate-source'] = ctx.hex()
4209 else:
4212 else:
4210 extra['source'] = ctx.hex()
4213 extra['source'] = ctx.hex()
4211 user = ctx.user()
4214 user = ctx.user()
4212 if opts.get('user'):
4215 if opts.get('user'):
4213 user = opts['user']
4216 user = opts['user']
4214 date = ctx.date()
4217 date = ctx.date()
4215 if opts.get('date'):
4218 if opts.get('date'):
4216 date = opts['date']
4219 date = opts['date']
4217 message = ctx.description()
4220 message = ctx.description()
4218 if opts.get('log'):
4221 if opts.get('log'):
4219 message += '\n(grafted from %s)' % ctx.hex()
4222 message += '\n(grafted from %s)' % ctx.hex()
4220
4223
4221 # we don't merge the first commit when continuing
4224 # we don't merge the first commit when continuing
4222 if not cont:
4225 if not cont:
4223 # perform the graft merge with p1(rev) as 'ancestor'
4226 # perform the graft merge with p1(rev) as 'ancestor'
4224 try:
4227 try:
4225 # ui.forcemerge is an internal variable, do not document
4228 # ui.forcemerge is an internal variable, do not document
4226 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4229 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4227 'graft')
4230 'graft')
4228 stats = mergemod.graft(repo, ctx, ctx.p1(),
4231 stats = mergemod.graft(repo, ctx, ctx.p1(),
4229 ['local', 'graft'])
4232 ['local', 'graft'])
4230 finally:
4233 finally:
4231 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4234 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4232 # report any conflicts
4235 # report any conflicts
4233 if stats and stats[3] > 0:
4236 if stats and stats[3] > 0:
4234 # write out state for --continue
4237 # write out state for --continue
4235 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4238 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4236 repo.vfs.write('graftstate', ''.join(nodelines))
4239 repo.vfs.write('graftstate', ''.join(nodelines))
4237 extra = ''
4240 extra = ''
4238 if opts.get('user'):
4241 if opts.get('user'):
4239 extra += ' --user %s' % util.shellquote(opts['user'])
4242 extra += ' --user %s' % util.shellquote(opts['user'])
4240 if opts.get('date'):
4243 if opts.get('date'):
4241 extra += ' --date %s' % util.shellquote(opts['date'])
4244 extra += ' --date %s' % util.shellquote(opts['date'])
4242 if opts.get('log'):
4245 if opts.get('log'):
4243 extra += ' --log'
4246 extra += ' --log'
4244 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4247 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
4245 raise error.Abort(
4248 raise error.Abort(
4246 _("unresolved conflicts, can't continue"),
4249 _("unresolved conflicts, can't continue"),
4247 hint=hint)
4250 hint=hint)
4248 else:
4251 else:
4249 cont = False
4252 cont = False
4250
4253
4251 # commit
4254 # commit
4252 node = repo.commit(text=message, user=user,
4255 node = repo.commit(text=message, user=user,
4253 date=date, extra=extra, editor=editor)
4256 date=date, extra=extra, editor=editor)
4254 if node is None:
4257 if node is None:
4255 ui.warn(
4258 ui.warn(
4256 _('note: graft of %d:%s created no changes to commit\n') %
4259 _('note: graft of %d:%s created no changes to commit\n') %
4257 (ctx.rev(), ctx))
4260 (ctx.rev(), ctx))
4258
4261
4259 # remove state when we complete successfully
4262 # remove state when we complete successfully
4260 if not opts.get('dry_run'):
4263 if not opts.get('dry_run'):
4261 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4264 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4262
4265
4263 return 0
4266 return 0
4264
4267
4265 @command('grep',
4268 @command('grep',
4266 [('0', 'print0', None, _('end fields with NUL')),
4269 [('0', 'print0', None, _('end fields with NUL')),
4267 ('', 'all', None, _('print all revisions that match')),
4270 ('', 'all', None, _('print all revisions that match')),
4268 ('a', 'text', None, _('treat all files as text')),
4271 ('a', 'text', None, _('treat all files as text')),
4269 ('f', 'follow', None,
4272 ('f', 'follow', None,
4270 _('follow changeset history,'
4273 _('follow changeset history,'
4271 ' or file history across copies and renames')),
4274 ' or file history across copies and renames')),
4272 ('i', 'ignore-case', None, _('ignore case when matching')),
4275 ('i', 'ignore-case', None, _('ignore case when matching')),
4273 ('l', 'files-with-matches', None,
4276 ('l', 'files-with-matches', None,
4274 _('print only filenames and revisions that match')),
4277 _('print only filenames and revisions that match')),
4275 ('n', 'line-number', None, _('print matching line numbers')),
4278 ('n', 'line-number', None, _('print matching line numbers')),
4276 ('r', 'rev', [],
4279 ('r', 'rev', [],
4277 _('only search files changed within revision range'), _('REV')),
4280 _('only search files changed within revision range'), _('REV')),
4278 ('u', 'user', None, _('list the author (long with -v)')),
4281 ('u', 'user', None, _('list the author (long with -v)')),
4279 ('d', 'date', None, _('list the date (short with -q)')),
4282 ('d', 'date', None, _('list the date (short with -q)')),
4280 ] + walkopts,
4283 ] + walkopts,
4281 _('[OPTION]... PATTERN [FILE]...'),
4284 _('[OPTION]... PATTERN [FILE]...'),
4282 inferrepo=True)
4285 inferrepo=True)
4283 def grep(ui, repo, pattern, *pats, **opts):
4286 def grep(ui, repo, pattern, *pats, **opts):
4284 """search for a pattern in specified files and revisions
4287 """search for a pattern in specified files and revisions
4285
4288
4286 Search revisions of files for a regular expression.
4289 Search revisions of files for a regular expression.
4287
4290
4288 This command behaves differently than Unix grep. It only accepts
4291 This command behaves differently than Unix grep. It only accepts
4289 Python/Perl regexps. It searches repository history, not the
4292 Python/Perl regexps. It searches repository history, not the
4290 working directory. It always prints the revision number in which a
4293 working directory. It always prints the revision number in which a
4291 match appears.
4294 match appears.
4292
4295
4293 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
4294 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
4295 that contains a change in match status ("-" for a match that
4298 that contains a change in match status ("-" for a match that
4296 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),
4297 use the --all flag.
4300 use the --all flag.
4298
4301
4299 Returns 0 if a match is found, 1 otherwise.
4302 Returns 0 if a match is found, 1 otherwise.
4300 """
4303 """
4301 reflags = re.M
4304 reflags = re.M
4302 if opts.get('ignore_case'):
4305 if opts.get('ignore_case'):
4303 reflags |= re.I
4306 reflags |= re.I
4304 try:
4307 try:
4305 regexp = util.re.compile(pattern, reflags)
4308 regexp = util.re.compile(pattern, reflags)
4306 except re.error as inst:
4309 except re.error as inst:
4307 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4310 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4308 return 1
4311 return 1
4309 sep, eol = ':', '\n'
4312 sep, eol = ':', '\n'
4310 if opts.get('print0'):
4313 if opts.get('print0'):
4311 sep = eol = '\0'
4314 sep = eol = '\0'
4312
4315
4313 getfile = util.lrucachefunc(repo.file)
4316 getfile = util.lrucachefunc(repo.file)
4314
4317
4315 def matchlines(body):
4318 def matchlines(body):
4316 begin = 0
4319 begin = 0
4317 linenum = 0
4320 linenum = 0
4318 while begin < len(body):
4321 while begin < len(body):
4319 match = regexp.search(body, begin)
4322 match = regexp.search(body, begin)
4320 if not match:
4323 if not match:
4321 break
4324 break
4322 mstart, mend = match.span()
4325 mstart, mend = match.span()
4323 linenum += body.count('\n', begin, mstart) + 1
4326 linenum += body.count('\n', begin, mstart) + 1
4324 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4327 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4325 begin = body.find('\n', mend) + 1 or len(body) + 1
4328 begin = body.find('\n', mend) + 1 or len(body) + 1
4326 lend = begin - 1
4329 lend = begin - 1
4327 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4330 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4328
4331
4329 class linestate(object):
4332 class linestate(object):
4330 def __init__(self, line, linenum, colstart, colend):
4333 def __init__(self, line, linenum, colstart, colend):
4331 self.line = line
4334 self.line = line
4332 self.linenum = linenum
4335 self.linenum = linenum
4333 self.colstart = colstart
4336 self.colstart = colstart
4334 self.colend = colend
4337 self.colend = colend
4335
4338
4336 def __hash__(self):
4339 def __hash__(self):
4337 return hash((self.linenum, self.line))
4340 return hash((self.linenum, self.line))
4338
4341
4339 def __eq__(self, other):
4342 def __eq__(self, other):
4340 return self.line == other.line
4343 return self.line == other.line
4341
4344
4342 def __iter__(self):
4345 def __iter__(self):
4343 yield (self.line[:self.colstart], '')
4346 yield (self.line[:self.colstart], '')
4344 yield (self.line[self.colstart:self.colend], 'grep.match')
4347 yield (self.line[self.colstart:self.colend], 'grep.match')
4345 rest = self.line[self.colend:]
4348 rest = self.line[self.colend:]
4346 while rest != '':
4349 while rest != '':
4347 match = regexp.search(rest)
4350 match = regexp.search(rest)
4348 if not match:
4351 if not match:
4349 yield (rest, '')
4352 yield (rest, '')
4350 break
4353 break
4351 mstart, mend = match.span()
4354 mstart, mend = match.span()
4352 yield (rest[:mstart], '')
4355 yield (rest[:mstart], '')
4353 yield (rest[mstart:mend], 'grep.match')
4356 yield (rest[mstart:mend], 'grep.match')
4354 rest = rest[mend:]
4357 rest = rest[mend:]
4355
4358
4356 matches = {}
4359 matches = {}
4357 copies = {}
4360 copies = {}
4358 def grepbody(fn, rev, body):
4361 def grepbody(fn, rev, body):
4359 matches[rev].setdefault(fn, [])
4362 matches[rev].setdefault(fn, [])
4360 m = matches[rev][fn]
4363 m = matches[rev][fn]
4361 for lnum, cstart, cend, line in matchlines(body):
4364 for lnum, cstart, cend, line in matchlines(body):
4362 s = linestate(line, lnum, cstart, cend)
4365 s = linestate(line, lnum, cstart, cend)
4363 m.append(s)
4366 m.append(s)
4364
4367
4365 def difflinestates(a, b):
4368 def difflinestates(a, b):
4366 sm = difflib.SequenceMatcher(None, a, b)
4369 sm = difflib.SequenceMatcher(None, a, b)
4367 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4370 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4368 if tag == 'insert':
4371 if tag == 'insert':
4369 for i in xrange(blo, bhi):
4372 for i in xrange(blo, bhi):
4370 yield ('+', b[i])
4373 yield ('+', b[i])
4371 elif tag == 'delete':
4374 elif tag == 'delete':
4372 for i in xrange(alo, ahi):
4375 for i in xrange(alo, ahi):
4373 yield ('-', a[i])
4376 yield ('-', a[i])
4374 elif tag == 'replace':
4377 elif tag == 'replace':
4375 for i in xrange(alo, ahi):
4378 for i in xrange(alo, ahi):
4376 yield ('-', a[i])
4379 yield ('-', a[i])
4377 for i in xrange(blo, bhi):
4380 for i in xrange(blo, bhi):
4378 yield ('+', b[i])
4381 yield ('+', b[i])
4379
4382
4380 def display(fn, ctx, pstates, states):
4383 def display(fn, ctx, pstates, states):
4381 rev = ctx.rev()
4384 rev = ctx.rev()
4382 if ui.quiet:
4385 if ui.quiet:
4383 datefunc = util.shortdate
4386 datefunc = util.shortdate
4384 else:
4387 else:
4385 datefunc = util.datestr
4388 datefunc = util.datestr
4386 found = False
4389 found = False
4387 @util.cachefunc
4390 @util.cachefunc
4388 def binary():
4391 def binary():
4389 flog = getfile(fn)
4392 flog = getfile(fn)
4390 return util.binary(flog.read(ctx.filenode(fn)))
4393 return util.binary(flog.read(ctx.filenode(fn)))
4391
4394
4392 if opts.get('all'):
4395 if opts.get('all'):
4393 iter = difflinestates(pstates, states)
4396 iter = difflinestates(pstates, states)
4394 else:
4397 else:
4395 iter = [('', l) for l in states]
4398 iter = [('', l) for l in states]
4396 for change, l in iter:
4399 for change, l in iter:
4397 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4400 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4398
4401
4399 if opts.get('line_number'):
4402 if opts.get('line_number'):
4400 cols.append((str(l.linenum), 'grep.linenumber'))
4403 cols.append((str(l.linenum), 'grep.linenumber'))
4401 if opts.get('all'):
4404 if opts.get('all'):
4402 cols.append((change, 'grep.change'))
4405 cols.append((change, 'grep.change'))
4403 if opts.get('user'):
4406 if opts.get('user'):
4404 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4407 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4405 if opts.get('date'):
4408 if opts.get('date'):
4406 cols.append((datefunc(ctx.date()), 'grep.date'))
4409 cols.append((datefunc(ctx.date()), 'grep.date'))
4407 for col, label in cols[:-1]:
4410 for col, label in cols[:-1]:
4408 ui.write(col, label=label)
4411 ui.write(col, label=label)
4409 ui.write(sep, label='grep.sep')
4412 ui.write(sep, label='grep.sep')
4410 ui.write(cols[-1][0], label=cols[-1][1])
4413 ui.write(cols[-1][0], label=cols[-1][1])
4411 if not opts.get('files_with_matches'):
4414 if not opts.get('files_with_matches'):
4412 ui.write(sep, label='grep.sep')
4415 ui.write(sep, label='grep.sep')
4413 if not opts.get('text') and binary():
4416 if not opts.get('text') and binary():
4414 ui.write(_(" Binary file matches"))
4417 ui.write(_(" Binary file matches"))
4415 else:
4418 else:
4416 for s, label in l:
4419 for s, label in l:
4417 ui.write(s, label=label)
4420 ui.write(s, label=label)
4418 ui.write(eol)
4421 ui.write(eol)
4419 found = True
4422 found = True
4420 if opts.get('files_with_matches'):
4423 if opts.get('files_with_matches'):
4421 break
4424 break
4422 return found
4425 return found
4423
4426
4424 skip = {}
4427 skip = {}
4425 revfiles = {}
4428 revfiles = {}
4426 matchfn = scmutil.match(repo[None], pats, opts)
4429 matchfn = scmutil.match(repo[None], pats, opts)
4427 found = False
4430 found = False
4428 follow = opts.get('follow')
4431 follow = opts.get('follow')
4429
4432
4430 def prep(ctx, fns):
4433 def prep(ctx, fns):
4431 rev = ctx.rev()
4434 rev = ctx.rev()
4432 pctx = ctx.p1()
4435 pctx = ctx.p1()
4433 parent = pctx.rev()
4436 parent = pctx.rev()
4434 matches.setdefault(rev, {})
4437 matches.setdefault(rev, {})
4435 matches.setdefault(parent, {})
4438 matches.setdefault(parent, {})
4436 files = revfiles.setdefault(rev, [])
4439 files = revfiles.setdefault(rev, [])
4437 for fn in fns:
4440 for fn in fns:
4438 flog = getfile(fn)
4441 flog = getfile(fn)
4439 try:
4442 try:
4440 fnode = ctx.filenode(fn)
4443 fnode = ctx.filenode(fn)
4441 except error.LookupError:
4444 except error.LookupError:
4442 continue
4445 continue
4443
4446
4444 copied = flog.renamed(fnode)
4447 copied = flog.renamed(fnode)
4445 copy = follow and copied and copied[0]
4448 copy = follow and copied and copied[0]
4446 if copy:
4449 if copy:
4447 copies.setdefault(rev, {})[fn] = copy
4450 copies.setdefault(rev, {})[fn] = copy
4448 if fn in skip:
4451 if fn in skip:
4449 if copy:
4452 if copy:
4450 skip[copy] = True
4453 skip[copy] = True
4451 continue
4454 continue
4452 files.append(fn)
4455 files.append(fn)
4453
4456
4454 if fn not in matches[rev]:
4457 if fn not in matches[rev]:
4455 grepbody(fn, rev, flog.read(fnode))
4458 grepbody(fn, rev, flog.read(fnode))
4456
4459
4457 pfn = copy or fn
4460 pfn = copy or fn
4458 if pfn not in matches[parent]:
4461 if pfn not in matches[parent]:
4459 try:
4462 try:
4460 fnode = pctx.filenode(pfn)
4463 fnode = pctx.filenode(pfn)
4461 grepbody(pfn, parent, flog.read(fnode))
4464 grepbody(pfn, parent, flog.read(fnode))
4462 except error.LookupError:
4465 except error.LookupError:
4463 pass
4466 pass
4464
4467
4465 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4468 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4466 rev = ctx.rev()
4469 rev = ctx.rev()
4467 parent = ctx.p1().rev()
4470 parent = ctx.p1().rev()
4468 for fn in sorted(revfiles.get(rev, [])):
4471 for fn in sorted(revfiles.get(rev, [])):
4469 states = matches[rev][fn]
4472 states = matches[rev][fn]
4470 copy = copies.get(rev, {}).get(fn)
4473 copy = copies.get(rev, {}).get(fn)
4471 if fn in skip:
4474 if fn in skip:
4472 if copy:
4475 if copy:
4473 skip[copy] = True
4476 skip[copy] = True
4474 continue
4477 continue
4475 pstates = matches.get(parent, {}).get(copy or fn, [])
4478 pstates = matches.get(parent, {}).get(copy or fn, [])
4476 if pstates or states:
4479 if pstates or states:
4477 r = display(fn, ctx, pstates, states)
4480 r = display(fn, ctx, pstates, states)
4478 found = found or r
4481 found = found or r
4479 if r and not opts.get('all'):
4482 if r and not opts.get('all'):
4480 skip[fn] = True
4483 skip[fn] = True
4481 if copy:
4484 if copy:
4482 skip[copy] = True
4485 skip[copy] = True
4483 del matches[rev]
4486 del matches[rev]
4484 del revfiles[rev]
4487 del revfiles[rev]
4485
4488
4486 return not found
4489 return not found
4487
4490
4488 @command('heads',
4491 @command('heads',
4489 [('r', 'rev', '',
4492 [('r', 'rev', '',
4490 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4493 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4491 ('t', 'topo', False, _('show topological heads only')),
4494 ('t', 'topo', False, _('show topological heads only')),
4492 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4495 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4493 ('c', 'closed', False, _('show normal and closed branch heads')),
4496 ('c', 'closed', False, _('show normal and closed branch heads')),
4494 ] + templateopts,
4497 ] + templateopts,
4495 _('[-ct] [-r STARTREV] [REV]...'))
4498 _('[-ct] [-r STARTREV] [REV]...'))
4496 def heads(ui, repo, *branchrevs, **opts):
4499 def heads(ui, repo, *branchrevs, **opts):
4497 """show branch heads
4500 """show branch heads
4498
4501
4499 With no arguments, show all open branch heads in the repository.
4502 With no arguments, show all open branch heads in the repository.
4500 Branch heads are changesets that have no descendants on the
4503 Branch heads are changesets that have no descendants on the
4501 same branch. They are where development generally takes place and
4504 same branch. They are where development generally takes place and
4502 are the usual targets for update and merge operations.
4505 are the usual targets for update and merge operations.
4503
4506
4504 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
4505 branches associated with the specified changesets are shown. This
4508 branches associated with the specified changesets are shown. This
4506 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
4507 currently checked-out branch.
4510 currently checked-out branch.
4508
4511
4509 If -c/--closed is specified, also show branch heads marked closed
4512 If -c/--closed is specified, also show branch heads marked closed
4510 (see :hg:`commit --close-branch`).
4513 (see :hg:`commit --close-branch`).
4511
4514
4512 If STARTREV is specified, only those heads that are descendants of
4515 If STARTREV is specified, only those heads that are descendants of
4513 STARTREV will be displayed.
4516 STARTREV will be displayed.
4514
4517
4515 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
4516 topological heads (changesets with no children) will be shown.
4519 topological heads (changesets with no children) will be shown.
4517
4520
4518 Returns 0 if matching heads are found, 1 if not.
4521 Returns 0 if matching heads are found, 1 if not.
4519 """
4522 """
4520
4523
4521 start = None
4524 start = None
4522 if 'rev' in opts:
4525 if 'rev' in opts:
4523 start = scmutil.revsingle(repo, opts['rev'], None).node()
4526 start = scmutil.revsingle(repo, opts['rev'], None).node()
4524
4527
4525 if opts.get('topo'):
4528 if opts.get('topo'):
4526 heads = [repo[h] for h in repo.heads(start)]
4529 heads = [repo[h] for h in repo.heads(start)]
4527 else:
4530 else:
4528 heads = []
4531 heads = []
4529 for branch in repo.branchmap():
4532 for branch in repo.branchmap():
4530 heads += repo.branchheads(branch, start, opts.get('closed'))
4533 heads += repo.branchheads(branch, start, opts.get('closed'))
4531 heads = [repo[h] for h in heads]
4534 heads = [repo[h] for h in heads]
4532
4535
4533 if branchrevs:
4536 if branchrevs:
4534 branches = set(repo[br].branch() for br in branchrevs)
4537 branches = set(repo[br].branch() for br in branchrevs)
4535 heads = [h for h in heads if h.branch() in branches]
4538 heads = [h for h in heads if h.branch() in branches]
4536
4539
4537 if opts.get('active') and branchrevs:
4540 if opts.get('active') and branchrevs:
4538 dagheads = repo.heads(start)
4541 dagheads = repo.heads(start)
4539 heads = [h for h in heads if h.node() in dagheads]
4542 heads = [h for h in heads if h.node() in dagheads]
4540
4543
4541 if branchrevs:
4544 if branchrevs:
4542 haveheads = set(h.branch() for h in heads)
4545 haveheads = set(h.branch() for h in heads)
4543 if branches - haveheads:
4546 if branches - haveheads:
4544 headless = ', '.join(b for b in branches - haveheads)
4547 headless = ', '.join(b for b in branches - haveheads)
4545 msg = _('no open branch heads found on branches %s')
4548 msg = _('no open branch heads found on branches %s')
4546 if opts.get('rev'):
4549 if opts.get('rev'):
4547 msg += _(' (started at %s)') % opts['rev']
4550 msg += _(' (started at %s)') % opts['rev']
4548 ui.warn((msg + '\n') % headless)
4551 ui.warn((msg + '\n') % headless)
4549
4552
4550 if not heads:
4553 if not heads:
4551 return 1
4554 return 1
4552
4555
4553 heads = sorted(heads, key=lambda x: -x.rev())
4556 heads = sorted(heads, key=lambda x: -x.rev())
4554 displayer = cmdutil.show_changeset(ui, repo, opts)
4557 displayer = cmdutil.show_changeset(ui, repo, opts)
4555 for ctx in heads:
4558 for ctx in heads:
4556 displayer.show(ctx)
4559 displayer.show(ctx)
4557 displayer.close()
4560 displayer.close()
4558
4561
4559 @command('help',
4562 @command('help',
4560 [('e', 'extension', None, _('show only help for extensions')),
4563 [('e', 'extension', None, _('show only help for extensions')),
4561 ('c', 'command', None, _('show only help for commands')),
4564 ('c', 'command', None, _('show only help for commands')),
4562 ('k', 'keyword', None, _('show topics matching keyword')),
4565 ('k', 'keyword', None, _('show topics matching keyword')),
4563 ('s', 'system', [], _('show help for specific platform(s)')),
4566 ('s', 'system', [], _('show help for specific platform(s)')),
4564 ],
4567 ],
4565 _('[-ecks] [TOPIC]'),
4568 _('[-ecks] [TOPIC]'),
4566 norepo=True)
4569 norepo=True)
4567 def help_(ui, name=None, **opts):
4570 def help_(ui, name=None, **opts):
4568 """show help for a given topic or a help overview
4571 """show help for a given topic or a help overview
4569
4572
4570 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.
4571
4574
4572 Given a topic, extension, or command name, print help for that
4575 Given a topic, extension, or command name, print help for that
4573 topic.
4576 topic.
4574
4577
4575 Returns 0 if successful.
4578 Returns 0 if successful.
4576 """
4579 """
4577
4580
4578 textwidth = ui.configint('ui', 'textwidth', 78)
4581 textwidth = ui.configint('ui', 'textwidth', 78)
4579 termwidth = ui.termwidth() - 2
4582 termwidth = ui.termwidth() - 2
4580 if textwidth <= 0 or termwidth < textwidth:
4583 if textwidth <= 0 or termwidth < textwidth:
4581 textwidth = termwidth
4584 textwidth = termwidth
4582
4585
4583 keep = opts.get('system') or []
4586 keep = opts.get('system') or []
4584 if len(keep) == 0:
4587 if len(keep) == 0:
4585 if sys.platform.startswith('win'):
4588 if sys.platform.startswith('win'):
4586 keep.append('windows')
4589 keep.append('windows')
4587 elif sys.platform == 'OpenVMS':
4590 elif sys.platform == 'OpenVMS':
4588 keep.append('vms')
4591 keep.append('vms')
4589 elif sys.platform == 'plan9':
4592 elif sys.platform == 'plan9':
4590 keep.append('plan9')
4593 keep.append('plan9')
4591 else:
4594 else:
4592 keep.append('unix')
4595 keep.append('unix')
4593 keep.append(sys.platform.lower())
4596 keep.append(sys.platform.lower())
4594 if ui.verbose:
4597 if ui.verbose:
4595 keep.append('verbose')
4598 keep.append('verbose')
4596
4599
4597 section = None
4600 section = None
4598 subtopic = None
4601 subtopic = None
4599 if name and '.' in name:
4602 if name and '.' in name:
4600 name, section = name.split('.', 1)
4603 name, section = name.split('.', 1)
4601 section = encoding.lower(section)
4604 section = encoding.lower(section)
4602 if '.' in section:
4605 if '.' in section:
4603 subtopic, section = section.split('.', 1)
4606 subtopic, section = section.split('.', 1)
4604 else:
4607 else:
4605 subtopic = section
4608 subtopic = section
4606
4609
4607 text = help.help_(ui, name, subtopic=subtopic, **opts)
4610 text = help.help_(ui, name, subtopic=subtopic, **opts)
4608
4611
4609 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4612 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4610 section=section)
4613 section=section)
4611
4614
4612 # 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
4613 # 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"
4614 # because bar isn't a section of foo
4617 # because bar isn't a section of foo
4615 if section and not (formatted and name):
4618 if section and not (formatted and name):
4616 raise error.Abort(_("help section not found"))
4619 raise error.Abort(_("help section not found"))
4617
4620
4618 if 'verbose' in pruned:
4621 if 'verbose' in pruned:
4619 keep.append('omitted')
4622 keep.append('omitted')
4620 else:
4623 else:
4621 keep.append('notomitted')
4624 keep.append('notomitted')
4622 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4625 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4623 section=section)
4626 section=section)
4624 ui.write(formatted)
4627 ui.write(formatted)
4625
4628
4626
4629
4627 @command('identify|id',
4630 @command('identify|id',
4628 [('r', 'rev', '',
4631 [('r', 'rev', '',
4629 _('identify the specified revision'), _('REV')),
4632 _('identify the specified revision'), _('REV')),
4630 ('n', 'num', None, _('show local revision number')),
4633 ('n', 'num', None, _('show local revision number')),
4631 ('i', 'id', None, _('show global revision id')),
4634 ('i', 'id', None, _('show global revision id')),
4632 ('b', 'branch', None, _('show branch')),
4635 ('b', 'branch', None, _('show branch')),
4633 ('t', 'tags', None, _('show tags')),
4636 ('t', 'tags', None, _('show tags')),
4634 ('B', 'bookmarks', None, _('show bookmarks')),
4637 ('B', 'bookmarks', None, _('show bookmarks')),
4635 ] + remoteopts,
4638 ] + remoteopts,
4636 _('[-nibtB] [-r REV] [SOURCE]'),
4639 _('[-nibtB] [-r REV] [SOURCE]'),
4637 optionalrepo=True)
4640 optionalrepo=True)
4638 def identify(ui, repo, source=None, rev=None,
4641 def identify(ui, repo, source=None, rev=None,
4639 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4642 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4640 """identify the working directory or specified revision
4643 """identify the working directory or specified revision
4641
4644
4642 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
4643 two parent hash identifiers, followed by a "+" if the working
4646 two parent hash identifiers, followed by a "+" if the working
4644 directory has uncommitted changes, the branch name (if not default),
4647 directory has uncommitted changes, the branch name (if not default),
4645 a list of tags, and a list of bookmarks.
4648 a list of tags, and a list of bookmarks.
4646
4649
4647 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
4648 repository.
4651 repository.
4649
4652
4650 Specifying a path to a repository root or Mercurial bundle will
4653 Specifying a path to a repository root or Mercurial bundle will
4651 cause lookup to operate on that repository/bundle.
4654 cause lookup to operate on that repository/bundle.
4652
4655
4653 .. container:: verbose
4656 .. container:: verbose
4654
4657
4655 Examples:
4658 Examples:
4656
4659
4657 - generate a build identifier for the working directory::
4660 - generate a build identifier for the working directory::
4658
4661
4659 hg id --id > build-id.dat
4662 hg id --id > build-id.dat
4660
4663
4661 - find the revision corresponding to a tag::
4664 - find the revision corresponding to a tag::
4662
4665
4663 hg id -n -r 1.3
4666 hg id -n -r 1.3
4664
4667
4665 - check the most recent revision of a remote repository::
4668 - check the most recent revision of a remote repository::
4666
4669
4667 hg id -r tip http://selenic.com/hg/
4670 hg id -r tip http://selenic.com/hg/
4668
4671
4669 See :hg:`log` for generating more information about specific revisions,
4672 See :hg:`log` for generating more information about specific revisions,
4670 including full hash identifiers.
4673 including full hash identifiers.
4671
4674
4672 Returns 0 if successful.
4675 Returns 0 if successful.
4673 """
4676 """
4674
4677
4675 if not repo and not source:
4678 if not repo and not source:
4676 raise error.Abort(_("there is no Mercurial repository here "
4679 raise error.Abort(_("there is no Mercurial repository here "
4677 "(.hg not found)"))
4680 "(.hg not found)"))
4678
4681
4679 if ui.debugflag:
4682 if ui.debugflag:
4680 hexfunc = hex
4683 hexfunc = hex
4681 else:
4684 else:
4682 hexfunc = short
4685 hexfunc = short
4683 default = not (num or id or branch or tags or bookmarks)
4686 default = not (num or id or branch or tags or bookmarks)
4684 output = []
4687 output = []
4685 revs = []
4688 revs = []
4686
4689
4687 if source:
4690 if source:
4688 source, branches = hg.parseurl(ui.expandpath(source))
4691 source, branches = hg.parseurl(ui.expandpath(source))
4689 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
4690 repo = peer.local()
4693 repo = peer.local()
4691 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4694 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4692
4695
4693 if not repo:
4696 if not repo:
4694 if num or branch or tags:
4697 if num or branch or tags:
4695 raise error.Abort(
4698 raise error.Abort(
4696 _("can't query remote revision number, branch, or tags"))
4699 _("can't query remote revision number, branch, or tags"))
4697 if not rev and revs:
4700 if not rev and revs:
4698 rev = revs[0]
4701 rev = revs[0]
4699 if not rev:
4702 if not rev:
4700 rev = "tip"
4703 rev = "tip"
4701
4704
4702 remoterev = peer.lookup(rev)
4705 remoterev = peer.lookup(rev)
4703 if default or id:
4706 if default or id:
4704 output = [hexfunc(remoterev)]
4707 output = [hexfunc(remoterev)]
4705
4708
4706 def getbms():
4709 def getbms():
4707 bms = []
4710 bms = []
4708
4711
4709 if 'bookmarks' in peer.listkeys('namespaces'):
4712 if 'bookmarks' in peer.listkeys('namespaces'):
4710 hexremoterev = hex(remoterev)
4713 hexremoterev = hex(remoterev)
4711 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4714 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4712 if bmr == hexremoterev]
4715 if bmr == hexremoterev]
4713
4716
4714 return sorted(bms)
4717 return sorted(bms)
4715
4718
4716 if bookmarks:
4719 if bookmarks:
4717 output.extend(getbms())
4720 output.extend(getbms())
4718 elif default and not ui.quiet:
4721 elif default and not ui.quiet:
4719 # multiple bookmarks for a single parent separated by '/'
4722 # multiple bookmarks for a single parent separated by '/'
4720 bm = '/'.join(getbms())
4723 bm = '/'.join(getbms())
4721 if bm:
4724 if bm:
4722 output.append(bm)
4725 output.append(bm)
4723 else:
4726 else:
4724 ctx = scmutil.revsingle(repo, rev, None)
4727 ctx = scmutil.revsingle(repo, rev, None)
4725
4728
4726 if ctx.rev() is None:
4729 if ctx.rev() is None:
4727 ctx = repo[None]
4730 ctx = repo[None]
4728 parents = ctx.parents()
4731 parents = ctx.parents()
4729 taglist = []
4732 taglist = []
4730 for p in parents:
4733 for p in parents:
4731 taglist.extend(p.tags())
4734 taglist.extend(p.tags())
4732
4735
4733 changed = ""
4736 changed = ""
4734 if default or id or num:
4737 if default or id or num:
4735 if (any(repo.status())
4738 if (any(repo.status())
4736 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4739 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4737 changed = '+'
4740 changed = '+'
4738 if default or id:
4741 if default or id:
4739 output = ["%s%s" %
4742 output = ["%s%s" %
4740 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4743 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4741 if num:
4744 if num:
4742 output.append("%s%s" %
4745 output.append("%s%s" %
4743 ('+'.join([str(p.rev()) for p in parents]), changed))
4746 ('+'.join([str(p.rev()) for p in parents]), changed))
4744 else:
4747 else:
4745 if default or id:
4748 if default or id:
4746 output = [hexfunc(ctx.node())]
4749 output = [hexfunc(ctx.node())]
4747 if num:
4750 if num:
4748 output.append(str(ctx.rev()))
4751 output.append(str(ctx.rev()))
4749 taglist = ctx.tags()
4752 taglist = ctx.tags()
4750
4753
4751 if default and not ui.quiet:
4754 if default and not ui.quiet:
4752 b = ctx.branch()
4755 b = ctx.branch()
4753 if b != 'default':
4756 if b != 'default':
4754 output.append("(%s)" % b)
4757 output.append("(%s)" % b)
4755
4758
4756 # multiple tags for a single parent separated by '/'
4759 # multiple tags for a single parent separated by '/'
4757 t = '/'.join(taglist)
4760 t = '/'.join(taglist)
4758 if t:
4761 if t:
4759 output.append(t)
4762 output.append(t)
4760
4763
4761 # multiple bookmarks for a single parent separated by '/'
4764 # multiple bookmarks for a single parent separated by '/'
4762 bm = '/'.join(ctx.bookmarks())
4765 bm = '/'.join(ctx.bookmarks())
4763 if bm:
4766 if bm:
4764 output.append(bm)
4767 output.append(bm)
4765 else:
4768 else:
4766 if branch:
4769 if branch:
4767 output.append(ctx.branch())
4770 output.append(ctx.branch())
4768
4771
4769 if tags:
4772 if tags:
4770 output.extend(taglist)
4773 output.extend(taglist)
4771
4774
4772 if bookmarks:
4775 if bookmarks:
4773 output.extend(ctx.bookmarks())
4776 output.extend(ctx.bookmarks())
4774
4777
4775 ui.write("%s\n" % ' '.join(output))
4778 ui.write("%s\n" % ' '.join(output))
4776
4779
4777 @command('import|patch',
4780 @command('import|patch',
4778 [('p', 'strip', 1,
4781 [('p', 'strip', 1,
4779 _('directory strip option for patch. This has the same '
4782 _('directory strip option for patch. This has the same '
4780 'meaning as the corresponding patch option'), _('NUM')),
4783 'meaning as the corresponding patch option'), _('NUM')),
4781 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4784 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4782 ('e', 'edit', False, _('invoke editor on commit messages')),
4785 ('e', 'edit', False, _('invoke editor on commit messages')),
4783 ('f', 'force', None,
4786 ('f', 'force', None,
4784 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4787 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4785 ('', 'no-commit', None,
4788 ('', 'no-commit', None,
4786 _("don't commit, just update the working directory")),
4789 _("don't commit, just update the working directory")),
4787 ('', 'bypass', None,
4790 ('', 'bypass', None,
4788 _("apply patch without touching the working directory")),
4791 _("apply patch without touching the working directory")),
4789 ('', 'partial', None,
4792 ('', 'partial', None,
4790 _('commit even if some hunks fail')),
4793 _('commit even if some hunks fail')),
4791 ('', 'exact', None,
4794 ('', 'exact', None,
4792 _('abort if patch would apply lossily')),
4795 _('abort if patch would apply lossily')),
4793 ('', 'prefix', '',
4796 ('', 'prefix', '',
4794 _('apply patch to subdirectory'), _('DIR')),
4797 _('apply patch to subdirectory'), _('DIR')),
4795 ('', 'import-branch', None,
4798 ('', 'import-branch', None,
4796 _('use any branch information in patch (implied by --exact)'))] +
4799 _('use any branch information in patch (implied by --exact)'))] +
4797 commitopts + commitopts2 + similarityopts,
4800 commitopts + commitopts2 + similarityopts,
4798 _('[OPTION]... PATCH...'))
4801 _('[OPTION]... PATCH...'))
4799 def import_(ui, repo, patch1=None, *patches, **opts):
4802 def import_(ui, repo, patch1=None, *patches, **opts):
4800 """import an ordered set of patches
4803 """import an ordered set of patches
4801
4804
4802 Import a list of patches and commit them individually (unless
4805 Import a list of patches and commit them individually (unless
4803 --no-commit is specified).
4806 --no-commit is specified).
4804
4807
4805 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
4806 a URL is specified, the patch will be downloaded from there.
4809 a URL is specified, the patch will be downloaded from there.
4807
4810
4808 Import first applies changes to the working directory (unless
4811 Import first applies changes to the working directory (unless
4809 --bypass is specified), import will abort if there are outstanding
4812 --bypass is specified), import will abort if there are outstanding
4810 changes.
4813 changes.
4811
4814
4812 Use --bypass to apply and commit patches directly to the
4815 Use --bypass to apply and commit patches directly to the
4813 repository, without affecting the working directory. Without
4816 repository, without affecting the working directory. Without
4814 --exact, patches will be applied on top of the working directory
4817 --exact, patches will be applied on top of the working directory
4815 parent revision.
4818 parent revision.
4816
4819
4817 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
4818 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
4819 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
4820 message are used as default committer and commit message. All
4823 message are used as default committer and commit message. All
4821 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
4822 message.
4825 message.
4823
4826
4824 If the imported patch was generated by :hg:`export`, user and
4827 If the imported patch was generated by :hg:`export`, user and
4825 description from patch override values from message headers and
4828 description from patch override values from message headers and
4826 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
4827 override these.
4830 override these.
4828
4831
4829 If --exact is specified, import will set the working directory to
4832 If --exact is specified, import will set the working directory to
4830 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
4831 resulting changeset has a different ID than the one recorded in
4834 resulting changeset has a different ID than the one recorded in
4832 the patch. This will guard against various ways that portable
4835 the patch. This will guard against various ways that portable
4833 patch formats and mail systems might fail to transfer Mercurial
4836 patch formats and mail systems might fail to transfer Mercurial
4834 data or metadata. See ':hg: bundle' for lossless transmission.
4837 data or metadata. See ':hg: bundle' for lossless transmission.
4835
4838
4836 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
4837 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
4838 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
4839 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
4840 changeset. This flag exists to let people import patches that
4843 changeset. This flag exists to let people import patches that
4841 partially apply without losing the associated metadata (author,
4844 partially apply without losing the associated metadata (author,
4842 date, description, ...).
4845 date, description, ...).
4843
4846
4844 .. note::
4847 .. note::
4845
4848
4846 When no hunks apply cleanly, :hg:`import --partial` will create
4849 When no hunks apply cleanly, :hg:`import --partial` will create
4847 an empty changeset, importing only the patch metadata.
4850 an empty changeset, importing only the patch metadata.
4848
4851
4849 With -s/--similarity, hg will attempt to discover renames and
4852 With -s/--similarity, hg will attempt to discover renames and
4850 copies in the patch in the same way as :hg:`addremove`.
4853 copies in the patch in the same way as :hg:`addremove`.
4851
4854
4852 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
4853 by setting the ``ui.patch`` configuration option. For the default
4856 by setting the ``ui.patch`` configuration option. For the default
4854 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4857 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4855 See :hg:`help config` for more information about configuration
4858 See :hg:`help config` for more information about configuration
4856 files and how to use these options.
4859 files and how to use these options.
4857
4860
4858 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.
4859
4862
4860 .. container:: verbose
4863 .. container:: verbose
4861
4864
4862 Examples:
4865 Examples:
4863
4866
4864 - import a traditional patch from a website and detect renames::
4867 - import a traditional patch from a website and detect renames::
4865
4868
4866 hg import -s 80 http://example.com/bugfix.patch
4869 hg import -s 80 http://example.com/bugfix.patch
4867
4870
4868 - import a changeset from an hgweb server::
4871 - import a changeset from an hgweb server::
4869
4872
4870 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4873 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4871
4874
4872 - import all the patches in an Unix-style mbox::
4875 - import all the patches in an Unix-style mbox::
4873
4876
4874 hg import incoming-patches.mbox
4877 hg import incoming-patches.mbox
4875
4878
4876 - attempt to exactly restore an exported changeset (not always
4879 - attempt to exactly restore an exported changeset (not always
4877 possible)::
4880 possible)::
4878
4881
4879 hg import --exact proposed-fix.patch
4882 hg import --exact proposed-fix.patch
4880
4883
4881 - 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
4882 the default internal tool.
4885 the default internal tool.
4883
4886
4884 hg import --config ui.patch="patch --merge" fuzzy.patch
4887 hg import --config ui.patch="patch --merge" fuzzy.patch
4885
4888
4886 - change the default fuzzing from 2 to a less strict 7
4889 - change the default fuzzing from 2 to a less strict 7
4887
4890
4888 hg import --config ui.fuzz=7 fuzz.patch
4891 hg import --config ui.fuzz=7 fuzz.patch
4889
4892
4890 Returns 0 on success, 1 on partial success (see --partial).
4893 Returns 0 on success, 1 on partial success (see --partial).
4891 """
4894 """
4892
4895
4893 if not patch1:
4896 if not patch1:
4894 raise error.Abort(_('need at least one patch to import'))
4897 raise error.Abort(_('need at least one patch to import'))
4895
4898
4896 patches = (patch1,) + patches
4899 patches = (patch1,) + patches
4897
4900
4898 date = opts.get('date')
4901 date = opts.get('date')
4899 if date:
4902 if date:
4900 opts['date'] = util.parsedate(date)
4903 opts['date'] = util.parsedate(date)
4901
4904
4902 exact = opts.get('exact')
4905 exact = opts.get('exact')
4903 update = not opts.get('bypass')
4906 update = not opts.get('bypass')
4904 if not update and opts.get('no_commit'):
4907 if not update and opts.get('no_commit'):
4905 raise error.Abort(_('cannot use --no-commit with --bypass'))
4908 raise error.Abort(_('cannot use --no-commit with --bypass'))
4906 try:
4909 try:
4907 sim = float(opts.get('similarity') or 0)
4910 sim = float(opts.get('similarity') or 0)
4908 except ValueError:
4911 except ValueError:
4909 raise error.Abort(_('similarity must be a number'))
4912 raise error.Abort(_('similarity must be a number'))
4910 if sim < 0 or sim > 100:
4913 if sim < 0 or sim > 100:
4911 raise error.Abort(_('similarity must be between 0 and 100'))
4914 raise error.Abort(_('similarity must be between 0 and 100'))
4912 if sim and not update:
4915 if sim and not update:
4913 raise error.Abort(_('cannot use --similarity with --bypass'))
4916 raise error.Abort(_('cannot use --similarity with --bypass'))
4914 if exact:
4917 if exact:
4915 if opts.get('edit'):
4918 if opts.get('edit'):
4916 raise error.Abort(_('cannot use --exact with --edit'))
4919 raise error.Abort(_('cannot use --exact with --edit'))
4917 if opts.get('prefix'):
4920 if opts.get('prefix'):
4918 raise error.Abort(_('cannot use --exact with --prefix'))
4921 raise error.Abort(_('cannot use --exact with --prefix'))
4919
4922
4920 base = opts["base"]
4923 base = opts["base"]
4921 wlock = dsguard = lock = tr = None
4924 wlock = dsguard = lock = tr = None
4922 msgs = []
4925 msgs = []
4923 ret = 0
4926 ret = 0
4924
4927
4925
4928
4926 try:
4929 try:
4927 wlock = repo.wlock()
4930 wlock = repo.wlock()
4928
4931
4929 if update:
4932 if update:
4930 cmdutil.checkunfinished(repo)
4933 cmdutil.checkunfinished(repo)
4931 if (exact or not opts.get('force')):
4934 if (exact or not opts.get('force')):
4932 cmdutil.bailifchanged(repo)
4935 cmdutil.bailifchanged(repo)
4933
4936
4934 if not opts.get('no_commit'):
4937 if not opts.get('no_commit'):
4935 lock = repo.lock()
4938 lock = repo.lock()
4936 tr = repo.transaction('import')
4939 tr = repo.transaction('import')
4937 else:
4940 else:
4938 dsguard = cmdutil.dirstateguard(repo, 'import')
4941 dsguard = cmdutil.dirstateguard(repo, 'import')
4939 parents = repo[None].parents()
4942 parents = repo[None].parents()
4940 for patchurl in patches:
4943 for patchurl in patches:
4941 if patchurl == '-':
4944 if patchurl == '-':
4942 ui.status(_('applying patch from stdin\n'))
4945 ui.status(_('applying patch from stdin\n'))
4943 patchfile = ui.fin
4946 patchfile = ui.fin
4944 patchurl = 'stdin' # for error message
4947 patchurl = 'stdin' # for error message
4945 else:
4948 else:
4946 patchurl = os.path.join(base, patchurl)
4949 patchurl = os.path.join(base, patchurl)
4947 ui.status(_('applying %s\n') % patchurl)
4950 ui.status(_('applying %s\n') % patchurl)
4948 patchfile = hg.openpath(ui, patchurl)
4951 patchfile = hg.openpath(ui, patchurl)
4949
4952
4950 haspatch = False
4953 haspatch = False
4951 for hunk in patch.split(patchfile):
4954 for hunk in patch.split(patchfile):
4952 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4955 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4953 parents, opts,
4956 parents, opts,
4954 msgs, hg.clean)
4957 msgs, hg.clean)
4955 if msg:
4958 if msg:
4956 haspatch = True
4959 haspatch = True
4957 ui.note(msg + '\n')
4960 ui.note(msg + '\n')
4958 if update or exact:
4961 if update or exact:
4959 parents = repo[None].parents()
4962 parents = repo[None].parents()
4960 else:
4963 else:
4961 parents = [repo[node]]
4964 parents = [repo[node]]
4962 if rej:
4965 if rej:
4963 ui.write_err(_("patch applied partially\n"))
4966 ui.write_err(_("patch applied partially\n"))
4964 ui.write_err(_("(fix the .rej files and run "
4967 ui.write_err(_("(fix the .rej files and run "
4965 "`hg commit --amend`)\n"))
4968 "`hg commit --amend`)\n"))
4966 ret = 1
4969 ret = 1
4967 break
4970 break
4968
4971
4969 if not haspatch:
4972 if not haspatch:
4970 raise error.Abort(_('%s: no diffs found') % patchurl)
4973 raise error.Abort(_('%s: no diffs found') % patchurl)
4971
4974
4972 if tr:
4975 if tr:
4973 tr.close()
4976 tr.close()
4974 if msgs:
4977 if msgs:
4975 repo.savecommitmessage('\n* * *\n'.join(msgs))
4978 repo.savecommitmessage('\n* * *\n'.join(msgs))
4976 if dsguard:
4979 if dsguard:
4977 dsguard.close()
4980 dsguard.close()
4978 return ret
4981 return ret
4979 finally:
4982 finally:
4980 if tr:
4983 if tr:
4981 tr.release()
4984 tr.release()
4982 release(lock, dsguard, wlock)
4985 release(lock, dsguard, wlock)
4983
4986
4984 @command('incoming|in',
4987 @command('incoming|in',
4985 [('f', 'force', None,
4988 [('f', 'force', None,
4986 _('run even if remote repository is unrelated')),
4989 _('run even if remote repository is unrelated')),
4987 ('n', 'newest-first', None, _('show newest record first')),
4990 ('n', 'newest-first', None, _('show newest record first')),
4988 ('', 'bundle', '',
4991 ('', 'bundle', '',
4989 _('file to store the bundles into'), _('FILE')),
4992 _('file to store the bundles into'), _('FILE')),
4990 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4993 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4991 ('B', 'bookmarks', False, _("compare bookmarks")),
4994 ('B', 'bookmarks', False, _("compare bookmarks")),
4992 ('b', 'branch', [],
4995 ('b', 'branch', [],
4993 _('a specific branch you would like to pull'), _('BRANCH')),
4996 _('a specific branch you would like to pull'), _('BRANCH')),
4994 ] + logopts + remoteopts + subrepoopts,
4997 ] + logopts + remoteopts + subrepoopts,
4995 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4998 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4996 def incoming(ui, repo, source="default", **opts):
4999 def incoming(ui, repo, source="default", **opts):
4997 """show new changesets found in source
5000 """show new changesets found in source
4998
5001
4999 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
5000 pull location. These are the changesets that would have been pulled
5003 pull location. These are the changesets that would have been pulled
5001 if a pull at the time you issued this command.
5004 if a pull at the time you issued this command.
5002
5005
5003 See pull for valid source format details.
5006 See pull for valid source format details.
5004
5007
5005 .. container:: verbose
5008 .. container:: verbose
5006
5009
5007 With -B/--bookmarks, the result of bookmark comparison between
5010 With -B/--bookmarks, the result of bookmark comparison between
5008 local and remote repositories is displayed. With -v/--verbose,
5011 local and remote repositories is displayed. With -v/--verbose,
5009 status is also displayed for each bookmark like below::
5012 status is also displayed for each bookmark like below::
5010
5013
5011 BM1 01234567890a added
5014 BM1 01234567890a added
5012 BM2 1234567890ab advanced
5015 BM2 1234567890ab advanced
5013 BM3 234567890abc diverged
5016 BM3 234567890abc diverged
5014 BM4 34567890abcd changed
5017 BM4 34567890abcd changed
5015
5018
5016 The action taken locally when pulling depends on the
5019 The action taken locally when pulling depends on the
5017 status of each bookmark:
5020 status of each bookmark:
5018
5021
5019 :``added``: pull will create it
5022 :``added``: pull will create it
5020 :``advanced``: pull will update it
5023 :``advanced``: pull will update it
5021 :``diverged``: pull will create a divergent bookmark
5024 :``diverged``: pull will create a divergent bookmark
5022 :``changed``: result depends on remote changesets
5025 :``changed``: result depends on remote changesets
5023
5026
5024 From the point of view of pulling behavior, bookmark
5027 From the point of view of pulling behavior, bookmark
5025 existing only in the remote repository are treated as ``added``,
5028 existing only in the remote repository are treated as ``added``,
5026 even if it is in fact locally deleted.
5029 even if it is in fact locally deleted.
5027
5030
5028 .. container:: verbose
5031 .. container:: verbose
5029
5032
5030 For remote repository, using --bundle avoids downloading the
5033 For remote repository, using --bundle avoids downloading the
5031 changesets twice if the incoming is followed by a pull.
5034 changesets twice if the incoming is followed by a pull.
5032
5035
5033 Examples:
5036 Examples:
5034
5037
5035 - show incoming changes with patches and full description::
5038 - show incoming changes with patches and full description::
5036
5039
5037 hg incoming -vp
5040 hg incoming -vp
5038
5041
5039 - show incoming changes excluding merges, store a bundle::
5042 - show incoming changes excluding merges, store a bundle::
5040
5043
5041 hg in -vpM --bundle incoming.hg
5044 hg in -vpM --bundle incoming.hg
5042 hg pull incoming.hg
5045 hg pull incoming.hg
5043
5046
5044 - briefly list changes inside a bundle::
5047 - briefly list changes inside a bundle::
5045
5048
5046 hg in changes.hg -T "{desc|firstline}\\n"
5049 hg in changes.hg -T "{desc|firstline}\\n"
5047
5050
5048 Returns 0 if there are incoming changes, 1 otherwise.
5051 Returns 0 if there are incoming changes, 1 otherwise.
5049 """
5052 """
5050 if opts.get('graph'):
5053 if opts.get('graph'):
5051 cmdutil.checkunsupportedgraphflags([], opts)
5054 cmdutil.checkunsupportedgraphflags([], opts)
5052 def display(other, chlist, displayer):
5055 def display(other, chlist, displayer):
5053 revdag = cmdutil.graphrevs(other, chlist, opts)
5056 revdag = cmdutil.graphrevs(other, chlist, opts)
5054 cmdutil.displaygraph(ui, repo, revdag, displayer,
5057 cmdutil.displaygraph(ui, repo, revdag, displayer,
5055 graphmod.asciiedges)
5058 graphmod.asciiedges)
5056
5059
5057 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5060 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5058 return 0
5061 return 0
5059
5062
5060 if opts.get('bundle') and opts.get('subrepos'):
5063 if opts.get('bundle') and opts.get('subrepos'):
5061 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5064 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5062
5065
5063 if opts.get('bookmarks'):
5066 if opts.get('bookmarks'):
5064 source, branches = hg.parseurl(ui.expandpath(source),
5067 source, branches = hg.parseurl(ui.expandpath(source),
5065 opts.get('branch'))
5068 opts.get('branch'))
5066 other = hg.peer(repo, opts, source)
5069 other = hg.peer(repo, opts, source)
5067 if 'bookmarks' not in other.listkeys('namespaces'):
5070 if 'bookmarks' not in other.listkeys('namespaces'):
5068 ui.warn(_("remote doesn't support bookmarks\n"))
5071 ui.warn(_("remote doesn't support bookmarks\n"))
5069 return 0
5072 return 0
5070 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5073 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5071 return bookmarks.incoming(ui, repo, other)
5074 return bookmarks.incoming(ui, repo, other)
5072
5075
5073 repo._subtoppath = ui.expandpath(source)
5076 repo._subtoppath = ui.expandpath(source)
5074 try:
5077 try:
5075 return hg.incoming(ui, repo, source, opts)
5078 return hg.incoming(ui, repo, source, opts)
5076 finally:
5079 finally:
5077 del repo._subtoppath
5080 del repo._subtoppath
5078
5081
5079
5082
5080 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5083 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5081 norepo=True)
5084 norepo=True)
5082 def init(ui, dest=".", **opts):
5085 def init(ui, dest=".", **opts):
5083 """create a new repository in the given directory
5086 """create a new repository in the given directory
5084
5087
5085 Initialize a new repository in the given directory. If the given
5088 Initialize a new repository in the given directory. If the given
5086 directory does not exist, it will be created.
5089 directory does not exist, it will be created.
5087
5090
5088 If no directory is given, the current directory is used.
5091 If no directory is given, the current directory is used.
5089
5092
5090 It is possible to specify an ``ssh://`` URL as the destination.
5093 It is possible to specify an ``ssh://`` URL as the destination.
5091 See :hg:`help urls` for more information.
5094 See :hg:`help urls` for more information.
5092
5095
5093 Returns 0 on success.
5096 Returns 0 on success.
5094 """
5097 """
5095 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5098 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5096
5099
5097 @command('locate',
5100 @command('locate',
5098 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5101 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5099 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5102 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5100 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5103 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5101 ] + walkopts,
5104 ] + walkopts,
5102 _('[OPTION]... [PATTERN]...'))
5105 _('[OPTION]... [PATTERN]...'))
5103 def locate(ui, repo, *pats, **opts):
5106 def locate(ui, repo, *pats, **opts):
5104 """locate files matching specific patterns (DEPRECATED)
5107 """locate files matching specific patterns (DEPRECATED)
5105
5108
5106 Print files under Mercurial control in the working directory whose
5109 Print files under Mercurial control in the working directory whose
5107 names match the given patterns.
5110 names match the given patterns.
5108
5111
5109 By default, this command searches all directories in the working
5112 By default, this command searches all directories in the working
5110 directory. To search just the current directory and its
5113 directory. To search just the current directory and its
5111 subdirectories, use "--include .".
5114 subdirectories, use "--include .".
5112
5115
5113 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
5114 of all files under Mercurial control in the working directory.
5117 of all files under Mercurial control in the working directory.
5115
5118
5116 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"
5117 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
5118 will avoid the problem of "xargs" treating single filenames that
5121 will avoid the problem of "xargs" treating single filenames that
5119 contain whitespace as multiple filenames.
5122 contain whitespace as multiple filenames.
5120
5123
5121 See :hg:`help files` for a more versatile command.
5124 See :hg:`help files` for a more versatile command.
5122
5125
5123 Returns 0 if a match is found, 1 otherwise.
5126 Returns 0 if a match is found, 1 otherwise.
5124 """
5127 """
5125 if opts.get('print0'):
5128 if opts.get('print0'):
5126 end = '\0'
5129 end = '\0'
5127 else:
5130 else:
5128 end = '\n'
5131 end = '\n'
5129 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5132 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5130
5133
5131 ret = 1
5134 ret = 1
5132 ctx = repo[rev]
5135 ctx = repo[rev]
5133 m = scmutil.match(ctx, pats, opts, default='relglob',
5136 m = scmutil.match(ctx, pats, opts, default='relglob',
5134 badfn=lambda x, y: False)
5137 badfn=lambda x, y: False)
5135
5138
5136 for abs in ctx.matches(m):
5139 for abs in ctx.matches(m):
5137 if opts.get('fullpath'):
5140 if opts.get('fullpath'):
5138 ui.write(repo.wjoin(abs), end)
5141 ui.write(repo.wjoin(abs), end)
5139 else:
5142 else:
5140 ui.write(((pats and m.rel(abs)) or abs), end)
5143 ui.write(((pats and m.rel(abs)) or abs), end)
5141 ret = 0
5144 ret = 0
5142
5145
5143 return ret
5146 return ret
5144
5147
5145 @command('^log|history',
5148 @command('^log|history',
5146 [('f', 'follow', None,
5149 [('f', 'follow', None,
5147 _('follow changeset history, or file history across copies and renames')),
5150 _('follow changeset history, or file history across copies and renames')),
5148 ('', 'follow-first', None,
5151 ('', 'follow-first', None,
5149 _('only follow the first parent of merge changesets (DEPRECATED)')),
5152 _('only follow the first parent of merge changesets (DEPRECATED)')),
5150 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5153 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5151 ('C', 'copies', None, _('show copied files')),
5154 ('C', 'copies', None, _('show copied files')),
5152 ('k', 'keyword', [],
5155 ('k', 'keyword', [],
5153 _('do case-insensitive search for a given text'), _('TEXT')),
5156 _('do case-insensitive search for a given text'), _('TEXT')),
5154 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5157 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5155 ('', 'removed', None, _('include revisions where files were removed')),
5158 ('', 'removed', None, _('include revisions where files were removed')),
5156 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5159 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5157 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5160 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5158 ('', 'only-branch', [],
5161 ('', 'only-branch', [],
5159 _('show only changesets within the given named branch (DEPRECATED)'),
5162 _('show only changesets within the given named branch (DEPRECATED)'),
5160 _('BRANCH')),
5163 _('BRANCH')),
5161 ('b', 'branch', [],
5164 ('b', 'branch', [],
5162 _('show changesets within the given named branch'), _('BRANCH')),
5165 _('show changesets within the given named branch'), _('BRANCH')),
5163 ('P', 'prune', [],
5166 ('P', 'prune', [],
5164 _('do not display revision or any of its ancestors'), _('REV')),
5167 _('do not display revision or any of its ancestors'), _('REV')),
5165 ] + logopts + walkopts,
5168 ] + logopts + walkopts,
5166 _('[OPTION]... [FILE]'),
5169 _('[OPTION]... [FILE]'),
5167 inferrepo=True)
5170 inferrepo=True)
5168 def log(ui, repo, *pats, **opts):
5171 def log(ui, repo, *pats, **opts):
5169 """show revision history of entire repository or files
5172 """show revision history of entire repository or files
5170
5173
5171 Print the revision history of the specified files or the entire
5174 Print the revision history of the specified files or the entire
5172 project.
5175 project.
5173
5176
5174 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
5175 --follow is set, in which case the working directory parent is
5178 --follow is set, in which case the working directory parent is
5176 used as the starting revision.
5179 used as the starting revision.
5177
5180
5178 File history is shown without following rename or copy history of
5181 File history is shown without following rename or copy history of
5179 files. Use -f/--follow with a filename to follow history across
5182 files. Use -f/--follow with a filename to follow history across
5180 renames and copies. --follow without a filename will only show
5183 renames and copies. --follow without a filename will only show
5181 ancestors or descendants of the starting revision.
5184 ancestors or descendants of the starting revision.
5182
5185
5183 By default this command prints revision number and changeset id,
5186 By default this command prints revision number and changeset id,
5184 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
5185 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
5186 changed files and full commit message are shown.
5189 changed files and full commit message are shown.
5187
5190
5188 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
5189 recent changeset at the top.
5192 recent changeset at the top.
5190 '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,
5191 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
5192 parent of the 'o' merge on the same line.
5195 parent of the 'o' merge on the same line.
5193
5196
5194 .. note::
5197 .. note::
5195
5198
5196 :hg:`log --patch` may generate unexpected diff output for merge
5199 :hg:`log --patch` may generate unexpected diff output for merge
5197 changesets, as it will only compare the merge changeset against
5200 changesets, as it will only compare the merge changeset against
5198 its first parent. Also, only files different from BOTH parents
5201 its first parent. Also, only files different from BOTH parents
5199 will appear in files:.
5202 will appear in files:.
5200
5203
5201 .. note::
5204 .. note::
5202
5205
5203 For performance reasons, :hg:`log FILE` may omit duplicate changes
5206 For performance reasons, :hg:`log FILE` may omit duplicate changes
5204 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
5205 see all such changes, use the --removed switch.
5208 see all such changes, use the --removed switch.
5206
5209
5207 .. container:: verbose
5210 .. container:: verbose
5208
5211
5209 Some examples:
5212 Some examples:
5210
5213
5211 - changesets with full descriptions and file lists::
5214 - changesets with full descriptions and file lists::
5212
5215
5213 hg log -v
5216 hg log -v
5214
5217
5215 - changesets ancestral to the working directory::
5218 - changesets ancestral to the working directory::
5216
5219
5217 hg log -f
5220 hg log -f
5218
5221
5219 - last 10 commits on the current branch::
5222 - last 10 commits on the current branch::
5220
5223
5221 hg log -l 10 -b .
5224 hg log -l 10 -b .
5222
5225
5223 - changesets showing all modifications of a file, including removals::
5226 - changesets showing all modifications of a file, including removals::
5224
5227
5225 hg log --removed file.c
5228 hg log --removed file.c
5226
5229
5227 - all changesets that touch a directory, with diffs, excluding merges::
5230 - all changesets that touch a directory, with diffs, excluding merges::
5228
5231
5229 hg log -Mp lib/
5232 hg log -Mp lib/
5230
5233
5231 - all revision numbers that match a keyword::
5234 - all revision numbers that match a keyword::
5232
5235
5233 hg log -k bug --template "{rev}\\n"
5236 hg log -k bug --template "{rev}\\n"
5234
5237
5235 - the full hash identifier of the working directory parent::
5238 - the full hash identifier of the working directory parent::
5236
5239
5237 hg log -r . --template "{node}\\n"
5240 hg log -r . --template "{node}\\n"
5238
5241
5239 - list available log templates::
5242 - list available log templates::
5240
5243
5241 hg log -T list
5244 hg log -T list
5242
5245
5243 - check if a given changeset is included in a tagged release::
5246 - check if a given changeset is included in a tagged release::
5244
5247
5245 hg log -r "a21ccf and ancestor(1.9)"
5248 hg log -r "a21ccf and ancestor(1.9)"
5246
5249
5247 - find all changesets by some user in a date range::
5250 - find all changesets by some user in a date range::
5248
5251
5249 hg log -k alice -d "may 2008 to jul 2008"
5252 hg log -k alice -d "may 2008 to jul 2008"
5250
5253
5251 - summary of all changesets after the last tag::
5254 - summary of all changesets after the last tag::
5252
5255
5253 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5256 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5254
5257
5255 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.
5256
5259
5257 See :hg:`help revisions` and :hg:`help revsets` for more about
5260 See :hg:`help revisions` and :hg:`help revsets` for more about
5258 specifying and ordering revisions.
5261 specifying and ordering revisions.
5259
5262
5260 See :hg:`help templates` for more about pre-packaged styles and
5263 See :hg:`help templates` for more about pre-packaged styles and
5261 specifying custom templates.
5264 specifying custom templates.
5262
5265
5263 Returns 0 on success.
5266 Returns 0 on success.
5264
5267
5265 """
5268 """
5266 if opts.get('follow') and opts.get('rev'):
5269 if opts.get('follow') and opts.get('rev'):
5267 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5270 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5268 del opts['follow']
5271 del opts['follow']
5269
5272
5270 if opts.get('graph'):
5273 if opts.get('graph'):
5271 return cmdutil.graphlog(ui, repo, *pats, **opts)
5274 return cmdutil.graphlog(ui, repo, *pats, **opts)
5272
5275
5273 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5276 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5274 limit = cmdutil.loglimit(opts)
5277 limit = cmdutil.loglimit(opts)
5275 count = 0
5278 count = 0
5276
5279
5277 getrenamed = None
5280 getrenamed = None
5278 if opts.get('copies'):
5281 if opts.get('copies'):
5279 endrev = None
5282 endrev = None
5280 if opts.get('rev'):
5283 if opts.get('rev'):
5281 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5284 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5282 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5285 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5283
5286
5284 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5287 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5285 for rev in revs:
5288 for rev in revs:
5286 if count == limit:
5289 if count == limit:
5287 break
5290 break
5288 ctx = repo[rev]
5291 ctx = repo[rev]
5289 copies = None
5292 copies = None
5290 if getrenamed is not None and rev:
5293 if getrenamed is not None and rev:
5291 copies = []
5294 copies = []
5292 for fn in ctx.files():
5295 for fn in ctx.files():
5293 rename = getrenamed(fn, rev)
5296 rename = getrenamed(fn, rev)
5294 if rename:
5297 if rename:
5295 copies.append((fn, rename[0]))
5298 copies.append((fn, rename[0]))
5296 if filematcher:
5299 if filematcher:
5297 revmatchfn = filematcher(ctx.rev())
5300 revmatchfn = filematcher(ctx.rev())
5298 else:
5301 else:
5299 revmatchfn = None
5302 revmatchfn = None
5300 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5303 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5301 if displayer.flush(ctx):
5304 if displayer.flush(ctx):
5302 count += 1
5305 count += 1
5303
5306
5304 displayer.close()
5307 displayer.close()
5305
5308
5306 @command('manifest',
5309 @command('manifest',
5307 [('r', 'rev', '', _('revision to display'), _('REV')),
5310 [('r', 'rev', '', _('revision to display'), _('REV')),
5308 ('', 'all', False, _("list files from all revisions"))]
5311 ('', 'all', False, _("list files from all revisions"))]
5309 + formatteropts,
5312 + formatteropts,
5310 _('[-r REV]'))
5313 _('[-r REV]'))
5311 def manifest(ui, repo, node=None, rev=None, **opts):
5314 def manifest(ui, repo, node=None, rev=None, **opts):
5312 """output the current or given revision of the project manifest
5315 """output the current or given revision of the project manifest
5313
5316
5314 Print a list of version controlled files for the given revision.
5317 Print a list of version controlled files for the given revision.
5315 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
5316 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.
5317
5320
5318 With -v, print file permissions, symlink and executable bits.
5321 With -v, print file permissions, symlink and executable bits.
5319 With --debug, print file revision hashes.
5322 With --debug, print file revision hashes.
5320
5323
5321 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
5322 is printed. This includes deleted and renamed files.
5325 is printed. This includes deleted and renamed files.
5323
5326
5324 Returns 0 on success.
5327 Returns 0 on success.
5325 """
5328 """
5326
5329
5327 fm = ui.formatter('manifest', opts)
5330 fm = ui.formatter('manifest', opts)
5328
5331
5329 if opts.get('all'):
5332 if opts.get('all'):
5330 if rev or node:
5333 if rev or node:
5331 raise error.Abort(_("can't specify a revision with --all"))
5334 raise error.Abort(_("can't specify a revision with --all"))
5332
5335
5333 res = []
5336 res = []
5334 prefix = "data/"
5337 prefix = "data/"
5335 suffix = ".i"
5338 suffix = ".i"
5336 plen = len(prefix)
5339 plen = len(prefix)
5337 slen = len(suffix)
5340 slen = len(suffix)
5338 with repo.lock():
5341 with repo.lock():
5339 for fn, b, size in repo.store.datafiles():
5342 for fn, b, size in repo.store.datafiles():
5340 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5343 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5341 res.append(fn[plen:-slen])
5344 res.append(fn[plen:-slen])
5342 for f in res:
5345 for f in res:
5343 fm.startitem()
5346 fm.startitem()
5344 fm.write("path", '%s\n', f)
5347 fm.write("path", '%s\n', f)
5345 fm.end()
5348 fm.end()
5346 return
5349 return
5347
5350
5348 if rev and node:
5351 if rev and node:
5349 raise error.Abort(_("please specify just one revision"))
5352 raise error.Abort(_("please specify just one revision"))
5350
5353
5351 if not node:
5354 if not node:
5352 node = rev
5355 node = rev
5353
5356
5354 char = {'l': '@', 'x': '*', '': ''}
5357 char = {'l': '@', 'x': '*', '': ''}
5355 mode = {'l': '644', 'x': '755', '': '644'}
5358 mode = {'l': '644', 'x': '755', '': '644'}
5356 ctx = scmutil.revsingle(repo, node)
5359 ctx = scmutil.revsingle(repo, node)
5357 mf = ctx.manifest()
5360 mf = ctx.manifest()
5358 for f in ctx:
5361 for f in ctx:
5359 fm.startitem()
5362 fm.startitem()
5360 fl = ctx[f].flags()
5363 fl = ctx[f].flags()
5361 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5364 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5362 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])
5363 fm.write('path', '%s\n', f)
5366 fm.write('path', '%s\n', f)
5364 fm.end()
5367 fm.end()
5365
5368
5366 @command('^merge',
5369 @command('^merge',
5367 [('f', 'force', None,
5370 [('f', 'force', None,
5368 _('force a merge including outstanding changes (DEPRECATED)')),
5371 _('force a merge including outstanding changes (DEPRECATED)')),
5369 ('r', 'rev', '', _('revision to merge'), _('REV')),
5372 ('r', 'rev', '', _('revision to merge'), _('REV')),
5370 ('P', 'preview', None,
5373 ('P', 'preview', None,
5371 _('review revisions to merge (no merge is performed)'))
5374 _('review revisions to merge (no merge is performed)'))
5372 ] + mergetoolopts,
5375 ] + mergetoolopts,
5373 _('[-P] [[-r] REV]'))
5376 _('[-P] [[-r] REV]'))
5374 def merge(ui, repo, node=None, **opts):
5377 def merge(ui, repo, node=None, **opts):
5375 """merge another revision into working directory
5378 """merge another revision into working directory
5376
5379
5377 The current working directory is updated with all changes made in
5380 The current working directory is updated with all changes made in
5378 the requested revision since the last common predecessor revision.
5381 the requested revision since the last common predecessor revision.
5379
5382
5380 Files that changed between either parent are marked as changed for
5383 Files that changed between either parent are marked as changed for
5381 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
5382 updates to the repository are allowed. The next commit will have
5385 updates to the repository are allowed. The next commit will have
5383 two parents.
5386 two parents.
5384
5387
5385 ``--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
5386 merges. It overrides the HGMERGE environment variable and your
5389 merges. It overrides the HGMERGE environment variable and your
5387 configuration files. See :hg:`help merge-tools` for options.
5390 configuration files. See :hg:`help merge-tools` for options.
5388
5391
5389 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
5390 head revision, and the current branch contains exactly one other
5393 head revision, and the current branch contains exactly one other
5391 head, the other head is merged with by default. Otherwise, an
5394 head, the other head is merged with by default. Otherwise, an
5392 explicit revision with which to merge with must be provided.
5395 explicit revision with which to merge with must be provided.
5393
5396
5394 See :hg:`help resolve` for information on handling file conflicts.
5397 See :hg:`help resolve` for information on handling file conflicts.
5395
5398
5396 To undo an uncommitted merge, use :hg:`update --clean .` which
5399 To undo an uncommitted merge, use :hg:`update --clean .` which
5397 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
5398 all changes.
5401 all changes.
5399
5402
5400 Returns 0 on success, 1 if there are unresolved files.
5403 Returns 0 on success, 1 if there are unresolved files.
5401 """
5404 """
5402
5405
5403 if opts.get('rev') and node:
5406 if opts.get('rev') and node:
5404 raise error.Abort(_("please specify just one revision"))
5407 raise error.Abort(_("please specify just one revision"))
5405 if not node:
5408 if not node:
5406 node = opts.get('rev')
5409 node = opts.get('rev')
5407
5410
5408 if node:
5411 if node:
5409 node = scmutil.revsingle(repo, node).node()
5412 node = scmutil.revsingle(repo, node).node()
5410
5413
5411 if not node:
5414 if not node:
5412 node = repo[destutil.destmerge(repo)].node()
5415 node = repo[destutil.destmerge(repo)].node()
5413
5416
5414 if opts.get('preview'):
5417 if opts.get('preview'):
5415 # find nodes that are ancestors of p2 but not of p1
5418 # find nodes that are ancestors of p2 but not of p1
5416 p1 = repo.lookup('.')
5419 p1 = repo.lookup('.')
5417 p2 = repo.lookup(node)
5420 p2 = repo.lookup(node)
5418 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5421 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5419
5422
5420 displayer = cmdutil.show_changeset(ui, repo, opts)
5423 displayer = cmdutil.show_changeset(ui, repo, opts)
5421 for node in nodes:
5424 for node in nodes:
5422 displayer.show(repo[node])
5425 displayer.show(repo[node])
5423 displayer.close()
5426 displayer.close()
5424 return 0
5427 return 0
5425
5428
5426 try:
5429 try:
5427 # ui.forcemerge is an internal variable, do not document
5430 # ui.forcemerge is an internal variable, do not document
5428 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5431 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5429 force = opts.get('force')
5432 force = opts.get('force')
5430 return hg.merge(repo, node, force=force, mergeforce=force)
5433 return hg.merge(repo, node, force=force, mergeforce=force)
5431 finally:
5434 finally:
5432 ui.setconfig('ui', 'forcemerge', '', 'merge')
5435 ui.setconfig('ui', 'forcemerge', '', 'merge')
5433
5436
5434 @command('outgoing|out',
5437 @command('outgoing|out',
5435 [('f', 'force', None, _('run even when the destination is unrelated')),
5438 [('f', 'force', None, _('run even when the destination is unrelated')),
5436 ('r', 'rev', [],
5439 ('r', 'rev', [],
5437 _('a changeset intended to be included in the destination'), _('REV')),
5440 _('a changeset intended to be included in the destination'), _('REV')),
5438 ('n', 'newest-first', None, _('show newest record first')),
5441 ('n', 'newest-first', None, _('show newest record first')),
5439 ('B', 'bookmarks', False, _('compare bookmarks')),
5442 ('B', 'bookmarks', False, _('compare bookmarks')),
5440 ('b', 'branch', [], _('a specific branch you would like to push'),
5443 ('b', 'branch', [], _('a specific branch you would like to push'),
5441 _('BRANCH')),
5444 _('BRANCH')),
5442 ] + logopts + remoteopts + subrepoopts,
5445 ] + logopts + remoteopts + subrepoopts,
5443 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5446 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5444 def outgoing(ui, repo, dest=None, **opts):
5447 def outgoing(ui, repo, dest=None, **opts):
5445 """show changesets not found in the destination
5448 """show changesets not found in the destination
5446
5449
5447 Show changesets not found in the specified destination repository
5450 Show changesets not found in the specified destination repository
5448 or the default push location. These are the changesets that would
5451 or the default push location. These are the changesets that would
5449 be pushed if a push was requested.
5452 be pushed if a push was requested.
5450
5453
5451 See pull for details of valid destination formats.
5454 See pull for details of valid destination formats.
5452
5455
5453 .. container:: verbose
5456 .. container:: verbose
5454
5457
5455 With -B/--bookmarks, the result of bookmark comparison between
5458 With -B/--bookmarks, the result of bookmark comparison between
5456 local and remote repositories is displayed. With -v/--verbose,
5459 local and remote repositories is displayed. With -v/--verbose,
5457 status is also displayed for each bookmark like below::
5460 status is also displayed for each bookmark like below::
5458
5461
5459 BM1 01234567890a added
5462 BM1 01234567890a added
5460 BM2 deleted
5463 BM2 deleted
5461 BM3 234567890abc advanced
5464 BM3 234567890abc advanced
5462 BM4 34567890abcd diverged
5465 BM4 34567890abcd diverged
5463 BM5 4567890abcde changed
5466 BM5 4567890abcde changed
5464
5467
5465 The action taken when pushing depends on the
5468 The action taken when pushing depends on the
5466 status of each bookmark:
5469 status of each bookmark:
5467
5470
5468 :``added``: push with ``-B`` will create it
5471 :``added``: push with ``-B`` will create it
5469 :``deleted``: push with ``-B`` will delete it
5472 :``deleted``: push with ``-B`` will delete it
5470 :``advanced``: push will update it
5473 :``advanced``: push will update it
5471 :``diverged``: push with ``-B`` will update it
5474 :``diverged``: push with ``-B`` will update it
5472 :``changed``: push with ``-B`` will update it
5475 :``changed``: push with ``-B`` will update it
5473
5476
5474 From the point of view of pushing behavior, bookmarks
5477 From the point of view of pushing behavior, bookmarks
5475 existing only in the remote repository are treated as
5478 existing only in the remote repository are treated as
5476 ``deleted``, even if it is in fact added remotely.
5479 ``deleted``, even if it is in fact added remotely.
5477
5480
5478 Returns 0 if there are outgoing changes, 1 otherwise.
5481 Returns 0 if there are outgoing changes, 1 otherwise.
5479 """
5482 """
5480 if opts.get('graph'):
5483 if opts.get('graph'):
5481 cmdutil.checkunsupportedgraphflags([], opts)
5484 cmdutil.checkunsupportedgraphflags([], opts)
5482 o, other = hg._outgoing(ui, repo, dest, opts)
5485 o, other = hg._outgoing(ui, repo, dest, opts)
5483 if not o:
5486 if not o:
5484 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5487 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5485 return
5488 return
5486
5489
5487 revdag = cmdutil.graphrevs(repo, o, opts)
5490 revdag = cmdutil.graphrevs(repo, o, opts)
5488 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5491 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5489 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5492 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5490 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5493 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5491 return 0
5494 return 0
5492
5495
5493 if opts.get('bookmarks'):
5496 if opts.get('bookmarks'):
5494 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5497 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5495 dest, branches = hg.parseurl(dest, opts.get('branch'))
5498 dest, branches = hg.parseurl(dest, opts.get('branch'))
5496 other = hg.peer(repo, opts, dest)
5499 other = hg.peer(repo, opts, dest)
5497 if 'bookmarks' not in other.listkeys('namespaces'):
5500 if 'bookmarks' not in other.listkeys('namespaces'):
5498 ui.warn(_("remote doesn't support bookmarks\n"))
5501 ui.warn(_("remote doesn't support bookmarks\n"))
5499 return 0
5502 return 0
5500 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5503 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5501 return bookmarks.outgoing(ui, repo, other)
5504 return bookmarks.outgoing(ui, repo, other)
5502
5505
5503 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5506 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5504 try:
5507 try:
5505 return hg.outgoing(ui, repo, dest, opts)
5508 return hg.outgoing(ui, repo, dest, opts)
5506 finally:
5509 finally:
5507 del repo._subtoppath
5510 del repo._subtoppath
5508
5511
5509 @command('parents',
5512 @command('parents',
5510 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5513 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5511 ] + templateopts,
5514 ] + templateopts,
5512 _('[-r REV] [FILE]'),
5515 _('[-r REV] [FILE]'),
5513 inferrepo=True)
5516 inferrepo=True)
5514 def parents(ui, repo, file_=None, **opts):
5517 def parents(ui, repo, file_=None, **opts):
5515 """show the parents of the working directory or revision (DEPRECATED)
5518 """show the parents of the working directory or revision (DEPRECATED)
5516
5519
5517 Print the working directory's parent revisions. If a revision is
5520 Print the working directory's parent revisions. If a revision is
5518 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.
5519 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
5520 last changed (before the working directory revision or the
5523 last changed (before the working directory revision or the
5521 argument to --rev if given) is printed.
5524 argument to --rev if given) is printed.
5522
5525
5523 This command is equivalent to::
5526 This command is equivalent to::
5524
5527
5525 hg log -r "p1()+p2()" or
5528 hg log -r "p1()+p2()" or
5526 hg log -r "p1(REV)+p2(REV)" or
5529 hg log -r "p1(REV)+p2(REV)" or
5527 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
5528 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))"
5529
5532
5530 See :hg:`summary` and :hg:`help revsets` for related information.
5533 See :hg:`summary` and :hg:`help revsets` for related information.
5531
5534
5532 Returns 0 on success.
5535 Returns 0 on success.
5533 """
5536 """
5534
5537
5535 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5538 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5536
5539
5537 if file_:
5540 if file_:
5538 m = scmutil.match(ctx, (file_,), opts)
5541 m = scmutil.match(ctx, (file_,), opts)
5539 if m.anypats() or len(m.files()) != 1:
5542 if m.anypats() or len(m.files()) != 1:
5540 raise error.Abort(_('can only specify an explicit filename'))
5543 raise error.Abort(_('can only specify an explicit filename'))
5541 file_ = m.files()[0]
5544 file_ = m.files()[0]
5542 filenodes = []
5545 filenodes = []
5543 for cp in ctx.parents():
5546 for cp in ctx.parents():
5544 if not cp:
5547 if not cp:
5545 continue
5548 continue
5546 try:
5549 try:
5547 filenodes.append(cp.filenode(file_))
5550 filenodes.append(cp.filenode(file_))
5548 except error.LookupError:
5551 except error.LookupError:
5549 pass
5552 pass
5550 if not filenodes:
5553 if not filenodes:
5551 raise error.Abort(_("'%s' not found in manifest!") % file_)
5554 raise error.Abort(_("'%s' not found in manifest!") % file_)
5552 p = []
5555 p = []
5553 for fn in filenodes:
5556 for fn in filenodes:
5554 fctx = repo.filectx(file_, fileid=fn)
5557 fctx = repo.filectx(file_, fileid=fn)
5555 p.append(fctx.node())
5558 p.append(fctx.node())
5556 else:
5559 else:
5557 p = [cp.node() for cp in ctx.parents()]
5560 p = [cp.node() for cp in ctx.parents()]
5558
5561
5559 displayer = cmdutil.show_changeset(ui, repo, opts)
5562 displayer = cmdutil.show_changeset(ui, repo, opts)
5560 for n in p:
5563 for n in p:
5561 if n != nullid:
5564 if n != nullid:
5562 displayer.show(repo[n])
5565 displayer.show(repo[n])
5563 displayer.close()
5566 displayer.close()
5564
5567
5565 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5568 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5566 def paths(ui, repo, search=None, **opts):
5569 def paths(ui, repo, search=None, **opts):
5567 """show aliases for remote repositories
5570 """show aliases for remote repositories
5568
5571
5569 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,
5570 show definition of all available names.
5573 show definition of all available names.
5571
5574
5572 Option -q/--quiet suppresses all output when searching for NAME
5575 Option -q/--quiet suppresses all output when searching for NAME
5573 and shows only the path names when listing all definitions.
5576 and shows only the path names when listing all definitions.
5574
5577
5575 Path names are defined in the [paths] section of your
5578 Path names are defined in the [paths] section of your
5576 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5579 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5577 repository, ``.hg/hgrc`` is used, too.
5580 repository, ``.hg/hgrc`` is used, too.
5578
5581
5579 The path names ``default`` and ``default-push`` have a special
5582 The path names ``default`` and ``default-push`` have a special
5580 meaning. When performing a push or pull operation, they are used
5583 meaning. When performing a push or pull operation, they are used
5581 as fallbacks if no location is specified on the command-line.
5584 as fallbacks if no location is specified on the command-line.
5582 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
5583 ``default`` will be used for pull; otherwise ``default`` is used
5586 ``default`` will be used for pull; otherwise ``default`` is used
5584 as the fallback for both. When cloning a repository, the clone
5587 as the fallback for both. When cloning a repository, the clone
5585 source is written as ``default`` in ``.hg/hgrc``.
5588 source is written as ``default`` in ``.hg/hgrc``.
5586
5589
5587 .. note::
5590 .. note::
5588
5591
5589 ``default`` and ``default-push`` apply to all inbound (e.g.
5592 ``default`` and ``default-push`` apply to all inbound (e.g.
5590 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5593 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5591 and :hg:`bundle`) operations.
5594 and :hg:`bundle`) operations.
5592
5595
5593 See :hg:`help urls` for more information.
5596 See :hg:`help urls` for more information.
5594
5597
5595 Returns 0 on success.
5598 Returns 0 on success.
5596 """
5599 """
5597 if search:
5600 if search:
5598 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5601 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5599 if name == search]
5602 if name == search]
5600 else:
5603 else:
5601 pathitems = sorted(ui.paths.iteritems())
5604 pathitems = sorted(ui.paths.iteritems())
5602
5605
5603 fm = ui.formatter('paths', opts)
5606 fm = ui.formatter('paths', opts)
5604 if fm:
5607 if fm:
5605 hidepassword = str
5608 hidepassword = str
5606 else:
5609 else:
5607 hidepassword = util.hidepassword
5610 hidepassword = util.hidepassword
5608 if ui.quiet:
5611 if ui.quiet:
5609 namefmt = '%s\n'
5612 namefmt = '%s\n'
5610 else:
5613 else:
5611 namefmt = '%s = '
5614 namefmt = '%s = '
5612 showsubopts = not search and not ui.quiet
5615 showsubopts = not search and not ui.quiet
5613
5616
5614 for name, path in pathitems:
5617 for name, path in pathitems:
5615 fm.startitem()
5618 fm.startitem()
5616 fm.condwrite(not search, 'name', namefmt, name)
5619 fm.condwrite(not search, 'name', namefmt, name)
5617 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5620 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5618 for subopt, value in sorted(path.suboptions.items()):
5621 for subopt, value in sorted(path.suboptions.items()):
5619 assert subopt not in ('name', 'url')
5622 assert subopt not in ('name', 'url')
5620 if showsubopts:
5623 if showsubopts:
5621 fm.plain('%s:%s = ' % (name, subopt))
5624 fm.plain('%s:%s = ' % (name, subopt))
5622 fm.condwrite(showsubopts, subopt, '%s\n', value)
5625 fm.condwrite(showsubopts, subopt, '%s\n', value)
5623
5626
5624 fm.end()
5627 fm.end()
5625
5628
5626 if search and not pathitems:
5629 if search and not pathitems:
5627 if not ui.quiet:
5630 if not ui.quiet:
5628 ui.warn(_("not found!\n"))
5631 ui.warn(_("not found!\n"))
5629 return 1
5632 return 1
5630 else:
5633 else:
5631 return 0
5634 return 0
5632
5635
5633 @command('phase',
5636 @command('phase',
5634 [('p', 'public', False, _('set changeset phase to public')),
5637 [('p', 'public', False, _('set changeset phase to public')),
5635 ('d', 'draft', False, _('set changeset phase to draft')),
5638 ('d', 'draft', False, _('set changeset phase to draft')),
5636 ('s', 'secret', False, _('set changeset phase to secret')),
5639 ('s', 'secret', False, _('set changeset phase to secret')),
5637 ('f', 'force', False, _('allow to move boundary backward')),
5640 ('f', 'force', False, _('allow to move boundary backward')),
5638 ('r', 'rev', [], _('target revision'), _('REV')),
5641 ('r', 'rev', [], _('target revision'), _('REV')),
5639 ],
5642 ],
5640 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5643 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5641 def phase(ui, repo, *revs, **opts):
5644 def phase(ui, repo, *revs, **opts):
5642 """set or show the current phase name
5645 """set or show the current phase name
5643
5646
5644 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).
5645
5648
5646 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
5647 phase value of the specified revisions.
5650 phase value of the specified revisions.
5648
5651
5649 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
5650 lower phase to an higher phase. Phases are ordered as follows::
5653 lower phase to an higher phase. Phases are ordered as follows::
5651
5654
5652 public < draft < secret
5655 public < draft < secret
5653
5656
5654 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.
5655
5658
5656 (For more information about the phases concept, see :hg:`help phases`.)
5659 (For more information about the phases concept, see :hg:`help phases`.)
5657 """
5660 """
5658 # search for a unique phase argument
5661 # search for a unique phase argument
5659 targetphase = None
5662 targetphase = None
5660 for idx, name in enumerate(phases.phasenames):
5663 for idx, name in enumerate(phases.phasenames):
5661 if opts[name]:
5664 if opts[name]:
5662 if targetphase is not None:
5665 if targetphase is not None:
5663 raise error.Abort(_('only one phase can be specified'))
5666 raise error.Abort(_('only one phase can be specified'))
5664 targetphase = idx
5667 targetphase = idx
5665
5668
5666 # look for specified revision
5669 # look for specified revision
5667 revs = list(revs)
5670 revs = list(revs)
5668 revs.extend(opts['rev'])
5671 revs.extend(opts['rev'])
5669 if not revs:
5672 if not revs:
5670 # display both parents as the second parent phase can influence
5673 # display both parents as the second parent phase can influence
5671 # the phase of a merge commit
5674 # the phase of a merge commit
5672 revs = [c.rev() for c in repo[None].parents()]
5675 revs = [c.rev() for c in repo[None].parents()]
5673
5676
5674 revs = scmutil.revrange(repo, revs)
5677 revs = scmutil.revrange(repo, revs)
5675
5678
5676 lock = None
5679 lock = None
5677 ret = 0
5680 ret = 0
5678 if targetphase is None:
5681 if targetphase is None:
5679 # display
5682 # display
5680 for r in revs:
5683 for r in revs:
5681 ctx = repo[r]
5684 ctx = repo[r]
5682 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5685 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5683 else:
5686 else:
5684 tr = None
5687 tr = None
5685 lock = repo.lock()
5688 lock = repo.lock()
5686 try:
5689 try:
5687 tr = repo.transaction("phase")
5690 tr = repo.transaction("phase")
5688 # set phase
5691 # set phase
5689 if not revs:
5692 if not revs:
5690 raise error.Abort(_('empty revision set'))
5693 raise error.Abort(_('empty revision set'))
5691 nodes = [repo[r].node() for r in revs]
5694 nodes = [repo[r].node() for r in revs]
5692 # moving revision from public to draft may hide them
5695 # moving revision from public to draft may hide them
5693 # We have to check result on an unfiltered repository
5696 # We have to check result on an unfiltered repository
5694 unfi = repo.unfiltered()
5697 unfi = repo.unfiltered()
5695 getphase = unfi._phasecache.phase
5698 getphase = unfi._phasecache.phase
5696 olddata = [getphase(unfi, r) for r in unfi]
5699 olddata = [getphase(unfi, r) for r in unfi]
5697 phases.advanceboundary(repo, tr, targetphase, nodes)
5700 phases.advanceboundary(repo, tr, targetphase, nodes)
5698 if opts['force']:
5701 if opts['force']:
5699 phases.retractboundary(repo, tr, targetphase, nodes)
5702 phases.retractboundary(repo, tr, targetphase, nodes)
5700 tr.close()
5703 tr.close()
5701 finally:
5704 finally:
5702 if tr is not None:
5705 if tr is not None:
5703 tr.release()
5706 tr.release()
5704 lock.release()
5707 lock.release()
5705 getphase = unfi._phasecache.phase
5708 getphase = unfi._phasecache.phase
5706 newdata = [getphase(unfi, r) for r in unfi]
5709 newdata = [getphase(unfi, r) for r in unfi]
5707 changes = sum(newdata[r] != olddata[r] for r in unfi)
5710 changes = sum(newdata[r] != olddata[r] for r in unfi)
5708 cl = unfi.changelog
5711 cl = unfi.changelog
5709 rejected = [n for n in nodes
5712 rejected = [n for n in nodes
5710 if newdata[cl.rev(n)] < targetphase]
5713 if newdata[cl.rev(n)] < targetphase]
5711 if rejected:
5714 if rejected:
5712 ui.warn(_('cannot move %i changesets to a higher '
5715 ui.warn(_('cannot move %i changesets to a higher '
5713 'phase, use --force\n') % len(rejected))
5716 'phase, use --force\n') % len(rejected))
5714 ret = 1
5717 ret = 1
5715 if changes:
5718 if changes:
5716 msg = _('phase changed for %i changesets\n') % changes
5719 msg = _('phase changed for %i changesets\n') % changes
5717 if ret:
5720 if ret:
5718 ui.status(msg)
5721 ui.status(msg)
5719 else:
5722 else:
5720 ui.note(msg)
5723 ui.note(msg)
5721 else:
5724 else:
5722 ui.warn(_('no phases changed\n'))
5725 ui.warn(_('no phases changed\n'))
5723 return ret
5726 return ret
5724
5727
5725 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5728 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5726 """Run after a changegroup has been added via pull/unbundle
5729 """Run after a changegroup has been added via pull/unbundle
5727
5730
5728 This takes arguments below:
5731 This takes arguments below:
5729
5732
5730 :modheads: change of heads by pull/unbundle
5733 :modheads: change of heads by pull/unbundle
5731 :optupdate: updating working directory is needed or not
5734 :optupdate: updating working directory is needed or not
5732 :checkout: update destination revision (or None to default destination)
5735 :checkout: update destination revision (or None to default destination)
5733 :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
5734 """
5737 """
5735 if modheads == 0:
5738 if modheads == 0:
5736 return
5739 return
5737 if optupdate:
5740 if optupdate:
5738 try:
5741 try:
5739 return hg.updatetotally(ui, repo, checkout, brev)
5742 return hg.updatetotally(ui, repo, checkout, brev)
5740 except error.UpdateAbort as inst:
5743 except error.UpdateAbort as inst:
5741 msg = _("not updating: %s") % str(inst)
5744 msg = _("not updating: %s") % str(inst)
5742 hint = inst.hint
5745 hint = inst.hint
5743 raise error.UpdateAbort(msg, hint=hint)
5746 raise error.UpdateAbort(msg, hint=hint)
5744 if modheads > 1:
5747 if modheads > 1:
5745 currentbranchheads = len(repo.branchheads())
5748 currentbranchheads = len(repo.branchheads())
5746 if currentbranchheads == modheads:
5749 if currentbranchheads == modheads:
5747 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"))
5748 elif currentbranchheads > 1:
5751 elif currentbranchheads > 1:
5749 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5752 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5750 "merge)\n"))
5753 "merge)\n"))
5751 else:
5754 else:
5752 ui.status(_("(run 'hg heads' to see heads)\n"))
5755 ui.status(_("(run 'hg heads' to see heads)\n"))
5753 else:
5756 else:
5754 ui.status(_("(run 'hg update' to get a working copy)\n"))
5757 ui.status(_("(run 'hg update' to get a working copy)\n"))
5755
5758
5756 @command('^pull',
5759 @command('^pull',
5757 [('u', 'update', None,
5760 [('u', 'update', None,
5758 _('update to new branch head if changesets were pulled')),
5761 _('update to new branch head if changesets were pulled')),
5759 ('f', 'force', None, _('run even when remote repository is unrelated')),
5762 ('f', 'force', None, _('run even when remote repository is unrelated')),
5760 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5763 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5761 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5764 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5762 ('b', 'branch', [], _('a specific branch you would like to pull'),
5765 ('b', 'branch', [], _('a specific branch you would like to pull'),
5763 _('BRANCH')),
5766 _('BRANCH')),
5764 ] + remoteopts,
5767 ] + remoteopts,
5765 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5768 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5766 def pull(ui, repo, source="default", **opts):
5769 def pull(ui, repo, source="default", **opts):
5767 """pull changes from the specified source
5770 """pull changes from the specified source
5768
5771
5769 Pull changes from a remote repository to a local one.
5772 Pull changes from a remote repository to a local one.
5770
5773
5771 This finds all changes from the repository at the specified path
5774 This finds all changes from the repository at the specified path
5772 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
5773 -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
5774 project in the working directory.
5777 project in the working directory.
5775
5778
5776 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
5777 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
5778 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
5779 -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`.
5780
5783
5781 If SOURCE is omitted, the 'default' path will be used.
5784 If SOURCE is omitted, the 'default' path will be used.
5782 See :hg:`help urls` for more information.
5785 See :hg:`help urls` for more information.
5783
5786
5784 Returns 0 on success, 1 if an update had unresolved files.
5787 Returns 0 on success, 1 if an update had unresolved files.
5785 """
5788 """
5786 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5789 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5787 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5790 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5788 other = hg.peer(repo, opts, source)
5791 other = hg.peer(repo, opts, source)
5789 try:
5792 try:
5790 revs, checkout = hg.addbranchrevs(repo, other, branches,
5793 revs, checkout = hg.addbranchrevs(repo, other, branches,
5791 opts.get('rev'))
5794 opts.get('rev'))
5792
5795
5793
5796
5794 pullopargs = {}
5797 pullopargs = {}
5795 if opts.get('bookmark'):
5798 if opts.get('bookmark'):
5796 if not revs:
5799 if not revs:
5797 revs = []
5800 revs = []
5798 # The list of bookmark used here is not the one used to actually
5801 # The list of bookmark used here is not the one used to actually
5799 # update the bookmark name. This can result in the revision pulled
5802 # update the bookmark name. This can result in the revision pulled
5800 # not ending up with the name of the bookmark because of a race
5803 # not ending up with the name of the bookmark because of a race
5801 # condition on the server. (See issue 4689 for details)
5804 # condition on the server. (See issue 4689 for details)
5802 remotebookmarks = other.listkeys('bookmarks')
5805 remotebookmarks = other.listkeys('bookmarks')
5803 pullopargs['remotebookmarks'] = remotebookmarks
5806 pullopargs['remotebookmarks'] = remotebookmarks
5804 for b in opts['bookmark']:
5807 for b in opts['bookmark']:
5805 if b not in remotebookmarks:
5808 if b not in remotebookmarks:
5806 raise error.Abort(_('remote bookmark %s not found!') % b)
5809 raise error.Abort(_('remote bookmark %s not found!') % b)
5807 revs.append(remotebookmarks[b])
5810 revs.append(remotebookmarks[b])
5808
5811
5809 if revs:
5812 if revs:
5810 try:
5813 try:
5811 # When 'rev' is a bookmark name, we cannot guarantee that it
5814 # When 'rev' is a bookmark name, we cannot guarantee that it
5812 # will be updated with that name because of a race condition
5815 # will be updated with that name because of a race condition
5813 # server side. (See issue 4689 for details)
5816 # server side. (See issue 4689 for details)
5814 oldrevs = revs
5817 oldrevs = revs
5815 revs = [] # actually, nodes
5818 revs = [] # actually, nodes
5816 for r in oldrevs:
5819 for r in oldrevs:
5817 node = other.lookup(r)
5820 node = other.lookup(r)
5818 revs.append(node)
5821 revs.append(node)
5819 if r == checkout:
5822 if r == checkout:
5820 checkout = node
5823 checkout = node
5821 except error.CapabilityError:
5824 except error.CapabilityError:
5822 err = _("other repository doesn't support revision lookup, "
5825 err = _("other repository doesn't support revision lookup, "
5823 "so a rev cannot be specified.")
5826 "so a rev cannot be specified.")
5824 raise error.Abort(err)
5827 raise error.Abort(err)
5825
5828
5826 pullopargs.update(opts.get('opargs', {}))
5829 pullopargs.update(opts.get('opargs', {}))
5827 modheads = exchange.pull(repo, other, heads=revs,
5830 modheads = exchange.pull(repo, other, heads=revs,
5828 force=opts.get('force'),
5831 force=opts.get('force'),
5829 bookmarks=opts.get('bookmark', ()),
5832 bookmarks=opts.get('bookmark', ()),
5830 opargs=pullopargs).cgresult
5833 opargs=pullopargs).cgresult
5831
5834
5832 # brev is a name, which might be a bookmark to be activated at
5835 # brev is a name, which might be a bookmark to be activated at
5833 # the end of the update. In other words, it is an explicit
5836 # the end of the update. In other words, it is an explicit
5834 # destination of the update
5837 # destination of the update
5835 brev = None
5838 brev = None
5836
5839
5837 if checkout:
5840 if checkout:
5838 checkout = str(repo.changelog.rev(checkout))
5841 checkout = str(repo.changelog.rev(checkout))
5839
5842
5840 # order below depends on implementation of
5843 # order below depends on implementation of
5841 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5844 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5842 # because 'checkout' is determined without it.
5845 # because 'checkout' is determined without it.
5843 if opts.get('rev'):
5846 if opts.get('rev'):
5844 brev = opts['rev'][0]
5847 brev = opts['rev'][0]
5845 elif opts.get('branch'):
5848 elif opts.get('branch'):
5846 brev = opts['branch'][0]
5849 brev = opts['branch'][0]
5847 else:
5850 else:
5848 brev = branches[0]
5851 brev = branches[0]
5849 repo._subtoppath = source
5852 repo._subtoppath = source
5850 try:
5853 try:
5851 ret = postincoming(ui, repo, modheads, opts.get('update'),
5854 ret = postincoming(ui, repo, modheads, opts.get('update'),
5852 checkout, brev)
5855 checkout, brev)
5853
5856
5854 finally:
5857 finally:
5855 del repo._subtoppath
5858 del repo._subtoppath
5856
5859
5857 finally:
5860 finally:
5858 other.close()
5861 other.close()
5859 return ret
5862 return ret
5860
5863
5861 @command('^push',
5864 @command('^push',
5862 [('f', 'force', None, _('force push')),
5865 [('f', 'force', None, _('force push')),
5863 ('r', 'rev', [],
5866 ('r', 'rev', [],
5864 _('a changeset intended to be included in the destination'),
5867 _('a changeset intended to be included in the destination'),
5865 _('REV')),
5868 _('REV')),
5866 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5869 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5867 ('b', 'branch', [],
5870 ('b', 'branch', [],
5868 _('a specific branch you would like to push'), _('BRANCH')),
5871 _('a specific branch you would like to push'), _('BRANCH')),
5869 ('', 'new-branch', False, _('allow pushing a new branch')),
5872 ('', 'new-branch', False, _('allow pushing a new branch')),
5870 ] + remoteopts,
5873 ] + remoteopts,
5871 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5874 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5872 def push(ui, repo, dest=None, **opts):
5875 def push(ui, repo, dest=None, **opts):
5873 """push changes to the specified destination
5876 """push changes to the specified destination
5874
5877
5875 Push changesets from the local repository to the specified
5878 Push changesets from the local repository to the specified
5876 destination.
5879 destination.
5877
5880
5878 This operation is symmetrical to pull: it is identical to a pull
5881 This operation is symmetrical to pull: it is identical to a pull
5879 in the destination repository from the current one.
5882 in the destination repository from the current one.
5880
5883
5881 By default, push will not allow creation of new heads at the
5884 By default, push will not allow creation of new heads at the
5882 destination, since multiple heads would make it unclear which head
5885 destination, since multiple heads would make it unclear which head
5883 to use. In this situation, it is recommended to pull and merge
5886 to use. In this situation, it is recommended to pull and merge
5884 before pushing.
5887 before pushing.
5885
5888
5886 Use --new-branch if you want to allow push to create a new named
5889 Use --new-branch if you want to allow push to create a new named
5887 branch that is not present at the destination. This allows you to
5890 branch that is not present at the destination. This allows you to
5888 only create a new branch without forcing other changes.
5891 only create a new branch without forcing other changes.
5889
5892
5890 .. note::
5893 .. note::
5891
5894
5892 Extra care should be taken with the -f/--force option,
5895 Extra care should be taken with the -f/--force option,
5893 which will push all new heads on all branches, an action which will
5896 which will push all new heads on all branches, an action which will
5894 almost always cause confusion for collaborators.
5897 almost always cause confusion for collaborators.
5895
5898
5896 If -r/--rev is used, the specified revision and all its ancestors
5899 If -r/--rev is used, the specified revision and all its ancestors
5897 will be pushed to the remote repository.
5900 will be pushed to the remote repository.
5898
5901
5899 If -B/--bookmark is used, the specified bookmarked revision, its
5902 If -B/--bookmark is used, the specified bookmarked revision, its
5900 ancestors, and the bookmark will be pushed to the remote
5903 ancestors, and the bookmark will be pushed to the remote
5901 repository. Specifying ``.`` is equivalent to specifying the active
5904 repository. Specifying ``.`` is equivalent to specifying the active
5902 bookmark's name.
5905 bookmark's name.
5903
5906
5904 Please see :hg:`help urls` for important details about ``ssh://``
5907 Please see :hg:`help urls` for important details about ``ssh://``
5905 URLs. If DESTINATION is omitted, a default path will be used.
5908 URLs. If DESTINATION is omitted, a default path will be used.
5906
5909
5907 Returns 0 if push was successful, 1 if nothing to push.
5910 Returns 0 if push was successful, 1 if nothing to push.
5908 """
5911 """
5909
5912
5910 if opts.get('bookmark'):
5913 if opts.get('bookmark'):
5911 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5914 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5912 for b in opts['bookmark']:
5915 for b in opts['bookmark']:
5913 # translate -B options to -r so changesets get pushed
5916 # translate -B options to -r so changesets get pushed
5914 b = repo._bookmarks.expandname(b)
5917 b = repo._bookmarks.expandname(b)
5915 if b in repo._bookmarks:
5918 if b in repo._bookmarks:
5916 opts.setdefault('rev', []).append(b)
5919 opts.setdefault('rev', []).append(b)
5917 else:
5920 else:
5918 # if we try to push a deleted bookmark, translate it to null
5921 # if we try to push a deleted bookmark, translate it to null
5919 # this lets simultaneous -r, -b options continue working
5922 # this lets simultaneous -r, -b options continue working
5920 opts.setdefault('rev', []).append("null")
5923 opts.setdefault('rev', []).append("null")
5921
5924
5922 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5925 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5923 if not path:
5926 if not path:
5924 raise error.Abort(_('default repository not configured!'),
5927 raise error.Abort(_('default repository not configured!'),
5925 hint=_('see the "path" section in "hg help config"'))
5928 hint=_('see the "path" section in "hg help config"'))
5926 dest = path.pushloc or path.loc
5929 dest = path.pushloc or path.loc
5927 branches = (path.branch, opts.get('branch') or [])
5930 branches = (path.branch, opts.get('branch') or [])
5928 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5931 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5929 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5932 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5930 other = hg.peer(repo, opts, dest)
5933 other = hg.peer(repo, opts, dest)
5931
5934
5932 if revs:
5935 if revs:
5933 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5936 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5934 if not revs:
5937 if not revs:
5935 raise error.Abort(_("specified revisions evaluate to an empty set"),
5938 raise error.Abort(_("specified revisions evaluate to an empty set"),
5936 hint=_("use different revision arguments"))
5939 hint=_("use different revision arguments"))
5937
5940
5938 repo._subtoppath = dest
5941 repo._subtoppath = dest
5939 try:
5942 try:
5940 # push subrepos depth-first for coherent ordering
5943 # push subrepos depth-first for coherent ordering
5941 c = repo['']
5944 c = repo['']
5942 subs = c.substate # only repos that are committed
5945 subs = c.substate # only repos that are committed
5943 for s in sorted(subs):
5946 for s in sorted(subs):
5944 result = c.sub(s).push(opts)
5947 result = c.sub(s).push(opts)
5945 if result == 0:
5948 if result == 0:
5946 return not result
5949 return not result
5947 finally:
5950 finally:
5948 del repo._subtoppath
5951 del repo._subtoppath
5949 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5952 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5950 newbranch=opts.get('new_branch'),
5953 newbranch=opts.get('new_branch'),
5951 bookmarks=opts.get('bookmark', ()),
5954 bookmarks=opts.get('bookmark', ()),
5952 opargs=opts.get('opargs'))
5955 opargs=opts.get('opargs'))
5953
5956
5954 result = not pushop.cgresult
5957 result = not pushop.cgresult
5955
5958
5956 if pushop.bkresult is not None:
5959 if pushop.bkresult is not None:
5957 if pushop.bkresult == 2:
5960 if pushop.bkresult == 2:
5958 result = 2
5961 result = 2
5959 elif not result and pushop.bkresult:
5962 elif not result and pushop.bkresult:
5960 result = 2
5963 result = 2
5961
5964
5962 return result
5965 return result
5963
5966
5964 @command('recover', [])
5967 @command('recover', [])
5965 def recover(ui, repo):
5968 def recover(ui, repo):
5966 """roll back an interrupted transaction
5969 """roll back an interrupted transaction
5967
5970
5968 Recover from an interrupted commit or pull.
5971 Recover from an interrupted commit or pull.
5969
5972
5970 This command tries to fix the repository status after an
5973 This command tries to fix the repository status after an
5971 interrupted operation. It should only be necessary when Mercurial
5974 interrupted operation. It should only be necessary when Mercurial
5972 suggests it.
5975 suggests it.
5973
5976
5974 Returns 0 if successful, 1 if nothing to recover or verify fails.
5977 Returns 0 if successful, 1 if nothing to recover or verify fails.
5975 """
5978 """
5976 if repo.recover():
5979 if repo.recover():
5977 return hg.verify(repo)
5980 return hg.verify(repo)
5978 return 1
5981 return 1
5979
5982
5980 @command('^remove|rm',
5983 @command('^remove|rm',
5981 [('A', 'after', None, _('record delete for missing files')),
5984 [('A', 'after', None, _('record delete for missing files')),
5982 ('f', 'force', None,
5985 ('f', 'force', None,
5983 _('forget added files, delete modified files')),
5986 _('forget added files, delete modified files')),
5984 ] + subrepoopts + walkopts,
5987 ] + subrepoopts + walkopts,
5985 _('[OPTION]... FILE...'),
5988 _('[OPTION]... FILE...'),
5986 inferrepo=True)
5989 inferrepo=True)
5987 def remove(ui, repo, *pats, **opts):
5990 def remove(ui, repo, *pats, **opts):
5988 """remove the specified files on the next commit
5991 """remove the specified files on the next commit
5989
5992
5990 Schedule the indicated files for removal from the current branch.
5993 Schedule the indicated files for removal from the current branch.
5991
5994
5992 This command schedules the files to be removed at the next commit.
5995 This command schedules the files to be removed at the next commit.
5993 To undo a remove before that, see :hg:`revert`. To undo added
5996 To undo a remove before that, see :hg:`revert`. To undo added
5994 files, see :hg:`forget`.
5997 files, see :hg:`forget`.
5995
5998
5996 .. container:: verbose
5999 .. container:: verbose
5997
6000
5998 -A/--after can be used to remove only files that have already
6001 -A/--after can be used to remove only files that have already
5999 been deleted, -f/--force can be used to force deletion, and -Af
6002 been deleted, -f/--force can be used to force deletion, and -Af
6000 can be used to remove files from the next revision without
6003 can be used to remove files from the next revision without
6001 deleting them from the working directory.
6004 deleting them from the working directory.
6002
6005
6003 The following table details the behavior of remove for different
6006 The following table details the behavior of remove for different
6004 file states (columns) and option combinations (rows). The file
6007 file states (columns) and option combinations (rows). The file
6005 states are Added [A], Clean [C], Modified [M] and Missing [!]
6008 states are Added [A], Clean [C], Modified [M] and Missing [!]
6006 (as reported by :hg:`status`). The actions are Warn, Remove
6009 (as reported by :hg:`status`). The actions are Warn, Remove
6007 (from branch) and Delete (from disk):
6010 (from branch) and Delete (from disk):
6008
6011
6009 ========= == == == ==
6012 ========= == == == ==
6010 opt/state A C M !
6013 opt/state A C M !
6011 ========= == == == ==
6014 ========= == == == ==
6012 none W RD W R
6015 none W RD W R
6013 -f R RD RD R
6016 -f R RD RD R
6014 -A W W W R
6017 -A W W W R
6015 -Af R R R R
6018 -Af R R R R
6016 ========= == == == ==
6019 ========= == == == ==
6017
6020
6018 .. note::
6021 .. note::
6019
6022
6020 :hg:`remove` never deletes files in Added [A] state from the
6023 :hg:`remove` never deletes files in Added [A] state from the
6021 working directory, not even if ``--force`` is specified.
6024 working directory, not even if ``--force`` is specified.
6022
6025
6023 Returns 0 on success, 1 if any warnings encountered.
6026 Returns 0 on success, 1 if any warnings encountered.
6024 """
6027 """
6025
6028
6026 after, force = opts.get('after'), opts.get('force')
6029 after, force = opts.get('after'), opts.get('force')
6027 if not pats and not after:
6030 if not pats and not after:
6028 raise error.Abort(_('no files specified'))
6031 raise error.Abort(_('no files specified'))
6029
6032
6030 m = scmutil.match(repo[None], pats, opts)
6033 m = scmutil.match(repo[None], pats, opts)
6031 subrepos = opts.get('subrepos')
6034 subrepos = opts.get('subrepos')
6032 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6035 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
6033
6036
6034 @command('rename|move|mv',
6037 @command('rename|move|mv',
6035 [('A', 'after', None, _('record a rename that has already occurred')),
6038 [('A', 'after', None, _('record a rename that has already occurred')),
6036 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6039 ('f', 'force', None, _('forcibly copy over an existing managed file')),
6037 ] + walkopts + dryrunopts,
6040 ] + walkopts + dryrunopts,
6038 _('[OPTION]... SOURCE... DEST'))
6041 _('[OPTION]... SOURCE... DEST'))
6039 def rename(ui, repo, *pats, **opts):
6042 def rename(ui, repo, *pats, **opts):
6040 """rename files; equivalent of copy + remove
6043 """rename files; equivalent of copy + remove
6041
6044
6042 Mark dest as copies of sources; mark sources for deletion. If dest
6045 Mark dest as copies of sources; mark sources for deletion. If dest
6043 is a directory, copies are put in that directory. If dest is a
6046 is a directory, copies are put in that directory. If dest is a
6044 file, there can only be one source.
6047 file, there can only be one source.
6045
6048
6046 By default, this command copies the contents of files as they
6049 By default, this command copies the contents of files as they
6047 exist in the working directory. If invoked with -A/--after, the
6050 exist in the working directory. If invoked with -A/--after, the
6048 operation is recorded, but no copying is performed.
6051 operation is recorded, but no copying is performed.
6049
6052
6050 This command takes effect at the next commit. To undo a rename
6053 This command takes effect at the next commit. To undo a rename
6051 before that, see :hg:`revert`.
6054 before that, see :hg:`revert`.
6052
6055
6053 Returns 0 on success, 1 if errors are encountered.
6056 Returns 0 on success, 1 if errors are encountered.
6054 """
6057 """
6055 with repo.wlock(False):
6058 with repo.wlock(False):
6056 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6059 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6057
6060
6058 @command('resolve',
6061 @command('resolve',
6059 [('a', 'all', None, _('select all unresolved files')),
6062 [('a', 'all', None, _('select all unresolved files')),
6060 ('l', 'list', None, _('list state of files needing merge')),
6063 ('l', 'list', None, _('list state of files needing merge')),
6061 ('m', 'mark', None, _('mark files as resolved')),
6064 ('m', 'mark', None, _('mark files as resolved')),
6062 ('u', 'unmark', None, _('mark files as unresolved')),
6065 ('u', 'unmark', None, _('mark files as unresolved')),
6063 ('n', 'no-status', None, _('hide status prefix'))]
6066 ('n', 'no-status', None, _('hide status prefix'))]
6064 + mergetoolopts + walkopts + formatteropts,
6067 + mergetoolopts + walkopts + formatteropts,
6065 _('[OPTION]... [FILE]...'),
6068 _('[OPTION]... [FILE]...'),
6066 inferrepo=True)
6069 inferrepo=True)
6067 def resolve(ui, repo, *pats, **opts):
6070 def resolve(ui, repo, *pats, **opts):
6068 """redo merges or set/view the merge status of files
6071 """redo merges or set/view the merge status of files
6069
6072
6070 Merges with unresolved conflicts are often the result of
6073 Merges with unresolved conflicts are often the result of
6071 non-interactive merging using the ``internal:merge`` configuration
6074 non-interactive merging using the ``internal:merge`` configuration
6072 setting, or a command-line merge tool like ``diff3``. The resolve
6075 setting, or a command-line merge tool like ``diff3``. The resolve
6073 command is used to manage the files involved in a merge, after
6076 command is used to manage the files involved in a merge, after
6074 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6077 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6075 working directory must have two parents). See :hg:`help
6078 working directory must have two parents). See :hg:`help
6076 merge-tools` for information on configuring merge tools.
6079 merge-tools` for information on configuring merge tools.
6077
6080
6078 The resolve command can be used in the following ways:
6081 The resolve command can be used in the following ways:
6079
6082
6080 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6083 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6081 files, discarding any previous merge attempts. Re-merging is not
6084 files, discarding any previous merge attempts. Re-merging is not
6082 performed for files already marked as resolved. Use ``--all/-a``
6085 performed for files already marked as resolved. Use ``--all/-a``
6083 to select all unresolved files. ``--tool`` can be used to specify
6086 to select all unresolved files. ``--tool`` can be used to specify
6084 the merge tool used for the given files. It overrides the HGMERGE
6087 the merge tool used for the given files. It overrides the HGMERGE
6085 environment variable and your configuration files. Previous file
6088 environment variable and your configuration files. Previous file
6086 contents are saved with a ``.orig`` suffix.
6089 contents are saved with a ``.orig`` suffix.
6087
6090
6088 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6091 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6089 (e.g. after having manually fixed-up the files). The default is
6092 (e.g. after having manually fixed-up the files). The default is
6090 to mark all unresolved files.
6093 to mark all unresolved files.
6091
6094
6092 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6095 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6093 default is to mark all resolved files.
6096 default is to mark all resolved files.
6094
6097
6095 - :hg:`resolve -l`: list files which had or still have conflicts.
6098 - :hg:`resolve -l`: list files which had or still have conflicts.
6096 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6099 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6097
6100
6098 .. note::
6101 .. note::
6099
6102
6100 Mercurial will not let you commit files with unresolved merge
6103 Mercurial will not let you commit files with unresolved merge
6101 conflicts. You must use :hg:`resolve -m ...` before you can
6104 conflicts. You must use :hg:`resolve -m ...` before you can
6102 commit after a conflicting merge.
6105 commit after a conflicting merge.
6103
6106
6104 Returns 0 on success, 1 if any files fail a resolve attempt.
6107 Returns 0 on success, 1 if any files fail a resolve attempt.
6105 """
6108 """
6106
6109
6107 flaglist = 'all mark unmark list no_status'.split()
6110 flaglist = 'all mark unmark list no_status'.split()
6108 all, mark, unmark, show, nostatus = \
6111 all, mark, unmark, show, nostatus = \
6109 [opts.get(o) for o in flaglist]
6112 [opts.get(o) for o in flaglist]
6110
6113
6111 if (show and (mark or unmark)) or (mark and unmark):
6114 if (show and (mark or unmark)) or (mark and unmark):
6112 raise error.Abort(_("too many options specified"))
6115 raise error.Abort(_("too many options specified"))
6113 if pats and all:
6116 if pats and all:
6114 raise error.Abort(_("can't specify --all and patterns"))
6117 raise error.Abort(_("can't specify --all and patterns"))
6115 if not (all or pats or show or mark or unmark):
6118 if not (all or pats or show or mark or unmark):
6116 raise error.Abort(_('no files or directories specified'),
6119 raise error.Abort(_('no files or directories specified'),
6117 hint=('use --all to re-merge all unresolved files'))
6120 hint=('use --all to re-merge all unresolved files'))
6118
6121
6119 if show:
6122 if show:
6120 fm = ui.formatter('resolve', opts)
6123 fm = ui.formatter('resolve', opts)
6121 ms = mergemod.mergestate.read(repo)
6124 ms = mergemod.mergestate.read(repo)
6122 m = scmutil.match(repo[None], pats, opts)
6125 m = scmutil.match(repo[None], pats, opts)
6123 for f in ms:
6126 for f in ms:
6124 if not m(f):
6127 if not m(f):
6125 continue
6128 continue
6126 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6129 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6127 'd': 'driverresolved'}[ms[f]]
6130 'd': 'driverresolved'}[ms[f]]
6128 fm.startitem()
6131 fm.startitem()
6129 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6132 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6130 fm.write('path', '%s\n', f, label=l)
6133 fm.write('path', '%s\n', f, label=l)
6131 fm.end()
6134 fm.end()
6132 return 0
6135 return 0
6133
6136
6134 with repo.wlock():
6137 with repo.wlock():
6135 ms = mergemod.mergestate.read(repo)
6138 ms = mergemod.mergestate.read(repo)
6136
6139
6137 if not (ms.active() or repo.dirstate.p2() != nullid):
6140 if not (ms.active() or repo.dirstate.p2() != nullid):
6138 raise error.Abort(
6141 raise error.Abort(
6139 _('resolve command not applicable when not merging'))
6142 _('resolve command not applicable when not merging'))
6140
6143
6141 wctx = repo[None]
6144 wctx = repo[None]
6142
6145
6143 if ms.mergedriver and ms.mdstate() == 'u':
6146 if ms.mergedriver and ms.mdstate() == 'u':
6144 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6147 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6145 ms.commit()
6148 ms.commit()
6146 # allow mark and unmark to go through
6149 # allow mark and unmark to go through
6147 if not mark and not unmark and not proceed:
6150 if not mark and not unmark and not proceed:
6148 return 1
6151 return 1
6149
6152
6150 m = scmutil.match(wctx, pats, opts)
6153 m = scmutil.match(wctx, pats, opts)
6151 ret = 0
6154 ret = 0
6152 didwork = False
6155 didwork = False
6153 runconclude = False
6156 runconclude = False
6154
6157
6155 tocomplete = []
6158 tocomplete = []
6156 for f in ms:
6159 for f in ms:
6157 if not m(f):
6160 if not m(f):
6158 continue
6161 continue
6159
6162
6160 didwork = True
6163 didwork = True
6161
6164
6162 # don't let driver-resolved files be marked, and run the conclude
6165 # don't let driver-resolved files be marked, and run the conclude
6163 # step if asked to resolve
6166 # step if asked to resolve
6164 if ms[f] == "d":
6167 if ms[f] == "d":
6165 exact = m.exact(f)
6168 exact = m.exact(f)
6166 if mark:
6169 if mark:
6167 if exact:
6170 if exact:
6168 ui.warn(_('not marking %s as it is driver-resolved\n')
6171 ui.warn(_('not marking %s as it is driver-resolved\n')
6169 % f)
6172 % f)
6170 elif unmark:
6173 elif unmark:
6171 if exact:
6174 if exact:
6172 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6175 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6173 % f)
6176 % f)
6174 else:
6177 else:
6175 runconclude = True
6178 runconclude = True
6176 continue
6179 continue
6177
6180
6178 if mark:
6181 if mark:
6179 ms.mark(f, "r")
6182 ms.mark(f, "r")
6180 elif unmark:
6183 elif unmark:
6181 ms.mark(f, "u")
6184 ms.mark(f, "u")
6182 else:
6185 else:
6183 # backup pre-resolve (merge uses .orig for its own purposes)
6186 # backup pre-resolve (merge uses .orig for its own purposes)
6184 a = repo.wjoin(f)
6187 a = repo.wjoin(f)
6185 try:
6188 try:
6186 util.copyfile(a, a + ".resolve")
6189 util.copyfile(a, a + ".resolve")
6187 except (IOError, OSError) as inst:
6190 except (IOError, OSError) as inst:
6188 if inst.errno != errno.ENOENT:
6191 if inst.errno != errno.ENOENT:
6189 raise
6192 raise
6190
6193
6191 try:
6194 try:
6192 # preresolve file
6195 # preresolve file
6193 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6196 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6194 'resolve')
6197 'resolve')
6195 complete, r = ms.preresolve(f, wctx)
6198 complete, r = ms.preresolve(f, wctx)
6196 if not complete:
6199 if not complete:
6197 tocomplete.append(f)
6200 tocomplete.append(f)
6198 elif r:
6201 elif r:
6199 ret = 1
6202 ret = 1
6200 finally:
6203 finally:
6201 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6204 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6202 ms.commit()
6205 ms.commit()
6203
6206
6204 # replace filemerge's .orig file with our resolve file, but only
6207 # replace filemerge's .orig file with our resolve file, but only
6205 # for merges that are complete
6208 # for merges that are complete
6206 if complete:
6209 if complete:
6207 try:
6210 try:
6208 util.rename(a + ".resolve",
6211 util.rename(a + ".resolve",
6209 scmutil.origpath(ui, repo, a))
6212 scmutil.origpath(ui, repo, a))
6210 except OSError as inst:
6213 except OSError as inst:
6211 if inst.errno != errno.ENOENT:
6214 if inst.errno != errno.ENOENT:
6212 raise
6215 raise
6213
6216
6214 for f in tocomplete:
6217 for f in tocomplete:
6215 try:
6218 try:
6216 # resolve file
6219 # resolve file
6217 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6220 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6218 'resolve')
6221 'resolve')
6219 r = ms.resolve(f, wctx)
6222 r = ms.resolve(f, wctx)
6220 if r:
6223 if r:
6221 ret = 1
6224 ret = 1
6222 finally:
6225 finally:
6223 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6226 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6224 ms.commit()
6227 ms.commit()
6225
6228
6226 # replace filemerge's .orig file with our resolve file
6229 # replace filemerge's .orig file with our resolve file
6227 a = repo.wjoin(f)
6230 a = repo.wjoin(f)
6228 try:
6231 try:
6229 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6232 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6230 except OSError as inst:
6233 except OSError as inst:
6231 if inst.errno != errno.ENOENT:
6234 if inst.errno != errno.ENOENT:
6232 raise
6235 raise
6233
6236
6234 ms.commit()
6237 ms.commit()
6235 ms.recordactions()
6238 ms.recordactions()
6236
6239
6237 if not didwork and pats:
6240 if not didwork and pats:
6238 hint = None
6241 hint = None
6239 if not any([p for p in pats if p.find(':') >= 0]):
6242 if not any([p for p in pats if p.find(':') >= 0]):
6240 pats = ['path:%s' % p for p in pats]
6243 pats = ['path:%s' % p for p in pats]
6241 m = scmutil.match(wctx, pats, opts)
6244 m = scmutil.match(wctx, pats, opts)
6242 for f in ms:
6245 for f in ms:
6243 if not m(f):
6246 if not m(f):
6244 continue
6247 continue
6245 flags = ''.join(['-%s ' % o[0] for o in flaglist
6248 flags = ''.join(['-%s ' % o[0] for o in flaglist
6246 if opts.get(o)])
6249 if opts.get(o)])
6247 hint = _("(try: hg resolve %s%s)\n") % (
6250 hint = _("(try: hg resolve %s%s)\n") % (
6248 flags,
6251 flags,
6249 ' '.join(pats))
6252 ' '.join(pats))
6250 break
6253 break
6251 ui.warn(_("arguments do not match paths that need resolving\n"))
6254 ui.warn(_("arguments do not match paths that need resolving\n"))
6252 if hint:
6255 if hint:
6253 ui.warn(hint)
6256 ui.warn(hint)
6254 elif ms.mergedriver and ms.mdstate() != 's':
6257 elif ms.mergedriver and ms.mdstate() != 's':
6255 # run conclude step when either a driver-resolved file is requested
6258 # run conclude step when either a driver-resolved file is requested
6256 # or there are no driver-resolved files
6259 # or there are no driver-resolved files
6257 # we can't use 'ret' to determine whether any files are unresolved
6260 # we can't use 'ret' to determine whether any files are unresolved
6258 # because we might not have tried to resolve some
6261 # because we might not have tried to resolve some
6259 if ((runconclude or not list(ms.driverresolved()))
6262 if ((runconclude or not list(ms.driverresolved()))
6260 and not list(ms.unresolved())):
6263 and not list(ms.unresolved())):
6261 proceed = mergemod.driverconclude(repo, ms, wctx)
6264 proceed = mergemod.driverconclude(repo, ms, wctx)
6262 ms.commit()
6265 ms.commit()
6263 if not proceed:
6266 if not proceed:
6264 return 1
6267 return 1
6265
6268
6266 # Nudge users into finishing an unfinished operation
6269 # Nudge users into finishing an unfinished operation
6267 unresolvedf = list(ms.unresolved())
6270 unresolvedf = list(ms.unresolved())
6268 driverresolvedf = list(ms.driverresolved())
6271 driverresolvedf = list(ms.driverresolved())
6269 if not unresolvedf and not driverresolvedf:
6272 if not unresolvedf and not driverresolvedf:
6270 ui.status(_('(no more unresolved files)\n'))
6273 ui.status(_('(no more unresolved files)\n'))
6271 cmdutil.checkafterresolved(repo)
6274 cmdutil.checkafterresolved(repo)
6272 elif not unresolvedf:
6275 elif not unresolvedf:
6273 ui.status(_('(no more unresolved files -- '
6276 ui.status(_('(no more unresolved files -- '
6274 'run "hg resolve --all" to conclude)\n'))
6277 'run "hg resolve --all" to conclude)\n'))
6275
6278
6276 return ret
6279 return ret
6277
6280
6278 @command('revert',
6281 @command('revert',
6279 [('a', 'all', None, _('revert all changes when no arguments given')),
6282 [('a', 'all', None, _('revert all changes when no arguments given')),
6280 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6283 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6281 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6284 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6282 ('C', 'no-backup', None, _('do not save backup copies of files')),
6285 ('C', 'no-backup', None, _('do not save backup copies of files')),
6283 ('i', 'interactive', None,
6286 ('i', 'interactive', None,
6284 _('interactively select the changes (EXPERIMENTAL)')),
6287 _('interactively select the changes (EXPERIMENTAL)')),
6285 ] + walkopts + dryrunopts,
6288 ] + walkopts + dryrunopts,
6286 _('[OPTION]... [-r REV] [NAME]...'))
6289 _('[OPTION]... [-r REV] [NAME]...'))
6287 def revert(ui, repo, *pats, **opts):
6290 def revert(ui, repo, *pats, **opts):
6288 """restore files to their checkout state
6291 """restore files to their checkout state
6289
6292
6290 .. note::
6293 .. note::
6291
6294
6292 To check out earlier revisions, you should use :hg:`update REV`.
6295 To check out earlier revisions, you should use :hg:`update REV`.
6293 To cancel an uncommitted merge (and lose your changes),
6296 To cancel an uncommitted merge (and lose your changes),
6294 use :hg:`update --clean .`.
6297 use :hg:`update --clean .`.
6295
6298
6296 With no revision specified, revert the specified files or directories
6299 With no revision specified, revert the specified files or directories
6297 to the contents they had in the parent of the working directory.
6300 to the contents they had in the parent of the working directory.
6298 This restores the contents of files to an unmodified
6301 This restores the contents of files to an unmodified
6299 state and unschedules adds, removes, copies, and renames. If the
6302 state and unschedules adds, removes, copies, and renames. If the
6300 working directory has two parents, you must explicitly specify a
6303 working directory has two parents, you must explicitly specify a
6301 revision.
6304 revision.
6302
6305
6303 Using the -r/--rev or -d/--date options, revert the given files or
6306 Using the -r/--rev or -d/--date options, revert the given files or
6304 directories to their states as of a specific revision. Because
6307 directories to their states as of a specific revision. Because
6305 revert does not change the working directory parents, this will
6308 revert does not change the working directory parents, this will
6306 cause these files to appear modified. This can be helpful to "back
6309 cause these files to appear modified. This can be helpful to "back
6307 out" some or all of an earlier change. See :hg:`backout` for a
6310 out" some or all of an earlier change. See :hg:`backout` for a
6308 related method.
6311 related method.
6309
6312
6310 Modified files are saved with a .orig suffix before reverting.
6313 Modified files are saved with a .orig suffix before reverting.
6311 To disable these backups, use --no-backup. It is possible to store
6314 To disable these backups, use --no-backup. It is possible to store
6312 the backup files in a custom directory relative to the root of the
6315 the backup files in a custom directory relative to the root of the
6313 repository by setting the ``ui.origbackuppath`` configuration
6316 repository by setting the ``ui.origbackuppath`` configuration
6314 option.
6317 option.
6315
6318
6316 See :hg:`help dates` for a list of formats valid for -d/--date.
6319 See :hg:`help dates` for a list of formats valid for -d/--date.
6317
6320
6318 See :hg:`help backout` for a way to reverse the effect of an
6321 See :hg:`help backout` for a way to reverse the effect of an
6319 earlier changeset.
6322 earlier changeset.
6320
6323
6321 Returns 0 on success.
6324 Returns 0 on success.
6322 """
6325 """
6323
6326
6324 if opts.get("date"):
6327 if opts.get("date"):
6325 if opts.get("rev"):
6328 if opts.get("rev"):
6326 raise error.Abort(_("you can't specify a revision and a date"))
6329 raise error.Abort(_("you can't specify a revision and a date"))
6327 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6330 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6328
6331
6329 parent, p2 = repo.dirstate.parents()
6332 parent, p2 = repo.dirstate.parents()
6330 if not opts.get('rev') and p2 != nullid:
6333 if not opts.get('rev') and p2 != nullid:
6331 # revert after merge is a trap for new users (issue2915)
6334 # revert after merge is a trap for new users (issue2915)
6332 raise error.Abort(_('uncommitted merge with no revision specified'),
6335 raise error.Abort(_('uncommitted merge with no revision specified'),
6333 hint=_("use 'hg update' or see 'hg help revert'"))
6336 hint=_("use 'hg update' or see 'hg help revert'"))
6334
6337
6335 ctx = scmutil.revsingle(repo, opts.get('rev'))
6338 ctx = scmutil.revsingle(repo, opts.get('rev'))
6336
6339
6337 if (not (pats or opts.get('include') or opts.get('exclude') or
6340 if (not (pats or opts.get('include') or opts.get('exclude') or
6338 opts.get('all') or opts.get('interactive'))):
6341 opts.get('all') or opts.get('interactive'))):
6339 msg = _("no files or directories specified")
6342 msg = _("no files or directories specified")
6340 if p2 != nullid:
6343 if p2 != nullid:
6341 hint = _("uncommitted merge, use --all to discard all changes,"
6344 hint = _("uncommitted merge, use --all to discard all changes,"
6342 " or 'hg update -C .' to abort the merge")
6345 " or 'hg update -C .' to abort the merge")
6343 raise error.Abort(msg, hint=hint)
6346 raise error.Abort(msg, hint=hint)
6344 dirty = any(repo.status())
6347 dirty = any(repo.status())
6345 node = ctx.node()
6348 node = ctx.node()
6346 if node != parent:
6349 if node != parent:
6347 if dirty:
6350 if dirty:
6348 hint = _("uncommitted changes, use --all to discard all"
6351 hint = _("uncommitted changes, use --all to discard all"
6349 " changes, or 'hg update %s' to update") % ctx.rev()
6352 " changes, or 'hg update %s' to update") % ctx.rev()
6350 else:
6353 else:
6351 hint = _("use --all to revert all files,"
6354 hint = _("use --all to revert all files,"
6352 " or 'hg update %s' to update") % ctx.rev()
6355 " or 'hg update %s' to update") % ctx.rev()
6353 elif dirty:
6356 elif dirty:
6354 hint = _("uncommitted changes, use --all to discard all changes")
6357 hint = _("uncommitted changes, use --all to discard all changes")
6355 else:
6358 else:
6356 hint = _("use --all to revert all files")
6359 hint = _("use --all to revert all files")
6357 raise error.Abort(msg, hint=hint)
6360 raise error.Abort(msg, hint=hint)
6358
6361
6359 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6362 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6360
6363
6361 @command('rollback', dryrunopts +
6364 @command('rollback', dryrunopts +
6362 [('f', 'force', False, _('ignore safety measures'))])
6365 [('f', 'force', False, _('ignore safety measures'))])
6363 def rollback(ui, repo, **opts):
6366 def rollback(ui, repo, **opts):
6364 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6367 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6365
6368
6366 Please use :hg:`commit --amend` instead of rollback to correct
6369 Please use :hg:`commit --amend` instead of rollback to correct
6367 mistakes in the last commit.
6370 mistakes in the last commit.
6368
6371
6369 This command should be used with care. There is only one level of
6372 This command should be used with care. There is only one level of
6370 rollback, and there is no way to undo a rollback. It will also
6373 rollback, and there is no way to undo a rollback. It will also
6371 restore the dirstate at the time of the last transaction, losing
6374 restore the dirstate at the time of the last transaction, losing
6372 any dirstate changes since that time. This command does not alter
6375 any dirstate changes since that time. This command does not alter
6373 the working directory.
6376 the working directory.
6374
6377
6375 Transactions are used to encapsulate the effects of all commands
6378 Transactions are used to encapsulate the effects of all commands
6376 that create new changesets or propagate existing changesets into a
6379 that create new changesets or propagate existing changesets into a
6377 repository.
6380 repository.
6378
6381
6379 .. container:: verbose
6382 .. container:: verbose
6380
6383
6381 For example, the following commands are transactional, and their
6384 For example, the following commands are transactional, and their
6382 effects can be rolled back:
6385 effects can be rolled back:
6383
6386
6384 - commit
6387 - commit
6385 - import
6388 - import
6386 - pull
6389 - pull
6387 - push (with this repository as the destination)
6390 - push (with this repository as the destination)
6388 - unbundle
6391 - unbundle
6389
6392
6390 To avoid permanent data loss, rollback will refuse to rollback a
6393 To avoid permanent data loss, rollback will refuse to rollback a
6391 commit transaction if it isn't checked out. Use --force to
6394 commit transaction if it isn't checked out. Use --force to
6392 override this protection.
6395 override this protection.
6393
6396
6394 The rollback command can be entirely disabled by setting the
6397 The rollback command can be entirely disabled by setting the
6395 ``ui.rollback`` configuration setting to false. If you're here
6398 ``ui.rollback`` configuration setting to false. If you're here
6396 because you want to use rollback and it's disabled, you can
6399 because you want to use rollback and it's disabled, you can
6397 re-enable the command by setting ``ui.rollback`` to true.
6400 re-enable the command by setting ``ui.rollback`` to true.
6398
6401
6399 This command is not intended for use on public repositories. Once
6402 This command is not intended for use on public repositories. Once
6400 changes are visible for pull by other users, rolling a transaction
6403 changes are visible for pull by other users, rolling a transaction
6401 back locally is ineffective (someone else may already have pulled
6404 back locally is ineffective (someone else may already have pulled
6402 the changes). Furthermore, a race is possible with readers of the
6405 the changes). Furthermore, a race is possible with readers of the
6403 repository; for example an in-progress pull from the repository
6406 repository; for example an in-progress pull from the repository
6404 may fail if a rollback is performed.
6407 may fail if a rollback is performed.
6405
6408
6406 Returns 0 on success, 1 if no rollback data is available.
6409 Returns 0 on success, 1 if no rollback data is available.
6407 """
6410 """
6408 if not ui.configbool('ui', 'rollback', True):
6411 if not ui.configbool('ui', 'rollback', True):
6409 raise error.Abort(_('rollback is disabled because it is unsafe'),
6412 raise error.Abort(_('rollback is disabled because it is unsafe'),
6410 hint=('see `hg help -v rollback` for information'))
6413 hint=('see `hg help -v rollback` for information'))
6411 return repo.rollback(dryrun=opts.get('dry_run'),
6414 return repo.rollback(dryrun=opts.get('dry_run'),
6412 force=opts.get('force'))
6415 force=opts.get('force'))
6413
6416
6414 @command('root', [])
6417 @command('root', [])
6415 def root(ui, repo):
6418 def root(ui, repo):
6416 """print the root (top) of the current working directory
6419 """print the root (top) of the current working directory
6417
6420
6418 Print the root directory of the current repository.
6421 Print the root directory of the current repository.
6419
6422
6420 Returns 0 on success.
6423 Returns 0 on success.
6421 """
6424 """
6422 ui.write(repo.root + "\n")
6425 ui.write(repo.root + "\n")
6423
6426
6424 @command('^serve',
6427 @command('^serve',
6425 [('A', 'accesslog', '', _('name of access log file to write to'),
6428 [('A', 'accesslog', '', _('name of access log file to write to'),
6426 _('FILE')),
6429 _('FILE')),
6427 ('d', 'daemon', None, _('run server in background')),
6430 ('d', 'daemon', None, _('run server in background')),
6428 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6431 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6429 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6432 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6430 # use string type, then we can check if something was passed
6433 # use string type, then we can check if something was passed
6431 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6434 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6432 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6435 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6433 _('ADDR')),
6436 _('ADDR')),
6434 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6437 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6435 _('PREFIX')),
6438 _('PREFIX')),
6436 ('n', 'name', '',
6439 ('n', 'name', '',
6437 _('name to show in web pages (default: working directory)'), _('NAME')),
6440 _('name to show in web pages (default: working directory)'), _('NAME')),
6438 ('', 'web-conf', '',
6441 ('', 'web-conf', '',
6439 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6442 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6440 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6443 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6441 _('FILE')),
6444 _('FILE')),
6442 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6445 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6443 ('', 'stdio', None, _('for remote clients')),
6446 ('', 'stdio', None, _('for remote clients')),
6444 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6447 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6445 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6448 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6446 ('', 'style', '', _('template style to use'), _('STYLE')),
6449 ('', 'style', '', _('template style to use'), _('STYLE')),
6447 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6450 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6448 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6451 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6449 _('[OPTION]...'),
6452 _('[OPTION]...'),
6450 optionalrepo=True)
6453 optionalrepo=True)
6451 def serve(ui, repo, **opts):
6454 def serve(ui, repo, **opts):
6452 """start stand-alone webserver
6455 """start stand-alone webserver
6453
6456
6454 Start a local HTTP repository browser and pull server. You can use
6457 Start a local HTTP repository browser and pull server. You can use
6455 this for ad-hoc sharing and browsing of repositories. It is
6458 this for ad-hoc sharing and browsing of repositories. It is
6456 recommended to use a real web server to serve a repository for
6459 recommended to use a real web server to serve a repository for
6457 longer periods of time.
6460 longer periods of time.
6458
6461
6459 Please note that the server does not implement access control.
6462 Please note that the server does not implement access control.
6460 This means that, by default, anybody can read from the server and
6463 This means that, by default, anybody can read from the server and
6461 nobody can write to it by default. Set the ``web.allow_push``
6464 nobody can write to it by default. Set the ``web.allow_push``
6462 option to ``*`` to allow everybody to push to the server. You
6465 option to ``*`` to allow everybody to push to the server. You
6463 should use a real web server if you need to authenticate users.
6466 should use a real web server if you need to authenticate users.
6464
6467
6465 By default, the server logs accesses to stdout and errors to
6468 By default, the server logs accesses to stdout and errors to
6466 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6469 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6467 files.
6470 files.
6468
6471
6469 To have the server choose a free port number to listen on, specify
6472 To have the server choose a free port number to listen on, specify
6470 a port number of 0; in this case, the server will print the port
6473 a port number of 0; in this case, the server will print the port
6471 number it uses.
6474 number it uses.
6472
6475
6473 Returns 0 on success.
6476 Returns 0 on success.
6474 """
6477 """
6475
6478
6476 if opts["stdio"] and opts["cmdserver"]:
6479 if opts["stdio"] and opts["cmdserver"]:
6477 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6480 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6478
6481
6479 if opts["stdio"]:
6482 if opts["stdio"]:
6480 if repo is None:
6483 if repo is None:
6481 raise error.RepoError(_("there is no Mercurial repository here"
6484 raise error.RepoError(_("there is no Mercurial repository here"
6482 " (.hg not found)"))
6485 " (.hg not found)"))
6483 s = sshserver.sshserver(ui, repo)
6486 s = sshserver.sshserver(ui, repo)
6484 s.serve_forever()
6487 s.serve_forever()
6485
6488
6486 if opts["cmdserver"]:
6489 if opts["cmdserver"]:
6487 service = commandserver.createservice(ui, repo, opts)
6490 service = commandserver.createservice(ui, repo, opts)
6488 else:
6491 else:
6489 service = hgweb.createservice(ui, repo, opts)
6492 service = hgweb.createservice(ui, repo, opts)
6490 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6493 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6491
6494
6492 @command('^status|st',
6495 @command('^status|st',
6493 [('A', 'all', None, _('show status of all files')),
6496 [('A', 'all', None, _('show status of all files')),
6494 ('m', 'modified', None, _('show only modified files')),
6497 ('m', 'modified', None, _('show only modified files')),
6495 ('a', 'added', None, _('show only added files')),
6498 ('a', 'added', None, _('show only added files')),
6496 ('r', 'removed', None, _('show only removed files')),
6499 ('r', 'removed', None, _('show only removed files')),
6497 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6500 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6498 ('c', 'clean', None, _('show only files without changes')),
6501 ('c', 'clean', None, _('show only files without changes')),
6499 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6502 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6500 ('i', 'ignored', None, _('show only ignored files')),
6503 ('i', 'ignored', None, _('show only ignored files')),
6501 ('n', 'no-status', None, _('hide status prefix')),
6504 ('n', 'no-status', None, _('hide status prefix')),
6502 ('C', 'copies', None, _('show source of copied files')),
6505 ('C', 'copies', None, _('show source of copied files')),
6503 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6506 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6504 ('', 'rev', [], _('show difference from revision'), _('REV')),
6507 ('', 'rev', [], _('show difference from revision'), _('REV')),
6505 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6508 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6506 ] + walkopts + subrepoopts + formatteropts,
6509 ] + walkopts + subrepoopts + formatteropts,
6507 _('[OPTION]... [FILE]...'),
6510 _('[OPTION]... [FILE]...'),
6508 inferrepo=True)
6511 inferrepo=True)
6509 def status(ui, repo, *pats, **opts):
6512 def status(ui, repo, *pats, **opts):
6510 """show changed files in the working directory
6513 """show changed files in the working directory
6511
6514
6512 Show status of files in the repository. If names are given, only
6515 Show status of files in the repository. If names are given, only
6513 files that match are shown. Files that are clean or ignored or
6516 files that match are shown. Files that are clean or ignored or
6514 the source of a copy/move operation, are not listed unless
6517 the source of a copy/move operation, are not listed unless
6515 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6518 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6516 Unless options described with "show only ..." are given, the
6519 Unless options described with "show only ..." are given, the
6517 options -mardu are used.
6520 options -mardu are used.
6518
6521
6519 Option -q/--quiet hides untracked (unknown and ignored) files
6522 Option -q/--quiet hides untracked (unknown and ignored) files
6520 unless explicitly requested with -u/--unknown or -i/--ignored.
6523 unless explicitly requested with -u/--unknown or -i/--ignored.
6521
6524
6522 .. note::
6525 .. note::
6523
6526
6524 :hg:`status` may appear to disagree with diff if permissions have
6527 :hg:`status` may appear to disagree with diff if permissions have
6525 changed or a merge has occurred. The standard diff format does
6528 changed or a merge has occurred. The standard diff format does
6526 not report permission changes and diff only reports changes
6529 not report permission changes and diff only reports changes
6527 relative to one merge parent.
6530 relative to one merge parent.
6528
6531
6529 If one revision is given, it is used as the base revision.
6532 If one revision is given, it is used as the base revision.
6530 If two revisions are given, the differences between them are
6533 If two revisions are given, the differences between them are
6531 shown. The --change option can also be used as a shortcut to list
6534 shown. The --change option can also be used as a shortcut to list
6532 the changed files of a revision from its first parent.
6535 the changed files of a revision from its first parent.
6533
6536
6534 The codes used to show the status of files are::
6537 The codes used to show the status of files are::
6535
6538
6536 M = modified
6539 M = modified
6537 A = added
6540 A = added
6538 R = removed
6541 R = removed
6539 C = clean
6542 C = clean
6540 ! = missing (deleted by non-hg command, but still tracked)
6543 ! = missing (deleted by non-hg command, but still tracked)
6541 ? = not tracked
6544 ? = not tracked
6542 I = ignored
6545 I = ignored
6543 = origin of the previous file (with --copies)
6546 = origin of the previous file (with --copies)
6544
6547
6545 .. container:: verbose
6548 .. container:: verbose
6546
6549
6547 Examples:
6550 Examples:
6548
6551
6549 - show changes in the working directory relative to a
6552 - show changes in the working directory relative to a
6550 changeset::
6553 changeset::
6551
6554
6552 hg status --rev 9353
6555 hg status --rev 9353
6553
6556
6554 - show changes in the working directory relative to the
6557 - show changes in the working directory relative to the
6555 current directory (see :hg:`help patterns` for more information)::
6558 current directory (see :hg:`help patterns` for more information)::
6556
6559
6557 hg status re:
6560 hg status re:
6558
6561
6559 - show all changes including copies in an existing changeset::
6562 - show all changes including copies in an existing changeset::
6560
6563
6561 hg status --copies --change 9353
6564 hg status --copies --change 9353
6562
6565
6563 - get a NUL separated list of added files, suitable for xargs::
6566 - get a NUL separated list of added files, suitable for xargs::
6564
6567
6565 hg status -an0
6568 hg status -an0
6566
6569
6567 Returns 0 on success.
6570 Returns 0 on success.
6568 """
6571 """
6569
6572
6570 revs = opts.get('rev')
6573 revs = opts.get('rev')
6571 change = opts.get('change')
6574 change = opts.get('change')
6572
6575
6573 if revs and change:
6576 if revs and change:
6574 msg = _('cannot specify --rev and --change at the same time')
6577 msg = _('cannot specify --rev and --change at the same time')
6575 raise error.Abort(msg)
6578 raise error.Abort(msg)
6576 elif change:
6579 elif change:
6577 node2 = scmutil.revsingle(repo, change, None).node()
6580 node2 = scmutil.revsingle(repo, change, None).node()
6578 node1 = repo[node2].p1().node()
6581 node1 = repo[node2].p1().node()
6579 else:
6582 else:
6580 node1, node2 = scmutil.revpair(repo, revs)
6583 node1, node2 = scmutil.revpair(repo, revs)
6581
6584
6582 if pats:
6585 if pats:
6583 cwd = repo.getcwd()
6586 cwd = repo.getcwd()
6584 else:
6587 else:
6585 cwd = ''
6588 cwd = ''
6586
6589
6587 if opts.get('print0'):
6590 if opts.get('print0'):
6588 end = '\0'
6591 end = '\0'
6589 else:
6592 else:
6590 end = '\n'
6593 end = '\n'
6591 copy = {}
6594 copy = {}
6592 states = 'modified added removed deleted unknown ignored clean'.split()
6595 states = 'modified added removed deleted unknown ignored clean'.split()
6593 show = [k for k in states if opts.get(k)]
6596 show = [k for k in states if opts.get(k)]
6594 if opts.get('all'):
6597 if opts.get('all'):
6595 show += ui.quiet and (states[:4] + ['clean']) or states
6598 show += ui.quiet and (states[:4] + ['clean']) or states
6596 if not show:
6599 if not show:
6597 if ui.quiet:
6600 if ui.quiet:
6598 show = states[:4]
6601 show = states[:4]
6599 else:
6602 else:
6600 show = states[:5]
6603 show = states[:5]
6601
6604
6602 m = scmutil.match(repo[node2], pats, opts)
6605 m = scmutil.match(repo[node2], pats, opts)
6603 stat = repo.status(node1, node2, m,
6606 stat = repo.status(node1, node2, m,
6604 'ignored' in show, 'clean' in show, 'unknown' in show,
6607 'ignored' in show, 'clean' in show, 'unknown' in show,
6605 opts.get('subrepos'))
6608 opts.get('subrepos'))
6606 changestates = zip(states, 'MAR!?IC', stat)
6609 changestates = zip(states, 'MAR!?IC', stat)
6607
6610
6608 if (opts.get('all') or opts.get('copies')
6611 if (opts.get('all') or opts.get('copies')
6609 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6612 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6610 copy = copies.pathcopies(repo[node1], repo[node2], m)
6613 copy = copies.pathcopies(repo[node1], repo[node2], m)
6611
6614
6612 fm = ui.formatter('status', opts)
6615 fm = ui.formatter('status', opts)
6613 fmt = '%s' + end
6616 fmt = '%s' + end
6614 showchar = not opts.get('no_status')
6617 showchar = not opts.get('no_status')
6615
6618
6616 for state, char, files in changestates:
6619 for state, char, files in changestates:
6617 if state in show:
6620 if state in show:
6618 label = 'status.' + state
6621 label = 'status.' + state
6619 for f in files:
6622 for f in files:
6620 fm.startitem()
6623 fm.startitem()
6621 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6624 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6622 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6625 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6623 if f in copy:
6626 if f in copy:
6624 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6627 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6625 label='status.copied')
6628 label='status.copied')
6626 fm.end()
6629 fm.end()
6627
6630
6628 @command('^summary|sum',
6631 @command('^summary|sum',
6629 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6632 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6630 def summary(ui, repo, **opts):
6633 def summary(ui, repo, **opts):
6631 """summarize working directory state
6634 """summarize working directory state
6632
6635
6633 This generates a brief summary of the working directory state,
6636 This generates a brief summary of the working directory state,
6634 including parents, branch, commit status, phase and available updates.
6637 including parents, branch, commit status, phase and available updates.
6635
6638
6636 With the --remote option, this will check the default paths for
6639 With the --remote option, this will check the default paths for
6637 incoming and outgoing changes. This can be time-consuming.
6640 incoming and outgoing changes. This can be time-consuming.
6638
6641
6639 Returns 0 on success.
6642 Returns 0 on success.
6640 """
6643 """
6641
6644
6642 ctx = repo[None]
6645 ctx = repo[None]
6643 parents = ctx.parents()
6646 parents = ctx.parents()
6644 pnode = parents[0].node()
6647 pnode = parents[0].node()
6645 marks = []
6648 marks = []
6646
6649
6647 ms = None
6650 ms = None
6648 try:
6651 try:
6649 ms = mergemod.mergestate.read(repo)
6652 ms = mergemod.mergestate.read(repo)
6650 except error.UnsupportedMergeRecords as e:
6653 except error.UnsupportedMergeRecords as e:
6651 s = ' '.join(e.recordtypes)
6654 s = ' '.join(e.recordtypes)
6652 ui.warn(
6655 ui.warn(
6653 _('warning: merge state has unsupported record types: %s\n') % s)
6656 _('warning: merge state has unsupported record types: %s\n') % s)
6654 unresolved = 0
6657 unresolved = 0
6655 else:
6658 else:
6656 unresolved = [f for f in ms if ms[f] == 'u']
6659 unresolved = [f for f in ms if ms[f] == 'u']
6657
6660
6658 for p in parents:
6661 for p in parents:
6659 # label with log.changeset (instead of log.parent) since this
6662 # label with log.changeset (instead of log.parent) since this
6660 # shows a working directory parent *changeset*:
6663 # shows a working directory parent *changeset*:
6661 # i18n: column positioning for "hg summary"
6664 # i18n: column positioning for "hg summary"
6662 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6665 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6663 label='log.changeset changeset.%s' % p.phasestr())
6666 label='log.changeset changeset.%s' % p.phasestr())
6664 ui.write(' '.join(p.tags()), label='log.tag')
6667 ui.write(' '.join(p.tags()), label='log.tag')
6665 if p.bookmarks():
6668 if p.bookmarks():
6666 marks.extend(p.bookmarks())
6669 marks.extend(p.bookmarks())
6667 if p.rev() == -1:
6670 if p.rev() == -1:
6668 if not len(repo):
6671 if not len(repo):
6669 ui.write(_(' (empty repository)'))
6672 ui.write(_(' (empty repository)'))
6670 else:
6673 else:
6671 ui.write(_(' (no revision checked out)'))
6674 ui.write(_(' (no revision checked out)'))
6672 ui.write('\n')
6675 ui.write('\n')
6673 if p.description():
6676 if p.description():
6674 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6677 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6675 label='log.summary')
6678 label='log.summary')
6676
6679
6677 branch = ctx.branch()
6680 branch = ctx.branch()
6678 bheads = repo.branchheads(branch)
6681 bheads = repo.branchheads(branch)
6679 # i18n: column positioning for "hg summary"
6682 # i18n: column positioning for "hg summary"
6680 m = _('branch: %s\n') % branch
6683 m = _('branch: %s\n') % branch
6681 if branch != 'default':
6684 if branch != 'default':
6682 ui.write(m, label='log.branch')
6685 ui.write(m, label='log.branch')
6683 else:
6686 else:
6684 ui.status(m, label='log.branch')
6687 ui.status(m, label='log.branch')
6685
6688
6686 if marks:
6689 if marks:
6687 active = repo._activebookmark
6690 active = repo._activebookmark
6688 # i18n: column positioning for "hg summary"
6691 # i18n: column positioning for "hg summary"
6689 ui.write(_('bookmarks:'), label='log.bookmark')
6692 ui.write(_('bookmarks:'), label='log.bookmark')
6690 if active is not None:
6693 if active is not None:
6691 if active in marks:
6694 if active in marks:
6692 ui.write(' *' + active, label=activebookmarklabel)
6695 ui.write(' *' + active, label=activebookmarklabel)
6693 marks.remove(active)
6696 marks.remove(active)
6694 else:
6697 else:
6695 ui.write(' [%s]' % active, label=activebookmarklabel)
6698 ui.write(' [%s]' % active, label=activebookmarklabel)
6696 for m in marks:
6699 for m in marks:
6697 ui.write(' ' + m, label='log.bookmark')
6700 ui.write(' ' + m, label='log.bookmark')
6698 ui.write('\n', label='log.bookmark')
6701 ui.write('\n', label='log.bookmark')
6699
6702
6700 status = repo.status(unknown=True)
6703 status = repo.status(unknown=True)
6701
6704
6702 c = repo.dirstate.copies()
6705 c = repo.dirstate.copies()
6703 copied, renamed = [], []
6706 copied, renamed = [], []
6704 for d, s in c.iteritems():
6707 for d, s in c.iteritems():
6705 if s in status.removed:
6708 if s in status.removed:
6706 status.removed.remove(s)
6709 status.removed.remove(s)
6707 renamed.append(d)
6710 renamed.append(d)
6708 else:
6711 else:
6709 copied.append(d)
6712 copied.append(d)
6710 if d in status.added:
6713 if d in status.added:
6711 status.added.remove(d)
6714 status.added.remove(d)
6712
6715
6713 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6716 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6714
6717
6715 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6718 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6716 (ui.label(_('%d added'), 'status.added'), status.added),
6719 (ui.label(_('%d added'), 'status.added'), status.added),
6717 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6720 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6718 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6721 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6719 (ui.label(_('%d copied'), 'status.copied'), copied),
6722 (ui.label(_('%d copied'), 'status.copied'), copied),
6720 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6723 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6721 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6724 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6722 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6725 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6723 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6726 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6724 t = []
6727 t = []
6725 for l, s in labels:
6728 for l, s in labels:
6726 if s:
6729 if s:
6727 t.append(l % len(s))
6730 t.append(l % len(s))
6728
6731
6729 t = ', '.join(t)
6732 t = ', '.join(t)
6730 cleanworkdir = False
6733 cleanworkdir = False
6731
6734
6732 if repo.vfs.exists('graftstate'):
6735 if repo.vfs.exists('graftstate'):
6733 t += _(' (graft in progress)')
6736 t += _(' (graft in progress)')
6734 if repo.vfs.exists('updatestate'):
6737 if repo.vfs.exists('updatestate'):
6735 t += _(' (interrupted update)')
6738 t += _(' (interrupted update)')
6736 elif len(parents) > 1:
6739 elif len(parents) > 1:
6737 t += _(' (merge)')
6740 t += _(' (merge)')
6738 elif branch != parents[0].branch():
6741 elif branch != parents[0].branch():
6739 t += _(' (new branch)')
6742 t += _(' (new branch)')
6740 elif (parents[0].closesbranch() and
6743 elif (parents[0].closesbranch() and
6741 pnode in repo.branchheads(branch, closed=True)):
6744 pnode in repo.branchheads(branch, closed=True)):
6742 t += _(' (head closed)')
6745 t += _(' (head closed)')
6743 elif not (status.modified or status.added or status.removed or renamed or
6746 elif not (status.modified or status.added or status.removed or renamed or
6744 copied or subs):
6747 copied or subs):
6745 t += _(' (clean)')
6748 t += _(' (clean)')
6746 cleanworkdir = True
6749 cleanworkdir = True
6747 elif pnode not in bheads:
6750 elif pnode not in bheads:
6748 t += _(' (new branch head)')
6751 t += _(' (new branch head)')
6749
6752
6750 if parents:
6753 if parents:
6751 pendingphase = max(p.phase() for p in parents)
6754 pendingphase = max(p.phase() for p in parents)
6752 else:
6755 else:
6753 pendingphase = phases.public
6756 pendingphase = phases.public
6754
6757
6755 if pendingphase > phases.newcommitphase(ui):
6758 if pendingphase > phases.newcommitphase(ui):
6756 t += ' (%s)' % phases.phasenames[pendingphase]
6759 t += ' (%s)' % phases.phasenames[pendingphase]
6757
6760
6758 if cleanworkdir:
6761 if cleanworkdir:
6759 # i18n: column positioning for "hg summary"
6762 # i18n: column positioning for "hg summary"
6760 ui.status(_('commit: %s\n') % t.strip())
6763 ui.status(_('commit: %s\n') % t.strip())
6761 else:
6764 else:
6762 # i18n: column positioning for "hg summary"
6765 # i18n: column positioning for "hg summary"
6763 ui.write(_('commit: %s\n') % t.strip())
6766 ui.write(_('commit: %s\n') % t.strip())
6764
6767
6765 # all ancestors of branch heads - all ancestors of parent = new csets
6768 # all ancestors of branch heads - all ancestors of parent = new csets
6766 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6769 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6767 bheads))
6770 bheads))
6768
6771
6769 if new == 0:
6772 if new == 0:
6770 # i18n: column positioning for "hg summary"
6773 # i18n: column positioning for "hg summary"
6771 ui.status(_('update: (current)\n'))
6774 ui.status(_('update: (current)\n'))
6772 elif pnode not in bheads:
6775 elif pnode not in bheads:
6773 # i18n: column positioning for "hg summary"
6776 # i18n: column positioning for "hg summary"
6774 ui.write(_('update: %d new changesets (update)\n') % new)
6777 ui.write(_('update: %d new changesets (update)\n') % new)
6775 else:
6778 else:
6776 # i18n: column positioning for "hg summary"
6779 # i18n: column positioning for "hg summary"
6777 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6780 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6778 (new, len(bheads)))
6781 (new, len(bheads)))
6779
6782
6780 t = []
6783 t = []
6781 draft = len(repo.revs('draft()'))
6784 draft = len(repo.revs('draft()'))
6782 if draft:
6785 if draft:
6783 t.append(_('%d draft') % draft)
6786 t.append(_('%d draft') % draft)
6784 secret = len(repo.revs('secret()'))
6787 secret = len(repo.revs('secret()'))
6785 if secret:
6788 if secret:
6786 t.append(_('%d secret') % secret)
6789 t.append(_('%d secret') % secret)
6787
6790
6788 if draft or secret:
6791 if draft or secret:
6789 ui.status(_('phases: %s\n') % ', '.join(t))
6792 ui.status(_('phases: %s\n') % ', '.join(t))
6790
6793
6791 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6794 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6792 for trouble in ("unstable", "divergent", "bumped"):
6795 for trouble in ("unstable", "divergent", "bumped"):
6793 numtrouble = len(repo.revs(trouble + "()"))
6796 numtrouble = len(repo.revs(trouble + "()"))
6794 # We write all the possibilities to ease translation
6797 # We write all the possibilities to ease translation
6795 troublemsg = {
6798 troublemsg = {
6796 "unstable": _("unstable: %d changesets"),
6799 "unstable": _("unstable: %d changesets"),
6797 "divergent": _("divergent: %d changesets"),
6800 "divergent": _("divergent: %d changesets"),
6798 "bumped": _("bumped: %d changesets"),
6801 "bumped": _("bumped: %d changesets"),
6799 }
6802 }
6800 if numtrouble > 0:
6803 if numtrouble > 0:
6801 ui.status(troublemsg[trouble] % numtrouble + "\n")
6804 ui.status(troublemsg[trouble] % numtrouble + "\n")
6802
6805
6803 cmdutil.summaryhooks(ui, repo)
6806 cmdutil.summaryhooks(ui, repo)
6804
6807
6805 if opts.get('remote'):
6808 if opts.get('remote'):
6806 needsincoming, needsoutgoing = True, True
6809 needsincoming, needsoutgoing = True, True
6807 else:
6810 else:
6808 needsincoming, needsoutgoing = False, False
6811 needsincoming, needsoutgoing = False, False
6809 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6812 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6810 if i:
6813 if i:
6811 needsincoming = True
6814 needsincoming = True
6812 if o:
6815 if o:
6813 needsoutgoing = True
6816 needsoutgoing = True
6814 if not needsincoming and not needsoutgoing:
6817 if not needsincoming and not needsoutgoing:
6815 return
6818 return
6816
6819
6817 def getincoming():
6820 def getincoming():
6818 source, branches = hg.parseurl(ui.expandpath('default'))
6821 source, branches = hg.parseurl(ui.expandpath('default'))
6819 sbranch = branches[0]
6822 sbranch = branches[0]
6820 try:
6823 try:
6821 other = hg.peer(repo, {}, source)
6824 other = hg.peer(repo, {}, source)
6822 except error.RepoError:
6825 except error.RepoError:
6823 if opts.get('remote'):
6826 if opts.get('remote'):
6824 raise
6827 raise
6825 return source, sbranch, None, None, None
6828 return source, sbranch, None, None, None
6826 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6829 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6827 if revs:
6830 if revs:
6828 revs = [other.lookup(rev) for rev in revs]
6831 revs = [other.lookup(rev) for rev in revs]
6829 ui.debug('comparing with %s\n' % util.hidepassword(source))
6832 ui.debug('comparing with %s\n' % util.hidepassword(source))
6830 repo.ui.pushbuffer()
6833 repo.ui.pushbuffer()
6831 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6834 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6832 repo.ui.popbuffer()
6835 repo.ui.popbuffer()
6833 return source, sbranch, other, commoninc, commoninc[1]
6836 return source, sbranch, other, commoninc, commoninc[1]
6834
6837
6835 if needsincoming:
6838 if needsincoming:
6836 source, sbranch, sother, commoninc, incoming = getincoming()
6839 source, sbranch, sother, commoninc, incoming = getincoming()
6837 else:
6840 else:
6838 source = sbranch = sother = commoninc = incoming = None
6841 source = sbranch = sother = commoninc = incoming = None
6839
6842
6840 def getoutgoing():
6843 def getoutgoing():
6841 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6844 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6842 dbranch = branches[0]
6845 dbranch = branches[0]
6843 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6846 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6844 if source != dest:
6847 if source != dest:
6845 try:
6848 try:
6846 dother = hg.peer(repo, {}, dest)
6849 dother = hg.peer(repo, {}, dest)
6847 except error.RepoError:
6850 except error.RepoError:
6848 if opts.get('remote'):
6851 if opts.get('remote'):
6849 raise
6852 raise
6850 return dest, dbranch, None, None
6853 return dest, dbranch, None, None
6851 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6854 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6852 elif sother is None:
6855 elif sother is None:
6853 # there is no explicit destination peer, but source one is invalid
6856 # there is no explicit destination peer, but source one is invalid
6854 return dest, dbranch, None, None
6857 return dest, dbranch, None, None
6855 else:
6858 else:
6856 dother = sother
6859 dother = sother
6857 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6860 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6858 common = None
6861 common = None
6859 else:
6862 else:
6860 common = commoninc
6863 common = commoninc
6861 if revs:
6864 if revs:
6862 revs = [repo.lookup(rev) for rev in revs]
6865 revs = [repo.lookup(rev) for rev in revs]
6863 repo.ui.pushbuffer()
6866 repo.ui.pushbuffer()
6864 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6867 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6865 commoninc=common)
6868 commoninc=common)
6866 repo.ui.popbuffer()
6869 repo.ui.popbuffer()
6867 return dest, dbranch, dother, outgoing
6870 return dest, dbranch, dother, outgoing
6868
6871
6869 if needsoutgoing:
6872 if needsoutgoing:
6870 dest, dbranch, dother, outgoing = getoutgoing()
6873 dest, dbranch, dother, outgoing = getoutgoing()
6871 else:
6874 else:
6872 dest = dbranch = dother = outgoing = None
6875 dest = dbranch = dother = outgoing = None
6873
6876
6874 if opts.get('remote'):
6877 if opts.get('remote'):
6875 t = []
6878 t = []
6876 if incoming:
6879 if incoming:
6877 t.append(_('1 or more incoming'))
6880 t.append(_('1 or more incoming'))
6878 o = outgoing.missing
6881 o = outgoing.missing
6879 if o:
6882 if o:
6880 t.append(_('%d outgoing') % len(o))
6883 t.append(_('%d outgoing') % len(o))
6881 other = dother or sother
6884 other = dother or sother
6882 if 'bookmarks' in other.listkeys('namespaces'):
6885 if 'bookmarks' in other.listkeys('namespaces'):
6883 counts = bookmarks.summary(repo, other)
6886 counts = bookmarks.summary(repo, other)
6884 if counts[0] > 0:
6887 if counts[0] > 0:
6885 t.append(_('%d incoming bookmarks') % counts[0])
6888 t.append(_('%d incoming bookmarks') % counts[0])
6886 if counts[1] > 0:
6889 if counts[1] > 0:
6887 t.append(_('%d outgoing bookmarks') % counts[1])
6890 t.append(_('%d outgoing bookmarks') % counts[1])
6888
6891
6889 if t:
6892 if t:
6890 # i18n: column positioning for "hg summary"
6893 # i18n: column positioning for "hg summary"
6891 ui.write(_('remote: %s\n') % (', '.join(t)))
6894 ui.write(_('remote: %s\n') % (', '.join(t)))
6892 else:
6895 else:
6893 # i18n: column positioning for "hg summary"
6896 # i18n: column positioning for "hg summary"
6894 ui.status(_('remote: (synced)\n'))
6897 ui.status(_('remote: (synced)\n'))
6895
6898
6896 cmdutil.summaryremotehooks(ui, repo, opts,
6899 cmdutil.summaryremotehooks(ui, repo, opts,
6897 ((source, sbranch, sother, commoninc),
6900 ((source, sbranch, sother, commoninc),
6898 (dest, dbranch, dother, outgoing)))
6901 (dest, dbranch, dother, outgoing)))
6899
6902
6900 @command('tag',
6903 @command('tag',
6901 [('f', 'force', None, _('force tag')),
6904 [('f', 'force', None, _('force tag')),
6902 ('l', 'local', None, _('make the tag local')),
6905 ('l', 'local', None, _('make the tag local')),
6903 ('r', 'rev', '', _('revision to tag'), _('REV')),
6906 ('r', 'rev', '', _('revision to tag'), _('REV')),
6904 ('', 'remove', None, _('remove a tag')),
6907 ('', 'remove', None, _('remove a tag')),
6905 # -l/--local is already there, commitopts cannot be used
6908 # -l/--local is already there, commitopts cannot be used
6906 ('e', 'edit', None, _('invoke editor on commit messages')),
6909 ('e', 'edit', None, _('invoke editor on commit messages')),
6907 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6910 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6908 ] + commitopts2,
6911 ] + commitopts2,
6909 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6912 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6910 def tag(ui, repo, name1, *names, **opts):
6913 def tag(ui, repo, name1, *names, **opts):
6911 """add one or more tags for the current or given revision
6914 """add one or more tags for the current or given revision
6912
6915
6913 Name a particular revision using <name>.
6916 Name a particular revision using <name>.
6914
6917
6915 Tags are used to name particular revisions of the repository and are
6918 Tags are used to name particular revisions of the repository and are
6916 very useful to compare different revisions, to go back to significant
6919 very useful to compare different revisions, to go back to significant
6917 earlier versions or to mark branch points as releases, etc. Changing
6920 earlier versions or to mark branch points as releases, etc. Changing
6918 an existing tag is normally disallowed; use -f/--force to override.
6921 an existing tag is normally disallowed; use -f/--force to override.
6919
6922
6920 If no revision is given, the parent of the working directory is
6923 If no revision is given, the parent of the working directory is
6921 used.
6924 used.
6922
6925
6923 To facilitate version control, distribution, and merging of tags,
6926 To facilitate version control, distribution, and merging of tags,
6924 they are stored as a file named ".hgtags" which is managed similarly
6927 they are stored as a file named ".hgtags" which is managed similarly
6925 to other project files and can be hand-edited if necessary. This
6928 to other project files and can be hand-edited if necessary. This
6926 also means that tagging creates a new commit. The file
6929 also means that tagging creates a new commit. The file
6927 ".hg/localtags" is used for local tags (not shared among
6930 ".hg/localtags" is used for local tags (not shared among
6928 repositories).
6931 repositories).
6929
6932
6930 Tag commits are usually made at the head of a branch. If the parent
6933 Tag commits are usually made at the head of a branch. If the parent
6931 of the working directory is not a branch head, :hg:`tag` aborts; use
6934 of the working directory is not a branch head, :hg:`tag` aborts; use
6932 -f/--force to force the tag commit to be based on a non-head
6935 -f/--force to force the tag commit to be based on a non-head
6933 changeset.
6936 changeset.
6934
6937
6935 See :hg:`help dates` for a list of formats valid for -d/--date.
6938 See :hg:`help dates` for a list of formats valid for -d/--date.
6936
6939
6937 Since tag names have priority over branch names during revision
6940 Since tag names have priority over branch names during revision
6938 lookup, using an existing branch name as a tag name is discouraged.
6941 lookup, using an existing branch name as a tag name is discouraged.
6939
6942
6940 Returns 0 on success.
6943 Returns 0 on success.
6941 """
6944 """
6942 wlock = lock = None
6945 wlock = lock = None
6943 try:
6946 try:
6944 wlock = repo.wlock()
6947 wlock = repo.wlock()
6945 lock = repo.lock()
6948 lock = repo.lock()
6946 rev_ = "."
6949 rev_ = "."
6947 names = [t.strip() for t in (name1,) + names]
6950 names = [t.strip() for t in (name1,) + names]
6948 if len(names) != len(set(names)):
6951 if len(names) != len(set(names)):
6949 raise error.Abort(_('tag names must be unique'))
6952 raise error.Abort(_('tag names must be unique'))
6950 for n in names:
6953 for n in names:
6951 scmutil.checknewlabel(repo, n, 'tag')
6954 scmutil.checknewlabel(repo, n, 'tag')
6952 if not n:
6955 if not n:
6953 raise error.Abort(_('tag names cannot consist entirely of '
6956 raise error.Abort(_('tag names cannot consist entirely of '
6954 'whitespace'))
6957 'whitespace'))
6955 if opts.get('rev') and opts.get('remove'):
6958 if opts.get('rev') and opts.get('remove'):
6956 raise error.Abort(_("--rev and --remove are incompatible"))
6959 raise error.Abort(_("--rev and --remove are incompatible"))
6957 if opts.get('rev'):
6960 if opts.get('rev'):
6958 rev_ = opts['rev']
6961 rev_ = opts['rev']
6959 message = opts.get('message')
6962 message = opts.get('message')
6960 if opts.get('remove'):
6963 if opts.get('remove'):
6961 if opts.get('local'):
6964 if opts.get('local'):
6962 expectedtype = 'local'
6965 expectedtype = 'local'
6963 else:
6966 else:
6964 expectedtype = 'global'
6967 expectedtype = 'global'
6965
6968
6966 for n in names:
6969 for n in names:
6967 if not repo.tagtype(n):
6970 if not repo.tagtype(n):
6968 raise error.Abort(_("tag '%s' does not exist") % n)
6971 raise error.Abort(_("tag '%s' does not exist") % n)
6969 if repo.tagtype(n) != expectedtype:
6972 if repo.tagtype(n) != expectedtype:
6970 if expectedtype == 'global':
6973 if expectedtype == 'global':
6971 raise error.Abort(_("tag '%s' is not a global tag") % n)
6974 raise error.Abort(_("tag '%s' is not a global tag") % n)
6972 else:
6975 else:
6973 raise error.Abort(_("tag '%s' is not a local tag") % n)
6976 raise error.Abort(_("tag '%s' is not a local tag") % n)
6974 rev_ = 'null'
6977 rev_ = 'null'
6975 if not message:
6978 if not message:
6976 # we don't translate commit messages
6979 # we don't translate commit messages
6977 message = 'Removed tag %s' % ', '.join(names)
6980 message = 'Removed tag %s' % ', '.join(names)
6978 elif not opts.get('force'):
6981 elif not opts.get('force'):
6979 for n in names:
6982 for n in names:
6980 if n in repo.tags():
6983 if n in repo.tags():
6981 raise error.Abort(_("tag '%s' already exists "
6984 raise error.Abort(_("tag '%s' already exists "
6982 "(use -f to force)") % n)
6985 "(use -f to force)") % n)
6983 if not opts.get('local'):
6986 if not opts.get('local'):
6984 p1, p2 = repo.dirstate.parents()
6987 p1, p2 = repo.dirstate.parents()
6985 if p2 != nullid:
6988 if p2 != nullid:
6986 raise error.Abort(_('uncommitted merge'))
6989 raise error.Abort(_('uncommitted merge'))
6987 bheads = repo.branchheads()
6990 bheads = repo.branchheads()
6988 if not opts.get('force') and bheads and p1 not in bheads:
6991 if not opts.get('force') and bheads and p1 not in bheads:
6989 raise error.Abort(_('not at a branch head (use -f to force)'))
6992 raise error.Abort(_('not at a branch head (use -f to force)'))
6990 r = scmutil.revsingle(repo, rev_).node()
6993 r = scmutil.revsingle(repo, rev_).node()
6991
6994
6992 if not message:
6995 if not message:
6993 # we don't translate commit messages
6996 # we don't translate commit messages
6994 message = ('Added tag %s for changeset %s' %
6997 message = ('Added tag %s for changeset %s' %
6995 (', '.join(names), short(r)))
6998 (', '.join(names), short(r)))
6996
6999
6997 date = opts.get('date')
7000 date = opts.get('date')
6998 if date:
7001 if date:
6999 date = util.parsedate(date)
7002 date = util.parsedate(date)
7000
7003
7001 if opts.get('remove'):
7004 if opts.get('remove'):
7002 editform = 'tag.remove'
7005 editform = 'tag.remove'
7003 else:
7006 else:
7004 editform = 'tag.add'
7007 editform = 'tag.add'
7005 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7008 editor = cmdutil.getcommiteditor(editform=editform, **opts)
7006
7009
7007 # don't allow tagging the null rev
7010 # don't allow tagging the null rev
7008 if (not opts.get('remove') and
7011 if (not opts.get('remove') and
7009 scmutil.revsingle(repo, rev_).rev() == nullrev):
7012 scmutil.revsingle(repo, rev_).rev() == nullrev):
7010 raise error.Abort(_("cannot tag null revision"))
7013 raise error.Abort(_("cannot tag null revision"))
7011
7014
7012 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7015 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
7013 editor=editor)
7016 editor=editor)
7014 finally:
7017 finally:
7015 release(lock, wlock)
7018 release(lock, wlock)
7016
7019
7017 @command('tags', formatteropts, '')
7020 @command('tags', formatteropts, '')
7018 def tags(ui, repo, **opts):
7021 def tags(ui, repo, **opts):
7019 """list repository tags
7022 """list repository tags
7020
7023
7021 This lists both regular and local tags. When the -v/--verbose
7024 This lists both regular and local tags. When the -v/--verbose
7022 switch is used, a third column "local" is printed for local tags.
7025 switch is used, a third column "local" is printed for local tags.
7023 When the -q/--quiet switch is used, only the tag name is printed.
7026 When the -q/--quiet switch is used, only the tag name is printed.
7024
7027
7025 Returns 0 on success.
7028 Returns 0 on success.
7026 """
7029 """
7027
7030
7028 fm = ui.formatter('tags', opts)
7031 fm = ui.formatter('tags', opts)
7029 hexfunc = fm.hexfunc
7032 hexfunc = fm.hexfunc
7030 tagtype = ""
7033 tagtype = ""
7031
7034
7032 for t, n in reversed(repo.tagslist()):
7035 for t, n in reversed(repo.tagslist()):
7033 hn = hexfunc(n)
7036 hn = hexfunc(n)
7034 label = 'tags.normal'
7037 label = 'tags.normal'
7035 tagtype = ''
7038 tagtype = ''
7036 if repo.tagtype(t) == 'local':
7039 if repo.tagtype(t) == 'local':
7037 label = 'tags.local'
7040 label = 'tags.local'
7038 tagtype = 'local'
7041 tagtype = 'local'
7039
7042
7040 fm.startitem()
7043 fm.startitem()
7041 fm.write('tag', '%s', t, label=label)
7044 fm.write('tag', '%s', t, label=label)
7042 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7045 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
7043 fm.condwrite(not ui.quiet, 'rev node', fmt,
7046 fm.condwrite(not ui.quiet, 'rev node', fmt,
7044 repo.changelog.rev(n), hn, label=label)
7047 repo.changelog.rev(n), hn, label=label)
7045 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7048 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
7046 tagtype, label=label)
7049 tagtype, label=label)
7047 fm.plain('\n')
7050 fm.plain('\n')
7048 fm.end()
7051 fm.end()
7049
7052
7050 @command('tip',
7053 @command('tip',
7051 [('p', 'patch', None, _('show patch')),
7054 [('p', 'patch', None, _('show patch')),
7052 ('g', 'git', None, _('use git extended diff format')),
7055 ('g', 'git', None, _('use git extended diff format')),
7053 ] + templateopts,
7056 ] + templateopts,
7054 _('[-p] [-g]'))
7057 _('[-p] [-g]'))
7055 def tip(ui, repo, **opts):
7058 def tip(ui, repo, **opts):
7056 """show the tip revision (DEPRECATED)
7059 """show the tip revision (DEPRECATED)
7057
7060
7058 The tip revision (usually just called the tip) is the changeset
7061 The tip revision (usually just called the tip) is the changeset
7059 most recently added to the repository (and therefore the most
7062 most recently added to the repository (and therefore the most
7060 recently changed head).
7063 recently changed head).
7061
7064
7062 If you have just made a commit, that commit will be the tip. If
7065 If you have just made a commit, that commit will be the tip. If
7063 you have just pulled changes from another repository, the tip of
7066 you have just pulled changes from another repository, the tip of
7064 that repository becomes the current tip. The "tip" tag is special
7067 that repository becomes the current tip. The "tip" tag is special
7065 and cannot be renamed or assigned to a different changeset.
7068 and cannot be renamed or assigned to a different changeset.
7066
7069
7067 This command is deprecated, please use :hg:`heads` instead.
7070 This command is deprecated, please use :hg:`heads` instead.
7068
7071
7069 Returns 0 on success.
7072 Returns 0 on success.
7070 """
7073 """
7071 displayer = cmdutil.show_changeset(ui, repo, opts)
7074 displayer = cmdutil.show_changeset(ui, repo, opts)
7072 displayer.show(repo['tip'])
7075 displayer.show(repo['tip'])
7073 displayer.close()
7076 displayer.close()
7074
7077
7075 @command('unbundle',
7078 @command('unbundle',
7076 [('u', 'update', None,
7079 [('u', 'update', None,
7077 _('update to new branch head if changesets were unbundled'))],
7080 _('update to new branch head if changesets were unbundled'))],
7078 _('[-u] FILE...'))
7081 _('[-u] FILE...'))
7079 def unbundle(ui, repo, fname1, *fnames, **opts):
7082 def unbundle(ui, repo, fname1, *fnames, **opts):
7080 """apply one or more changegroup files
7083 """apply one or more changegroup files
7081
7084
7082 Apply one or more compressed changegroup files generated by the
7085 Apply one or more compressed changegroup files generated by the
7083 bundle command.
7086 bundle command.
7084
7087
7085 Returns 0 on success, 1 if an update has unresolved files.
7088 Returns 0 on success, 1 if an update has unresolved files.
7086 """
7089 """
7087 fnames = (fname1,) + fnames
7090 fnames = (fname1,) + fnames
7088
7091
7089 with repo.lock():
7092 with repo.lock():
7090 for fname in fnames:
7093 for fname in fnames:
7091 f = hg.openpath(ui, fname)
7094 f = hg.openpath(ui, fname)
7092 gen = exchange.readbundle(ui, f, fname)
7095 gen = exchange.readbundle(ui, f, fname)
7093 if isinstance(gen, bundle2.unbundle20):
7096 if isinstance(gen, bundle2.unbundle20):
7094 tr = repo.transaction('unbundle')
7097 tr = repo.transaction('unbundle')
7095 try:
7098 try:
7096 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7099 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7097 url='bundle:' + fname)
7100 url='bundle:' + fname)
7098 tr.close()
7101 tr.close()
7099 except error.BundleUnknownFeatureError as exc:
7102 except error.BundleUnknownFeatureError as exc:
7100 raise error.Abort(_('%s: unknown bundle feature, %s')
7103 raise error.Abort(_('%s: unknown bundle feature, %s')
7101 % (fname, exc),
7104 % (fname, exc),
7102 hint=_("see https://mercurial-scm.org/"
7105 hint=_("see https://mercurial-scm.org/"
7103 "wiki/BundleFeature for more "
7106 "wiki/BundleFeature for more "
7104 "information"))
7107 "information"))
7105 finally:
7108 finally:
7106 if tr:
7109 if tr:
7107 tr.release()
7110 tr.release()
7108 changes = [r.get('return', 0)
7111 changes = [r.get('return', 0)
7109 for r in op.records['changegroup']]
7112 for r in op.records['changegroup']]
7110 modheads = changegroup.combineresults(changes)
7113 modheads = changegroup.combineresults(changes)
7111 elif isinstance(gen, streamclone.streamcloneapplier):
7114 elif isinstance(gen, streamclone.streamcloneapplier):
7112 raise error.Abort(
7115 raise error.Abort(
7113 _('packed bundles cannot be applied with '
7116 _('packed bundles cannot be applied with '
7114 '"hg unbundle"'),
7117 '"hg unbundle"'),
7115 hint=_('use "hg debugapplystreamclonebundle"'))
7118 hint=_('use "hg debugapplystreamclonebundle"'))
7116 else:
7119 else:
7117 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7120 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7118
7121
7119 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7122 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7120
7123
7121 @command('^update|up|checkout|co',
7124 @command('^update|up|checkout|co',
7122 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7125 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7123 ('c', 'check', None, _('require clean working directory')),
7126 ('c', 'check', None, _('require clean working directory')),
7124 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7127 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7125 ('r', 'rev', '', _('revision'), _('REV'))
7128 ('r', 'rev', '', _('revision'), _('REV'))
7126 ] + mergetoolopts,
7129 ] + mergetoolopts,
7127 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7130 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7128 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7131 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7129 tool=None):
7132 tool=None):
7130 """update working directory (or switch revisions)
7133 """update working directory (or switch revisions)
7131
7134
7132 Update the repository's working directory to the specified
7135 Update the repository's working directory to the specified
7133 changeset. If no changeset is specified, update to the tip of the
7136 changeset. If no changeset is specified, update to the tip of the
7134 current named branch and move the active bookmark (see :hg:`help
7137 current named branch and move the active bookmark (see :hg:`help
7135 bookmarks`).
7138 bookmarks`).
7136
7139
7137 Update sets the working directory's parent revision to the specified
7140 Update sets the working directory's parent revision to the specified
7138 changeset (see :hg:`help parents`).
7141 changeset (see :hg:`help parents`).
7139
7142
7140 If the changeset is not a descendant or ancestor of the working
7143 If the changeset is not a descendant or ancestor of the working
7141 directory's parent, the update is aborted. With the -c/--check
7144 directory's parent, the update is aborted. With the -c/--check
7142 option, the working directory is checked for uncommitted changes; if
7145 option, the working directory is checked for uncommitted changes; if
7143 none are found, the working directory is updated to the specified
7146 none are found, the working directory is updated to the specified
7144 changeset.
7147 changeset.
7145
7148
7146 .. container:: verbose
7149 .. container:: verbose
7147
7150
7148 The following rules apply when the working directory contains
7151 The following rules apply when the working directory contains
7149 uncommitted changes:
7152 uncommitted changes:
7150
7153
7151 1. If neither -c/--check nor -C/--clean is specified, and if
7154 1. If neither -c/--check nor -C/--clean is specified, and if
7152 the requested changeset is an ancestor or descendant of
7155 the requested changeset is an ancestor or descendant of
7153 the working directory's parent, the uncommitted changes
7156 the working directory's parent, the uncommitted changes
7154 are merged into the requested changeset and the merged
7157 are merged into the requested changeset and the merged
7155 result is left uncommitted. If the requested changeset is
7158 result is left uncommitted. If the requested changeset is
7156 not an ancestor or descendant (that is, it is on another
7159 not an ancestor or descendant (that is, it is on another
7157 branch), the update is aborted and the uncommitted changes
7160 branch), the update is aborted and the uncommitted changes
7158 are preserved.
7161 are preserved.
7159
7162
7160 2. With the -c/--check option, the update is aborted and the
7163 2. With the -c/--check option, the update is aborted and the
7161 uncommitted changes are preserved.
7164 uncommitted changes are preserved.
7162
7165
7163 3. With the -C/--clean option, uncommitted changes are discarded and
7166 3. With the -C/--clean option, uncommitted changes are discarded and
7164 the working directory is updated to the requested changeset.
7167 the working directory is updated to the requested changeset.
7165
7168
7166 To cancel an uncommitted merge (and lose your changes), use
7169 To cancel an uncommitted merge (and lose your changes), use
7167 :hg:`update --clean .`.
7170 :hg:`update --clean .`.
7168
7171
7169 Use null as the changeset to remove the working directory (like
7172 Use null as the changeset to remove the working directory (like
7170 :hg:`clone -U`).
7173 :hg:`clone -U`).
7171
7174
7172 If you want to revert just one file to an older revision, use
7175 If you want to revert just one file to an older revision, use
7173 :hg:`revert [-r REV] NAME`.
7176 :hg:`revert [-r REV] NAME`.
7174
7177
7175 See :hg:`help dates` for a list of formats valid for -d/--date.
7178 See :hg:`help dates` for a list of formats valid for -d/--date.
7176
7179
7177 Returns 0 on success, 1 if there are unresolved files.
7180 Returns 0 on success, 1 if there are unresolved files.
7178 """
7181 """
7179 if rev and node:
7182 if rev and node:
7180 raise error.Abort(_("please specify just one revision"))
7183 raise error.Abort(_("please specify just one revision"))
7181
7184
7182 if rev is None or rev == '':
7185 if rev is None or rev == '':
7183 rev = node
7186 rev = node
7184
7187
7185 if date and rev is not None:
7188 if date and rev is not None:
7186 raise error.Abort(_("you can't specify a revision and a date"))
7189 raise error.Abort(_("you can't specify a revision and a date"))
7187
7190
7188 if check and clean:
7191 if check and clean:
7189 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7192 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7190
7193
7191 with repo.wlock():
7194 with repo.wlock():
7192 cmdutil.clearunfinished(repo)
7195 cmdutil.clearunfinished(repo)
7193
7196
7194 if date:
7197 if date:
7195 rev = cmdutil.finddate(ui, repo, date)
7198 rev = cmdutil.finddate(ui, repo, date)
7196
7199
7197 # if we defined a bookmark, we have to remember the original name
7200 # if we defined a bookmark, we have to remember the original name
7198 brev = rev
7201 brev = rev
7199 rev = scmutil.revsingle(repo, rev, rev).rev()
7202 rev = scmutil.revsingle(repo, rev, rev).rev()
7200
7203
7201 if check:
7204 if check:
7202 cmdutil.bailifchanged(repo, merge=False)
7205 cmdutil.bailifchanged(repo, merge=False)
7203
7206
7204 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7207 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7205
7208
7206 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7209 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7207
7210
7208 @command('verify', [])
7211 @command('verify', [])
7209 def verify(ui, repo):
7212 def verify(ui, repo):
7210 """verify the integrity of the repository
7213 """verify the integrity of the repository
7211
7214
7212 Verify the integrity of the current repository.
7215 Verify the integrity of the current repository.
7213
7216
7214 This will perform an extensive check of the repository's
7217 This will perform an extensive check of the repository's
7215 integrity, validating the hashes and checksums of each entry in
7218 integrity, validating the hashes and checksums of each entry in
7216 the changelog, manifest, and tracked files, as well as the
7219 the changelog, manifest, and tracked files, as well as the
7217 integrity of their crosslinks and indices.
7220 integrity of their crosslinks and indices.
7218
7221
7219 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7222 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7220 for more information about recovery from corruption of the
7223 for more information about recovery from corruption of the
7221 repository.
7224 repository.
7222
7225
7223 Returns 0 on success, 1 if errors are encountered.
7226 Returns 0 on success, 1 if errors are encountered.
7224 """
7227 """
7225 return hg.verify(repo)
7228 return hg.verify(repo)
7226
7229
7227 @command('version', [], norepo=True)
7230 @command('version', [], norepo=True)
7228 def version_(ui):
7231 def version_(ui):
7229 """output version and copyright information"""
7232 """output version and copyright information"""
7230 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7233 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7231 % util.version())
7234 % util.version())
7232 ui.status(_(
7235 ui.status(_(
7233 "(see https://mercurial-scm.org for more information)\n"
7236 "(see https://mercurial-scm.org for more information)\n"
7234 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7237 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7235 "This is free software; see the source for copying conditions. "
7238 "This is free software; see the source for copying conditions. "
7236 "There is NO\nwarranty; "
7239 "There is NO\nwarranty; "
7237 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7240 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7238 ))
7241 ))
7239
7242
7240 ui.note(_("\nEnabled extensions:\n\n"))
7243 ui.note(_("\nEnabled extensions:\n\n"))
7241 if ui.verbose:
7244 if ui.verbose:
7242 # format names and versions into columns
7245 # format names and versions into columns
7243 names = []
7246 names = []
7244 vers = []
7247 vers = []
7245 place = []
7248 place = []
7246 for name, module in extensions.extensions():
7249 for name, module in extensions.extensions():
7247 names.append(name)
7250 names.append(name)
7248 vers.append(extensions.moduleversion(module))
7251 vers.append(extensions.moduleversion(module))
7249 if extensions.ismoduleinternal(module):
7252 if extensions.ismoduleinternal(module):
7250 place.append(_("internal"))
7253 place.append(_("internal"))
7251 else:
7254 else:
7252 place.append(_("external"))
7255 place.append(_("external"))
7253 if names:
7256 if names:
7254 maxnamelen = max(len(n) for n in names)
7257 maxnamelen = max(len(n) for n in names)
7255 for i, name in enumerate(names):
7258 for i, name in enumerate(names):
7256 ui.write(" %-*s %s %s\n" %
7259 ui.write(" %-*s %s %s\n" %
7257 (maxnamelen, name, place[i], vers[i]))
7260 (maxnamelen, name, place[i], vers[i]))
7258
7261
7259 def loadcmdtable(ui, name, cmdtable):
7262 def loadcmdtable(ui, name, cmdtable):
7260 """Load command functions from specified cmdtable
7263 """Load command functions from specified cmdtable
7261 """
7264 """
7262 overrides = [cmd for cmd in cmdtable if cmd in table]
7265 overrides = [cmd for cmd in cmdtable if cmd in table]
7263 if overrides:
7266 if overrides:
7264 ui.warn(_("extension '%s' overrides commands: %s\n")
7267 ui.warn(_("extension '%s' overrides commands: %s\n")
7265 % (name, " ".join(overrides)))
7268 % (name, " ".join(overrides)))
7266 table.update(cmdtable)
7269 table.update(cmdtable)
@@ -1,149 +1,153 b''
1 hg debuginstall
1 hg debuginstall
2 $ hg debuginstall
2 $ hg debuginstall
3 checking encoding (ascii)...
3 checking encoding (ascii)...
4 checking Python executable (*) (glob)
4 checking Python executable (*) (glob)
5 checking Python version (2.*) (glob)
5 checking Python version (2.*) (glob)
6 checking Python lib (*lib*)... (glob)
6 checking Python lib (*lib*)... (glob)
7 checking Mercurial version (*) (glob)
7 checking Mercurial version (*) (glob)
8 checking Mercurial custom build (*) (glob)
8 checking Mercurial custom build (*) (glob)
9 checking module policy (*) (glob)
9 checking installed modules (*mercurial)... (glob)
10 checking installed modules (*mercurial)... (glob)
10 checking templates (*mercurial?templates)... (glob)
11 checking templates (*mercurial?templates)... (glob)
11 checking default template (*mercurial?templates?map-cmdline.default) (glob)
12 checking default template (*mercurial?templates?map-cmdline.default) (glob)
12 checking commit editor... (* -c "import sys; sys.exit(0)") (glob)
13 checking commit editor... (* -c "import sys; sys.exit(0)") (glob)
13 checking username (test)
14 checking username (test)
14 no problems detected
15 no problems detected
15
16
16 hg debuginstall JSON
17 hg debuginstall JSON
17 $ hg debuginstall -Tjson | sed 's|\\\\|\\|g'
18 $ hg debuginstall -Tjson | sed 's|\\\\|\\|g'
18 [
19 [
19 {
20 {
20 "defaulttemplate": "*mercurial?templates?map-cmdline.default", (glob)
21 "defaulttemplate": "*mercurial?templates?map-cmdline.default", (glob)
21 "defaulttemplateerror": null,
22 "defaulttemplateerror": null,
22 "defaulttemplatenotfound": "default",
23 "defaulttemplatenotfound": "default",
23 "editor": "* -c \"import sys; sys.exit(0)\"", (glob)
24 "editor": "* -c \"import sys; sys.exit(0)\"", (glob)
24 "editornotfound": false,
25 "editornotfound": false,
25 "encoding": "ascii",
26 "encoding": "ascii",
26 "encodingerror": null,
27 "encodingerror": null,
27 "extensionserror": null,
28 "extensionserror": null,
29 "hgmodulepolicy": "*", (glob)
28 "hgmodules": "*mercurial", (glob)
30 "hgmodules": "*mercurial", (glob)
29 "hgver": "*", (glob)
31 "hgver": "*", (glob)
30 "hgverextra": "*", (glob)
32 "hgverextra": "*", (glob)
31 "problems": 0,
33 "problems": 0,
32 "pythonexe": "*", (glob)
34 "pythonexe": "*", (glob)
33 "pythonlib": "*", (glob)
35 "pythonlib": "*", (glob)
34 "pythonver": "*.*.*", (glob)
36 "pythonver": "*.*.*", (glob)
35 "templatedirs": "*mercurial?templates", (glob)
37 "templatedirs": "*mercurial?templates", (glob)
36 "username": "test",
38 "username": "test",
37 "usernameerror": null,
39 "usernameerror": null,
38 "vinotfound": false
40 "vinotfound": false
39 }
41 }
40 ]
42 ]
41
43
42 hg debuginstall with no username
44 hg debuginstall with no username
43 $ HGUSER= hg debuginstall
45 $ HGUSER= hg debuginstall
44 checking encoding (ascii)...
46 checking encoding (ascii)...
45 checking Python executable (*) (glob)
47 checking Python executable (*) (glob)
46 checking Python version (2.*) (glob)
48 checking Python version (2.*) (glob)
47 checking Python lib (*lib*)... (glob)
49 checking Python lib (*lib*)... (glob)
48 checking Mercurial version (*) (glob)
50 checking Mercurial version (*) (glob)
49 checking Mercurial custom build (*) (glob)
51 checking Mercurial custom build (*) (glob)
52 checking module policy (*) (glob)
50 checking installed modules (*mercurial)... (glob)
53 checking installed modules (*mercurial)... (glob)
51 checking templates (*mercurial?templates)... (glob)
54 checking templates (*mercurial?templates)... (glob)
52 checking default template (*mercurial?templates?map-cmdline.default) (glob)
55 checking default template (*mercurial?templates?map-cmdline.default) (glob)
53 checking commit editor... (* -c "import sys; sys.exit(0)") (glob)
56 checking commit editor... (* -c "import sys; sys.exit(0)") (glob)
54 checking username...
57 checking username...
55 no username supplied
58 no username supplied
56 (specify a username in your configuration file)
59 (specify a username in your configuration file)
57 1 problems detected, please check your install!
60 1 problems detected, please check your install!
58 [1]
61 [1]
59
62
60 path variables are expanded (~ is the same as $TESTTMP)
63 path variables are expanded (~ is the same as $TESTTMP)
61 $ mkdir tools
64 $ mkdir tools
62 $ touch tools/testeditor.exe
65 $ touch tools/testeditor.exe
63 #if execbit
66 #if execbit
64 $ chmod 755 tools/testeditor.exe
67 $ chmod 755 tools/testeditor.exe
65 #endif
68 #endif
66 $ hg debuginstall --config ui.editor=~/tools/testeditor.exe
69 $ hg debuginstall --config ui.editor=~/tools/testeditor.exe
67 checking encoding (ascii)...
70 checking encoding (ascii)...
68 checking Python executable (*) (glob)
71 checking Python executable (*) (glob)
69 checking Python version (*) (glob)
72 checking Python version (*) (glob)
70 checking Python lib (*lib*)... (glob)
73 checking Python lib (*lib*)... (glob)
71 checking Mercurial version (*) (glob)
74 checking Mercurial version (*) (glob)
72 checking Mercurial custom build (*) (glob)
75 checking Mercurial custom build (*) (glob)
76 checking module policy (*) (glob)
73 checking installed modules (*mercurial)... (glob)
77 checking installed modules (*mercurial)... (glob)
74 checking templates (*mercurial?templates)... (glob)
78 checking templates (*mercurial?templates)... (glob)
75 checking default template (*mercurial?templates?map-cmdline.default) (glob)
79 checking default template (*mercurial?templates?map-cmdline.default) (glob)
76 checking commit editor... (* -c "import sys; sys.exit(0)") (glob)
80 checking commit editor... (* -c "import sys; sys.exit(0)") (glob)
77 checking username (test)
81 checking username (test)
78 no problems detected
82 no problems detected
79
83
80 #if test-repo
84 #if test-repo
81 $ . "$TESTDIR/helpers-testrepo.sh"
85 $ . "$TESTDIR/helpers-testrepo.sh"
82
86
83 $ cat >> wixxml.py << EOF
87 $ cat >> wixxml.py << EOF
84 > import os, subprocess, sys
88 > import os, subprocess, sys
85 > import xml.etree.ElementTree as ET
89 > import xml.etree.ElementTree as ET
86 >
90 >
87 > # MSYS mangles the path if it expands $TESTDIR
91 > # MSYS mangles the path if it expands $TESTDIR
88 > testdir = os.environ['TESTDIR']
92 > testdir = os.environ['TESTDIR']
89 > ns = {'wix' : 'http://schemas.microsoft.com/wix/2006/wi'}
93 > ns = {'wix' : 'http://schemas.microsoft.com/wix/2006/wi'}
90 >
94 >
91 > def directory(node, relpath):
95 > def directory(node, relpath):
92 > '''generator of files in the xml node, rooted at relpath'''
96 > '''generator of files in the xml node, rooted at relpath'''
93 > dirs = node.findall('./{%(wix)s}Directory' % ns)
97 > dirs = node.findall('./{%(wix)s}Directory' % ns)
94 >
98 >
95 > for d in dirs:
99 > for d in dirs:
96 > for subfile in directory(d, relpath + d.attrib['Name'] + '/'):
100 > for subfile in directory(d, relpath + d.attrib['Name'] + '/'):
97 > yield subfile
101 > yield subfile
98 >
102 >
99 > files = node.findall('./{%(wix)s}Component/{%(wix)s}File' % ns)
103 > files = node.findall('./{%(wix)s}Component/{%(wix)s}File' % ns)
100 >
104 >
101 > for f in files:
105 > for f in files:
102 > yield relpath + f.attrib['Name']
106 > yield relpath + f.attrib['Name']
103 >
107 >
104 > def hgdirectory(relpath):
108 > def hgdirectory(relpath):
105 > '''generator of tracked files, rooted at relpath'''
109 > '''generator of tracked files, rooted at relpath'''
106 > hgdir = "%s/../mercurial" % (testdir)
110 > hgdir = "%s/../mercurial" % (testdir)
107 > args = ['hg', '--cwd', hgdir, 'files', relpath]
111 > args = ['hg', '--cwd', hgdir, 'files', relpath]
108 > proc = subprocess.Popen(args, stdout=subprocess.PIPE,
112 > proc = subprocess.Popen(args, stdout=subprocess.PIPE,
109 > stderr=subprocess.PIPE)
113 > stderr=subprocess.PIPE)
110 > output = proc.communicate()[0]
114 > output = proc.communicate()[0]
111 >
115 >
112 > slash = '/'
116 > slash = '/'
113 > for line in output.splitlines():
117 > for line in output.splitlines():
114 > if os.name == 'nt':
118 > if os.name == 'nt':
115 > yield line.replace(os.sep, slash)
119 > yield line.replace(os.sep, slash)
116 > else:
120 > else:
117 > yield line
121 > yield line
118 >
122 >
119 > tracked = [f for f in hgdirectory(sys.argv[1])]
123 > tracked = [f for f in hgdirectory(sys.argv[1])]
120 >
124 >
121 > xml = ET.parse("%s/../contrib/wix/%s.wxs" % (testdir, sys.argv[1]))
125 > xml = ET.parse("%s/../contrib/wix/%s.wxs" % (testdir, sys.argv[1]))
122 > root = xml.getroot()
126 > root = xml.getroot()
123 > dir = root.find('.//{%(wix)s}DirectoryRef' % ns)
127 > dir = root.find('.//{%(wix)s}DirectoryRef' % ns)
124 >
128 >
125 > installed = [f for f in directory(dir, '')]
129 > installed = [f for f in directory(dir, '')]
126 >
130 >
127 > print('Not installed:')
131 > print('Not installed:')
128 > for f in sorted(set(tracked) - set(installed)):
132 > for f in sorted(set(tracked) - set(installed)):
129 > print(' %s' % f)
133 > print(' %s' % f)
130 >
134 >
131 > print('Not tracked:')
135 > print('Not tracked:')
132 > for f in sorted(set(installed) - set(tracked)):
136 > for f in sorted(set(installed) - set(tracked)):
133 > print(' %s' % f)
137 > print(' %s' % f)
134 > EOF
138 > EOF
135
139
136 $ python wixxml.py help
140 $ python wixxml.py help
137 Not installed:
141 Not installed:
138 help/common.txt
142 help/common.txt
139 help/hg-ssh.8.txt
143 help/hg-ssh.8.txt
140 help/hg.1.txt
144 help/hg.1.txt
141 help/hgignore.5.txt
145 help/hgignore.5.txt
142 help/hgrc.5.txt
146 help/hgrc.5.txt
143 Not tracked:
147 Not tracked:
144
148
145 $ python wixxml.py templates
149 $ python wixxml.py templates
146 Not installed:
150 Not installed:
147 Not tracked:
151 Not tracked:
148
152
149 #endif
153 #endif
General Comments 0
You need to be logged in to leave comments. Login now