##// END OF EJS Templates
subrepo: check phase of state in each subrepositories before committing...
FUJIWARA Katsunori -
r20176:4c96c50e default
parent child Browse files
Show More
@@ -1,1523 +1,1532 b''
1 The Mercurial system uses a set of configuration files to control
1 The Mercurial system uses a set of configuration files to control
2 aspects of its behavior.
2 aspects of its behavior.
3
3
4 The configuration files use a simple ini-file format. A configuration
4 The configuration files use a simple ini-file format. A configuration
5 file consists of sections, led by a ``[section]`` header and followed
5 file consists of sections, led by a ``[section]`` header and followed
6 by ``name = value`` entries::
6 by ``name = value`` entries::
7
7
8 [ui]
8 [ui]
9 username = Firstname Lastname <firstname.lastname@example.net>
9 username = Firstname Lastname <firstname.lastname@example.net>
10 verbose = True
10 verbose = True
11
11
12 The above entries will be referred to as ``ui.username`` and
12 The above entries will be referred to as ``ui.username`` and
13 ``ui.verbose``, respectively. See the Syntax section below.
13 ``ui.verbose``, respectively. See the Syntax section below.
14
14
15 Files
15 Files
16 =====
16 =====
17
17
18 Mercurial reads configuration data from several files, if they exist.
18 Mercurial reads configuration data from several files, if they exist.
19 These files do not exist by default and you will have to create the
19 These files do not exist by default and you will have to create the
20 appropriate configuration files yourself: global configuration like
20 appropriate configuration files yourself: global configuration like
21 the username setting is typically put into
21 the username setting is typically put into
22 ``%USERPROFILE%\mercurial.ini`` or ``$HOME/.hgrc`` and local
22 ``%USERPROFILE%\mercurial.ini`` or ``$HOME/.hgrc`` and local
23 configuration is put into the per-repository ``<repo>/.hg/hgrc`` file.
23 configuration is put into the per-repository ``<repo>/.hg/hgrc`` file.
24
24
25 The names of these files depend on the system on which Mercurial is
25 The names of these files depend on the system on which Mercurial is
26 installed. ``*.rc`` files from a single directory are read in
26 installed. ``*.rc`` files from a single directory are read in
27 alphabetical order, later ones overriding earlier ones. Where multiple
27 alphabetical order, later ones overriding earlier ones. Where multiple
28 paths are given below, settings from earlier paths override later
28 paths are given below, settings from earlier paths override later
29 ones.
29 ones.
30
30
31 | (All) ``<repo>/.hg/hgrc``
31 | (All) ``<repo>/.hg/hgrc``
32
32
33 Per-repository configuration options that only apply in a
33 Per-repository configuration options that only apply in a
34 particular repository. This file is not version-controlled, and
34 particular repository. This file is not version-controlled, and
35 will not get transferred during a "clone" operation. Options in
35 will not get transferred during a "clone" operation. Options in
36 this file override options in all other configuration files. On
36 this file override options in all other configuration files. On
37 Plan 9 and Unix, most of this file will be ignored if it doesn't
37 Plan 9 and Unix, most of this file will be ignored if it doesn't
38 belong to a trusted user or to a trusted group. See the documentation
38 belong to a trusted user or to a trusted group. See the documentation
39 for the ``[trusted]`` section below for more details.
39 for the ``[trusted]`` section below for more details.
40
40
41 | (Plan 9) ``$home/lib/hgrc``
41 | (Plan 9) ``$home/lib/hgrc``
42 | (Unix) ``$HOME/.hgrc``
42 | (Unix) ``$HOME/.hgrc``
43 | (Windows) ``%USERPROFILE%\.hgrc``
43 | (Windows) ``%USERPROFILE%\.hgrc``
44 | (Windows) ``%USERPROFILE%\Mercurial.ini``
44 | (Windows) ``%USERPROFILE%\Mercurial.ini``
45 | (Windows) ``%HOME%\.hgrc``
45 | (Windows) ``%HOME%\.hgrc``
46 | (Windows) ``%HOME%\Mercurial.ini``
46 | (Windows) ``%HOME%\Mercurial.ini``
47
47
48 Per-user configuration file(s), for the user running Mercurial. On
48 Per-user configuration file(s), for the user running Mercurial. On
49 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
49 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
50 files apply to all Mercurial commands executed by this user in any
50 files apply to all Mercurial commands executed by this user in any
51 directory. Options in these files override per-system and per-installation
51 directory. Options in these files override per-system and per-installation
52 options.
52 options.
53
53
54 | (Plan 9) ``/lib/mercurial/hgrc``
54 | (Plan 9) ``/lib/mercurial/hgrc``
55 | (Plan 9) ``/lib/mercurial/hgrc.d/*.rc``
55 | (Plan 9) ``/lib/mercurial/hgrc.d/*.rc``
56 | (Unix) ``/etc/mercurial/hgrc``
56 | (Unix) ``/etc/mercurial/hgrc``
57 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
57 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
58
58
59 Per-system configuration files, for the system on which Mercurial
59 Per-system configuration files, for the system on which Mercurial
60 is running. Options in these files apply to all Mercurial commands
60 is running. Options in these files apply to all Mercurial commands
61 executed by any user in any directory. Options in these files
61 executed by any user in any directory. Options in these files
62 override per-installation options.
62 override per-installation options.
63
63
64 | (Plan 9) ``<install-root>/lib/mercurial/hgrc``
64 | (Plan 9) ``<install-root>/lib/mercurial/hgrc``
65 | (Plan 9) ``<install-root>/lib/mercurial/hgrc.d/*.rc``
65 | (Plan 9) ``<install-root>/lib/mercurial/hgrc.d/*.rc``
66 | (Unix) ``<install-root>/etc/mercurial/hgrc``
66 | (Unix) ``<install-root>/etc/mercurial/hgrc``
67 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
67 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
68
68
69 Per-installation configuration files, searched for in the
69 Per-installation configuration files, searched for in the
70 directory where Mercurial is installed. ``<install-root>`` is the
70 directory where Mercurial is installed. ``<install-root>`` is the
71 parent directory of the **hg** executable (or symlink) being run. For
71 parent directory of the **hg** executable (or symlink) being run. For
72 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
72 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
73 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
73 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
74 to all Mercurial commands executed by any user in any directory.
74 to all Mercurial commands executed by any user in any directory.
75
75
76 | (Windows) ``<install-dir>\Mercurial.ini`` **or**
76 | (Windows) ``<install-dir>\Mercurial.ini`` **or**
77 | (Windows) ``<install-dir>\hgrc.d\*.rc`` **or**
77 | (Windows) ``<install-dir>\hgrc.d\*.rc`` **or**
78 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
78 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
79
79
80 Per-installation/system configuration files, for the system on
80 Per-installation/system configuration files, for the system on
81 which Mercurial is running. Options in these files apply to all
81 which Mercurial is running. Options in these files apply to all
82 Mercurial commands executed by any user in any directory. Registry
82 Mercurial commands executed by any user in any directory. Registry
83 keys contain PATH-like strings, every part of which must reference
83 keys contain PATH-like strings, every part of which must reference
84 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
84 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
85 be read. Mercurial checks each of these locations in the specified
85 be read. Mercurial checks each of these locations in the specified
86 order until one or more configuration files are detected.
86 order until one or more configuration files are detected.
87
87
88 .. note:: The registry key ``HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Mercurial``
88 .. note:: The registry key ``HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Mercurial``
89 is used when running 32-bit Python on 64-bit Windows.
89 is used when running 32-bit Python on 64-bit Windows.
90
90
91 Syntax
91 Syntax
92 ======
92 ======
93
93
94 A configuration file consists of sections, led by a ``[section]`` header
94 A configuration file consists of sections, led by a ``[section]`` header
95 and followed by ``name = value`` entries (sometimes called
95 and followed by ``name = value`` entries (sometimes called
96 ``configuration keys``)::
96 ``configuration keys``)::
97
97
98 [spam]
98 [spam]
99 eggs=ham
99 eggs=ham
100 green=
100 green=
101 eggs
101 eggs
102
102
103 Each line contains one entry. If the lines that follow are indented,
103 Each line contains one entry. If the lines that follow are indented,
104 they are treated as continuations of that entry. Leading whitespace is
104 they are treated as continuations of that entry. Leading whitespace is
105 removed from values. Empty lines are skipped. Lines beginning with
105 removed from values. Empty lines are skipped. Lines beginning with
106 ``#`` or ``;`` are ignored and may be used to provide comments.
106 ``#`` or ``;`` are ignored and may be used to provide comments.
107
107
108 Configuration keys can be set multiple times, in which case Mercurial
108 Configuration keys can be set multiple times, in which case Mercurial
109 will use the value that was configured last. As an example::
109 will use the value that was configured last. As an example::
110
110
111 [spam]
111 [spam]
112 eggs=large
112 eggs=large
113 ham=serrano
113 ham=serrano
114 eggs=small
114 eggs=small
115
115
116 This would set the configuration key named ``eggs`` to ``small``.
116 This would set the configuration key named ``eggs`` to ``small``.
117
117
118 It is also possible to define a section multiple times. A section can
118 It is also possible to define a section multiple times. A section can
119 be redefined on the same and/or on different configuration files. For
119 be redefined on the same and/or on different configuration files. For
120 example::
120 example::
121
121
122 [foo]
122 [foo]
123 eggs=large
123 eggs=large
124 ham=serrano
124 ham=serrano
125 eggs=small
125 eggs=small
126
126
127 [bar]
127 [bar]
128 eggs=ham
128 eggs=ham
129 green=
129 green=
130 eggs
130 eggs
131
131
132 [foo]
132 [foo]
133 ham=prosciutto
133 ham=prosciutto
134 eggs=medium
134 eggs=medium
135 bread=toasted
135 bread=toasted
136
136
137 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
137 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
138 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
138 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
139 respectively. As you can see there only thing that matters is the last
139 respectively. As you can see there only thing that matters is the last
140 value that was set for each of the configuration keys.
140 value that was set for each of the configuration keys.
141
141
142 If a configuration key is set multiple times in different
142 If a configuration key is set multiple times in different
143 configuration files the final value will depend on the order in which
143 configuration files the final value will depend on the order in which
144 the different configuration files are read, with settings from earlier
144 the different configuration files are read, with settings from earlier
145 paths overriding later ones as described on the ``Files`` section
145 paths overriding later ones as described on the ``Files`` section
146 above.
146 above.
147
147
148 A line of the form ``%include file`` will include ``file`` into the
148 A line of the form ``%include file`` will include ``file`` into the
149 current configuration file. The inclusion is recursive, which means
149 current configuration file. The inclusion is recursive, which means
150 that included files can include other files. Filenames are relative to
150 that included files can include other files. Filenames are relative to
151 the configuration file in which the ``%include`` directive is found.
151 the configuration file in which the ``%include`` directive is found.
152 Environment variables and ``~user`` constructs are expanded in
152 Environment variables and ``~user`` constructs are expanded in
153 ``file``. This lets you do something like::
153 ``file``. This lets you do something like::
154
154
155 %include ~/.hgrc.d/$HOST.rc
155 %include ~/.hgrc.d/$HOST.rc
156
156
157 to include a different configuration file on each computer you use.
157 to include a different configuration file on each computer you use.
158
158
159 A line with ``%unset name`` will remove ``name`` from the current
159 A line with ``%unset name`` will remove ``name`` from the current
160 section, if it has been set previously.
160 section, if it has been set previously.
161
161
162 The values are either free-form text strings, lists of text strings,
162 The values are either free-form text strings, lists of text strings,
163 or Boolean values. Boolean values can be set to true using any of "1",
163 or Boolean values. Boolean values can be set to true using any of "1",
164 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
164 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
165 (all case insensitive).
165 (all case insensitive).
166
166
167 List values are separated by whitespace or comma, except when values are
167 List values are separated by whitespace or comma, except when values are
168 placed in double quotation marks::
168 placed in double quotation marks::
169
169
170 allow_read = "John Doe, PhD", brian, betty
170 allow_read = "John Doe, PhD", brian, betty
171
171
172 Quotation marks can be escaped by prefixing them with a backslash. Only
172 Quotation marks can be escaped by prefixing them with a backslash. Only
173 quotation marks at the beginning of a word is counted as a quotation
173 quotation marks at the beginning of a word is counted as a quotation
174 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
174 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
175
175
176 Sections
176 Sections
177 ========
177 ========
178
178
179 This section describes the different sections that may appear in a
179 This section describes the different sections that may appear in a
180 Mercurial configuration file, the purpose of each section, its possible
180 Mercurial configuration file, the purpose of each section, its possible
181 keys, and their possible values.
181 keys, and their possible values.
182
182
183 ``alias``
183 ``alias``
184 ---------
184 ---------
185
185
186 Defines command aliases.
186 Defines command aliases.
187 Aliases allow you to define your own commands in terms of other
187 Aliases allow you to define your own commands in terms of other
188 commands (or aliases), optionally including arguments. Positional
188 commands (or aliases), optionally including arguments. Positional
189 arguments in the form of ``$1``, ``$2``, etc in the alias definition
189 arguments in the form of ``$1``, ``$2``, etc in the alias definition
190 are expanded by Mercurial before execution. Positional arguments not
190 are expanded by Mercurial before execution. Positional arguments not
191 already used by ``$N`` in the definition are put at the end of the
191 already used by ``$N`` in the definition are put at the end of the
192 command to be executed.
192 command to be executed.
193
193
194 Alias definitions consist of lines of the form::
194 Alias definitions consist of lines of the form::
195
195
196 <alias> = <command> [<argument>]...
196 <alias> = <command> [<argument>]...
197
197
198 For example, this definition::
198 For example, this definition::
199
199
200 latest = log --limit 5
200 latest = log --limit 5
201
201
202 creates a new command ``latest`` that shows only the five most recent
202 creates a new command ``latest`` that shows only the five most recent
203 changesets. You can define subsequent aliases using earlier ones::
203 changesets. You can define subsequent aliases using earlier ones::
204
204
205 stable5 = latest -b stable
205 stable5 = latest -b stable
206
206
207 .. note:: It is possible to create aliases with the same names as
207 .. note:: It is possible to create aliases with the same names as
208 existing commands, which will then override the original
208 existing commands, which will then override the original
209 definitions. This is almost always a bad idea!
209 definitions. This is almost always a bad idea!
210
210
211 An alias can start with an exclamation point (``!``) to make it a
211 An alias can start with an exclamation point (``!``) to make it a
212 shell alias. A shell alias is executed with the shell and will let you
212 shell alias. A shell alias is executed with the shell and will let you
213 run arbitrary commands. As an example, ::
213 run arbitrary commands. As an example, ::
214
214
215 echo = !echo $@
215 echo = !echo $@
216
216
217 will let you do ``hg echo foo`` to have ``foo`` printed in your
217 will let you do ``hg echo foo`` to have ``foo`` printed in your
218 terminal. A better example might be::
218 terminal. A better example might be::
219
219
220 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
220 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
221
221
222 which will make ``hg purge`` delete all unknown files in the
222 which will make ``hg purge`` delete all unknown files in the
223 repository in the same manner as the purge extension.
223 repository in the same manner as the purge extension.
224
224
225 Positional arguments like ``$1``, ``$2``, etc. in the alias definition
225 Positional arguments like ``$1``, ``$2``, etc. in the alias definition
226 expand to the command arguments. Unmatched arguments are
226 expand to the command arguments. Unmatched arguments are
227 removed. ``$0`` expands to the alias name and ``$@`` expands to all
227 removed. ``$0`` expands to the alias name and ``$@`` expands to all
228 arguments separated by a space. These expansions happen before the
228 arguments separated by a space. These expansions happen before the
229 command is passed to the shell.
229 command is passed to the shell.
230
230
231 Shell aliases are executed in an environment where ``$HG`` expands to
231 Shell aliases are executed in an environment where ``$HG`` expands to
232 the path of the Mercurial that was used to execute the alias. This is
232 the path of the Mercurial that was used to execute the alias. This is
233 useful when you want to call further Mercurial commands in a shell
233 useful when you want to call further Mercurial commands in a shell
234 alias, as was done above for the purge alias. In addition,
234 alias, as was done above for the purge alias. In addition,
235 ``$HG_ARGS`` expands to the arguments given to Mercurial. In the ``hg
235 ``$HG_ARGS`` expands to the arguments given to Mercurial. In the ``hg
236 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
236 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
237
237
238 .. note:: Some global configuration options such as ``-R`` are
238 .. note:: Some global configuration options such as ``-R`` are
239 processed before shell aliases and will thus not be passed to
239 processed before shell aliases and will thus not be passed to
240 aliases.
240 aliases.
241
241
242
242
243 ``annotate``
243 ``annotate``
244 ------------
244 ------------
245
245
246 Settings used when displaying file annotations. All values are
246 Settings used when displaying file annotations. All values are
247 Booleans and default to False. See ``diff`` section for related
247 Booleans and default to False. See ``diff`` section for related
248 options for the diff command.
248 options for the diff command.
249
249
250 ``ignorews``
250 ``ignorews``
251 Ignore white space when comparing lines.
251 Ignore white space when comparing lines.
252
252
253 ``ignorewsamount``
253 ``ignorewsamount``
254 Ignore changes in the amount of white space.
254 Ignore changes in the amount of white space.
255
255
256 ``ignoreblanklines``
256 ``ignoreblanklines``
257 Ignore changes whose lines are all blank.
257 Ignore changes whose lines are all blank.
258
258
259
259
260 ``auth``
260 ``auth``
261 --------
261 --------
262
262
263 Authentication credentials for HTTP authentication. This section
263 Authentication credentials for HTTP authentication. This section
264 allows you to store usernames and passwords for use when logging
264 allows you to store usernames and passwords for use when logging
265 *into* HTTP servers. See the ``[web]`` configuration section if
265 *into* HTTP servers. See the ``[web]`` configuration section if
266 you want to configure *who* can login to your HTTP server.
266 you want to configure *who* can login to your HTTP server.
267
267
268 Each line has the following format::
268 Each line has the following format::
269
269
270 <name>.<argument> = <value>
270 <name>.<argument> = <value>
271
271
272 where ``<name>`` is used to group arguments into authentication
272 where ``<name>`` is used to group arguments into authentication
273 entries. Example::
273 entries. Example::
274
274
275 foo.prefix = hg.intevation.org/mercurial
275 foo.prefix = hg.intevation.org/mercurial
276 foo.username = foo
276 foo.username = foo
277 foo.password = bar
277 foo.password = bar
278 foo.schemes = http https
278 foo.schemes = http https
279
279
280 bar.prefix = secure.example.org
280 bar.prefix = secure.example.org
281 bar.key = path/to/file.key
281 bar.key = path/to/file.key
282 bar.cert = path/to/file.cert
282 bar.cert = path/to/file.cert
283 bar.schemes = https
283 bar.schemes = https
284
284
285 Supported arguments:
285 Supported arguments:
286
286
287 ``prefix``
287 ``prefix``
288 Either ``*`` or a URI prefix with or without the scheme part.
288 Either ``*`` or a URI prefix with or without the scheme part.
289 The authentication entry with the longest matching prefix is used
289 The authentication entry with the longest matching prefix is used
290 (where ``*`` matches everything and counts as a match of length
290 (where ``*`` matches everything and counts as a match of length
291 1). If the prefix doesn't include a scheme, the match is performed
291 1). If the prefix doesn't include a scheme, the match is performed
292 against the URI with its scheme stripped as well, and the schemes
292 against the URI with its scheme stripped as well, and the schemes
293 argument, q.v., is then subsequently consulted.
293 argument, q.v., is then subsequently consulted.
294
294
295 ``username``
295 ``username``
296 Optional. Username to authenticate with. If not given, and the
296 Optional. Username to authenticate with. If not given, and the
297 remote site requires basic or digest authentication, the user will
297 remote site requires basic or digest authentication, the user will
298 be prompted for it. Environment variables are expanded in the
298 be prompted for it. Environment variables are expanded in the
299 username letting you do ``foo.username = $USER``. If the URI
299 username letting you do ``foo.username = $USER``. If the URI
300 includes a username, only ``[auth]`` entries with a matching
300 includes a username, only ``[auth]`` entries with a matching
301 username or without a username will be considered.
301 username or without a username will be considered.
302
302
303 ``password``
303 ``password``
304 Optional. Password to authenticate with. If not given, and the
304 Optional. Password to authenticate with. If not given, and the
305 remote site requires basic or digest authentication, the user
305 remote site requires basic or digest authentication, the user
306 will be prompted for it.
306 will be prompted for it.
307
307
308 ``key``
308 ``key``
309 Optional. PEM encoded client certificate key file. Environment
309 Optional. PEM encoded client certificate key file. Environment
310 variables are expanded in the filename.
310 variables are expanded in the filename.
311
311
312 ``cert``
312 ``cert``
313 Optional. PEM encoded client certificate chain file. Environment
313 Optional. PEM encoded client certificate chain file. Environment
314 variables are expanded in the filename.
314 variables are expanded in the filename.
315
315
316 ``schemes``
316 ``schemes``
317 Optional. Space separated list of URI schemes to use this
317 Optional. Space separated list of URI schemes to use this
318 authentication entry with. Only used if the prefix doesn't include
318 authentication entry with. Only used if the prefix doesn't include
319 a scheme. Supported schemes are http and https. They will match
319 a scheme. Supported schemes are http and https. They will match
320 static-http and static-https respectively, as well.
320 static-http and static-https respectively, as well.
321 Default: https.
321 Default: https.
322
322
323 If no suitable authentication entry is found, the user is prompted
323 If no suitable authentication entry is found, the user is prompted
324 for credentials as usual if required by the remote.
324 for credentials as usual if required by the remote.
325
325
326
326
327 ``decode/encode``
327 ``decode/encode``
328 -----------------
328 -----------------
329
329
330 Filters for transforming files on checkout/checkin. This would
330 Filters for transforming files on checkout/checkin. This would
331 typically be used for newline processing or other
331 typically be used for newline processing or other
332 localization/canonicalization of files.
332 localization/canonicalization of files.
333
333
334 Filters consist of a filter pattern followed by a filter command.
334 Filters consist of a filter pattern followed by a filter command.
335 Filter patterns are globs by default, rooted at the repository root.
335 Filter patterns are globs by default, rooted at the repository root.
336 For example, to match any file ending in ``.txt`` in the root
336 For example, to match any file ending in ``.txt`` in the root
337 directory only, use the pattern ``*.txt``. To match any file ending
337 directory only, use the pattern ``*.txt``. To match any file ending
338 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
338 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
339 For each file only the first matching filter applies.
339 For each file only the first matching filter applies.
340
340
341 The filter command can start with a specifier, either ``pipe:`` or
341 The filter command can start with a specifier, either ``pipe:`` or
342 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
342 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
343
343
344 A ``pipe:`` command must accept data on stdin and return the transformed
344 A ``pipe:`` command must accept data on stdin and return the transformed
345 data on stdout.
345 data on stdout.
346
346
347 Pipe example::
347 Pipe example::
348
348
349 [encode]
349 [encode]
350 # uncompress gzip files on checkin to improve delta compression
350 # uncompress gzip files on checkin to improve delta compression
351 # note: not necessarily a good idea, just an example
351 # note: not necessarily a good idea, just an example
352 *.gz = pipe: gunzip
352 *.gz = pipe: gunzip
353
353
354 [decode]
354 [decode]
355 # recompress gzip files when writing them to the working dir (we
355 # recompress gzip files when writing them to the working dir (we
356 # can safely omit "pipe:", because it's the default)
356 # can safely omit "pipe:", because it's the default)
357 *.gz = gzip
357 *.gz = gzip
358
358
359 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
359 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
360 with the name of a temporary file that contains the data to be
360 with the name of a temporary file that contains the data to be
361 filtered by the command. The string ``OUTFILE`` is replaced with the name
361 filtered by the command. The string ``OUTFILE`` is replaced with the name
362 of an empty temporary file, where the filtered data must be written by
362 of an empty temporary file, where the filtered data must be written by
363 the command.
363 the command.
364
364
365 .. note:: The tempfile mechanism is recommended for Windows systems,
365 .. note:: The tempfile mechanism is recommended for Windows systems,
366 where the standard shell I/O redirection operators often have
366 where the standard shell I/O redirection operators often have
367 strange effects and may corrupt the contents of your files.
367 strange effects and may corrupt the contents of your files.
368
368
369 This filter mechanism is used internally by the ``eol`` extension to
369 This filter mechanism is used internally by the ``eol`` extension to
370 translate line ending characters between Windows (CRLF) and Unix (LF)
370 translate line ending characters between Windows (CRLF) and Unix (LF)
371 format. We suggest you use the ``eol`` extension for convenience.
371 format. We suggest you use the ``eol`` extension for convenience.
372
372
373
373
374 ``defaults``
374 ``defaults``
375 ------------
375 ------------
376
376
377 (defaults are deprecated. Don't use them. Use aliases instead)
377 (defaults are deprecated. Don't use them. Use aliases instead)
378
378
379 Use the ``[defaults]`` section to define command defaults, i.e. the
379 Use the ``[defaults]`` section to define command defaults, i.e. the
380 default options/arguments to pass to the specified commands.
380 default options/arguments to pass to the specified commands.
381
381
382 The following example makes :hg:`log` run in verbose mode, and
382 The following example makes :hg:`log` run in verbose mode, and
383 :hg:`status` show only the modified files, by default::
383 :hg:`status` show only the modified files, by default::
384
384
385 [defaults]
385 [defaults]
386 log = -v
386 log = -v
387 status = -m
387 status = -m
388
388
389 The actual commands, instead of their aliases, must be used when
389 The actual commands, instead of their aliases, must be used when
390 defining command defaults. The command defaults will also be applied
390 defining command defaults. The command defaults will also be applied
391 to the aliases of the commands defined.
391 to the aliases of the commands defined.
392
392
393
393
394 ``diff``
394 ``diff``
395 --------
395 --------
396
396
397 Settings used when displaying diffs. Everything except for ``unified``
397 Settings used when displaying diffs. Everything except for ``unified``
398 is a Boolean and defaults to False. See ``annotate`` section for
398 is a Boolean and defaults to False. See ``annotate`` section for
399 related options for the annotate command.
399 related options for the annotate command.
400
400
401 ``git``
401 ``git``
402 Use git extended diff format.
402 Use git extended diff format.
403
403
404 ``nodates``
404 ``nodates``
405 Don't include dates in diff headers.
405 Don't include dates in diff headers.
406
406
407 ``showfunc``
407 ``showfunc``
408 Show which function each change is in.
408 Show which function each change is in.
409
409
410 ``ignorews``
410 ``ignorews``
411 Ignore white space when comparing lines.
411 Ignore white space when comparing lines.
412
412
413 ``ignorewsamount``
413 ``ignorewsamount``
414 Ignore changes in the amount of white space.
414 Ignore changes in the amount of white space.
415
415
416 ``ignoreblanklines``
416 ``ignoreblanklines``
417 Ignore changes whose lines are all blank.
417 Ignore changes whose lines are all blank.
418
418
419 ``unified``
419 ``unified``
420 Number of lines of context to show.
420 Number of lines of context to show.
421
421
422 ``email``
422 ``email``
423 ---------
423 ---------
424
424
425 Settings for extensions that send email messages.
425 Settings for extensions that send email messages.
426
426
427 ``from``
427 ``from``
428 Optional. Email address to use in "From" header and SMTP envelope
428 Optional. Email address to use in "From" header and SMTP envelope
429 of outgoing messages.
429 of outgoing messages.
430
430
431 ``to``
431 ``to``
432 Optional. Comma-separated list of recipients' email addresses.
432 Optional. Comma-separated list of recipients' email addresses.
433
433
434 ``cc``
434 ``cc``
435 Optional. Comma-separated list of carbon copy recipients'
435 Optional. Comma-separated list of carbon copy recipients'
436 email addresses.
436 email addresses.
437
437
438 ``bcc``
438 ``bcc``
439 Optional. Comma-separated list of blind carbon copy recipients'
439 Optional. Comma-separated list of blind carbon copy recipients'
440 email addresses.
440 email addresses.
441
441
442 ``method``
442 ``method``
443 Optional. Method to use to send email messages. If value is ``smtp``
443 Optional. Method to use to send email messages. If value is ``smtp``
444 (default), use SMTP (see the ``[smtp]`` section for configuration).
444 (default), use SMTP (see the ``[smtp]`` section for configuration).
445 Otherwise, use as name of program to run that acts like sendmail
445 Otherwise, use as name of program to run that acts like sendmail
446 (takes ``-f`` option for sender, list of recipients on command line,
446 (takes ``-f`` option for sender, list of recipients on command line,
447 message on stdin). Normally, setting this to ``sendmail`` or
447 message on stdin). Normally, setting this to ``sendmail`` or
448 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
448 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
449
449
450 ``charsets``
450 ``charsets``
451 Optional. Comma-separated list of character sets considered
451 Optional. Comma-separated list of character sets considered
452 convenient for recipients. Addresses, headers, and parts not
452 convenient for recipients. Addresses, headers, and parts not
453 containing patches of outgoing messages will be encoded in the
453 containing patches of outgoing messages will be encoded in the
454 first character set to which conversion from local encoding
454 first character set to which conversion from local encoding
455 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
455 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
456 conversion fails, the text in question is sent as is. Defaults to
456 conversion fails, the text in question is sent as is. Defaults to
457 empty (explicit) list.
457 empty (explicit) list.
458
458
459 Order of outgoing email character sets:
459 Order of outgoing email character sets:
460
460
461 1. ``us-ascii``: always first, regardless of settings
461 1. ``us-ascii``: always first, regardless of settings
462 2. ``email.charsets``: in order given by user
462 2. ``email.charsets``: in order given by user
463 3. ``ui.fallbackencoding``: if not in email.charsets
463 3. ``ui.fallbackencoding``: if not in email.charsets
464 4. ``$HGENCODING``: if not in email.charsets
464 4. ``$HGENCODING``: if not in email.charsets
465 5. ``utf-8``: always last, regardless of settings
465 5. ``utf-8``: always last, regardless of settings
466
466
467 Email example::
467 Email example::
468
468
469 [email]
469 [email]
470 from = Joseph User <joe.user@example.com>
470 from = Joseph User <joe.user@example.com>
471 method = /usr/sbin/sendmail
471 method = /usr/sbin/sendmail
472 # charsets for western Europeans
472 # charsets for western Europeans
473 # us-ascii, utf-8 omitted, as they are tried first and last
473 # us-ascii, utf-8 omitted, as they are tried first and last
474 charsets = iso-8859-1, iso-8859-15, windows-1252
474 charsets = iso-8859-1, iso-8859-15, windows-1252
475
475
476
476
477 ``extensions``
477 ``extensions``
478 --------------
478 --------------
479
479
480 Mercurial has an extension mechanism for adding new features. To
480 Mercurial has an extension mechanism for adding new features. To
481 enable an extension, create an entry for it in this section.
481 enable an extension, create an entry for it in this section.
482
482
483 If you know that the extension is already in Python's search path,
483 If you know that the extension is already in Python's search path,
484 you can give the name of the module, followed by ``=``, with nothing
484 you can give the name of the module, followed by ``=``, with nothing
485 after the ``=``.
485 after the ``=``.
486
486
487 Otherwise, give a name that you choose, followed by ``=``, followed by
487 Otherwise, give a name that you choose, followed by ``=``, followed by
488 the path to the ``.py`` file (including the file name extension) that
488 the path to the ``.py`` file (including the file name extension) that
489 defines the extension.
489 defines the extension.
490
490
491 To explicitly disable an extension that is enabled in an hgrc of
491 To explicitly disable an extension that is enabled in an hgrc of
492 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
492 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
493 or ``foo = !`` when path is not supplied.
493 or ``foo = !`` when path is not supplied.
494
494
495 Example for ``~/.hgrc``::
495 Example for ``~/.hgrc``::
496
496
497 [extensions]
497 [extensions]
498 # (the progress extension will get loaded from Mercurial's path)
498 # (the progress extension will get loaded from Mercurial's path)
499 progress =
499 progress =
500 # (this extension will get loaded from the file specified)
500 # (this extension will get loaded from the file specified)
501 myfeature = ~/.hgext/myfeature.py
501 myfeature = ~/.hgext/myfeature.py
502
502
503
503
504 ``format``
504 ``format``
505 ----------
505 ----------
506
506
507 ``usestore``
507 ``usestore``
508 Enable or disable the "store" repository format which improves
508 Enable or disable the "store" repository format which improves
509 compatibility with systems that fold case or otherwise mangle
509 compatibility with systems that fold case or otherwise mangle
510 filenames. Enabled by default. Disabling this option will allow
510 filenames. Enabled by default. Disabling this option will allow
511 you to store longer filenames in some situations at the expense of
511 you to store longer filenames in some situations at the expense of
512 compatibility and ensures that the on-disk format of newly created
512 compatibility and ensures that the on-disk format of newly created
513 repositories will be compatible with Mercurial before version 0.9.4.
513 repositories will be compatible with Mercurial before version 0.9.4.
514
514
515 ``usefncache``
515 ``usefncache``
516 Enable or disable the "fncache" repository format which enhances
516 Enable or disable the "fncache" repository format which enhances
517 the "store" repository format (which has to be enabled to use
517 the "store" repository format (which has to be enabled to use
518 fncache) to allow longer filenames and avoids using Windows
518 fncache) to allow longer filenames and avoids using Windows
519 reserved names, e.g. "nul". Enabled by default. Disabling this
519 reserved names, e.g. "nul". Enabled by default. Disabling this
520 option ensures that the on-disk format of newly created
520 option ensures that the on-disk format of newly created
521 repositories will be compatible with Mercurial before version 1.1.
521 repositories will be compatible with Mercurial before version 1.1.
522
522
523 ``dotencode``
523 ``dotencode``
524 Enable or disable the "dotencode" repository format which enhances
524 Enable or disable the "dotencode" repository format which enhances
525 the "fncache" repository format (which has to be enabled to use
525 the "fncache" repository format (which has to be enabled to use
526 dotencode) to avoid issues with filenames starting with ._ on
526 dotencode) to avoid issues with filenames starting with ._ on
527 Mac OS X and spaces on Windows. Enabled by default. Disabling this
527 Mac OS X and spaces on Windows. Enabled by default. Disabling this
528 option ensures that the on-disk format of newly created
528 option ensures that the on-disk format of newly created
529 repositories will be compatible with Mercurial before version 1.7.
529 repositories will be compatible with Mercurial before version 1.7.
530
530
531 ``graph``
531 ``graph``
532 ---------
532 ---------
533
533
534 Web graph view configuration. This section let you change graph
534 Web graph view configuration. This section let you change graph
535 elements display properties by branches, for instance to make the
535 elements display properties by branches, for instance to make the
536 ``default`` branch stand out.
536 ``default`` branch stand out.
537
537
538 Each line has the following format::
538 Each line has the following format::
539
539
540 <branch>.<argument> = <value>
540 <branch>.<argument> = <value>
541
541
542 where ``<branch>`` is the name of the branch being
542 where ``<branch>`` is the name of the branch being
543 customized. Example::
543 customized. Example::
544
544
545 [graph]
545 [graph]
546 # 2px width
546 # 2px width
547 default.width = 2
547 default.width = 2
548 # red color
548 # red color
549 default.color = FF0000
549 default.color = FF0000
550
550
551 Supported arguments:
551 Supported arguments:
552
552
553 ``width``
553 ``width``
554 Set branch edges width in pixels.
554 Set branch edges width in pixels.
555
555
556 ``color``
556 ``color``
557 Set branch edges color in hexadecimal RGB notation.
557 Set branch edges color in hexadecimal RGB notation.
558
558
559 ``hooks``
559 ``hooks``
560 ---------
560 ---------
561
561
562 Commands or Python functions that get automatically executed by
562 Commands or Python functions that get automatically executed by
563 various actions such as starting or finishing a commit. Multiple
563 various actions such as starting or finishing a commit. Multiple
564 hooks can be run for the same action by appending a suffix to the
564 hooks can be run for the same action by appending a suffix to the
565 action. Overriding a site-wide hook can be done by changing its
565 action. Overriding a site-wide hook can be done by changing its
566 value or setting it to an empty string. Hooks can be prioritized
566 value or setting it to an empty string. Hooks can be prioritized
567 by adding a prefix of ``priority`` to the hook name on a new line
567 by adding a prefix of ``priority`` to the hook name on a new line
568 and setting the priority. The default priority is 0 if
568 and setting the priority. The default priority is 0 if
569 not specified.
569 not specified.
570
570
571 Example ``.hg/hgrc``::
571 Example ``.hg/hgrc``::
572
572
573 [hooks]
573 [hooks]
574 # update working directory after adding changesets
574 # update working directory after adding changesets
575 changegroup.update = hg update
575 changegroup.update = hg update
576 # do not use the site-wide hook
576 # do not use the site-wide hook
577 incoming =
577 incoming =
578 incoming.email = /my/email/hook
578 incoming.email = /my/email/hook
579 incoming.autobuild = /my/build/hook
579 incoming.autobuild = /my/build/hook
580 # force autobuild hook to run before other incoming hooks
580 # force autobuild hook to run before other incoming hooks
581 priority.incoming.autobuild = 1
581 priority.incoming.autobuild = 1
582
582
583 Most hooks are run with environment variables set that give useful
583 Most hooks are run with environment variables set that give useful
584 additional information. For each hook below, the environment
584 additional information. For each hook below, the environment
585 variables it is passed are listed with names of the form ``$HG_foo``.
585 variables it is passed are listed with names of the form ``$HG_foo``.
586
586
587 ``changegroup``
587 ``changegroup``
588 Run after a changegroup has been added via push, pull or unbundle.
588 Run after a changegroup has been added via push, pull or unbundle.
589 ID of the first new changeset is in ``$HG_NODE``. URL from which
589 ID of the first new changeset is in ``$HG_NODE``. URL from which
590 changes came is in ``$HG_URL``.
590 changes came is in ``$HG_URL``.
591
591
592 ``commit``
592 ``commit``
593 Run after a changeset has been created in the local repository. ID
593 Run after a changeset has been created in the local repository. ID
594 of the newly created changeset is in ``$HG_NODE``. Parent changeset
594 of the newly created changeset is in ``$HG_NODE``. Parent changeset
595 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
595 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
596
596
597 ``incoming``
597 ``incoming``
598 Run after a changeset has been pulled, pushed, or unbundled into
598 Run after a changeset has been pulled, pushed, or unbundled into
599 the local repository. The ID of the newly arrived changeset is in
599 the local repository. The ID of the newly arrived changeset is in
600 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
600 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
601
601
602 ``outgoing``
602 ``outgoing``
603 Run after sending changes from local repository to another. ID of
603 Run after sending changes from local repository to another. ID of
604 first changeset sent is in ``$HG_NODE``. Source of operation is in
604 first changeset sent is in ``$HG_NODE``. Source of operation is in
605 ``$HG_SOURCE``; see "preoutgoing" hook for description.
605 ``$HG_SOURCE``; see "preoutgoing" hook for description.
606
606
607 ``post-<command>``
607 ``post-<command>``
608 Run after successful invocations of the associated command. The
608 Run after successful invocations of the associated command. The
609 contents of the command line are passed as ``$HG_ARGS`` and the result
609 contents of the command line are passed as ``$HG_ARGS`` and the result
610 code in ``$HG_RESULT``. Parsed command line arguments are passed as
610 code in ``$HG_RESULT``. Parsed command line arguments are passed as
611 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
611 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
612 the python data internally passed to <command>. ``$HG_OPTS`` is a
612 the python data internally passed to <command>. ``$HG_OPTS`` is a
613 dictionary of options (with unspecified options set to their defaults).
613 dictionary of options (with unspecified options set to their defaults).
614 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
614 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
615
615
616 ``pre-<command>``
616 ``pre-<command>``
617 Run before executing the associated command. The contents of the
617 Run before executing the associated command. The contents of the
618 command line are passed as ``$HG_ARGS``. Parsed command line arguments
618 command line are passed as ``$HG_ARGS``. Parsed command line arguments
619 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
619 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
620 representations of the data internally passed to <command>. ``$HG_OPTS``
620 representations of the data internally passed to <command>. ``$HG_OPTS``
621 is a dictionary of options (with unspecified options set to their
621 is a dictionary of options (with unspecified options set to their
622 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
622 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
623 failure, the command doesn't execute and Mercurial returns the failure
623 failure, the command doesn't execute and Mercurial returns the failure
624 code.
624 code.
625
625
626 ``prechangegroup``
626 ``prechangegroup``
627 Run before a changegroup is added via push, pull or unbundle. Exit
627 Run before a changegroup is added via push, pull or unbundle. Exit
628 status 0 allows the changegroup to proceed. Non-zero status will
628 status 0 allows the changegroup to proceed. Non-zero status will
629 cause the push, pull or unbundle to fail. URL from which changes
629 cause the push, pull or unbundle to fail. URL from which changes
630 will come is in ``$HG_URL``.
630 will come is in ``$HG_URL``.
631
631
632 ``precommit``
632 ``precommit``
633 Run before starting a local commit. Exit status 0 allows the
633 Run before starting a local commit. Exit status 0 allows the
634 commit to proceed. Non-zero status will cause the commit to fail.
634 commit to proceed. Non-zero status will cause the commit to fail.
635 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
635 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
636
636
637 ``prelistkeys``
637 ``prelistkeys``
638 Run before listing pushkeys (like bookmarks) in the
638 Run before listing pushkeys (like bookmarks) in the
639 repository. Non-zero status will cause failure. The key namespace is
639 repository. Non-zero status will cause failure. The key namespace is
640 in ``$HG_NAMESPACE``.
640 in ``$HG_NAMESPACE``.
641
641
642 ``preoutgoing``
642 ``preoutgoing``
643 Run before collecting changes to send from the local repository to
643 Run before collecting changes to send from the local repository to
644 another. Non-zero status will cause failure. This lets you prevent
644 another. Non-zero status will cause failure. This lets you prevent
645 pull over HTTP or SSH. Also prevents against local pull, push
645 pull over HTTP or SSH. Also prevents against local pull, push
646 (outbound) or bundle commands, but not effective, since you can
646 (outbound) or bundle commands, but not effective, since you can
647 just copy files instead then. Source of operation is in
647 just copy files instead then. Source of operation is in
648 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
648 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
649 SSH or HTTP repository. If "push", "pull" or "bundle", operation
649 SSH or HTTP repository. If "push", "pull" or "bundle", operation
650 is happening on behalf of repository on same system.
650 is happening on behalf of repository on same system.
651
651
652 ``prepushkey``
652 ``prepushkey``
653 Run before a pushkey (like a bookmark) is added to the
653 Run before a pushkey (like a bookmark) is added to the
654 repository. Non-zero status will cause the key to be rejected. The
654 repository. Non-zero status will cause the key to be rejected. The
655 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
655 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
656 the old value (if any) is in ``$HG_OLD``, and the new value is in
656 the old value (if any) is in ``$HG_OLD``, and the new value is in
657 ``$HG_NEW``.
657 ``$HG_NEW``.
658
658
659 ``pretag``
659 ``pretag``
660 Run before creating a tag. Exit status 0 allows the tag to be
660 Run before creating a tag. Exit status 0 allows the tag to be
661 created. Non-zero status will cause the tag to fail. ID of
661 created. Non-zero status will cause the tag to fail. ID of
662 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
662 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
663 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
663 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
664
664
665 ``pretxnchangegroup``
665 ``pretxnchangegroup``
666 Run after a changegroup has been added via push, pull or unbundle,
666 Run after a changegroup has been added via push, pull or unbundle,
667 but before the transaction has been committed. Changegroup is
667 but before the transaction has been committed. Changegroup is
668 visible to hook program. This lets you validate incoming changes
668 visible to hook program. This lets you validate incoming changes
669 before accepting them. Passed the ID of the first new changeset in
669 before accepting them. Passed the ID of the first new changeset in
670 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
670 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
671 status will cause the transaction to be rolled back and the push,
671 status will cause the transaction to be rolled back and the push,
672 pull or unbundle will fail. URL that was source of changes is in
672 pull or unbundle will fail. URL that was source of changes is in
673 ``$HG_URL``.
673 ``$HG_URL``.
674
674
675 ``pretxncommit``
675 ``pretxncommit``
676 Run after a changeset has been created but the transaction not yet
676 Run after a changeset has been created but the transaction not yet
677 committed. Changeset is visible to hook program. This lets you
677 committed. Changeset is visible to hook program. This lets you
678 validate commit message and changes. Exit status 0 allows the
678 validate commit message and changes. Exit status 0 allows the
679 commit to proceed. Non-zero status will cause the transaction to
679 commit to proceed. Non-zero status will cause the transaction to
680 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
680 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
681 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
681 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
682
682
683 ``preupdate``
683 ``preupdate``
684 Run before updating the working directory. Exit status 0 allows
684 Run before updating the working directory. Exit status 0 allows
685 the update to proceed. Non-zero status will prevent the update.
685 the update to proceed. Non-zero status will prevent the update.
686 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
686 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
687 of second new parent is in ``$HG_PARENT2``.
687 of second new parent is in ``$HG_PARENT2``.
688
688
689 ``listkeys``
689 ``listkeys``
690 Run after listing pushkeys (like bookmarks) in the repository. The
690 Run after listing pushkeys (like bookmarks) in the repository. The
691 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
691 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
692 dictionary containing the keys and values.
692 dictionary containing the keys and values.
693
693
694 ``pushkey``
694 ``pushkey``
695 Run after a pushkey (like a bookmark) is added to the
695 Run after a pushkey (like a bookmark) is added to the
696 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
696 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
697 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
697 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
698 value is in ``$HG_NEW``.
698 value is in ``$HG_NEW``.
699
699
700 ``tag``
700 ``tag``
701 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
701 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
702 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
702 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
703 repository if ``$HG_LOCAL=0``.
703 repository if ``$HG_LOCAL=0``.
704
704
705 ``update``
705 ``update``
706 Run after updating the working directory. Changeset ID of first
706 Run after updating the working directory. Changeset ID of first
707 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
707 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
708 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
708 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
709 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
709 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
710
710
711 .. note:: It is generally better to use standard hooks rather than the
711 .. note:: It is generally better to use standard hooks rather than the
712 generic pre- and post- command hooks as they are guaranteed to be
712 generic pre- and post- command hooks as they are guaranteed to be
713 called in the appropriate contexts for influencing transactions.
713 called in the appropriate contexts for influencing transactions.
714 Also, hooks like "commit" will be called in all contexts that
714 Also, hooks like "commit" will be called in all contexts that
715 generate a commit (e.g. tag) and not just the commit command.
715 generate a commit (e.g. tag) and not just the commit command.
716
716
717 .. note:: Environment variables with empty values may not be passed to
717 .. note:: Environment variables with empty values may not be passed to
718 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
718 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
719 will have an empty value under Unix-like platforms for non-merge
719 will have an empty value under Unix-like platforms for non-merge
720 changesets, while it will not be available at all under Windows.
720 changesets, while it will not be available at all under Windows.
721
721
722 The syntax for Python hooks is as follows::
722 The syntax for Python hooks is as follows::
723
723
724 hookname = python:modulename.submodule.callable
724 hookname = python:modulename.submodule.callable
725 hookname = python:/path/to/python/module.py:callable
725 hookname = python:/path/to/python/module.py:callable
726
726
727 Python hooks are run within the Mercurial process. Each hook is
727 Python hooks are run within the Mercurial process. Each hook is
728 called with at least three keyword arguments: a ui object (keyword
728 called with at least three keyword arguments: a ui object (keyword
729 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
729 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
730 keyword that tells what kind of hook is used. Arguments listed as
730 keyword that tells what kind of hook is used. Arguments listed as
731 environment variables above are passed as keyword arguments, with no
731 environment variables above are passed as keyword arguments, with no
732 ``HG_`` prefix, and names in lower case.
732 ``HG_`` prefix, and names in lower case.
733
733
734 If a Python hook returns a "true" value or raises an exception, this
734 If a Python hook returns a "true" value or raises an exception, this
735 is treated as a failure.
735 is treated as a failure.
736
736
737
737
738 ``hostfingerprints``
738 ``hostfingerprints``
739 --------------------
739 --------------------
740
740
741 Fingerprints of the certificates of known HTTPS servers.
741 Fingerprints of the certificates of known HTTPS servers.
742 A HTTPS connection to a server with a fingerprint configured here will
742 A HTTPS connection to a server with a fingerprint configured here will
743 only succeed if the servers certificate matches the fingerprint.
743 only succeed if the servers certificate matches the fingerprint.
744 This is very similar to how ssh known hosts works.
744 This is very similar to how ssh known hosts works.
745 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
745 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
746 The CA chain and web.cacerts is not used for servers with a fingerprint.
746 The CA chain and web.cacerts is not used for servers with a fingerprint.
747
747
748 For example::
748 For example::
749
749
750 [hostfingerprints]
750 [hostfingerprints]
751 hg.intevation.org = 44:ed:af:1f:97:11:b6:01:7a:48:45:fc:10:3c:b7:f9:d4:89:2a:9d
751 hg.intevation.org = 44:ed:af:1f:97:11:b6:01:7a:48:45:fc:10:3c:b7:f9:d4:89:2a:9d
752
752
753 This feature is only supported when using Python 2.6 or later.
753 This feature is only supported when using Python 2.6 or later.
754
754
755
755
756 ``http_proxy``
756 ``http_proxy``
757 --------------
757 --------------
758
758
759 Used to access web-based Mercurial repositories through a HTTP
759 Used to access web-based Mercurial repositories through a HTTP
760 proxy.
760 proxy.
761
761
762 ``host``
762 ``host``
763 Host name and (optional) port of the proxy server, for example
763 Host name and (optional) port of the proxy server, for example
764 "myproxy:8000".
764 "myproxy:8000".
765
765
766 ``no``
766 ``no``
767 Optional. Comma-separated list of host names that should bypass
767 Optional. Comma-separated list of host names that should bypass
768 the proxy.
768 the proxy.
769
769
770 ``passwd``
770 ``passwd``
771 Optional. Password to authenticate with at the proxy server.
771 Optional. Password to authenticate with at the proxy server.
772
772
773 ``user``
773 ``user``
774 Optional. User name to authenticate with at the proxy server.
774 Optional. User name to authenticate with at the proxy server.
775
775
776 ``always``
776 ``always``
777 Optional. Always use the proxy, even for localhost and any entries
777 Optional. Always use the proxy, even for localhost and any entries
778 in ``http_proxy.no``. True or False. Default: False.
778 in ``http_proxy.no``. True or False. Default: False.
779
779
780 ``merge-patterns``
780 ``merge-patterns``
781 ------------------
781 ------------------
782
782
783 This section specifies merge tools to associate with particular file
783 This section specifies merge tools to associate with particular file
784 patterns. Tools matched here will take precedence over the default
784 patterns. Tools matched here will take precedence over the default
785 merge tool. Patterns are globs by default, rooted at the repository
785 merge tool. Patterns are globs by default, rooted at the repository
786 root.
786 root.
787
787
788 Example::
788 Example::
789
789
790 [merge-patterns]
790 [merge-patterns]
791 **.c = kdiff3
791 **.c = kdiff3
792 **.jpg = myimgmerge
792 **.jpg = myimgmerge
793
793
794 ``merge-tools``
794 ``merge-tools``
795 ---------------
795 ---------------
796
796
797 This section configures external merge tools to use for file-level
797 This section configures external merge tools to use for file-level
798 merges.
798 merges.
799
799
800 Example ``~/.hgrc``::
800 Example ``~/.hgrc``::
801
801
802 [merge-tools]
802 [merge-tools]
803 # Override stock tool location
803 # Override stock tool location
804 kdiff3.executable = ~/bin/kdiff3
804 kdiff3.executable = ~/bin/kdiff3
805 # Specify command line
805 # Specify command line
806 kdiff3.args = $base $local $other -o $output
806 kdiff3.args = $base $local $other -o $output
807 # Give higher priority
807 # Give higher priority
808 kdiff3.priority = 1
808 kdiff3.priority = 1
809
809
810 # Define new tool
810 # Define new tool
811 myHtmlTool.args = -m $local $other $base $output
811 myHtmlTool.args = -m $local $other $base $output
812 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
812 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
813 myHtmlTool.priority = 1
813 myHtmlTool.priority = 1
814
814
815 Supported arguments:
815 Supported arguments:
816
816
817 ``priority``
817 ``priority``
818 The priority in which to evaluate this tool.
818 The priority in which to evaluate this tool.
819 Default: 0.
819 Default: 0.
820
820
821 ``executable``
821 ``executable``
822 Either just the name of the executable or its pathname. On Windows,
822 Either just the name of the executable or its pathname. On Windows,
823 the path can use environment variables with ${ProgramFiles} syntax.
823 the path can use environment variables with ${ProgramFiles} syntax.
824 Default: the tool name.
824 Default: the tool name.
825
825
826 ``args``
826 ``args``
827 The arguments to pass to the tool executable. You can refer to the
827 The arguments to pass to the tool executable. You can refer to the
828 files being merged as well as the output file through these
828 files being merged as well as the output file through these
829 variables: ``$base``, ``$local``, ``$other``, ``$output``.
829 variables: ``$base``, ``$local``, ``$other``, ``$output``.
830 Default: ``$local $base $other``
830 Default: ``$local $base $other``
831
831
832 ``premerge``
832 ``premerge``
833 Attempt to run internal non-interactive 3-way merge tool before
833 Attempt to run internal non-interactive 3-way merge tool before
834 launching external tool. Options are ``true``, ``false``, or ``keep``
834 launching external tool. Options are ``true``, ``false``, or ``keep``
835 to leave markers in the file if the premerge fails.
835 to leave markers in the file if the premerge fails.
836 Default: True
836 Default: True
837
837
838 ``binary``
838 ``binary``
839 This tool can merge binary files. Defaults to False, unless tool
839 This tool can merge binary files. Defaults to False, unless tool
840 was selected by file pattern match.
840 was selected by file pattern match.
841
841
842 ``symlink``
842 ``symlink``
843 This tool can merge symlinks. Defaults to False, even if tool was
843 This tool can merge symlinks. Defaults to False, even if tool was
844 selected by file pattern match.
844 selected by file pattern match.
845
845
846 ``check``
846 ``check``
847 A list of merge success-checking options:
847 A list of merge success-checking options:
848
848
849 ``changed``
849 ``changed``
850 Ask whether merge was successful when the merged file shows no changes.
850 Ask whether merge was successful when the merged file shows no changes.
851 ``conflicts``
851 ``conflicts``
852 Check whether there are conflicts even though the tool reported success.
852 Check whether there are conflicts even though the tool reported success.
853 ``prompt``
853 ``prompt``
854 Always prompt for merge success, regardless of success reported by tool.
854 Always prompt for merge success, regardless of success reported by tool.
855
855
856 ``fixeol``
856 ``fixeol``
857 Attempt to fix up EOL changes caused by the merge tool.
857 Attempt to fix up EOL changes caused by the merge tool.
858 Default: False
858 Default: False
859
859
860 ``gui``
860 ``gui``
861 This tool requires a graphical interface to run. Default: False
861 This tool requires a graphical interface to run. Default: False
862
862
863 ``regkey``
863 ``regkey``
864 Windows registry key which describes install location of this
864 Windows registry key which describes install location of this
865 tool. Mercurial will search for this key first under
865 tool. Mercurial will search for this key first under
866 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
866 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
867 Default: None
867 Default: None
868
868
869 ``regkeyalt``
869 ``regkeyalt``
870 An alternate Windows registry key to try if the first key is not
870 An alternate Windows registry key to try if the first key is not
871 found. The alternate key uses the same ``regname`` and ``regappend``
871 found. The alternate key uses the same ``regname`` and ``regappend``
872 semantics of the primary key. The most common use for this key
872 semantics of the primary key. The most common use for this key
873 is to search for 32bit applications on 64bit operating systems.
873 is to search for 32bit applications on 64bit operating systems.
874 Default: None
874 Default: None
875
875
876 ``regname``
876 ``regname``
877 Name of value to read from specified registry key. Defaults to the
877 Name of value to read from specified registry key. Defaults to the
878 unnamed (default) value.
878 unnamed (default) value.
879
879
880 ``regappend``
880 ``regappend``
881 String to append to the value read from the registry, typically
881 String to append to the value read from the registry, typically
882 the executable name of the tool.
882 the executable name of the tool.
883 Default: None
883 Default: None
884
884
885
885
886 ``patch``
886 ``patch``
887 ---------
887 ---------
888
888
889 Settings used when applying patches, for instance through the 'import'
889 Settings used when applying patches, for instance through the 'import'
890 command or with Mercurial Queues extension.
890 command or with Mercurial Queues extension.
891
891
892 ``eol``
892 ``eol``
893 When set to 'strict' patch content and patched files end of lines
893 When set to 'strict' patch content and patched files end of lines
894 are preserved. When set to ``lf`` or ``crlf``, both files end of
894 are preserved. When set to ``lf`` or ``crlf``, both files end of
895 lines are ignored when patching and the result line endings are
895 lines are ignored when patching and the result line endings are
896 normalized to either LF (Unix) or CRLF (Windows). When set to
896 normalized to either LF (Unix) or CRLF (Windows). When set to
897 ``auto``, end of lines are again ignored while patching but line
897 ``auto``, end of lines are again ignored while patching but line
898 endings in patched files are normalized to their original setting
898 endings in patched files are normalized to their original setting
899 on a per-file basis. If target file does not exist or has no end
899 on a per-file basis. If target file does not exist or has no end
900 of line, patch line endings are preserved.
900 of line, patch line endings are preserved.
901 Default: strict.
901 Default: strict.
902
902
903
903
904 ``paths``
904 ``paths``
905 ---------
905 ---------
906
906
907 Assigns symbolic names to repositories. The left side is the
907 Assigns symbolic names to repositories. The left side is the
908 symbolic name, and the right gives the directory or URL that is the
908 symbolic name, and the right gives the directory or URL that is the
909 location of the repository. Default paths can be declared by setting
909 location of the repository. Default paths can be declared by setting
910 the following entries.
910 the following entries.
911
911
912 ``default``
912 ``default``
913 Directory or URL to use when pulling if no source is specified.
913 Directory or URL to use when pulling if no source is specified.
914 Default is set to repository from which the current repository was
914 Default is set to repository from which the current repository was
915 cloned.
915 cloned.
916
916
917 ``default-push``
917 ``default-push``
918 Optional. Directory or URL to use when pushing if no destination
918 Optional. Directory or URL to use when pushing if no destination
919 is specified.
919 is specified.
920
920
921 Custom paths can be defined by assigning the path to a name that later can be
921 Custom paths can be defined by assigning the path to a name that later can be
922 used from the command line. Example::
922 used from the command line. Example::
923
923
924 [paths]
924 [paths]
925 my_path = http://example.com/path
925 my_path = http://example.com/path
926
926
927 To push to the path defined in ``my_path`` run the command::
927 To push to the path defined in ``my_path`` run the command::
928
928
929 hg push my_path
929 hg push my_path
930
930
931
931
932 ``phases``
932 ``phases``
933 ----------
933 ----------
934
934
935 Specifies default handling of phases. See :hg:`help phases` for more
935 Specifies default handling of phases. See :hg:`help phases` for more
936 information about working with phases.
936 information about working with phases.
937
937
938 ``publish``
938 ``publish``
939 Controls draft phase behavior when working as a server. When true,
939 Controls draft phase behavior when working as a server. When true,
940 pushed changesets are set to public in both client and server and
940 pushed changesets are set to public in both client and server and
941 pulled or cloned changesets are set to public in the client.
941 pulled or cloned changesets are set to public in the client.
942 Default: True
942 Default: True
943
943
944 ``new-commit``
944 ``new-commit``
945 Phase of newly-created commits.
945 Phase of newly-created commits.
946 Default: draft
946 Default: draft
947
947
948 ``checksubrepos``
949
950 Check phase of state in each subrepositories, allowed values are
951 "ignore", "follow" or "abort". For settings other than "ignore",
952 the phase of each subrepository commit is checked before committing
953 in the parent repository. If there is any greater phase than the parent
954 ("secret" vs "draft", for example), the commit is either aborted
955 with "abort" or the higher phase is used with "follow". Default: "follow".
956
948 ``profiling``
957 ``profiling``
949 -------------
958 -------------
950
959
951 Specifies profiling type, format, and file output. Two profilers are
960 Specifies profiling type, format, and file output. Two profilers are
952 supported: an instrumenting profiler (named ``ls``), and a sampling
961 supported: an instrumenting profiler (named ``ls``), and a sampling
953 profiler (named ``stat``).
962 profiler (named ``stat``).
954
963
955 In this section description, 'profiling data' stands for the raw data
964 In this section description, 'profiling data' stands for the raw data
956 collected during profiling, while 'profiling report' stands for a
965 collected during profiling, while 'profiling report' stands for a
957 statistical text report generated from the profiling data. The
966 statistical text report generated from the profiling data. The
958 profiling is done using lsprof.
967 profiling is done using lsprof.
959
968
960 ``type``
969 ``type``
961 The type of profiler to use.
970 The type of profiler to use.
962 Default: ls.
971 Default: ls.
963
972
964 ``ls``
973 ``ls``
965 Use Python's built-in instrumenting profiler. This profiler
974 Use Python's built-in instrumenting profiler. This profiler
966 works on all platforms, but each line number it reports is the
975 works on all platforms, but each line number it reports is the
967 first line of a function. This restriction makes it difficult to
976 first line of a function. This restriction makes it difficult to
968 identify the expensive parts of a non-trivial function.
977 identify the expensive parts of a non-trivial function.
969 ``stat``
978 ``stat``
970 Use a third-party statistical profiler, statprof. This profiler
979 Use a third-party statistical profiler, statprof. This profiler
971 currently runs only on Unix systems, and is most useful for
980 currently runs only on Unix systems, and is most useful for
972 profiling commands that run for longer than about 0.1 seconds.
981 profiling commands that run for longer than about 0.1 seconds.
973
982
974 ``format``
983 ``format``
975 Profiling format. Specific to the ``ls`` instrumenting profiler.
984 Profiling format. Specific to the ``ls`` instrumenting profiler.
976 Default: text.
985 Default: text.
977
986
978 ``text``
987 ``text``
979 Generate a profiling report. When saving to a file, it should be
988 Generate a profiling report. When saving to a file, it should be
980 noted that only the report is saved, and the profiling data is
989 noted that only the report is saved, and the profiling data is
981 not kept.
990 not kept.
982 ``kcachegrind``
991 ``kcachegrind``
983 Format profiling data for kcachegrind use: when saving to a
992 Format profiling data for kcachegrind use: when saving to a
984 file, the generated file can directly be loaded into
993 file, the generated file can directly be loaded into
985 kcachegrind.
994 kcachegrind.
986
995
987 ``frequency``
996 ``frequency``
988 Sampling frequency. Specific to the ``stat`` sampling profiler.
997 Sampling frequency. Specific to the ``stat`` sampling profiler.
989 Default: 1000.
998 Default: 1000.
990
999
991 ``output``
1000 ``output``
992 File path where profiling data or report should be saved. If the
1001 File path where profiling data or report should be saved. If the
993 file exists, it is replaced. Default: None, data is printed on
1002 file exists, it is replaced. Default: None, data is printed on
994 stderr
1003 stderr
995
1004
996 ``sort``
1005 ``sort``
997 Sort field. Specific to the ``ls`` instrumenting profiler.
1006 Sort field. Specific to the ``ls`` instrumenting profiler.
998 One of ``callcount``, ``reccallcount``, ``totaltime`` and
1007 One of ``callcount``, ``reccallcount``, ``totaltime`` and
999 ``inlinetime``.
1008 ``inlinetime``.
1000 Default: inlinetime.
1009 Default: inlinetime.
1001
1010
1002 ``limit``
1011 ``limit``
1003 Number of lines to show. Specific to the ``ls`` instrumenting profiler.
1012 Number of lines to show. Specific to the ``ls`` instrumenting profiler.
1004 Default: 30.
1013 Default: 30.
1005
1014
1006 ``nested``
1015 ``nested``
1007 Show at most this number of lines of drill-down info after each main entry.
1016 Show at most this number of lines of drill-down info after each main entry.
1008 This can help explain the difference between Total and Inline.
1017 This can help explain the difference between Total and Inline.
1009 Specific to the ``ls`` instrumenting profiler.
1018 Specific to the ``ls`` instrumenting profiler.
1010 Default: 5.
1019 Default: 5.
1011
1020
1012 ``revsetalias``
1021 ``revsetalias``
1013 ---------------
1022 ---------------
1014
1023
1015 Alias definitions for revsets. See :hg:`help revsets` for details.
1024 Alias definitions for revsets. See :hg:`help revsets` for details.
1016
1025
1017 ``server``
1026 ``server``
1018 ----------
1027 ----------
1019
1028
1020 Controls generic server settings.
1029 Controls generic server settings.
1021
1030
1022 ``uncompressed``
1031 ``uncompressed``
1023 Whether to allow clients to clone a repository using the
1032 Whether to allow clients to clone a repository using the
1024 uncompressed streaming protocol. This transfers about 40% more
1033 uncompressed streaming protocol. This transfers about 40% more
1025 data than a regular clone, but uses less memory and CPU on both
1034 data than a regular clone, but uses less memory and CPU on both
1026 server and client. Over a LAN (100 Mbps or better) or a very fast
1035 server and client. Over a LAN (100 Mbps or better) or a very fast
1027 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
1036 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
1028 regular clone. Over most WAN connections (anything slower than
1037 regular clone. Over most WAN connections (anything slower than
1029 about 6 Mbps), uncompressed streaming is slower, because of the
1038 about 6 Mbps), uncompressed streaming is slower, because of the
1030 extra data transfer overhead. This mode will also temporarily hold
1039 extra data transfer overhead. This mode will also temporarily hold
1031 the write lock while determining what data to transfer.
1040 the write lock while determining what data to transfer.
1032 Default is True.
1041 Default is True.
1033
1042
1034 ``preferuncompressed``
1043 ``preferuncompressed``
1035 When set, clients will try to use the uncompressed streaming
1044 When set, clients will try to use the uncompressed streaming
1036 protocol. Default is False.
1045 protocol. Default is False.
1037
1046
1038 ``validate``
1047 ``validate``
1039 Whether to validate the completeness of pushed changesets by
1048 Whether to validate the completeness of pushed changesets by
1040 checking that all new file revisions specified in manifests are
1049 checking that all new file revisions specified in manifests are
1041 present. Default is False.
1050 present. Default is False.
1042
1051
1043 ``smtp``
1052 ``smtp``
1044 --------
1053 --------
1045
1054
1046 Configuration for extensions that need to send email messages.
1055 Configuration for extensions that need to send email messages.
1047
1056
1048 ``host``
1057 ``host``
1049 Host name of mail server, e.g. "mail.example.com".
1058 Host name of mail server, e.g. "mail.example.com".
1050
1059
1051 ``port``
1060 ``port``
1052 Optional. Port to connect to on mail server. Default: 465 (if
1061 Optional. Port to connect to on mail server. Default: 465 (if
1053 ``tls`` is smtps) or 25 (otherwise).
1062 ``tls`` is smtps) or 25 (otherwise).
1054
1063
1055 ``tls``
1064 ``tls``
1056 Optional. Method to enable TLS when connecting to mail server: starttls,
1065 Optional. Method to enable TLS when connecting to mail server: starttls,
1057 smtps or none. Default: none.
1066 smtps or none. Default: none.
1058
1067
1059 ``verifycert``
1068 ``verifycert``
1060 Optional. Verification for the certificate of mail server, when
1069 Optional. Verification for the certificate of mail server, when
1061 ``tls`` is starttls or smtps. "strict", "loose" or False. For
1070 ``tls`` is starttls or smtps. "strict", "loose" or False. For
1062 "strict" or "loose", the certificate is verified as same as the
1071 "strict" or "loose", the certificate is verified as same as the
1063 verification for HTTPS connections (see ``[hostfingerprints]`` and
1072 verification for HTTPS connections (see ``[hostfingerprints]`` and
1064 ``[web] cacerts`` also). For "strict", sending email is also
1073 ``[web] cacerts`` also). For "strict", sending email is also
1065 aborted, if there is no configuration for mail server in
1074 aborted, if there is no configuration for mail server in
1066 ``[hostfingerprints]`` and ``[web] cacerts``. --insecure for
1075 ``[hostfingerprints]`` and ``[web] cacerts``. --insecure for
1067 :hg:`email` overwrites this as "loose". Default: "strict".
1076 :hg:`email` overwrites this as "loose". Default: "strict".
1068
1077
1069 ``username``
1078 ``username``
1070 Optional. User name for authenticating with the SMTP server.
1079 Optional. User name for authenticating with the SMTP server.
1071 Default: none.
1080 Default: none.
1072
1081
1073 ``password``
1082 ``password``
1074 Optional. Password for authenticating with the SMTP server. If not
1083 Optional. Password for authenticating with the SMTP server. If not
1075 specified, interactive sessions will prompt the user for a
1084 specified, interactive sessions will prompt the user for a
1076 password; non-interactive sessions will fail. Default: none.
1085 password; non-interactive sessions will fail. Default: none.
1077
1086
1078 ``local_hostname``
1087 ``local_hostname``
1079 Optional. It's the hostname that the sender can use to identify
1088 Optional. It's the hostname that the sender can use to identify
1080 itself to the MTA.
1089 itself to the MTA.
1081
1090
1082
1091
1083 ``subpaths``
1092 ``subpaths``
1084 ------------
1093 ------------
1085
1094
1086 Subrepository source URLs can go stale if a remote server changes name
1095 Subrepository source URLs can go stale if a remote server changes name
1087 or becomes temporarily unavailable. This section lets you define
1096 or becomes temporarily unavailable. This section lets you define
1088 rewrite rules of the form::
1097 rewrite rules of the form::
1089
1098
1090 <pattern> = <replacement>
1099 <pattern> = <replacement>
1091
1100
1092 where ``pattern`` is a regular expression matching a subrepository
1101 where ``pattern`` is a regular expression matching a subrepository
1093 source URL and ``replacement`` is the replacement string used to
1102 source URL and ``replacement`` is the replacement string used to
1094 rewrite it. Groups can be matched in ``pattern`` and referenced in
1103 rewrite it. Groups can be matched in ``pattern`` and referenced in
1095 ``replacements``. For instance::
1104 ``replacements``. For instance::
1096
1105
1097 http://server/(.*)-hg/ = http://hg.server/\1/
1106 http://server/(.*)-hg/ = http://hg.server/\1/
1098
1107
1099 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1108 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1100
1109
1101 Relative subrepository paths are first made absolute, and the
1110 Relative subrepository paths are first made absolute, and the
1102 rewrite rules are then applied on the full (absolute) path. The rules
1111 rewrite rules are then applied on the full (absolute) path. The rules
1103 are applied in definition order.
1112 are applied in definition order.
1104
1113
1105 ``trusted``
1114 ``trusted``
1106 -----------
1115 -----------
1107
1116
1108 Mercurial will not use the settings in the
1117 Mercurial will not use the settings in the
1109 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1118 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1110 user or to a trusted group, as various hgrc features allow arbitrary
1119 user or to a trusted group, as various hgrc features allow arbitrary
1111 commands to be run. This issue is often encountered when configuring
1120 commands to be run. This issue is often encountered when configuring
1112 hooks or extensions for shared repositories or servers. However,
1121 hooks or extensions for shared repositories or servers. However,
1113 the web interface will use some safe settings from the ``[web]``
1122 the web interface will use some safe settings from the ``[web]``
1114 section.
1123 section.
1115
1124
1116 This section specifies what users and groups are trusted. The
1125 This section specifies what users and groups are trusted. The
1117 current user is always trusted. To trust everybody, list a user or a
1126 current user is always trusted. To trust everybody, list a user or a
1118 group with name ``*``. These settings must be placed in an
1127 group with name ``*``. These settings must be placed in an
1119 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1128 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1120 user or service running Mercurial.
1129 user or service running Mercurial.
1121
1130
1122 ``users``
1131 ``users``
1123 Comma-separated list of trusted users.
1132 Comma-separated list of trusted users.
1124
1133
1125 ``groups``
1134 ``groups``
1126 Comma-separated list of trusted groups.
1135 Comma-separated list of trusted groups.
1127
1136
1128
1137
1129 ``ui``
1138 ``ui``
1130 ------
1139 ------
1131
1140
1132 User interface controls.
1141 User interface controls.
1133
1142
1134 ``archivemeta``
1143 ``archivemeta``
1135 Whether to include the .hg_archival.txt file containing meta data
1144 Whether to include the .hg_archival.txt file containing meta data
1136 (hashes for the repository base and for tip) in archives created
1145 (hashes for the repository base and for tip) in archives created
1137 by the :hg:`archive` command or downloaded via hgweb.
1146 by the :hg:`archive` command or downloaded via hgweb.
1138 Default is True.
1147 Default is True.
1139
1148
1140 ``askusername``
1149 ``askusername``
1141 Whether to prompt for a username when committing. If True, and
1150 Whether to prompt for a username when committing. If True, and
1142 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1151 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1143 be prompted to enter a username. If no username is entered, the
1152 be prompted to enter a username. If no username is entered, the
1144 default ``USER@HOST`` is used instead.
1153 default ``USER@HOST`` is used instead.
1145 Default is False.
1154 Default is False.
1146
1155
1147 ``commitsubrepos``
1156 ``commitsubrepos``
1148 Whether to commit modified subrepositories when committing the
1157 Whether to commit modified subrepositories when committing the
1149 parent repository. If False and one subrepository has uncommitted
1158 parent repository. If False and one subrepository has uncommitted
1150 changes, abort the commit.
1159 changes, abort the commit.
1151 Default is False.
1160 Default is False.
1152
1161
1153 ``debug``
1162 ``debug``
1154 Print debugging information. True or False. Default is False.
1163 Print debugging information. True or False. Default is False.
1155
1164
1156 ``editor``
1165 ``editor``
1157 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1166 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1158
1167
1159 ``fallbackencoding``
1168 ``fallbackencoding``
1160 Encoding to try if it's not possible to decode the changelog using
1169 Encoding to try if it's not possible to decode the changelog using
1161 UTF-8. Default is ISO-8859-1.
1170 UTF-8. Default is ISO-8859-1.
1162
1171
1163 ``ignore``
1172 ``ignore``
1164 A file to read per-user ignore patterns from. This file should be
1173 A file to read per-user ignore patterns from. This file should be
1165 in the same format as a repository-wide .hgignore file. This
1174 in the same format as a repository-wide .hgignore file. This
1166 option supports hook syntax, so if you want to specify multiple
1175 option supports hook syntax, so if you want to specify multiple
1167 ignore files, you can do so by setting something like
1176 ignore files, you can do so by setting something like
1168 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1177 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1169 format, see the ``hgignore(5)`` man page.
1178 format, see the ``hgignore(5)`` man page.
1170
1179
1171 ``interactive``
1180 ``interactive``
1172 Allow to prompt the user. True or False. Default is True.
1181 Allow to prompt the user. True or False. Default is True.
1173
1182
1174 ``logtemplate``
1183 ``logtemplate``
1175 Template string for commands that print changesets.
1184 Template string for commands that print changesets.
1176
1185
1177 ``merge``
1186 ``merge``
1178 The conflict resolution program to use during a manual merge.
1187 The conflict resolution program to use during a manual merge.
1179 For more information on merge tools see :hg:`help merge-tools`.
1188 For more information on merge tools see :hg:`help merge-tools`.
1180 For configuring merge tools see the ``[merge-tools]`` section.
1189 For configuring merge tools see the ``[merge-tools]`` section.
1181
1190
1182 ``portablefilenames``
1191 ``portablefilenames``
1183 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1192 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1184 Default is ``warn``.
1193 Default is ``warn``.
1185 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1194 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1186 platforms, if a file with a non-portable filename is added (e.g. a file
1195 platforms, if a file with a non-portable filename is added (e.g. a file
1187 with a name that can't be created on Windows because it contains reserved
1196 with a name that can't be created on Windows because it contains reserved
1188 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1197 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1189 collision with an existing file).
1198 collision with an existing file).
1190 If set to ``ignore`` (or ``false``), no warning is printed.
1199 If set to ``ignore`` (or ``false``), no warning is printed.
1191 If set to ``abort``, the command is aborted.
1200 If set to ``abort``, the command is aborted.
1192 On Windows, this configuration option is ignored and the command aborted.
1201 On Windows, this configuration option is ignored and the command aborted.
1193
1202
1194 ``quiet``
1203 ``quiet``
1195 Reduce the amount of output printed. True or False. Default is False.
1204 Reduce the amount of output printed. True or False. Default is False.
1196
1205
1197 ``remotecmd``
1206 ``remotecmd``
1198 remote command to use for clone/push/pull operations. Default is ``hg``.
1207 remote command to use for clone/push/pull operations. Default is ``hg``.
1199
1208
1200 ``reportoldssl``
1209 ``reportoldssl``
1201 Warn if an SSL certificate is unable to be due to using Python
1210 Warn if an SSL certificate is unable to be due to using Python
1202 2.5 or earlier. True or False. Default is True.
1211 2.5 or earlier. True or False. Default is True.
1203
1212
1204 ``report_untrusted``
1213 ``report_untrusted``
1205 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1214 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1206 trusted user or group. True or False. Default is True.
1215 trusted user or group. True or False. Default is True.
1207
1216
1208 ``slash``
1217 ``slash``
1209 Display paths using a slash (``/``) as the path separator. This
1218 Display paths using a slash (``/``) as the path separator. This
1210 only makes a difference on systems where the default path
1219 only makes a difference on systems where the default path
1211 separator is not the slash character (e.g. Windows uses the
1220 separator is not the slash character (e.g. Windows uses the
1212 backslash character (``\``)).
1221 backslash character (``\``)).
1213 Default is False.
1222 Default is False.
1214
1223
1215 ``ssh``
1224 ``ssh``
1216 command to use for SSH connections. Default is ``ssh``.
1225 command to use for SSH connections. Default is ``ssh``.
1217
1226
1218 ``strict``
1227 ``strict``
1219 Require exact command names, instead of allowing unambiguous
1228 Require exact command names, instead of allowing unambiguous
1220 abbreviations. True or False. Default is False.
1229 abbreviations. True or False. Default is False.
1221
1230
1222 ``style``
1231 ``style``
1223 Name of style to use for command output.
1232 Name of style to use for command output.
1224
1233
1225 ``timeout``
1234 ``timeout``
1226 The timeout used when a lock is held (in seconds), a negative value
1235 The timeout used when a lock is held (in seconds), a negative value
1227 means no timeout. Default is 600.
1236 means no timeout. Default is 600.
1228
1237
1229 ``traceback``
1238 ``traceback``
1230 Mercurial always prints a traceback when an unknown exception
1239 Mercurial always prints a traceback when an unknown exception
1231 occurs. Setting this to True will make Mercurial print a traceback
1240 occurs. Setting this to True will make Mercurial print a traceback
1232 on all exceptions, even those recognized by Mercurial (such as
1241 on all exceptions, even those recognized by Mercurial (such as
1233 IOError or MemoryError). Default is False.
1242 IOError or MemoryError). Default is False.
1234
1243
1235 ``username``
1244 ``username``
1236 The committer of a changeset created when running "commit".
1245 The committer of a changeset created when running "commit".
1237 Typically a person's name and email address, e.g. ``Fred Widget
1246 Typically a person's name and email address, e.g. ``Fred Widget
1238 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1247 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1239 the username in hgrc is empty, it has to be specified manually or
1248 the username in hgrc is empty, it has to be specified manually or
1240 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1249 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1241 ``username =`` in the system hgrc). Environment variables in the
1250 ``username =`` in the system hgrc). Environment variables in the
1242 username are expanded.
1251 username are expanded.
1243
1252
1244 ``verbose``
1253 ``verbose``
1245 Increase the amount of output printed. True or False. Default is False.
1254 Increase the amount of output printed. True or False. Default is False.
1246
1255
1247
1256
1248 ``web``
1257 ``web``
1249 -------
1258 -------
1250
1259
1251 Web interface configuration. The settings in this section apply to
1260 Web interface configuration. The settings in this section apply to
1252 both the builtin webserver (started by :hg:`serve`) and the script you
1261 both the builtin webserver (started by :hg:`serve`) and the script you
1253 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1262 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1254 and WSGI).
1263 and WSGI).
1255
1264
1256 The Mercurial webserver does no authentication (it does not prompt for
1265 The Mercurial webserver does no authentication (it does not prompt for
1257 usernames and passwords to validate *who* users are), but it does do
1266 usernames and passwords to validate *who* users are), but it does do
1258 authorization (it grants or denies access for *authenticated users*
1267 authorization (it grants or denies access for *authenticated users*
1259 based on settings in this section). You must either configure your
1268 based on settings in this section). You must either configure your
1260 webserver to do authentication for you, or disable the authorization
1269 webserver to do authentication for you, or disable the authorization
1261 checks.
1270 checks.
1262
1271
1263 For a quick setup in a trusted environment, e.g., a private LAN, where
1272 For a quick setup in a trusted environment, e.g., a private LAN, where
1264 you want it to accept pushes from anybody, you can use the following
1273 you want it to accept pushes from anybody, you can use the following
1265 command line::
1274 command line::
1266
1275
1267 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1276 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1268
1277
1269 Note that this will allow anybody to push anything to the server and
1278 Note that this will allow anybody to push anything to the server and
1270 that this should not be used for public servers.
1279 that this should not be used for public servers.
1271
1280
1272 The full set of options is:
1281 The full set of options is:
1273
1282
1274 ``accesslog``
1283 ``accesslog``
1275 Where to output the access log. Default is stdout.
1284 Where to output the access log. Default is stdout.
1276
1285
1277 ``address``
1286 ``address``
1278 Interface address to bind to. Default is all.
1287 Interface address to bind to. Default is all.
1279
1288
1280 ``allow_archive``
1289 ``allow_archive``
1281 List of archive format (bz2, gz, zip) allowed for downloading.
1290 List of archive format (bz2, gz, zip) allowed for downloading.
1282 Default is empty.
1291 Default is empty.
1283
1292
1284 ``allowbz2``
1293 ``allowbz2``
1285 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1294 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1286 revisions.
1295 revisions.
1287 Default is False.
1296 Default is False.
1288
1297
1289 ``allowgz``
1298 ``allowgz``
1290 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1299 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1291 revisions.
1300 revisions.
1292 Default is False.
1301 Default is False.
1293
1302
1294 ``allowpull``
1303 ``allowpull``
1295 Whether to allow pulling from the repository. Default is True.
1304 Whether to allow pulling from the repository. Default is True.
1296
1305
1297 ``allow_push``
1306 ``allow_push``
1298 Whether to allow pushing to the repository. If empty or not set,
1307 Whether to allow pushing to the repository. If empty or not set,
1299 push is not allowed. If the special value ``*``, any remote user can
1308 push is not allowed. If the special value ``*``, any remote user can
1300 push, including unauthenticated users. Otherwise, the remote user
1309 push, including unauthenticated users. Otherwise, the remote user
1301 must have been authenticated, and the authenticated user name must
1310 must have been authenticated, and the authenticated user name must
1302 be present in this list. The contents of the allow_push list are
1311 be present in this list. The contents of the allow_push list are
1303 examined after the deny_push list.
1312 examined after the deny_push list.
1304
1313
1305 ``allow_read``
1314 ``allow_read``
1306 If the user has not already been denied repository access due to
1315 If the user has not already been denied repository access due to
1307 the contents of deny_read, this list determines whether to grant
1316 the contents of deny_read, this list determines whether to grant
1308 repository access to the user. If this list is not empty, and the
1317 repository access to the user. If this list is not empty, and the
1309 user is unauthenticated or not present in the list, then access is
1318 user is unauthenticated or not present in the list, then access is
1310 denied for the user. If the list is empty or not set, then access
1319 denied for the user. If the list is empty or not set, then access
1311 is permitted to all users by default. Setting allow_read to the
1320 is permitted to all users by default. Setting allow_read to the
1312 special value ``*`` is equivalent to it not being set (i.e. access
1321 special value ``*`` is equivalent to it not being set (i.e. access
1313 is permitted to all users). The contents of the allow_read list are
1322 is permitted to all users). The contents of the allow_read list are
1314 examined after the deny_read list.
1323 examined after the deny_read list.
1315
1324
1316 ``allowzip``
1325 ``allowzip``
1317 (DEPRECATED) Whether to allow .zip downloading of repository
1326 (DEPRECATED) Whether to allow .zip downloading of repository
1318 revisions. Default is False. This feature creates temporary files.
1327 revisions. Default is False. This feature creates temporary files.
1319
1328
1320 ``archivesubrepos``
1329 ``archivesubrepos``
1321 Whether to recurse into subrepositories when archiving. Default is
1330 Whether to recurse into subrepositories when archiving. Default is
1322 False.
1331 False.
1323
1332
1324 ``baseurl``
1333 ``baseurl``
1325 Base URL to use when publishing URLs in other locations, so
1334 Base URL to use when publishing URLs in other locations, so
1326 third-party tools like email notification hooks can construct
1335 third-party tools like email notification hooks can construct
1327 URLs. Example: ``http://hgserver/repos/``.
1336 URLs. Example: ``http://hgserver/repos/``.
1328
1337
1329 ``cacerts``
1338 ``cacerts``
1330 Path to file containing a list of PEM encoded certificate
1339 Path to file containing a list of PEM encoded certificate
1331 authority certificates. Environment variables and ``~user``
1340 authority certificates. Environment variables and ``~user``
1332 constructs are expanded in the filename. If specified on the
1341 constructs are expanded in the filename. If specified on the
1333 client, then it will verify the identity of remote HTTPS servers
1342 client, then it will verify the identity of remote HTTPS servers
1334 with these certificates.
1343 with these certificates.
1335
1344
1336 This feature is only supported when using Python 2.6 or later. If you wish
1345 This feature is only supported when using Python 2.6 or later. If you wish
1337 to use it with earlier versions of Python, install the backported
1346 to use it with earlier versions of Python, install the backported
1338 version of the ssl library that is available from
1347 version of the ssl library that is available from
1339 ``http://pypi.python.org``.
1348 ``http://pypi.python.org``.
1340
1349
1341 To disable SSL verification temporarily, specify ``--insecure`` from
1350 To disable SSL verification temporarily, specify ``--insecure`` from
1342 command line.
1351 command line.
1343
1352
1344 You can use OpenSSL's CA certificate file if your platform has
1353 You can use OpenSSL's CA certificate file if your platform has
1345 one. On most Linux systems this will be
1354 one. On most Linux systems this will be
1346 ``/etc/ssl/certs/ca-certificates.crt``. Otherwise you will have to
1355 ``/etc/ssl/certs/ca-certificates.crt``. Otherwise you will have to
1347 generate this file manually. The form must be as follows::
1356 generate this file manually. The form must be as follows::
1348
1357
1349 -----BEGIN CERTIFICATE-----
1358 -----BEGIN CERTIFICATE-----
1350 ... (certificate in base64 PEM encoding) ...
1359 ... (certificate in base64 PEM encoding) ...
1351 -----END CERTIFICATE-----
1360 -----END CERTIFICATE-----
1352 -----BEGIN CERTIFICATE-----
1361 -----BEGIN CERTIFICATE-----
1353 ... (certificate in base64 PEM encoding) ...
1362 ... (certificate in base64 PEM encoding) ...
1354 -----END CERTIFICATE-----
1363 -----END CERTIFICATE-----
1355
1364
1356 ``cache``
1365 ``cache``
1357 Whether to support caching in hgweb. Defaults to True.
1366 Whether to support caching in hgweb. Defaults to True.
1358
1367
1359 ``collapse``
1368 ``collapse``
1360 With ``descend`` enabled, repositories in subdirectories are shown at
1369 With ``descend`` enabled, repositories in subdirectories are shown at
1361 a single level alongside repositories in the current path. With
1370 a single level alongside repositories in the current path. With
1362 ``collapse`` also enabled, repositories residing at a deeper level than
1371 ``collapse`` also enabled, repositories residing at a deeper level than
1363 the current path are grouped behind navigable directory entries that
1372 the current path are grouped behind navigable directory entries that
1364 lead to the locations of these repositories. In effect, this setting
1373 lead to the locations of these repositories. In effect, this setting
1365 collapses each collection of repositories found within a subdirectory
1374 collapses each collection of repositories found within a subdirectory
1366 into a single entry for that subdirectory. Default is False.
1375 into a single entry for that subdirectory. Default is False.
1367
1376
1368 ``comparisoncontext``
1377 ``comparisoncontext``
1369 Number of lines of context to show in side-by-side file comparison. If
1378 Number of lines of context to show in side-by-side file comparison. If
1370 negative or the value ``full``, whole files are shown. Default is 5.
1379 negative or the value ``full``, whole files are shown. Default is 5.
1371 This setting can be overridden by a ``context`` request parameter to the
1380 This setting can be overridden by a ``context`` request parameter to the
1372 ``comparison`` command, taking the same values.
1381 ``comparison`` command, taking the same values.
1373
1382
1374 ``contact``
1383 ``contact``
1375 Name or email address of the person in charge of the repository.
1384 Name or email address of the person in charge of the repository.
1376 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1385 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1377
1386
1378 ``deny_push``
1387 ``deny_push``
1379 Whether to deny pushing to the repository. If empty or not set,
1388 Whether to deny pushing to the repository. If empty or not set,
1380 push is not denied. If the special value ``*``, all remote users are
1389 push is not denied. If the special value ``*``, all remote users are
1381 denied push. Otherwise, unauthenticated users are all denied, and
1390 denied push. Otherwise, unauthenticated users are all denied, and
1382 any authenticated user name present in this list is also denied. The
1391 any authenticated user name present in this list is also denied. The
1383 contents of the deny_push list are examined before the allow_push list.
1392 contents of the deny_push list are examined before the allow_push list.
1384
1393
1385 ``deny_read``
1394 ``deny_read``
1386 Whether to deny reading/viewing of the repository. If this list is
1395 Whether to deny reading/viewing of the repository. If this list is
1387 not empty, unauthenticated users are all denied, and any
1396 not empty, unauthenticated users are all denied, and any
1388 authenticated user name present in this list is also denied access to
1397 authenticated user name present in this list is also denied access to
1389 the repository. If set to the special value ``*``, all remote users
1398 the repository. If set to the special value ``*``, all remote users
1390 are denied access (rarely needed ;). If deny_read is empty or not set,
1399 are denied access (rarely needed ;). If deny_read is empty or not set,
1391 the determination of repository access depends on the presence and
1400 the determination of repository access depends on the presence and
1392 content of the allow_read list (see description). If both
1401 content of the allow_read list (see description). If both
1393 deny_read and allow_read are empty or not set, then access is
1402 deny_read and allow_read are empty or not set, then access is
1394 permitted to all users by default. If the repository is being
1403 permitted to all users by default. If the repository is being
1395 served via hgwebdir, denied users will not be able to see it in
1404 served via hgwebdir, denied users will not be able to see it in
1396 the list of repositories. The contents of the deny_read list have
1405 the list of repositories. The contents of the deny_read list have
1397 priority over (are examined before) the contents of the allow_read
1406 priority over (are examined before) the contents of the allow_read
1398 list.
1407 list.
1399
1408
1400 ``descend``
1409 ``descend``
1401 hgwebdir indexes will not descend into subdirectories. Only repositories
1410 hgwebdir indexes will not descend into subdirectories. Only repositories
1402 directly in the current path will be shown (other repositories are still
1411 directly in the current path will be shown (other repositories are still
1403 available from the index corresponding to their containing path).
1412 available from the index corresponding to their containing path).
1404
1413
1405 ``description``
1414 ``description``
1406 Textual description of the repository's purpose or contents.
1415 Textual description of the repository's purpose or contents.
1407 Default is "unknown".
1416 Default is "unknown".
1408
1417
1409 ``encoding``
1418 ``encoding``
1410 Character encoding name. Default is the current locale charset.
1419 Character encoding name. Default is the current locale charset.
1411 Example: "UTF-8"
1420 Example: "UTF-8"
1412
1421
1413 ``errorlog``
1422 ``errorlog``
1414 Where to output the error log. Default is stderr.
1423 Where to output the error log. Default is stderr.
1415
1424
1416 ``guessmime``
1425 ``guessmime``
1417 Control MIME types for raw download of file content.
1426 Control MIME types for raw download of file content.
1418 Set to True to let hgweb guess the content type from the file
1427 Set to True to let hgweb guess the content type from the file
1419 extension. This will serve HTML files as ``text/html`` and might
1428 extension. This will serve HTML files as ``text/html`` and might
1420 allow cross-site scripting attacks when serving untrusted
1429 allow cross-site scripting attacks when serving untrusted
1421 repositories. Default is False.
1430 repositories. Default is False.
1422
1431
1423 ``hidden``
1432 ``hidden``
1424 Whether to hide the repository in the hgwebdir index.
1433 Whether to hide the repository in the hgwebdir index.
1425 Default is False.
1434 Default is False.
1426
1435
1427 ``ipv6``
1436 ``ipv6``
1428 Whether to use IPv6. Default is False.
1437 Whether to use IPv6. Default is False.
1429
1438
1430 ``logoimg``
1439 ``logoimg``
1431 File name of the logo image that some templates display on each page.
1440 File name of the logo image that some templates display on each page.
1432 The file name is relative to ``staticurl``. That is, the full path to
1441 The file name is relative to ``staticurl``. That is, the full path to
1433 the logo image is "staticurl/logoimg".
1442 the logo image is "staticurl/logoimg".
1434 If unset, ``hglogo.png`` will be used.
1443 If unset, ``hglogo.png`` will be used.
1435
1444
1436 ``logourl``
1445 ``logourl``
1437 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1446 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1438 will be used.
1447 will be used.
1439
1448
1440 ``maxchanges``
1449 ``maxchanges``
1441 Maximum number of changes to list on the changelog. Default is 10.
1450 Maximum number of changes to list on the changelog. Default is 10.
1442
1451
1443 ``maxfiles``
1452 ``maxfiles``
1444 Maximum number of files to list per changeset. Default is 10.
1453 Maximum number of files to list per changeset. Default is 10.
1445
1454
1446 ``maxshortchanges``
1455 ``maxshortchanges``
1447 Maximum number of changes to list on the shortlog, graph or filelog
1456 Maximum number of changes to list on the shortlog, graph or filelog
1448 pages. Default is 60.
1457 pages. Default is 60.
1449
1458
1450 ``name``
1459 ``name``
1451 Repository name to use in the web interface. Default is current
1460 Repository name to use in the web interface. Default is current
1452 working directory.
1461 working directory.
1453
1462
1454 ``port``
1463 ``port``
1455 Port to listen on. Default is 8000.
1464 Port to listen on. Default is 8000.
1456
1465
1457 ``prefix``
1466 ``prefix``
1458 Prefix path to serve from. Default is '' (server root).
1467 Prefix path to serve from. Default is '' (server root).
1459
1468
1460 ``push_ssl``
1469 ``push_ssl``
1461 Whether to require that inbound pushes be transported over SSL to
1470 Whether to require that inbound pushes be transported over SSL to
1462 prevent password sniffing. Default is True.
1471 prevent password sniffing. Default is True.
1463
1472
1464 ``staticurl``
1473 ``staticurl``
1465 Base URL to use for static files. If unset, static files (e.g. the
1474 Base URL to use for static files. If unset, static files (e.g. the
1466 hgicon.png favicon) will be served by the CGI script itself. Use
1475 hgicon.png favicon) will be served by the CGI script itself. Use
1467 this setting to serve them directly with the HTTP server.
1476 this setting to serve them directly with the HTTP server.
1468 Example: ``http://hgserver/static/``.
1477 Example: ``http://hgserver/static/``.
1469
1478
1470 ``stripes``
1479 ``stripes``
1471 How many lines a "zebra stripe" should span in multi-line output.
1480 How many lines a "zebra stripe" should span in multi-line output.
1472 Default is 1; set to 0 to disable.
1481 Default is 1; set to 0 to disable.
1473
1482
1474 ``style``
1483 ``style``
1475 Which template map style to use.
1484 Which template map style to use.
1476
1485
1477 ``templates``
1486 ``templates``
1478 Where to find the HTML templates. Default is install path.
1487 Where to find the HTML templates. Default is install path.
1479
1488
1480 ``websub``
1489 ``websub``
1481 ----------
1490 ----------
1482
1491
1483 Web substitution filter definition. You can use this section to
1492 Web substitution filter definition. You can use this section to
1484 define a set of regular expression substitution patterns which
1493 define a set of regular expression substitution patterns which
1485 let you automatically modify the hgweb server output.
1494 let you automatically modify the hgweb server output.
1486
1495
1487 The default hgweb templates only apply these substitution patterns
1496 The default hgweb templates only apply these substitution patterns
1488 on the revision description fields. You can apply them anywhere
1497 on the revision description fields. You can apply them anywhere
1489 you want when you create your own templates by adding calls to the
1498 you want when you create your own templates by adding calls to the
1490 "websub" filter (usually after calling the "escape" filter).
1499 "websub" filter (usually after calling the "escape" filter).
1491
1500
1492 This can be used, for example, to convert issue references to links
1501 This can be used, for example, to convert issue references to links
1493 to your issue tracker, or to convert "markdown-like" syntax into
1502 to your issue tracker, or to convert "markdown-like" syntax into
1494 HTML (see the examples below).
1503 HTML (see the examples below).
1495
1504
1496 Each entry in this section names a substitution filter.
1505 Each entry in this section names a substitution filter.
1497 The value of each entry defines the substitution expression itself.
1506 The value of each entry defines the substitution expression itself.
1498 The websub expressions follow the old interhg extension syntax,
1507 The websub expressions follow the old interhg extension syntax,
1499 which in turn imitates the Unix sed replacement syntax::
1508 which in turn imitates the Unix sed replacement syntax::
1500
1509
1501 patternname = s/SEARCH_REGEX/REPLACE_EXPRESSION/[i]
1510 patternname = s/SEARCH_REGEX/REPLACE_EXPRESSION/[i]
1502
1511
1503 You can use any separator other than "/". The final "i" is optional
1512 You can use any separator other than "/". The final "i" is optional
1504 and indicates that the search must be case insensitive.
1513 and indicates that the search must be case insensitive.
1505
1514
1506 Examples::
1515 Examples::
1507
1516
1508 [websub]
1517 [websub]
1509 issues = s|issue(\d+)|<a href="http://bts.example.org/issue\1">issue\1</a>|i
1518 issues = s|issue(\d+)|<a href="http://bts.example.org/issue\1">issue\1</a>|i
1510 italic = s/\b_(\S+)_\b/<i>\1<\/i>/
1519 italic = s/\b_(\S+)_\b/<i>\1<\/i>/
1511 bold = s/\*\b(\S+)\b\*/<b>\1<\/b>/
1520 bold = s/\*\b(\S+)\b\*/<b>\1<\/b>/
1512
1521
1513 ``worker``
1522 ``worker``
1514 ----------
1523 ----------
1515
1524
1516 Parallel master/worker configuration. We currently perform working
1525 Parallel master/worker configuration. We currently perform working
1517 directory updates in parallel on Unix-like systems, which greatly
1526 directory updates in parallel on Unix-like systems, which greatly
1518 helps performance.
1527 helps performance.
1519
1528
1520 ``numcpus``
1529 ``numcpus``
1521 Number of CPUs to use for parallel operations. Default is 4 or the
1530 Number of CPUs to use for parallel operations. Default is 4 or the
1522 number of CPUs on the system, whichever is larger. A zero or
1531 number of CPUs on the system, whichever is larger. A zero or
1523 negative value is treated as ``use the default``.
1532 negative value is treated as ``use the default``.
@@ -1,2464 +1,2464 b''
1 # localrepo.py - read/write repository class for mercurial
1 # localrepo.py - read/write repository class 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 from node import hex, nullid, short
7 from node import hex, nullid, short
8 from i18n import _
8 from i18n import _
9 import peer, changegroup, subrepo, discovery, pushkey, obsolete, repoview
9 import peer, changegroup, subrepo, discovery, pushkey, obsolete, repoview
10 import changelog, dirstate, filelog, manifest, context, bookmarks, phases
10 import changelog, dirstate, filelog, manifest, context, bookmarks, phases
11 import lock as lockmod
11 import lock as lockmod
12 import transaction, store, encoding
12 import transaction, store, encoding
13 import scmutil, util, extensions, hook, error, revset
13 import scmutil, util, extensions, hook, error, revset
14 import match as matchmod
14 import match as matchmod
15 import merge as mergemod
15 import merge as mergemod
16 import tags as tagsmod
16 import tags as tagsmod
17 from lock import release
17 from lock import release
18 import weakref, errno, os, time, inspect
18 import weakref, errno, os, time, inspect
19 import branchmap, pathutil
19 import branchmap, pathutil
20 propertycache = util.propertycache
20 propertycache = util.propertycache
21 filecache = scmutil.filecache
21 filecache = scmutil.filecache
22
22
23 class repofilecache(filecache):
23 class repofilecache(filecache):
24 """All filecache usage on repo are done for logic that should be unfiltered
24 """All filecache usage on repo are done for logic that should be unfiltered
25 """
25 """
26
26
27 def __get__(self, repo, type=None):
27 def __get__(self, repo, type=None):
28 return super(repofilecache, self).__get__(repo.unfiltered(), type)
28 return super(repofilecache, self).__get__(repo.unfiltered(), type)
29 def __set__(self, repo, value):
29 def __set__(self, repo, value):
30 return super(repofilecache, self).__set__(repo.unfiltered(), value)
30 return super(repofilecache, self).__set__(repo.unfiltered(), value)
31 def __delete__(self, repo):
31 def __delete__(self, repo):
32 return super(repofilecache, self).__delete__(repo.unfiltered())
32 return super(repofilecache, self).__delete__(repo.unfiltered())
33
33
34 class storecache(repofilecache):
34 class storecache(repofilecache):
35 """filecache for files in the store"""
35 """filecache for files in the store"""
36 def join(self, obj, fname):
36 def join(self, obj, fname):
37 return obj.sjoin(fname)
37 return obj.sjoin(fname)
38
38
39 class unfilteredpropertycache(propertycache):
39 class unfilteredpropertycache(propertycache):
40 """propertycache that apply to unfiltered repo only"""
40 """propertycache that apply to unfiltered repo only"""
41
41
42 def __get__(self, repo, type=None):
42 def __get__(self, repo, type=None):
43 unfi = repo.unfiltered()
43 unfi = repo.unfiltered()
44 if unfi is repo:
44 if unfi is repo:
45 return super(unfilteredpropertycache, self).__get__(unfi)
45 return super(unfilteredpropertycache, self).__get__(unfi)
46 return getattr(unfi, self.name)
46 return getattr(unfi, self.name)
47
47
48 class filteredpropertycache(propertycache):
48 class filteredpropertycache(propertycache):
49 """propertycache that must take filtering in account"""
49 """propertycache that must take filtering in account"""
50
50
51 def cachevalue(self, obj, value):
51 def cachevalue(self, obj, value):
52 object.__setattr__(obj, self.name, value)
52 object.__setattr__(obj, self.name, value)
53
53
54
54
55 def hasunfilteredcache(repo, name):
55 def hasunfilteredcache(repo, name):
56 """check if a repo has an unfilteredpropertycache value for <name>"""
56 """check if a repo has an unfilteredpropertycache value for <name>"""
57 return name in vars(repo.unfiltered())
57 return name in vars(repo.unfiltered())
58
58
59 def unfilteredmethod(orig):
59 def unfilteredmethod(orig):
60 """decorate method that always need to be run on unfiltered version"""
60 """decorate method that always need to be run on unfiltered version"""
61 def wrapper(repo, *args, **kwargs):
61 def wrapper(repo, *args, **kwargs):
62 return orig(repo.unfiltered(), *args, **kwargs)
62 return orig(repo.unfiltered(), *args, **kwargs)
63 return wrapper
63 return wrapper
64
64
65 MODERNCAPS = set(('lookup', 'branchmap', 'pushkey', 'known', 'getbundle'))
65 MODERNCAPS = set(('lookup', 'branchmap', 'pushkey', 'known', 'getbundle'))
66 LEGACYCAPS = MODERNCAPS.union(set(['changegroupsubset']))
66 LEGACYCAPS = MODERNCAPS.union(set(['changegroupsubset']))
67
67
68 class localpeer(peer.peerrepository):
68 class localpeer(peer.peerrepository):
69 '''peer for a local repo; reflects only the most recent API'''
69 '''peer for a local repo; reflects only the most recent API'''
70
70
71 def __init__(self, repo, caps=MODERNCAPS):
71 def __init__(self, repo, caps=MODERNCAPS):
72 peer.peerrepository.__init__(self)
72 peer.peerrepository.__init__(self)
73 self._repo = repo.filtered('served')
73 self._repo = repo.filtered('served')
74 self.ui = repo.ui
74 self.ui = repo.ui
75 self._caps = repo._restrictcapabilities(caps)
75 self._caps = repo._restrictcapabilities(caps)
76 self.requirements = repo.requirements
76 self.requirements = repo.requirements
77 self.supportedformats = repo.supportedformats
77 self.supportedformats = repo.supportedformats
78
78
79 def close(self):
79 def close(self):
80 self._repo.close()
80 self._repo.close()
81
81
82 def _capabilities(self):
82 def _capabilities(self):
83 return self._caps
83 return self._caps
84
84
85 def local(self):
85 def local(self):
86 return self._repo
86 return self._repo
87
87
88 def canpush(self):
88 def canpush(self):
89 return True
89 return True
90
90
91 def url(self):
91 def url(self):
92 return self._repo.url()
92 return self._repo.url()
93
93
94 def lookup(self, key):
94 def lookup(self, key):
95 return self._repo.lookup(key)
95 return self._repo.lookup(key)
96
96
97 def branchmap(self):
97 def branchmap(self):
98 return self._repo.branchmap()
98 return self._repo.branchmap()
99
99
100 def heads(self):
100 def heads(self):
101 return self._repo.heads()
101 return self._repo.heads()
102
102
103 def known(self, nodes):
103 def known(self, nodes):
104 return self._repo.known(nodes)
104 return self._repo.known(nodes)
105
105
106 def getbundle(self, source, heads=None, common=None, bundlecaps=None):
106 def getbundle(self, source, heads=None, common=None, bundlecaps=None):
107 return self._repo.getbundle(source, heads=heads, common=common,
107 return self._repo.getbundle(source, heads=heads, common=common,
108 bundlecaps=None)
108 bundlecaps=None)
109
109
110 # TODO We might want to move the next two calls into legacypeer and add
110 # TODO We might want to move the next two calls into legacypeer and add
111 # unbundle instead.
111 # unbundle instead.
112
112
113 def lock(self):
113 def lock(self):
114 return self._repo.lock()
114 return self._repo.lock()
115
115
116 def addchangegroup(self, cg, source, url):
116 def addchangegroup(self, cg, source, url):
117 return self._repo.addchangegroup(cg, source, url)
117 return self._repo.addchangegroup(cg, source, url)
118
118
119 def pushkey(self, namespace, key, old, new):
119 def pushkey(self, namespace, key, old, new):
120 return self._repo.pushkey(namespace, key, old, new)
120 return self._repo.pushkey(namespace, key, old, new)
121
121
122 def listkeys(self, namespace):
122 def listkeys(self, namespace):
123 return self._repo.listkeys(namespace)
123 return self._repo.listkeys(namespace)
124
124
125 def debugwireargs(self, one, two, three=None, four=None, five=None):
125 def debugwireargs(self, one, two, three=None, four=None, five=None):
126 '''used to test argument passing over the wire'''
126 '''used to test argument passing over the wire'''
127 return "%s %s %s %s %s" % (one, two, three, four, five)
127 return "%s %s %s %s %s" % (one, two, three, four, five)
128
128
129 class locallegacypeer(localpeer):
129 class locallegacypeer(localpeer):
130 '''peer extension which implements legacy methods too; used for tests with
130 '''peer extension which implements legacy methods too; used for tests with
131 restricted capabilities'''
131 restricted capabilities'''
132
132
133 def __init__(self, repo):
133 def __init__(self, repo):
134 localpeer.__init__(self, repo, caps=LEGACYCAPS)
134 localpeer.__init__(self, repo, caps=LEGACYCAPS)
135
135
136 def branches(self, nodes):
136 def branches(self, nodes):
137 return self._repo.branches(nodes)
137 return self._repo.branches(nodes)
138
138
139 def between(self, pairs):
139 def between(self, pairs):
140 return self._repo.between(pairs)
140 return self._repo.between(pairs)
141
141
142 def changegroup(self, basenodes, source):
142 def changegroup(self, basenodes, source):
143 return self._repo.changegroup(basenodes, source)
143 return self._repo.changegroup(basenodes, source)
144
144
145 def changegroupsubset(self, bases, heads, source):
145 def changegroupsubset(self, bases, heads, source):
146 return self._repo.changegroupsubset(bases, heads, source)
146 return self._repo.changegroupsubset(bases, heads, source)
147
147
148 class localrepository(object):
148 class localrepository(object):
149
149
150 supportedformats = set(('revlogv1', 'generaldelta'))
150 supportedformats = set(('revlogv1', 'generaldelta'))
151 _basesupported = supportedformats | set(('store', 'fncache', 'shared',
151 _basesupported = supportedformats | set(('store', 'fncache', 'shared',
152 'dotencode'))
152 'dotencode'))
153 openerreqs = set(('revlogv1', 'generaldelta'))
153 openerreqs = set(('revlogv1', 'generaldelta'))
154 requirements = ['revlogv1']
154 requirements = ['revlogv1']
155 filtername = None
155 filtername = None
156
156
157 # a list of (ui, featureset) functions.
157 # a list of (ui, featureset) functions.
158 # only functions defined in module of enabled extensions are invoked
158 # only functions defined in module of enabled extensions are invoked
159 featuresetupfuncs = set()
159 featuresetupfuncs = set()
160
160
161 def _baserequirements(self, create):
161 def _baserequirements(self, create):
162 return self.requirements[:]
162 return self.requirements[:]
163
163
164 def __init__(self, baseui, path=None, create=False):
164 def __init__(self, baseui, path=None, create=False):
165 self.wvfs = scmutil.vfs(path, expandpath=True, realpath=True)
165 self.wvfs = scmutil.vfs(path, expandpath=True, realpath=True)
166 self.wopener = self.wvfs
166 self.wopener = self.wvfs
167 self.root = self.wvfs.base
167 self.root = self.wvfs.base
168 self.path = self.wvfs.join(".hg")
168 self.path = self.wvfs.join(".hg")
169 self.origroot = path
169 self.origroot = path
170 self.auditor = pathutil.pathauditor(self.root, self._checknested)
170 self.auditor = pathutil.pathauditor(self.root, self._checknested)
171 self.vfs = scmutil.vfs(self.path)
171 self.vfs = scmutil.vfs(self.path)
172 self.opener = self.vfs
172 self.opener = self.vfs
173 self.baseui = baseui
173 self.baseui = baseui
174 self.ui = baseui.copy()
174 self.ui = baseui.copy()
175 self.ui.copy = baseui.copy # prevent copying repo configuration
175 self.ui.copy = baseui.copy # prevent copying repo configuration
176 # A list of callback to shape the phase if no data were found.
176 # A list of callback to shape the phase if no data were found.
177 # Callback are in the form: func(repo, roots) --> processed root.
177 # Callback are in the form: func(repo, roots) --> processed root.
178 # This list it to be filled by extension during repo setup
178 # This list it to be filled by extension during repo setup
179 self._phasedefaults = []
179 self._phasedefaults = []
180 try:
180 try:
181 self.ui.readconfig(self.join("hgrc"), self.root)
181 self.ui.readconfig(self.join("hgrc"), self.root)
182 extensions.loadall(self.ui)
182 extensions.loadall(self.ui)
183 except IOError:
183 except IOError:
184 pass
184 pass
185
185
186 if self.featuresetupfuncs:
186 if self.featuresetupfuncs:
187 self.supported = set(self._basesupported) # use private copy
187 self.supported = set(self._basesupported) # use private copy
188 extmods = set(m.__name__ for n, m
188 extmods = set(m.__name__ for n, m
189 in extensions.extensions(self.ui))
189 in extensions.extensions(self.ui))
190 for setupfunc in self.featuresetupfuncs:
190 for setupfunc in self.featuresetupfuncs:
191 if setupfunc.__module__ in extmods:
191 if setupfunc.__module__ in extmods:
192 setupfunc(self.ui, self.supported)
192 setupfunc(self.ui, self.supported)
193 else:
193 else:
194 self.supported = self._basesupported
194 self.supported = self._basesupported
195
195
196 if not self.vfs.isdir():
196 if not self.vfs.isdir():
197 if create:
197 if create:
198 if not self.wvfs.exists():
198 if not self.wvfs.exists():
199 self.wvfs.makedirs()
199 self.wvfs.makedirs()
200 self.vfs.makedir(notindexed=True)
200 self.vfs.makedir(notindexed=True)
201 requirements = self._baserequirements(create)
201 requirements = self._baserequirements(create)
202 if self.ui.configbool('format', 'usestore', True):
202 if self.ui.configbool('format', 'usestore', True):
203 self.vfs.mkdir("store")
203 self.vfs.mkdir("store")
204 requirements.append("store")
204 requirements.append("store")
205 if self.ui.configbool('format', 'usefncache', True):
205 if self.ui.configbool('format', 'usefncache', True):
206 requirements.append("fncache")
206 requirements.append("fncache")
207 if self.ui.configbool('format', 'dotencode', True):
207 if self.ui.configbool('format', 'dotencode', True):
208 requirements.append('dotencode')
208 requirements.append('dotencode')
209 # create an invalid changelog
209 # create an invalid changelog
210 self.vfs.append(
210 self.vfs.append(
211 "00changelog.i",
211 "00changelog.i",
212 '\0\0\0\2' # represents revlogv2
212 '\0\0\0\2' # represents revlogv2
213 ' dummy changelog to prevent using the old repo layout'
213 ' dummy changelog to prevent using the old repo layout'
214 )
214 )
215 if self.ui.configbool('format', 'generaldelta', False):
215 if self.ui.configbool('format', 'generaldelta', False):
216 requirements.append("generaldelta")
216 requirements.append("generaldelta")
217 requirements = set(requirements)
217 requirements = set(requirements)
218 else:
218 else:
219 raise error.RepoError(_("repository %s not found") % path)
219 raise error.RepoError(_("repository %s not found") % path)
220 elif create:
220 elif create:
221 raise error.RepoError(_("repository %s already exists") % path)
221 raise error.RepoError(_("repository %s already exists") % path)
222 else:
222 else:
223 try:
223 try:
224 requirements = scmutil.readrequires(self.vfs, self.supported)
224 requirements = scmutil.readrequires(self.vfs, self.supported)
225 except IOError, inst:
225 except IOError, inst:
226 if inst.errno != errno.ENOENT:
226 if inst.errno != errno.ENOENT:
227 raise
227 raise
228 requirements = set()
228 requirements = set()
229
229
230 self.sharedpath = self.path
230 self.sharedpath = self.path
231 try:
231 try:
232 vfs = scmutil.vfs(self.vfs.read("sharedpath").rstrip('\n'),
232 vfs = scmutil.vfs(self.vfs.read("sharedpath").rstrip('\n'),
233 realpath=True)
233 realpath=True)
234 s = vfs.base
234 s = vfs.base
235 if not vfs.exists():
235 if not vfs.exists():
236 raise error.RepoError(
236 raise error.RepoError(
237 _('.hg/sharedpath points to nonexistent directory %s') % s)
237 _('.hg/sharedpath points to nonexistent directory %s') % s)
238 self.sharedpath = s
238 self.sharedpath = s
239 except IOError, inst:
239 except IOError, inst:
240 if inst.errno != errno.ENOENT:
240 if inst.errno != errno.ENOENT:
241 raise
241 raise
242
242
243 self.store = store.store(requirements, self.sharedpath, scmutil.vfs)
243 self.store = store.store(requirements, self.sharedpath, scmutil.vfs)
244 self.spath = self.store.path
244 self.spath = self.store.path
245 self.svfs = self.store.vfs
245 self.svfs = self.store.vfs
246 self.sopener = self.svfs
246 self.sopener = self.svfs
247 self.sjoin = self.store.join
247 self.sjoin = self.store.join
248 self.vfs.createmode = self.store.createmode
248 self.vfs.createmode = self.store.createmode
249 self._applyrequirements(requirements)
249 self._applyrequirements(requirements)
250 if create:
250 if create:
251 self._writerequirements()
251 self._writerequirements()
252
252
253
253
254 self._branchcaches = {}
254 self._branchcaches = {}
255 self.filterpats = {}
255 self.filterpats = {}
256 self._datafilters = {}
256 self._datafilters = {}
257 self._transref = self._lockref = self._wlockref = None
257 self._transref = self._lockref = self._wlockref = None
258
258
259 # A cache for various files under .hg/ that tracks file changes,
259 # A cache for various files under .hg/ that tracks file changes,
260 # (used by the filecache decorator)
260 # (used by the filecache decorator)
261 #
261 #
262 # Maps a property name to its util.filecacheentry
262 # Maps a property name to its util.filecacheentry
263 self._filecache = {}
263 self._filecache = {}
264
264
265 # hold sets of revision to be filtered
265 # hold sets of revision to be filtered
266 # should be cleared when something might have changed the filter value:
266 # should be cleared when something might have changed the filter value:
267 # - new changesets,
267 # - new changesets,
268 # - phase change,
268 # - phase change,
269 # - new obsolescence marker,
269 # - new obsolescence marker,
270 # - working directory parent change,
270 # - working directory parent change,
271 # - bookmark changes
271 # - bookmark changes
272 self.filteredrevcache = {}
272 self.filteredrevcache = {}
273
273
274 def close(self):
274 def close(self):
275 pass
275 pass
276
276
277 def _restrictcapabilities(self, caps):
277 def _restrictcapabilities(self, caps):
278 return caps
278 return caps
279
279
280 def _applyrequirements(self, requirements):
280 def _applyrequirements(self, requirements):
281 self.requirements = requirements
281 self.requirements = requirements
282 self.sopener.options = dict((r, 1) for r in requirements
282 self.sopener.options = dict((r, 1) for r in requirements
283 if r in self.openerreqs)
283 if r in self.openerreqs)
284
284
285 def _writerequirements(self):
285 def _writerequirements(self):
286 reqfile = self.opener("requires", "w")
286 reqfile = self.opener("requires", "w")
287 for r in sorted(self.requirements):
287 for r in sorted(self.requirements):
288 reqfile.write("%s\n" % r)
288 reqfile.write("%s\n" % r)
289 reqfile.close()
289 reqfile.close()
290
290
291 def _checknested(self, path):
291 def _checknested(self, path):
292 """Determine if path is a legal nested repository."""
292 """Determine if path is a legal nested repository."""
293 if not path.startswith(self.root):
293 if not path.startswith(self.root):
294 return False
294 return False
295 subpath = path[len(self.root) + 1:]
295 subpath = path[len(self.root) + 1:]
296 normsubpath = util.pconvert(subpath)
296 normsubpath = util.pconvert(subpath)
297
297
298 # XXX: Checking against the current working copy is wrong in
298 # XXX: Checking against the current working copy is wrong in
299 # the sense that it can reject things like
299 # the sense that it can reject things like
300 #
300 #
301 # $ hg cat -r 10 sub/x.txt
301 # $ hg cat -r 10 sub/x.txt
302 #
302 #
303 # if sub/ is no longer a subrepository in the working copy
303 # if sub/ is no longer a subrepository in the working copy
304 # parent revision.
304 # parent revision.
305 #
305 #
306 # However, it can of course also allow things that would have
306 # However, it can of course also allow things that would have
307 # been rejected before, such as the above cat command if sub/
307 # been rejected before, such as the above cat command if sub/
308 # is a subrepository now, but was a normal directory before.
308 # is a subrepository now, but was a normal directory before.
309 # The old path auditor would have rejected by mistake since it
309 # The old path auditor would have rejected by mistake since it
310 # panics when it sees sub/.hg/.
310 # panics when it sees sub/.hg/.
311 #
311 #
312 # All in all, checking against the working copy seems sensible
312 # All in all, checking against the working copy seems sensible
313 # since we want to prevent access to nested repositories on
313 # since we want to prevent access to nested repositories on
314 # the filesystem *now*.
314 # the filesystem *now*.
315 ctx = self[None]
315 ctx = self[None]
316 parts = util.splitpath(subpath)
316 parts = util.splitpath(subpath)
317 while parts:
317 while parts:
318 prefix = '/'.join(parts)
318 prefix = '/'.join(parts)
319 if prefix in ctx.substate:
319 if prefix in ctx.substate:
320 if prefix == normsubpath:
320 if prefix == normsubpath:
321 return True
321 return True
322 else:
322 else:
323 sub = ctx.sub(prefix)
323 sub = ctx.sub(prefix)
324 return sub.checknested(subpath[len(prefix) + 1:])
324 return sub.checknested(subpath[len(prefix) + 1:])
325 else:
325 else:
326 parts.pop()
326 parts.pop()
327 return False
327 return False
328
328
329 def peer(self):
329 def peer(self):
330 return localpeer(self) # not cached to avoid reference cycle
330 return localpeer(self) # not cached to avoid reference cycle
331
331
332 def unfiltered(self):
332 def unfiltered(self):
333 """Return unfiltered version of the repository
333 """Return unfiltered version of the repository
334
334
335 Intended to be overwritten by filtered repo."""
335 Intended to be overwritten by filtered repo."""
336 return self
336 return self
337
337
338 def filtered(self, name):
338 def filtered(self, name):
339 """Return a filtered version of a repository"""
339 """Return a filtered version of a repository"""
340 # build a new class with the mixin and the current class
340 # build a new class with the mixin and the current class
341 # (possibly subclass of the repo)
341 # (possibly subclass of the repo)
342 class proxycls(repoview.repoview, self.unfiltered().__class__):
342 class proxycls(repoview.repoview, self.unfiltered().__class__):
343 pass
343 pass
344 return proxycls(self, name)
344 return proxycls(self, name)
345
345
346 @repofilecache('bookmarks')
346 @repofilecache('bookmarks')
347 def _bookmarks(self):
347 def _bookmarks(self):
348 return bookmarks.bmstore(self)
348 return bookmarks.bmstore(self)
349
349
350 @repofilecache('bookmarks.current')
350 @repofilecache('bookmarks.current')
351 def _bookmarkcurrent(self):
351 def _bookmarkcurrent(self):
352 return bookmarks.readcurrent(self)
352 return bookmarks.readcurrent(self)
353
353
354 def bookmarkheads(self, bookmark):
354 def bookmarkheads(self, bookmark):
355 name = bookmark.split('@', 1)[0]
355 name = bookmark.split('@', 1)[0]
356 heads = []
356 heads = []
357 for mark, n in self._bookmarks.iteritems():
357 for mark, n in self._bookmarks.iteritems():
358 if mark.split('@', 1)[0] == name:
358 if mark.split('@', 1)[0] == name:
359 heads.append(n)
359 heads.append(n)
360 return heads
360 return heads
361
361
362 @storecache('phaseroots')
362 @storecache('phaseroots')
363 def _phasecache(self):
363 def _phasecache(self):
364 return phases.phasecache(self, self._phasedefaults)
364 return phases.phasecache(self, self._phasedefaults)
365
365
366 @storecache('obsstore')
366 @storecache('obsstore')
367 def obsstore(self):
367 def obsstore(self):
368 store = obsolete.obsstore(self.sopener)
368 store = obsolete.obsstore(self.sopener)
369 if store and not obsolete._enabled:
369 if store and not obsolete._enabled:
370 # message is rare enough to not be translated
370 # message is rare enough to not be translated
371 msg = 'obsolete feature not enabled but %i markers found!\n'
371 msg = 'obsolete feature not enabled but %i markers found!\n'
372 self.ui.warn(msg % len(list(store)))
372 self.ui.warn(msg % len(list(store)))
373 return store
373 return store
374
374
375 @storecache('00changelog.i')
375 @storecache('00changelog.i')
376 def changelog(self):
376 def changelog(self):
377 c = changelog.changelog(self.sopener)
377 c = changelog.changelog(self.sopener)
378 if 'HG_PENDING' in os.environ:
378 if 'HG_PENDING' in os.environ:
379 p = os.environ['HG_PENDING']
379 p = os.environ['HG_PENDING']
380 if p.startswith(self.root):
380 if p.startswith(self.root):
381 c.readpending('00changelog.i.a')
381 c.readpending('00changelog.i.a')
382 return c
382 return c
383
383
384 @storecache('00manifest.i')
384 @storecache('00manifest.i')
385 def manifest(self):
385 def manifest(self):
386 return manifest.manifest(self.sopener)
386 return manifest.manifest(self.sopener)
387
387
388 @repofilecache('dirstate')
388 @repofilecache('dirstate')
389 def dirstate(self):
389 def dirstate(self):
390 warned = [0]
390 warned = [0]
391 def validate(node):
391 def validate(node):
392 try:
392 try:
393 self.changelog.rev(node)
393 self.changelog.rev(node)
394 return node
394 return node
395 except error.LookupError:
395 except error.LookupError:
396 if not warned[0]:
396 if not warned[0]:
397 warned[0] = True
397 warned[0] = True
398 self.ui.warn(_("warning: ignoring unknown"
398 self.ui.warn(_("warning: ignoring unknown"
399 " working parent %s!\n") % short(node))
399 " working parent %s!\n") % short(node))
400 return nullid
400 return nullid
401
401
402 return dirstate.dirstate(self.opener, self.ui, self.root, validate)
402 return dirstate.dirstate(self.opener, self.ui, self.root, validate)
403
403
404 def __getitem__(self, changeid):
404 def __getitem__(self, changeid):
405 if changeid is None:
405 if changeid is None:
406 return context.workingctx(self)
406 return context.workingctx(self)
407 return context.changectx(self, changeid)
407 return context.changectx(self, changeid)
408
408
409 def __contains__(self, changeid):
409 def __contains__(self, changeid):
410 try:
410 try:
411 return bool(self.lookup(changeid))
411 return bool(self.lookup(changeid))
412 except error.RepoLookupError:
412 except error.RepoLookupError:
413 return False
413 return False
414
414
415 def __nonzero__(self):
415 def __nonzero__(self):
416 return True
416 return True
417
417
418 def __len__(self):
418 def __len__(self):
419 return len(self.changelog)
419 return len(self.changelog)
420
420
421 def __iter__(self):
421 def __iter__(self):
422 return iter(self.changelog)
422 return iter(self.changelog)
423
423
424 def revs(self, expr, *args):
424 def revs(self, expr, *args):
425 '''Return a list of revisions matching the given revset'''
425 '''Return a list of revisions matching the given revset'''
426 expr = revset.formatspec(expr, *args)
426 expr = revset.formatspec(expr, *args)
427 m = revset.match(None, expr)
427 m = revset.match(None, expr)
428 return [r for r in m(self, list(self))]
428 return [r for r in m(self, list(self))]
429
429
430 def set(self, expr, *args):
430 def set(self, expr, *args):
431 '''
431 '''
432 Yield a context for each matching revision, after doing arg
432 Yield a context for each matching revision, after doing arg
433 replacement via revset.formatspec
433 replacement via revset.formatspec
434 '''
434 '''
435 for r in self.revs(expr, *args):
435 for r in self.revs(expr, *args):
436 yield self[r]
436 yield self[r]
437
437
438 def url(self):
438 def url(self):
439 return 'file:' + self.root
439 return 'file:' + self.root
440
440
441 def hook(self, name, throw=False, **args):
441 def hook(self, name, throw=False, **args):
442 return hook.hook(self.ui, self, name, throw, **args)
442 return hook.hook(self.ui, self, name, throw, **args)
443
443
444 @unfilteredmethod
444 @unfilteredmethod
445 def _tag(self, names, node, message, local, user, date, extra={}):
445 def _tag(self, names, node, message, local, user, date, extra={}):
446 if isinstance(names, str):
446 if isinstance(names, str):
447 names = (names,)
447 names = (names,)
448
448
449 branches = self.branchmap()
449 branches = self.branchmap()
450 for name in names:
450 for name in names:
451 self.hook('pretag', throw=True, node=hex(node), tag=name,
451 self.hook('pretag', throw=True, node=hex(node), tag=name,
452 local=local)
452 local=local)
453 if name in branches:
453 if name in branches:
454 self.ui.warn(_("warning: tag %s conflicts with existing"
454 self.ui.warn(_("warning: tag %s conflicts with existing"
455 " branch name\n") % name)
455 " branch name\n") % name)
456
456
457 def writetags(fp, names, munge, prevtags):
457 def writetags(fp, names, munge, prevtags):
458 fp.seek(0, 2)
458 fp.seek(0, 2)
459 if prevtags and prevtags[-1] != '\n':
459 if prevtags and prevtags[-1] != '\n':
460 fp.write('\n')
460 fp.write('\n')
461 for name in names:
461 for name in names:
462 m = munge and munge(name) or name
462 m = munge and munge(name) or name
463 if (self._tagscache.tagtypes and
463 if (self._tagscache.tagtypes and
464 name in self._tagscache.tagtypes):
464 name in self._tagscache.tagtypes):
465 old = self.tags().get(name, nullid)
465 old = self.tags().get(name, nullid)
466 fp.write('%s %s\n' % (hex(old), m))
466 fp.write('%s %s\n' % (hex(old), m))
467 fp.write('%s %s\n' % (hex(node), m))
467 fp.write('%s %s\n' % (hex(node), m))
468 fp.close()
468 fp.close()
469
469
470 prevtags = ''
470 prevtags = ''
471 if local:
471 if local:
472 try:
472 try:
473 fp = self.opener('localtags', 'r+')
473 fp = self.opener('localtags', 'r+')
474 except IOError:
474 except IOError:
475 fp = self.opener('localtags', 'a')
475 fp = self.opener('localtags', 'a')
476 else:
476 else:
477 prevtags = fp.read()
477 prevtags = fp.read()
478
478
479 # local tags are stored in the current charset
479 # local tags are stored in the current charset
480 writetags(fp, names, None, prevtags)
480 writetags(fp, names, None, prevtags)
481 for name in names:
481 for name in names:
482 self.hook('tag', node=hex(node), tag=name, local=local)
482 self.hook('tag', node=hex(node), tag=name, local=local)
483 return
483 return
484
484
485 try:
485 try:
486 fp = self.wfile('.hgtags', 'rb+')
486 fp = self.wfile('.hgtags', 'rb+')
487 except IOError, e:
487 except IOError, e:
488 if e.errno != errno.ENOENT:
488 if e.errno != errno.ENOENT:
489 raise
489 raise
490 fp = self.wfile('.hgtags', 'ab')
490 fp = self.wfile('.hgtags', 'ab')
491 else:
491 else:
492 prevtags = fp.read()
492 prevtags = fp.read()
493
493
494 # committed tags are stored in UTF-8
494 # committed tags are stored in UTF-8
495 writetags(fp, names, encoding.fromlocal, prevtags)
495 writetags(fp, names, encoding.fromlocal, prevtags)
496
496
497 fp.close()
497 fp.close()
498
498
499 self.invalidatecaches()
499 self.invalidatecaches()
500
500
501 if '.hgtags' not in self.dirstate:
501 if '.hgtags' not in self.dirstate:
502 self[None].add(['.hgtags'])
502 self[None].add(['.hgtags'])
503
503
504 m = matchmod.exact(self.root, '', ['.hgtags'])
504 m = matchmod.exact(self.root, '', ['.hgtags'])
505 tagnode = self.commit(message, user, date, extra=extra, match=m)
505 tagnode = self.commit(message, user, date, extra=extra, match=m)
506
506
507 for name in names:
507 for name in names:
508 self.hook('tag', node=hex(node), tag=name, local=local)
508 self.hook('tag', node=hex(node), tag=name, local=local)
509
509
510 return tagnode
510 return tagnode
511
511
512 def tag(self, names, node, message, local, user, date):
512 def tag(self, names, node, message, local, user, date):
513 '''tag a revision with one or more symbolic names.
513 '''tag a revision with one or more symbolic names.
514
514
515 names is a list of strings or, when adding a single tag, names may be a
515 names is a list of strings or, when adding a single tag, names may be a
516 string.
516 string.
517
517
518 if local is True, the tags are stored in a per-repository file.
518 if local is True, the tags are stored in a per-repository file.
519 otherwise, they are stored in the .hgtags file, and a new
519 otherwise, they are stored in the .hgtags file, and a new
520 changeset is committed with the change.
520 changeset is committed with the change.
521
521
522 keyword arguments:
522 keyword arguments:
523
523
524 local: whether to store tags in non-version-controlled file
524 local: whether to store tags in non-version-controlled file
525 (default False)
525 (default False)
526
526
527 message: commit message to use if committing
527 message: commit message to use if committing
528
528
529 user: name of user to use if committing
529 user: name of user to use if committing
530
530
531 date: date tuple to use if committing'''
531 date: date tuple to use if committing'''
532
532
533 if not local:
533 if not local:
534 for x in self.status()[:5]:
534 for x in self.status()[:5]:
535 if '.hgtags' in x:
535 if '.hgtags' in x:
536 raise util.Abort(_('working copy of .hgtags is changed '
536 raise util.Abort(_('working copy of .hgtags is changed '
537 '(please commit .hgtags manually)'))
537 '(please commit .hgtags manually)'))
538
538
539 self.tags() # instantiate the cache
539 self.tags() # instantiate the cache
540 self._tag(names, node, message, local, user, date)
540 self._tag(names, node, message, local, user, date)
541
541
542 @filteredpropertycache
542 @filteredpropertycache
543 def _tagscache(self):
543 def _tagscache(self):
544 '''Returns a tagscache object that contains various tags related
544 '''Returns a tagscache object that contains various tags related
545 caches.'''
545 caches.'''
546
546
547 # This simplifies its cache management by having one decorated
547 # This simplifies its cache management by having one decorated
548 # function (this one) and the rest simply fetch things from it.
548 # function (this one) and the rest simply fetch things from it.
549 class tagscache(object):
549 class tagscache(object):
550 def __init__(self):
550 def __init__(self):
551 # These two define the set of tags for this repository. tags
551 # These two define the set of tags for this repository. tags
552 # maps tag name to node; tagtypes maps tag name to 'global' or
552 # maps tag name to node; tagtypes maps tag name to 'global' or
553 # 'local'. (Global tags are defined by .hgtags across all
553 # 'local'. (Global tags are defined by .hgtags across all
554 # heads, and local tags are defined in .hg/localtags.)
554 # heads, and local tags are defined in .hg/localtags.)
555 # They constitute the in-memory cache of tags.
555 # They constitute the in-memory cache of tags.
556 self.tags = self.tagtypes = None
556 self.tags = self.tagtypes = None
557
557
558 self.nodetagscache = self.tagslist = None
558 self.nodetagscache = self.tagslist = None
559
559
560 cache = tagscache()
560 cache = tagscache()
561 cache.tags, cache.tagtypes = self._findtags()
561 cache.tags, cache.tagtypes = self._findtags()
562
562
563 return cache
563 return cache
564
564
565 def tags(self):
565 def tags(self):
566 '''return a mapping of tag to node'''
566 '''return a mapping of tag to node'''
567 t = {}
567 t = {}
568 if self.changelog.filteredrevs:
568 if self.changelog.filteredrevs:
569 tags, tt = self._findtags()
569 tags, tt = self._findtags()
570 else:
570 else:
571 tags = self._tagscache.tags
571 tags = self._tagscache.tags
572 for k, v in tags.iteritems():
572 for k, v in tags.iteritems():
573 try:
573 try:
574 # ignore tags to unknown nodes
574 # ignore tags to unknown nodes
575 self.changelog.rev(v)
575 self.changelog.rev(v)
576 t[k] = v
576 t[k] = v
577 except (error.LookupError, ValueError):
577 except (error.LookupError, ValueError):
578 pass
578 pass
579 return t
579 return t
580
580
581 def _findtags(self):
581 def _findtags(self):
582 '''Do the hard work of finding tags. Return a pair of dicts
582 '''Do the hard work of finding tags. Return a pair of dicts
583 (tags, tagtypes) where tags maps tag name to node, and tagtypes
583 (tags, tagtypes) where tags maps tag name to node, and tagtypes
584 maps tag name to a string like \'global\' or \'local\'.
584 maps tag name to a string like \'global\' or \'local\'.
585 Subclasses or extensions are free to add their own tags, but
585 Subclasses or extensions are free to add their own tags, but
586 should be aware that the returned dicts will be retained for the
586 should be aware that the returned dicts will be retained for the
587 duration of the localrepo object.'''
587 duration of the localrepo object.'''
588
588
589 # XXX what tagtype should subclasses/extensions use? Currently
589 # XXX what tagtype should subclasses/extensions use? Currently
590 # mq and bookmarks add tags, but do not set the tagtype at all.
590 # mq and bookmarks add tags, but do not set the tagtype at all.
591 # Should each extension invent its own tag type? Should there
591 # Should each extension invent its own tag type? Should there
592 # be one tagtype for all such "virtual" tags? Or is the status
592 # be one tagtype for all such "virtual" tags? Or is the status
593 # quo fine?
593 # quo fine?
594
594
595 alltags = {} # map tag name to (node, hist)
595 alltags = {} # map tag name to (node, hist)
596 tagtypes = {}
596 tagtypes = {}
597
597
598 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
598 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
599 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
599 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
600
600
601 # Build the return dicts. Have to re-encode tag names because
601 # Build the return dicts. Have to re-encode tag names because
602 # the tags module always uses UTF-8 (in order not to lose info
602 # the tags module always uses UTF-8 (in order not to lose info
603 # writing to the cache), but the rest of Mercurial wants them in
603 # writing to the cache), but the rest of Mercurial wants them in
604 # local encoding.
604 # local encoding.
605 tags = {}
605 tags = {}
606 for (name, (node, hist)) in alltags.iteritems():
606 for (name, (node, hist)) in alltags.iteritems():
607 if node != nullid:
607 if node != nullid:
608 tags[encoding.tolocal(name)] = node
608 tags[encoding.tolocal(name)] = node
609 tags['tip'] = self.changelog.tip()
609 tags['tip'] = self.changelog.tip()
610 tagtypes = dict([(encoding.tolocal(name), value)
610 tagtypes = dict([(encoding.tolocal(name), value)
611 for (name, value) in tagtypes.iteritems()])
611 for (name, value) in tagtypes.iteritems()])
612 return (tags, tagtypes)
612 return (tags, tagtypes)
613
613
614 def tagtype(self, tagname):
614 def tagtype(self, tagname):
615 '''
615 '''
616 return the type of the given tag. result can be:
616 return the type of the given tag. result can be:
617
617
618 'local' : a local tag
618 'local' : a local tag
619 'global' : a global tag
619 'global' : a global tag
620 None : tag does not exist
620 None : tag does not exist
621 '''
621 '''
622
622
623 return self._tagscache.tagtypes.get(tagname)
623 return self._tagscache.tagtypes.get(tagname)
624
624
625 def tagslist(self):
625 def tagslist(self):
626 '''return a list of tags ordered by revision'''
626 '''return a list of tags ordered by revision'''
627 if not self._tagscache.tagslist:
627 if not self._tagscache.tagslist:
628 l = []
628 l = []
629 for t, n in self.tags().iteritems():
629 for t, n in self.tags().iteritems():
630 r = self.changelog.rev(n)
630 r = self.changelog.rev(n)
631 l.append((r, t, n))
631 l.append((r, t, n))
632 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
632 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
633
633
634 return self._tagscache.tagslist
634 return self._tagscache.tagslist
635
635
636 def nodetags(self, node):
636 def nodetags(self, node):
637 '''return the tags associated with a node'''
637 '''return the tags associated with a node'''
638 if not self._tagscache.nodetagscache:
638 if not self._tagscache.nodetagscache:
639 nodetagscache = {}
639 nodetagscache = {}
640 for t, n in self._tagscache.tags.iteritems():
640 for t, n in self._tagscache.tags.iteritems():
641 nodetagscache.setdefault(n, []).append(t)
641 nodetagscache.setdefault(n, []).append(t)
642 for tags in nodetagscache.itervalues():
642 for tags in nodetagscache.itervalues():
643 tags.sort()
643 tags.sort()
644 self._tagscache.nodetagscache = nodetagscache
644 self._tagscache.nodetagscache = nodetagscache
645 return self._tagscache.nodetagscache.get(node, [])
645 return self._tagscache.nodetagscache.get(node, [])
646
646
647 def nodebookmarks(self, node):
647 def nodebookmarks(self, node):
648 marks = []
648 marks = []
649 for bookmark, n in self._bookmarks.iteritems():
649 for bookmark, n in self._bookmarks.iteritems():
650 if n == node:
650 if n == node:
651 marks.append(bookmark)
651 marks.append(bookmark)
652 return sorted(marks)
652 return sorted(marks)
653
653
654 def branchmap(self):
654 def branchmap(self):
655 '''returns a dictionary {branch: [branchheads]}'''
655 '''returns a dictionary {branch: [branchheads]}'''
656 branchmap.updatecache(self)
656 branchmap.updatecache(self)
657 return self._branchcaches[self.filtername]
657 return self._branchcaches[self.filtername]
658
658
659
659
660 def _branchtip(self, heads):
660 def _branchtip(self, heads):
661 '''return the tipmost branch head in heads'''
661 '''return the tipmost branch head in heads'''
662 tip = heads[-1]
662 tip = heads[-1]
663 for h in reversed(heads):
663 for h in reversed(heads):
664 if not self[h].closesbranch():
664 if not self[h].closesbranch():
665 tip = h
665 tip = h
666 break
666 break
667 return tip
667 return tip
668
668
669 def branchtip(self, branch):
669 def branchtip(self, branch):
670 '''return the tip node for a given branch'''
670 '''return the tip node for a given branch'''
671 if branch not in self.branchmap():
671 if branch not in self.branchmap():
672 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
672 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
673 return self._branchtip(self.branchmap()[branch])
673 return self._branchtip(self.branchmap()[branch])
674
674
675 def branchtags(self):
675 def branchtags(self):
676 '''return a dict where branch names map to the tipmost head of
676 '''return a dict where branch names map to the tipmost head of
677 the branch, open heads come before closed'''
677 the branch, open heads come before closed'''
678 bt = {}
678 bt = {}
679 for bn, heads in self.branchmap().iteritems():
679 for bn, heads in self.branchmap().iteritems():
680 bt[bn] = self._branchtip(heads)
680 bt[bn] = self._branchtip(heads)
681 return bt
681 return bt
682
682
683 def lookup(self, key):
683 def lookup(self, key):
684 return self[key].node()
684 return self[key].node()
685
685
686 def lookupbranch(self, key, remote=None):
686 def lookupbranch(self, key, remote=None):
687 repo = remote or self
687 repo = remote or self
688 if key in repo.branchmap():
688 if key in repo.branchmap():
689 return key
689 return key
690
690
691 repo = (remote and remote.local()) and remote or self
691 repo = (remote and remote.local()) and remote or self
692 return repo[key].branch()
692 return repo[key].branch()
693
693
694 def known(self, nodes):
694 def known(self, nodes):
695 nm = self.changelog.nodemap
695 nm = self.changelog.nodemap
696 pc = self._phasecache
696 pc = self._phasecache
697 result = []
697 result = []
698 for n in nodes:
698 for n in nodes:
699 r = nm.get(n)
699 r = nm.get(n)
700 resp = not (r is None or pc.phase(self, r) >= phases.secret)
700 resp = not (r is None or pc.phase(self, r) >= phases.secret)
701 result.append(resp)
701 result.append(resp)
702 return result
702 return result
703
703
704 def local(self):
704 def local(self):
705 return self
705 return self
706
706
707 def cancopy(self):
707 def cancopy(self):
708 return self.local() # so statichttprepo's override of local() works
708 return self.local() # so statichttprepo's override of local() works
709
709
710 def join(self, f):
710 def join(self, f):
711 return os.path.join(self.path, f)
711 return os.path.join(self.path, f)
712
712
713 def wjoin(self, f):
713 def wjoin(self, f):
714 return os.path.join(self.root, f)
714 return os.path.join(self.root, f)
715
715
716 def file(self, f):
716 def file(self, f):
717 if f[0] == '/':
717 if f[0] == '/':
718 f = f[1:]
718 f = f[1:]
719 return filelog.filelog(self.sopener, f)
719 return filelog.filelog(self.sopener, f)
720
720
721 def changectx(self, changeid):
721 def changectx(self, changeid):
722 return self[changeid]
722 return self[changeid]
723
723
724 def parents(self, changeid=None):
724 def parents(self, changeid=None):
725 '''get list of changectxs for parents of changeid'''
725 '''get list of changectxs for parents of changeid'''
726 return self[changeid].parents()
726 return self[changeid].parents()
727
727
728 def setparents(self, p1, p2=nullid):
728 def setparents(self, p1, p2=nullid):
729 copies = self.dirstate.setparents(p1, p2)
729 copies = self.dirstate.setparents(p1, p2)
730 pctx = self[p1]
730 pctx = self[p1]
731 if copies:
731 if copies:
732 # Adjust copy records, the dirstate cannot do it, it
732 # Adjust copy records, the dirstate cannot do it, it
733 # requires access to parents manifests. Preserve them
733 # requires access to parents manifests. Preserve them
734 # only for entries added to first parent.
734 # only for entries added to first parent.
735 for f in copies:
735 for f in copies:
736 if f not in pctx and copies[f] in pctx:
736 if f not in pctx and copies[f] in pctx:
737 self.dirstate.copy(copies[f], f)
737 self.dirstate.copy(copies[f], f)
738 if p2 == nullid:
738 if p2 == nullid:
739 for f, s in sorted(self.dirstate.copies().items()):
739 for f, s in sorted(self.dirstate.copies().items()):
740 if f not in pctx and s not in pctx:
740 if f not in pctx and s not in pctx:
741 self.dirstate.copy(None, f)
741 self.dirstate.copy(None, f)
742
742
743 def filectx(self, path, changeid=None, fileid=None):
743 def filectx(self, path, changeid=None, fileid=None):
744 """changeid can be a changeset revision, node, or tag.
744 """changeid can be a changeset revision, node, or tag.
745 fileid can be a file revision or node."""
745 fileid can be a file revision or node."""
746 return context.filectx(self, path, changeid, fileid)
746 return context.filectx(self, path, changeid, fileid)
747
747
748 def getcwd(self):
748 def getcwd(self):
749 return self.dirstate.getcwd()
749 return self.dirstate.getcwd()
750
750
751 def pathto(self, f, cwd=None):
751 def pathto(self, f, cwd=None):
752 return self.dirstate.pathto(f, cwd)
752 return self.dirstate.pathto(f, cwd)
753
753
754 def wfile(self, f, mode='r'):
754 def wfile(self, f, mode='r'):
755 return self.wopener(f, mode)
755 return self.wopener(f, mode)
756
756
757 def _link(self, f):
757 def _link(self, f):
758 return self.wvfs.islink(f)
758 return self.wvfs.islink(f)
759
759
760 def _loadfilter(self, filter):
760 def _loadfilter(self, filter):
761 if filter not in self.filterpats:
761 if filter not in self.filterpats:
762 l = []
762 l = []
763 for pat, cmd in self.ui.configitems(filter):
763 for pat, cmd in self.ui.configitems(filter):
764 if cmd == '!':
764 if cmd == '!':
765 continue
765 continue
766 mf = matchmod.match(self.root, '', [pat])
766 mf = matchmod.match(self.root, '', [pat])
767 fn = None
767 fn = None
768 params = cmd
768 params = cmd
769 for name, filterfn in self._datafilters.iteritems():
769 for name, filterfn in self._datafilters.iteritems():
770 if cmd.startswith(name):
770 if cmd.startswith(name):
771 fn = filterfn
771 fn = filterfn
772 params = cmd[len(name):].lstrip()
772 params = cmd[len(name):].lstrip()
773 break
773 break
774 if not fn:
774 if not fn:
775 fn = lambda s, c, **kwargs: util.filter(s, c)
775 fn = lambda s, c, **kwargs: util.filter(s, c)
776 # Wrap old filters not supporting keyword arguments
776 # Wrap old filters not supporting keyword arguments
777 if not inspect.getargspec(fn)[2]:
777 if not inspect.getargspec(fn)[2]:
778 oldfn = fn
778 oldfn = fn
779 fn = lambda s, c, **kwargs: oldfn(s, c)
779 fn = lambda s, c, **kwargs: oldfn(s, c)
780 l.append((mf, fn, params))
780 l.append((mf, fn, params))
781 self.filterpats[filter] = l
781 self.filterpats[filter] = l
782 return self.filterpats[filter]
782 return self.filterpats[filter]
783
783
784 def _filter(self, filterpats, filename, data):
784 def _filter(self, filterpats, filename, data):
785 for mf, fn, cmd in filterpats:
785 for mf, fn, cmd in filterpats:
786 if mf(filename):
786 if mf(filename):
787 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
787 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
788 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
788 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
789 break
789 break
790
790
791 return data
791 return data
792
792
793 @unfilteredpropertycache
793 @unfilteredpropertycache
794 def _encodefilterpats(self):
794 def _encodefilterpats(self):
795 return self._loadfilter('encode')
795 return self._loadfilter('encode')
796
796
797 @unfilteredpropertycache
797 @unfilteredpropertycache
798 def _decodefilterpats(self):
798 def _decodefilterpats(self):
799 return self._loadfilter('decode')
799 return self._loadfilter('decode')
800
800
801 def adddatafilter(self, name, filter):
801 def adddatafilter(self, name, filter):
802 self._datafilters[name] = filter
802 self._datafilters[name] = filter
803
803
804 def wread(self, filename):
804 def wread(self, filename):
805 if self._link(filename):
805 if self._link(filename):
806 data = self.wvfs.readlink(filename)
806 data = self.wvfs.readlink(filename)
807 else:
807 else:
808 data = self.wopener.read(filename)
808 data = self.wopener.read(filename)
809 return self._filter(self._encodefilterpats, filename, data)
809 return self._filter(self._encodefilterpats, filename, data)
810
810
811 def wwrite(self, filename, data, flags):
811 def wwrite(self, filename, data, flags):
812 data = self._filter(self._decodefilterpats, filename, data)
812 data = self._filter(self._decodefilterpats, filename, data)
813 if 'l' in flags:
813 if 'l' in flags:
814 self.wopener.symlink(data, filename)
814 self.wopener.symlink(data, filename)
815 else:
815 else:
816 self.wopener.write(filename, data)
816 self.wopener.write(filename, data)
817 if 'x' in flags:
817 if 'x' in flags:
818 self.wvfs.setflags(filename, False, True)
818 self.wvfs.setflags(filename, False, True)
819
819
820 def wwritedata(self, filename, data):
820 def wwritedata(self, filename, data):
821 return self._filter(self._decodefilterpats, filename, data)
821 return self._filter(self._decodefilterpats, filename, data)
822
822
823 def transaction(self, desc, report=None):
823 def transaction(self, desc, report=None):
824 tr = self._transref and self._transref() or None
824 tr = self._transref and self._transref() or None
825 if tr and tr.running():
825 if tr and tr.running():
826 return tr.nest()
826 return tr.nest()
827
827
828 # abort here if the journal already exists
828 # abort here if the journal already exists
829 if self.svfs.exists("journal"):
829 if self.svfs.exists("journal"):
830 raise error.RepoError(
830 raise error.RepoError(
831 _("abandoned transaction found - run hg recover"))
831 _("abandoned transaction found - run hg recover"))
832
832
833 self._writejournal(desc)
833 self._writejournal(desc)
834 renames = [(vfs, x, undoname(x)) for vfs, x in self._journalfiles()]
834 renames = [(vfs, x, undoname(x)) for vfs, x in self._journalfiles()]
835 rp = report and report or self.ui.warn
835 rp = report and report or self.ui.warn
836 tr = transaction.transaction(rp, self.sopener,
836 tr = transaction.transaction(rp, self.sopener,
837 "journal",
837 "journal",
838 aftertrans(renames),
838 aftertrans(renames),
839 self.store.createmode)
839 self.store.createmode)
840 self._transref = weakref.ref(tr)
840 self._transref = weakref.ref(tr)
841 return tr
841 return tr
842
842
843 def _journalfiles(self):
843 def _journalfiles(self):
844 return ((self.svfs, 'journal'),
844 return ((self.svfs, 'journal'),
845 (self.vfs, 'journal.dirstate'),
845 (self.vfs, 'journal.dirstate'),
846 (self.vfs, 'journal.branch'),
846 (self.vfs, 'journal.branch'),
847 (self.vfs, 'journal.desc'),
847 (self.vfs, 'journal.desc'),
848 (self.vfs, 'journal.bookmarks'),
848 (self.vfs, 'journal.bookmarks'),
849 (self.svfs, 'journal.phaseroots'))
849 (self.svfs, 'journal.phaseroots'))
850
850
851 def undofiles(self):
851 def undofiles(self):
852 return [vfs.join(undoname(x)) for vfs, x in self._journalfiles()]
852 return [vfs.join(undoname(x)) for vfs, x in self._journalfiles()]
853
853
854 def _writejournal(self, desc):
854 def _writejournal(self, desc):
855 self.opener.write("journal.dirstate",
855 self.opener.write("journal.dirstate",
856 self.opener.tryread("dirstate"))
856 self.opener.tryread("dirstate"))
857 self.opener.write("journal.branch",
857 self.opener.write("journal.branch",
858 encoding.fromlocal(self.dirstate.branch()))
858 encoding.fromlocal(self.dirstate.branch()))
859 self.opener.write("journal.desc",
859 self.opener.write("journal.desc",
860 "%d\n%s\n" % (len(self), desc))
860 "%d\n%s\n" % (len(self), desc))
861 self.opener.write("journal.bookmarks",
861 self.opener.write("journal.bookmarks",
862 self.opener.tryread("bookmarks"))
862 self.opener.tryread("bookmarks"))
863 self.sopener.write("journal.phaseroots",
863 self.sopener.write("journal.phaseroots",
864 self.sopener.tryread("phaseroots"))
864 self.sopener.tryread("phaseroots"))
865
865
866 def recover(self):
866 def recover(self):
867 lock = self.lock()
867 lock = self.lock()
868 try:
868 try:
869 if self.svfs.exists("journal"):
869 if self.svfs.exists("journal"):
870 self.ui.status(_("rolling back interrupted transaction\n"))
870 self.ui.status(_("rolling back interrupted transaction\n"))
871 transaction.rollback(self.sopener, "journal",
871 transaction.rollback(self.sopener, "journal",
872 self.ui.warn)
872 self.ui.warn)
873 self.invalidate()
873 self.invalidate()
874 return True
874 return True
875 else:
875 else:
876 self.ui.warn(_("no interrupted transaction available\n"))
876 self.ui.warn(_("no interrupted transaction available\n"))
877 return False
877 return False
878 finally:
878 finally:
879 lock.release()
879 lock.release()
880
880
881 def rollback(self, dryrun=False, force=False):
881 def rollback(self, dryrun=False, force=False):
882 wlock = lock = None
882 wlock = lock = None
883 try:
883 try:
884 wlock = self.wlock()
884 wlock = self.wlock()
885 lock = self.lock()
885 lock = self.lock()
886 if self.svfs.exists("undo"):
886 if self.svfs.exists("undo"):
887 return self._rollback(dryrun, force)
887 return self._rollback(dryrun, force)
888 else:
888 else:
889 self.ui.warn(_("no rollback information available\n"))
889 self.ui.warn(_("no rollback information available\n"))
890 return 1
890 return 1
891 finally:
891 finally:
892 release(lock, wlock)
892 release(lock, wlock)
893
893
894 @unfilteredmethod # Until we get smarter cache management
894 @unfilteredmethod # Until we get smarter cache management
895 def _rollback(self, dryrun, force):
895 def _rollback(self, dryrun, force):
896 ui = self.ui
896 ui = self.ui
897 try:
897 try:
898 args = self.opener.read('undo.desc').splitlines()
898 args = self.opener.read('undo.desc').splitlines()
899 (oldlen, desc, detail) = (int(args[0]), args[1], None)
899 (oldlen, desc, detail) = (int(args[0]), args[1], None)
900 if len(args) >= 3:
900 if len(args) >= 3:
901 detail = args[2]
901 detail = args[2]
902 oldtip = oldlen - 1
902 oldtip = oldlen - 1
903
903
904 if detail and ui.verbose:
904 if detail and ui.verbose:
905 msg = (_('repository tip rolled back to revision %s'
905 msg = (_('repository tip rolled back to revision %s'
906 ' (undo %s: %s)\n')
906 ' (undo %s: %s)\n')
907 % (oldtip, desc, detail))
907 % (oldtip, desc, detail))
908 else:
908 else:
909 msg = (_('repository tip rolled back to revision %s'
909 msg = (_('repository tip rolled back to revision %s'
910 ' (undo %s)\n')
910 ' (undo %s)\n')
911 % (oldtip, desc))
911 % (oldtip, desc))
912 except IOError:
912 except IOError:
913 msg = _('rolling back unknown transaction\n')
913 msg = _('rolling back unknown transaction\n')
914 desc = None
914 desc = None
915
915
916 if not force and self['.'] != self['tip'] and desc == 'commit':
916 if not force and self['.'] != self['tip'] and desc == 'commit':
917 raise util.Abort(
917 raise util.Abort(
918 _('rollback of last commit while not checked out '
918 _('rollback of last commit while not checked out '
919 'may lose data'), hint=_('use -f to force'))
919 'may lose data'), hint=_('use -f to force'))
920
920
921 ui.status(msg)
921 ui.status(msg)
922 if dryrun:
922 if dryrun:
923 return 0
923 return 0
924
924
925 parents = self.dirstate.parents()
925 parents = self.dirstate.parents()
926 self.destroying()
926 self.destroying()
927 transaction.rollback(self.sopener, 'undo', ui.warn)
927 transaction.rollback(self.sopener, 'undo', ui.warn)
928 if self.vfs.exists('undo.bookmarks'):
928 if self.vfs.exists('undo.bookmarks'):
929 self.vfs.rename('undo.bookmarks', 'bookmarks')
929 self.vfs.rename('undo.bookmarks', 'bookmarks')
930 if self.svfs.exists('undo.phaseroots'):
930 if self.svfs.exists('undo.phaseroots'):
931 self.svfs.rename('undo.phaseroots', 'phaseroots')
931 self.svfs.rename('undo.phaseroots', 'phaseroots')
932 self.invalidate()
932 self.invalidate()
933
933
934 parentgone = (parents[0] not in self.changelog.nodemap or
934 parentgone = (parents[0] not in self.changelog.nodemap or
935 parents[1] not in self.changelog.nodemap)
935 parents[1] not in self.changelog.nodemap)
936 if parentgone:
936 if parentgone:
937 self.vfs.rename('undo.dirstate', 'dirstate')
937 self.vfs.rename('undo.dirstate', 'dirstate')
938 try:
938 try:
939 branch = self.opener.read('undo.branch')
939 branch = self.opener.read('undo.branch')
940 self.dirstate.setbranch(encoding.tolocal(branch))
940 self.dirstate.setbranch(encoding.tolocal(branch))
941 except IOError:
941 except IOError:
942 ui.warn(_('named branch could not be reset: '
942 ui.warn(_('named branch could not be reset: '
943 'current branch is still \'%s\'\n')
943 'current branch is still \'%s\'\n')
944 % self.dirstate.branch())
944 % self.dirstate.branch())
945
945
946 self.dirstate.invalidate()
946 self.dirstate.invalidate()
947 parents = tuple([p.rev() for p in self.parents()])
947 parents = tuple([p.rev() for p in self.parents()])
948 if len(parents) > 1:
948 if len(parents) > 1:
949 ui.status(_('working directory now based on '
949 ui.status(_('working directory now based on '
950 'revisions %d and %d\n') % parents)
950 'revisions %d and %d\n') % parents)
951 else:
951 else:
952 ui.status(_('working directory now based on '
952 ui.status(_('working directory now based on '
953 'revision %d\n') % parents)
953 'revision %d\n') % parents)
954 # TODO: if we know which new heads may result from this rollback, pass
954 # TODO: if we know which new heads may result from this rollback, pass
955 # them to destroy(), which will prevent the branchhead cache from being
955 # them to destroy(), which will prevent the branchhead cache from being
956 # invalidated.
956 # invalidated.
957 self.destroyed()
957 self.destroyed()
958 return 0
958 return 0
959
959
960 def invalidatecaches(self):
960 def invalidatecaches(self):
961
961
962 if '_tagscache' in vars(self):
962 if '_tagscache' in vars(self):
963 # can't use delattr on proxy
963 # can't use delattr on proxy
964 del self.__dict__['_tagscache']
964 del self.__dict__['_tagscache']
965
965
966 self.unfiltered()._branchcaches.clear()
966 self.unfiltered()._branchcaches.clear()
967 self.invalidatevolatilesets()
967 self.invalidatevolatilesets()
968
968
969 def invalidatevolatilesets(self):
969 def invalidatevolatilesets(self):
970 self.filteredrevcache.clear()
970 self.filteredrevcache.clear()
971 obsolete.clearobscaches(self)
971 obsolete.clearobscaches(self)
972
972
973 def invalidatedirstate(self):
973 def invalidatedirstate(self):
974 '''Invalidates the dirstate, causing the next call to dirstate
974 '''Invalidates the dirstate, causing the next call to dirstate
975 to check if it was modified since the last time it was read,
975 to check if it was modified since the last time it was read,
976 rereading it if it has.
976 rereading it if it has.
977
977
978 This is different to dirstate.invalidate() that it doesn't always
978 This is different to dirstate.invalidate() that it doesn't always
979 rereads the dirstate. Use dirstate.invalidate() if you want to
979 rereads the dirstate. Use dirstate.invalidate() if you want to
980 explicitly read the dirstate again (i.e. restoring it to a previous
980 explicitly read the dirstate again (i.e. restoring it to a previous
981 known good state).'''
981 known good state).'''
982 if hasunfilteredcache(self, 'dirstate'):
982 if hasunfilteredcache(self, 'dirstate'):
983 for k in self.dirstate._filecache:
983 for k in self.dirstate._filecache:
984 try:
984 try:
985 delattr(self.dirstate, k)
985 delattr(self.dirstate, k)
986 except AttributeError:
986 except AttributeError:
987 pass
987 pass
988 delattr(self.unfiltered(), 'dirstate')
988 delattr(self.unfiltered(), 'dirstate')
989
989
990 def invalidate(self):
990 def invalidate(self):
991 unfiltered = self.unfiltered() # all file caches are stored unfiltered
991 unfiltered = self.unfiltered() # all file caches are stored unfiltered
992 for k in self._filecache:
992 for k in self._filecache:
993 # dirstate is invalidated separately in invalidatedirstate()
993 # dirstate is invalidated separately in invalidatedirstate()
994 if k == 'dirstate':
994 if k == 'dirstate':
995 continue
995 continue
996
996
997 try:
997 try:
998 delattr(unfiltered, k)
998 delattr(unfiltered, k)
999 except AttributeError:
999 except AttributeError:
1000 pass
1000 pass
1001 self.invalidatecaches()
1001 self.invalidatecaches()
1002
1002
1003 def _lock(self, vfs, lockname, wait, releasefn, acquirefn, desc):
1003 def _lock(self, vfs, lockname, wait, releasefn, acquirefn, desc):
1004 try:
1004 try:
1005 l = lockmod.lock(vfs, lockname, 0, releasefn, desc=desc)
1005 l = lockmod.lock(vfs, lockname, 0, releasefn, desc=desc)
1006 except error.LockHeld, inst:
1006 except error.LockHeld, inst:
1007 if not wait:
1007 if not wait:
1008 raise
1008 raise
1009 self.ui.warn(_("waiting for lock on %s held by %r\n") %
1009 self.ui.warn(_("waiting for lock on %s held by %r\n") %
1010 (desc, inst.locker))
1010 (desc, inst.locker))
1011 # default to 600 seconds timeout
1011 # default to 600 seconds timeout
1012 l = lockmod.lock(vfs, lockname,
1012 l = lockmod.lock(vfs, lockname,
1013 int(self.ui.config("ui", "timeout", "600")),
1013 int(self.ui.config("ui", "timeout", "600")),
1014 releasefn, desc=desc)
1014 releasefn, desc=desc)
1015 if acquirefn:
1015 if acquirefn:
1016 acquirefn()
1016 acquirefn()
1017 return l
1017 return l
1018
1018
1019 def _afterlock(self, callback):
1019 def _afterlock(self, callback):
1020 """add a callback to the current repository lock.
1020 """add a callback to the current repository lock.
1021
1021
1022 The callback will be executed on lock release."""
1022 The callback will be executed on lock release."""
1023 l = self._lockref and self._lockref()
1023 l = self._lockref and self._lockref()
1024 if l:
1024 if l:
1025 l.postrelease.append(callback)
1025 l.postrelease.append(callback)
1026 else:
1026 else:
1027 callback()
1027 callback()
1028
1028
1029 def lock(self, wait=True):
1029 def lock(self, wait=True):
1030 '''Lock the repository store (.hg/store) and return a weak reference
1030 '''Lock the repository store (.hg/store) and return a weak reference
1031 to the lock. Use this before modifying the store (e.g. committing or
1031 to the lock. Use this before modifying the store (e.g. committing or
1032 stripping). If you are opening a transaction, get a lock as well.)'''
1032 stripping). If you are opening a transaction, get a lock as well.)'''
1033 l = self._lockref and self._lockref()
1033 l = self._lockref and self._lockref()
1034 if l is not None and l.held:
1034 if l is not None and l.held:
1035 l.lock()
1035 l.lock()
1036 return l
1036 return l
1037
1037
1038 def unlock():
1038 def unlock():
1039 self.store.write()
1039 self.store.write()
1040 if hasunfilteredcache(self, '_phasecache'):
1040 if hasunfilteredcache(self, '_phasecache'):
1041 self._phasecache.write()
1041 self._phasecache.write()
1042 for k, ce in self._filecache.items():
1042 for k, ce in self._filecache.items():
1043 if k == 'dirstate' or k not in self.__dict__:
1043 if k == 'dirstate' or k not in self.__dict__:
1044 continue
1044 continue
1045 ce.refresh()
1045 ce.refresh()
1046
1046
1047 l = self._lock(self.svfs, "lock", wait, unlock,
1047 l = self._lock(self.svfs, "lock", wait, unlock,
1048 self.invalidate, _('repository %s') % self.origroot)
1048 self.invalidate, _('repository %s') % self.origroot)
1049 self._lockref = weakref.ref(l)
1049 self._lockref = weakref.ref(l)
1050 return l
1050 return l
1051
1051
1052 def wlock(self, wait=True):
1052 def wlock(self, wait=True):
1053 '''Lock the non-store parts of the repository (everything under
1053 '''Lock the non-store parts of the repository (everything under
1054 .hg except .hg/store) and return a weak reference to the lock.
1054 .hg except .hg/store) and return a weak reference to the lock.
1055 Use this before modifying files in .hg.'''
1055 Use this before modifying files in .hg.'''
1056 l = self._wlockref and self._wlockref()
1056 l = self._wlockref and self._wlockref()
1057 if l is not None and l.held:
1057 if l is not None and l.held:
1058 l.lock()
1058 l.lock()
1059 return l
1059 return l
1060
1060
1061 def unlock():
1061 def unlock():
1062 self.dirstate.write()
1062 self.dirstate.write()
1063 self._filecache['dirstate'].refresh()
1063 self._filecache['dirstate'].refresh()
1064
1064
1065 l = self._lock(self.vfs, "wlock", wait, unlock,
1065 l = self._lock(self.vfs, "wlock", wait, unlock,
1066 self.invalidatedirstate, _('working directory of %s') %
1066 self.invalidatedirstate, _('working directory of %s') %
1067 self.origroot)
1067 self.origroot)
1068 self._wlockref = weakref.ref(l)
1068 self._wlockref = weakref.ref(l)
1069 return l
1069 return l
1070
1070
1071 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
1071 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
1072 """
1072 """
1073 commit an individual file as part of a larger transaction
1073 commit an individual file as part of a larger transaction
1074 """
1074 """
1075
1075
1076 fname = fctx.path()
1076 fname = fctx.path()
1077 text = fctx.data()
1077 text = fctx.data()
1078 flog = self.file(fname)
1078 flog = self.file(fname)
1079 fparent1 = manifest1.get(fname, nullid)
1079 fparent1 = manifest1.get(fname, nullid)
1080 fparent2 = fparent2o = manifest2.get(fname, nullid)
1080 fparent2 = fparent2o = manifest2.get(fname, nullid)
1081
1081
1082 meta = {}
1082 meta = {}
1083 copy = fctx.renamed()
1083 copy = fctx.renamed()
1084 if copy and copy[0] != fname:
1084 if copy and copy[0] != fname:
1085 # Mark the new revision of this file as a copy of another
1085 # Mark the new revision of this file as a copy of another
1086 # file. This copy data will effectively act as a parent
1086 # file. This copy data will effectively act as a parent
1087 # of this new revision. If this is a merge, the first
1087 # of this new revision. If this is a merge, the first
1088 # parent will be the nullid (meaning "look up the copy data")
1088 # parent will be the nullid (meaning "look up the copy data")
1089 # and the second one will be the other parent. For example:
1089 # and the second one will be the other parent. For example:
1090 #
1090 #
1091 # 0 --- 1 --- 3 rev1 changes file foo
1091 # 0 --- 1 --- 3 rev1 changes file foo
1092 # \ / rev2 renames foo to bar and changes it
1092 # \ / rev2 renames foo to bar and changes it
1093 # \- 2 -/ rev3 should have bar with all changes and
1093 # \- 2 -/ rev3 should have bar with all changes and
1094 # should record that bar descends from
1094 # should record that bar descends from
1095 # bar in rev2 and foo in rev1
1095 # bar in rev2 and foo in rev1
1096 #
1096 #
1097 # this allows this merge to succeed:
1097 # this allows this merge to succeed:
1098 #
1098 #
1099 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
1099 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
1100 # \ / merging rev3 and rev4 should use bar@rev2
1100 # \ / merging rev3 and rev4 should use bar@rev2
1101 # \- 2 --- 4 as the merge base
1101 # \- 2 --- 4 as the merge base
1102 #
1102 #
1103
1103
1104 cfname = copy[0]
1104 cfname = copy[0]
1105 crev = manifest1.get(cfname)
1105 crev = manifest1.get(cfname)
1106 newfparent = fparent2
1106 newfparent = fparent2
1107
1107
1108 if manifest2: # branch merge
1108 if manifest2: # branch merge
1109 if fparent2 == nullid or crev is None: # copied on remote side
1109 if fparent2 == nullid or crev is None: # copied on remote side
1110 if cfname in manifest2:
1110 if cfname in manifest2:
1111 crev = manifest2[cfname]
1111 crev = manifest2[cfname]
1112 newfparent = fparent1
1112 newfparent = fparent1
1113
1113
1114 # find source in nearest ancestor if we've lost track
1114 # find source in nearest ancestor if we've lost track
1115 if not crev:
1115 if not crev:
1116 self.ui.debug(" %s: searching for copy revision for %s\n" %
1116 self.ui.debug(" %s: searching for copy revision for %s\n" %
1117 (fname, cfname))
1117 (fname, cfname))
1118 for ancestor in self[None].ancestors():
1118 for ancestor in self[None].ancestors():
1119 if cfname in ancestor:
1119 if cfname in ancestor:
1120 crev = ancestor[cfname].filenode()
1120 crev = ancestor[cfname].filenode()
1121 break
1121 break
1122
1122
1123 if crev:
1123 if crev:
1124 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
1124 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
1125 meta["copy"] = cfname
1125 meta["copy"] = cfname
1126 meta["copyrev"] = hex(crev)
1126 meta["copyrev"] = hex(crev)
1127 fparent1, fparent2 = nullid, newfparent
1127 fparent1, fparent2 = nullid, newfparent
1128 else:
1128 else:
1129 self.ui.warn(_("warning: can't find ancestor for '%s' "
1129 self.ui.warn(_("warning: can't find ancestor for '%s' "
1130 "copied from '%s'!\n") % (fname, cfname))
1130 "copied from '%s'!\n") % (fname, cfname))
1131
1131
1132 elif fparent2 != nullid:
1132 elif fparent2 != nullid:
1133 # is one parent an ancestor of the other?
1133 # is one parent an ancestor of the other?
1134 fparentancestor = flog.ancestor(fparent1, fparent2)
1134 fparentancestor = flog.ancestor(fparent1, fparent2)
1135 if fparentancestor == fparent1:
1135 if fparentancestor == fparent1:
1136 fparent1, fparent2 = fparent2, nullid
1136 fparent1, fparent2 = fparent2, nullid
1137 elif fparentancestor == fparent2:
1137 elif fparentancestor == fparent2:
1138 fparent2 = nullid
1138 fparent2 = nullid
1139
1139
1140 # is the file changed?
1140 # is the file changed?
1141 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
1141 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
1142 changelist.append(fname)
1142 changelist.append(fname)
1143 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
1143 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
1144
1144
1145 # are just the flags changed during merge?
1145 # are just the flags changed during merge?
1146 if fparent1 != fparent2o and manifest1.flags(fname) != fctx.flags():
1146 if fparent1 != fparent2o and manifest1.flags(fname) != fctx.flags():
1147 changelist.append(fname)
1147 changelist.append(fname)
1148
1148
1149 return fparent1
1149 return fparent1
1150
1150
1151 @unfilteredmethod
1151 @unfilteredmethod
1152 def commit(self, text="", user=None, date=None, match=None, force=False,
1152 def commit(self, text="", user=None, date=None, match=None, force=False,
1153 editor=False, extra={}):
1153 editor=False, extra={}):
1154 """Add a new revision to current repository.
1154 """Add a new revision to current repository.
1155
1155
1156 Revision information is gathered from the working directory,
1156 Revision information is gathered from the working directory,
1157 match can be used to filter the committed files. If editor is
1157 match can be used to filter the committed files. If editor is
1158 supplied, it is called to get a commit message.
1158 supplied, it is called to get a commit message.
1159 """
1159 """
1160
1160
1161 def fail(f, msg):
1161 def fail(f, msg):
1162 raise util.Abort('%s: %s' % (f, msg))
1162 raise util.Abort('%s: %s' % (f, msg))
1163
1163
1164 if not match:
1164 if not match:
1165 match = matchmod.always(self.root, '')
1165 match = matchmod.always(self.root, '')
1166
1166
1167 if not force:
1167 if not force:
1168 vdirs = []
1168 vdirs = []
1169 match.explicitdir = vdirs.append
1169 match.explicitdir = vdirs.append
1170 match.bad = fail
1170 match.bad = fail
1171
1171
1172 wlock = self.wlock()
1172 wlock = self.wlock()
1173 try:
1173 try:
1174 wctx = self[None]
1174 wctx = self[None]
1175 merge = len(wctx.parents()) > 1
1175 merge = len(wctx.parents()) > 1
1176
1176
1177 if (not force and merge and match and
1177 if (not force and merge and match and
1178 (match.files() or match.anypats())):
1178 (match.files() or match.anypats())):
1179 raise util.Abort(_('cannot partially commit a merge '
1179 raise util.Abort(_('cannot partially commit a merge '
1180 '(do not specify files or patterns)'))
1180 '(do not specify files or patterns)'))
1181
1181
1182 changes = self.status(match=match, clean=force)
1182 changes = self.status(match=match, clean=force)
1183 if force:
1183 if force:
1184 changes[0].extend(changes[6]) # mq may commit unchanged files
1184 changes[0].extend(changes[6]) # mq may commit unchanged files
1185
1185
1186 # check subrepos
1186 # check subrepos
1187 subs = []
1187 subs = []
1188 commitsubs = set()
1188 commitsubs = set()
1189 newstate = wctx.substate.copy()
1189 newstate = wctx.substate.copy()
1190 # only manage subrepos and .hgsubstate if .hgsub is present
1190 # only manage subrepos and .hgsubstate if .hgsub is present
1191 if '.hgsub' in wctx:
1191 if '.hgsub' in wctx:
1192 # we'll decide whether to track this ourselves, thanks
1192 # we'll decide whether to track this ourselves, thanks
1193 if '.hgsubstate' in changes[0]:
1193 if '.hgsubstate' in changes[0]:
1194 changes[0].remove('.hgsubstate')
1194 changes[0].remove('.hgsubstate')
1195 if '.hgsubstate' in changes[2]:
1195 if '.hgsubstate' in changes[2]:
1196 changes[2].remove('.hgsubstate')
1196 changes[2].remove('.hgsubstate')
1197
1197
1198 # compare current state to last committed state
1198 # compare current state to last committed state
1199 # build new substate based on last committed state
1199 # build new substate based on last committed state
1200 oldstate = wctx.p1().substate
1200 oldstate = wctx.p1().substate
1201 for s in sorted(newstate.keys()):
1201 for s in sorted(newstate.keys()):
1202 if not match(s):
1202 if not match(s):
1203 # ignore working copy, use old state if present
1203 # ignore working copy, use old state if present
1204 if s in oldstate:
1204 if s in oldstate:
1205 newstate[s] = oldstate[s]
1205 newstate[s] = oldstate[s]
1206 continue
1206 continue
1207 if not force:
1207 if not force:
1208 raise util.Abort(
1208 raise util.Abort(
1209 _("commit with new subrepo %s excluded") % s)
1209 _("commit with new subrepo %s excluded") % s)
1210 if wctx.sub(s).dirty(True):
1210 if wctx.sub(s).dirty(True):
1211 if not self.ui.configbool('ui', 'commitsubrepos'):
1211 if not self.ui.configbool('ui', 'commitsubrepos'):
1212 raise util.Abort(
1212 raise util.Abort(
1213 _("uncommitted changes in subrepo %s") % s,
1213 _("uncommitted changes in subrepo %s") % s,
1214 hint=_("use --subrepos for recursive commit"))
1214 hint=_("use --subrepos for recursive commit"))
1215 subs.append(s)
1215 subs.append(s)
1216 commitsubs.add(s)
1216 commitsubs.add(s)
1217 else:
1217 else:
1218 bs = wctx.sub(s).basestate()
1218 bs = wctx.sub(s).basestate()
1219 newstate[s] = (newstate[s][0], bs, newstate[s][2])
1219 newstate[s] = (newstate[s][0], bs, newstate[s][2])
1220 if oldstate.get(s, (None, None, None))[1] != bs:
1220 if oldstate.get(s, (None, None, None))[1] != bs:
1221 subs.append(s)
1221 subs.append(s)
1222
1222
1223 # check for removed subrepos
1223 # check for removed subrepos
1224 for p in wctx.parents():
1224 for p in wctx.parents():
1225 r = [s for s in p.substate if s not in newstate]
1225 r = [s for s in p.substate if s not in newstate]
1226 subs += [s for s in r if match(s)]
1226 subs += [s for s in r if match(s)]
1227 if subs:
1227 if subs:
1228 if (not match('.hgsub') and
1228 if (not match('.hgsub') and
1229 '.hgsub' in (wctx.modified() + wctx.added())):
1229 '.hgsub' in (wctx.modified() + wctx.added())):
1230 raise util.Abort(
1230 raise util.Abort(
1231 _("can't commit subrepos without .hgsub"))
1231 _("can't commit subrepos without .hgsub"))
1232 changes[0].insert(0, '.hgsubstate')
1232 changes[0].insert(0, '.hgsubstate')
1233
1233
1234 elif '.hgsub' in changes[2]:
1234 elif '.hgsub' in changes[2]:
1235 # clean up .hgsubstate when .hgsub is removed
1235 # clean up .hgsubstate when .hgsub is removed
1236 if ('.hgsubstate' in wctx and
1236 if ('.hgsubstate' in wctx and
1237 '.hgsubstate' not in changes[0] + changes[1] + changes[2]):
1237 '.hgsubstate' not in changes[0] + changes[1] + changes[2]):
1238 changes[2].insert(0, '.hgsubstate')
1238 changes[2].insert(0, '.hgsubstate')
1239
1239
1240 # make sure all explicit patterns are matched
1240 # make sure all explicit patterns are matched
1241 if not force and match.files():
1241 if not force and match.files():
1242 matched = set(changes[0] + changes[1] + changes[2])
1242 matched = set(changes[0] + changes[1] + changes[2])
1243
1243
1244 for f in match.files():
1244 for f in match.files():
1245 f = self.dirstate.normalize(f)
1245 f = self.dirstate.normalize(f)
1246 if f == '.' or f in matched or f in wctx.substate:
1246 if f == '.' or f in matched or f in wctx.substate:
1247 continue
1247 continue
1248 if f in changes[3]: # missing
1248 if f in changes[3]: # missing
1249 fail(f, _('file not found!'))
1249 fail(f, _('file not found!'))
1250 if f in vdirs: # visited directory
1250 if f in vdirs: # visited directory
1251 d = f + '/'
1251 d = f + '/'
1252 for mf in matched:
1252 for mf in matched:
1253 if mf.startswith(d):
1253 if mf.startswith(d):
1254 break
1254 break
1255 else:
1255 else:
1256 fail(f, _("no match under directory!"))
1256 fail(f, _("no match under directory!"))
1257 elif f not in self.dirstate:
1257 elif f not in self.dirstate:
1258 fail(f, _("file not tracked!"))
1258 fail(f, _("file not tracked!"))
1259
1259
1260 cctx = context.workingctx(self, text, user, date, extra, changes)
1260 cctx = context.workingctx(self, text, user, date, extra, changes)
1261
1261
1262 if (not force and not extra.get("close") and not merge
1262 if (not force and not extra.get("close") and not merge
1263 and not cctx.files()
1263 and not cctx.files()
1264 and wctx.branch() == wctx.p1().branch()):
1264 and wctx.branch() == wctx.p1().branch()):
1265 return None
1265 return None
1266
1266
1267 if merge and cctx.deleted():
1267 if merge and cctx.deleted():
1268 raise util.Abort(_("cannot commit merge with missing files"))
1268 raise util.Abort(_("cannot commit merge with missing files"))
1269
1269
1270 ms = mergemod.mergestate(self)
1270 ms = mergemod.mergestate(self)
1271 for f in changes[0]:
1271 for f in changes[0]:
1272 if f in ms and ms[f] == 'u':
1272 if f in ms and ms[f] == 'u':
1273 raise util.Abort(_("unresolved merge conflicts "
1273 raise util.Abort(_("unresolved merge conflicts "
1274 "(see hg help resolve)"))
1274 "(see hg help resolve)"))
1275
1275
1276 if editor:
1276 if editor:
1277 cctx._text = editor(self, cctx, subs)
1277 cctx._text = editor(self, cctx, subs)
1278 edited = (text != cctx._text)
1278 edited = (text != cctx._text)
1279
1279
1280 # commit subs and write new state
1280 # commit subs and write new state
1281 if subs:
1281 if subs:
1282 for s in sorted(commitsubs):
1282 for s in sorted(commitsubs):
1283 sub = wctx.sub(s)
1283 sub = wctx.sub(s)
1284 self.ui.status(_('committing subrepository %s\n') %
1284 self.ui.status(_('committing subrepository %s\n') %
1285 subrepo.subrelpath(sub))
1285 subrepo.subrelpath(sub))
1286 sr = sub.commit(cctx._text, user, date)
1286 sr = sub.commit(cctx._text, user, date)
1287 newstate[s] = (newstate[s][0], sr)
1287 newstate[s] = (newstate[s][0], sr)
1288 subrepo.writestate(self, newstate)
1288 subrepo.writestate(self, newstate)
1289
1289
1290 # Save commit message in case this transaction gets rolled back
1290 # Save commit message in case this transaction gets rolled back
1291 # (e.g. by a pretxncommit hook). Leave the content alone on
1291 # (e.g. by a pretxncommit hook). Leave the content alone on
1292 # the assumption that the user will use the same editor again.
1292 # the assumption that the user will use the same editor again.
1293 msgfn = self.savecommitmessage(cctx._text)
1293 msgfn = self.savecommitmessage(cctx._text)
1294
1294
1295 p1, p2 = self.dirstate.parents()
1295 p1, p2 = self.dirstate.parents()
1296 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1296 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1297 try:
1297 try:
1298 self.hook("precommit", throw=True, parent1=hookp1,
1298 self.hook("precommit", throw=True, parent1=hookp1,
1299 parent2=hookp2)
1299 parent2=hookp2)
1300 ret = self.commitctx(cctx, True)
1300 ret = self.commitctx(cctx, True)
1301 except: # re-raises
1301 except: # re-raises
1302 if edited:
1302 if edited:
1303 self.ui.write(
1303 self.ui.write(
1304 _('note: commit message saved in %s\n') % msgfn)
1304 _('note: commit message saved in %s\n') % msgfn)
1305 raise
1305 raise
1306
1306
1307 # update bookmarks, dirstate and mergestate
1307 # update bookmarks, dirstate and mergestate
1308 bookmarks.update(self, [p1, p2], ret)
1308 bookmarks.update(self, [p1, p2], ret)
1309 cctx.markcommitted(ret)
1309 cctx.markcommitted(ret)
1310 ms.reset()
1310 ms.reset()
1311 finally:
1311 finally:
1312 wlock.release()
1312 wlock.release()
1313
1313
1314 def commithook(node=hex(ret), parent1=hookp1, parent2=hookp2):
1314 def commithook(node=hex(ret), parent1=hookp1, parent2=hookp2):
1315 self.hook("commit", node=node, parent1=parent1, parent2=parent2)
1315 self.hook("commit", node=node, parent1=parent1, parent2=parent2)
1316 self._afterlock(commithook)
1316 self._afterlock(commithook)
1317 return ret
1317 return ret
1318
1318
1319 @unfilteredmethod
1319 @unfilteredmethod
1320 def commitctx(self, ctx, error=False):
1320 def commitctx(self, ctx, error=False):
1321 """Add a new revision to current repository.
1321 """Add a new revision to current repository.
1322 Revision information is passed via the context argument.
1322 Revision information is passed via the context argument.
1323 """
1323 """
1324
1324
1325 tr = lock = None
1325 tr = lock = None
1326 removed = list(ctx.removed())
1326 removed = list(ctx.removed())
1327 p1, p2 = ctx.p1(), ctx.p2()
1327 p1, p2 = ctx.p1(), ctx.p2()
1328 user = ctx.user()
1328 user = ctx.user()
1329
1329
1330 lock = self.lock()
1330 lock = self.lock()
1331 try:
1331 try:
1332 tr = self.transaction("commit")
1332 tr = self.transaction("commit")
1333 trp = weakref.proxy(tr)
1333 trp = weakref.proxy(tr)
1334
1334
1335 if ctx.files():
1335 if ctx.files():
1336 m1 = p1.manifest().copy()
1336 m1 = p1.manifest().copy()
1337 m2 = p2.manifest()
1337 m2 = p2.manifest()
1338
1338
1339 # check in files
1339 # check in files
1340 new = {}
1340 new = {}
1341 changed = []
1341 changed = []
1342 linkrev = len(self)
1342 linkrev = len(self)
1343 for f in sorted(ctx.modified() + ctx.added()):
1343 for f in sorted(ctx.modified() + ctx.added()):
1344 self.ui.note(f + "\n")
1344 self.ui.note(f + "\n")
1345 try:
1345 try:
1346 fctx = ctx[f]
1346 fctx = ctx[f]
1347 new[f] = self._filecommit(fctx, m1, m2, linkrev, trp,
1347 new[f] = self._filecommit(fctx, m1, m2, linkrev, trp,
1348 changed)
1348 changed)
1349 m1.set(f, fctx.flags())
1349 m1.set(f, fctx.flags())
1350 except OSError, inst:
1350 except OSError, inst:
1351 self.ui.warn(_("trouble committing %s!\n") % f)
1351 self.ui.warn(_("trouble committing %s!\n") % f)
1352 raise
1352 raise
1353 except IOError, inst:
1353 except IOError, inst:
1354 errcode = getattr(inst, 'errno', errno.ENOENT)
1354 errcode = getattr(inst, 'errno', errno.ENOENT)
1355 if error or errcode and errcode != errno.ENOENT:
1355 if error or errcode and errcode != errno.ENOENT:
1356 self.ui.warn(_("trouble committing %s!\n") % f)
1356 self.ui.warn(_("trouble committing %s!\n") % f)
1357 raise
1357 raise
1358 else:
1358 else:
1359 removed.append(f)
1359 removed.append(f)
1360
1360
1361 # update manifest
1361 # update manifest
1362 m1.update(new)
1362 m1.update(new)
1363 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1363 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1364 drop = [f for f in removed if f in m1]
1364 drop = [f for f in removed if f in m1]
1365 for f in drop:
1365 for f in drop:
1366 del m1[f]
1366 del m1[f]
1367 mn = self.manifest.add(m1, trp, linkrev, p1.manifestnode(),
1367 mn = self.manifest.add(m1, trp, linkrev, p1.manifestnode(),
1368 p2.manifestnode(), (new, drop))
1368 p2.manifestnode(), (new, drop))
1369 files = changed + removed
1369 files = changed + removed
1370 else:
1370 else:
1371 mn = p1.manifestnode()
1371 mn = p1.manifestnode()
1372 files = []
1372 files = []
1373
1373
1374 # update changelog
1374 # update changelog
1375 self.changelog.delayupdate()
1375 self.changelog.delayupdate()
1376 n = self.changelog.add(mn, files, ctx.description(),
1376 n = self.changelog.add(mn, files, ctx.description(),
1377 trp, p1.node(), p2.node(),
1377 trp, p1.node(), p2.node(),
1378 user, ctx.date(), ctx.extra().copy())
1378 user, ctx.date(), ctx.extra().copy())
1379 p = lambda: self.changelog.writepending() and self.root or ""
1379 p = lambda: self.changelog.writepending() and self.root or ""
1380 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1380 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1381 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1381 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1382 parent2=xp2, pending=p)
1382 parent2=xp2, pending=p)
1383 self.changelog.finalize(trp)
1383 self.changelog.finalize(trp)
1384 # set the new commit is proper phase
1384 # set the new commit is proper phase
1385 targetphase = phases.newcommitphase(self.ui)
1385 targetphase = subrepo.newcommitphase(self.ui, ctx)
1386 if targetphase:
1386 if targetphase:
1387 # retract boundary do not alter parent changeset.
1387 # retract boundary do not alter parent changeset.
1388 # if a parent have higher the resulting phase will
1388 # if a parent have higher the resulting phase will
1389 # be compliant anyway
1389 # be compliant anyway
1390 #
1390 #
1391 # if minimal phase was 0 we don't need to retract anything
1391 # if minimal phase was 0 we don't need to retract anything
1392 phases.retractboundary(self, targetphase, [n])
1392 phases.retractboundary(self, targetphase, [n])
1393 tr.close()
1393 tr.close()
1394 branchmap.updatecache(self.filtered('served'))
1394 branchmap.updatecache(self.filtered('served'))
1395 return n
1395 return n
1396 finally:
1396 finally:
1397 if tr:
1397 if tr:
1398 tr.release()
1398 tr.release()
1399 lock.release()
1399 lock.release()
1400
1400
1401 @unfilteredmethod
1401 @unfilteredmethod
1402 def destroying(self):
1402 def destroying(self):
1403 '''Inform the repository that nodes are about to be destroyed.
1403 '''Inform the repository that nodes are about to be destroyed.
1404 Intended for use by strip and rollback, so there's a common
1404 Intended for use by strip and rollback, so there's a common
1405 place for anything that has to be done before destroying history.
1405 place for anything that has to be done before destroying history.
1406
1406
1407 This is mostly useful for saving state that is in memory and waiting
1407 This is mostly useful for saving state that is in memory and waiting
1408 to be flushed when the current lock is released. Because a call to
1408 to be flushed when the current lock is released. Because a call to
1409 destroyed is imminent, the repo will be invalidated causing those
1409 destroyed is imminent, the repo will be invalidated causing those
1410 changes to stay in memory (waiting for the next unlock), or vanish
1410 changes to stay in memory (waiting for the next unlock), or vanish
1411 completely.
1411 completely.
1412 '''
1412 '''
1413 # When using the same lock to commit and strip, the phasecache is left
1413 # When using the same lock to commit and strip, the phasecache is left
1414 # dirty after committing. Then when we strip, the repo is invalidated,
1414 # dirty after committing. Then when we strip, the repo is invalidated,
1415 # causing those changes to disappear.
1415 # causing those changes to disappear.
1416 if '_phasecache' in vars(self):
1416 if '_phasecache' in vars(self):
1417 self._phasecache.write()
1417 self._phasecache.write()
1418
1418
1419 @unfilteredmethod
1419 @unfilteredmethod
1420 def destroyed(self):
1420 def destroyed(self):
1421 '''Inform the repository that nodes have been destroyed.
1421 '''Inform the repository that nodes have been destroyed.
1422 Intended for use by strip and rollback, so there's a common
1422 Intended for use by strip and rollback, so there's a common
1423 place for anything that has to be done after destroying history.
1423 place for anything that has to be done after destroying history.
1424 '''
1424 '''
1425 # When one tries to:
1425 # When one tries to:
1426 # 1) destroy nodes thus calling this method (e.g. strip)
1426 # 1) destroy nodes thus calling this method (e.g. strip)
1427 # 2) use phasecache somewhere (e.g. commit)
1427 # 2) use phasecache somewhere (e.g. commit)
1428 #
1428 #
1429 # then 2) will fail because the phasecache contains nodes that were
1429 # then 2) will fail because the phasecache contains nodes that were
1430 # removed. We can either remove phasecache from the filecache,
1430 # removed. We can either remove phasecache from the filecache,
1431 # causing it to reload next time it is accessed, or simply filter
1431 # causing it to reload next time it is accessed, or simply filter
1432 # the removed nodes now and write the updated cache.
1432 # the removed nodes now and write the updated cache.
1433 self._phasecache.filterunknown(self)
1433 self._phasecache.filterunknown(self)
1434 self._phasecache.write()
1434 self._phasecache.write()
1435
1435
1436 # update the 'served' branch cache to help read only server process
1436 # update the 'served' branch cache to help read only server process
1437 # Thanks to branchcache collaboration this is done from the nearest
1437 # Thanks to branchcache collaboration this is done from the nearest
1438 # filtered subset and it is expected to be fast.
1438 # filtered subset and it is expected to be fast.
1439 branchmap.updatecache(self.filtered('served'))
1439 branchmap.updatecache(self.filtered('served'))
1440
1440
1441 # Ensure the persistent tag cache is updated. Doing it now
1441 # Ensure the persistent tag cache is updated. Doing it now
1442 # means that the tag cache only has to worry about destroyed
1442 # means that the tag cache only has to worry about destroyed
1443 # heads immediately after a strip/rollback. That in turn
1443 # heads immediately after a strip/rollback. That in turn
1444 # guarantees that "cachetip == currenttip" (comparing both rev
1444 # guarantees that "cachetip == currenttip" (comparing both rev
1445 # and node) always means no nodes have been added or destroyed.
1445 # and node) always means no nodes have been added or destroyed.
1446
1446
1447 # XXX this is suboptimal when qrefresh'ing: we strip the current
1447 # XXX this is suboptimal when qrefresh'ing: we strip the current
1448 # head, refresh the tag cache, then immediately add a new head.
1448 # head, refresh the tag cache, then immediately add a new head.
1449 # But I think doing it this way is necessary for the "instant
1449 # But I think doing it this way is necessary for the "instant
1450 # tag cache retrieval" case to work.
1450 # tag cache retrieval" case to work.
1451 self.invalidate()
1451 self.invalidate()
1452
1452
1453 def walk(self, match, node=None):
1453 def walk(self, match, node=None):
1454 '''
1454 '''
1455 walk recursively through the directory tree or a given
1455 walk recursively through the directory tree or a given
1456 changeset, finding all files matched by the match
1456 changeset, finding all files matched by the match
1457 function
1457 function
1458 '''
1458 '''
1459 return self[node].walk(match)
1459 return self[node].walk(match)
1460
1460
1461 def status(self, node1='.', node2=None, match=None,
1461 def status(self, node1='.', node2=None, match=None,
1462 ignored=False, clean=False, unknown=False,
1462 ignored=False, clean=False, unknown=False,
1463 listsubrepos=False):
1463 listsubrepos=False):
1464 """return status of files between two nodes or node and working
1464 """return status of files between two nodes or node and working
1465 directory.
1465 directory.
1466
1466
1467 If node1 is None, use the first dirstate parent instead.
1467 If node1 is None, use the first dirstate parent instead.
1468 If node2 is None, compare node1 with working directory.
1468 If node2 is None, compare node1 with working directory.
1469 """
1469 """
1470
1470
1471 def mfmatches(ctx):
1471 def mfmatches(ctx):
1472 mf = ctx.manifest().copy()
1472 mf = ctx.manifest().copy()
1473 if match.always():
1473 if match.always():
1474 return mf
1474 return mf
1475 for fn in mf.keys():
1475 for fn in mf.keys():
1476 if not match(fn):
1476 if not match(fn):
1477 del mf[fn]
1477 del mf[fn]
1478 return mf
1478 return mf
1479
1479
1480 ctx1 = self[node1]
1480 ctx1 = self[node1]
1481 ctx2 = self[node2]
1481 ctx2 = self[node2]
1482
1482
1483 working = ctx2.rev() is None
1483 working = ctx2.rev() is None
1484 parentworking = working and ctx1 == self['.']
1484 parentworking = working and ctx1 == self['.']
1485 match = match or matchmod.always(self.root, self.getcwd())
1485 match = match or matchmod.always(self.root, self.getcwd())
1486 listignored, listclean, listunknown = ignored, clean, unknown
1486 listignored, listclean, listunknown = ignored, clean, unknown
1487
1487
1488 # load earliest manifest first for caching reasons
1488 # load earliest manifest first for caching reasons
1489 if not working and ctx2.rev() < ctx1.rev():
1489 if not working and ctx2.rev() < ctx1.rev():
1490 ctx2.manifest()
1490 ctx2.manifest()
1491
1491
1492 if not parentworking:
1492 if not parentworking:
1493 def bad(f, msg):
1493 def bad(f, msg):
1494 # 'f' may be a directory pattern from 'match.files()',
1494 # 'f' may be a directory pattern from 'match.files()',
1495 # so 'f not in ctx1' is not enough
1495 # so 'f not in ctx1' is not enough
1496 if f not in ctx1 and f not in ctx1.dirs():
1496 if f not in ctx1 and f not in ctx1.dirs():
1497 self.ui.warn('%s: %s\n' % (self.dirstate.pathto(f), msg))
1497 self.ui.warn('%s: %s\n' % (self.dirstate.pathto(f), msg))
1498 match.bad = bad
1498 match.bad = bad
1499
1499
1500 if working: # we need to scan the working dir
1500 if working: # we need to scan the working dir
1501 subrepos = []
1501 subrepos = []
1502 if '.hgsub' in self.dirstate:
1502 if '.hgsub' in self.dirstate:
1503 subrepos = sorted(ctx2.substate)
1503 subrepos = sorted(ctx2.substate)
1504 s = self.dirstate.status(match, subrepos, listignored,
1504 s = self.dirstate.status(match, subrepos, listignored,
1505 listclean, listunknown)
1505 listclean, listunknown)
1506 cmp, modified, added, removed, deleted, unknown, ignored, clean = s
1506 cmp, modified, added, removed, deleted, unknown, ignored, clean = s
1507
1507
1508 # check for any possibly clean files
1508 # check for any possibly clean files
1509 if parentworking and cmp:
1509 if parentworking and cmp:
1510 fixup = []
1510 fixup = []
1511 # do a full compare of any files that might have changed
1511 # do a full compare of any files that might have changed
1512 for f in sorted(cmp):
1512 for f in sorted(cmp):
1513 if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
1513 if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
1514 or ctx1[f].cmp(ctx2[f])):
1514 or ctx1[f].cmp(ctx2[f])):
1515 modified.append(f)
1515 modified.append(f)
1516 else:
1516 else:
1517 fixup.append(f)
1517 fixup.append(f)
1518
1518
1519 # update dirstate for files that are actually clean
1519 # update dirstate for files that are actually clean
1520 if fixup:
1520 if fixup:
1521 if listclean:
1521 if listclean:
1522 clean += fixup
1522 clean += fixup
1523
1523
1524 try:
1524 try:
1525 # updating the dirstate is optional
1525 # updating the dirstate is optional
1526 # so we don't wait on the lock
1526 # so we don't wait on the lock
1527 wlock = self.wlock(False)
1527 wlock = self.wlock(False)
1528 try:
1528 try:
1529 for f in fixup:
1529 for f in fixup:
1530 self.dirstate.normal(f)
1530 self.dirstate.normal(f)
1531 finally:
1531 finally:
1532 wlock.release()
1532 wlock.release()
1533 except error.LockError:
1533 except error.LockError:
1534 pass
1534 pass
1535
1535
1536 if not parentworking:
1536 if not parentworking:
1537 mf1 = mfmatches(ctx1)
1537 mf1 = mfmatches(ctx1)
1538 if working:
1538 if working:
1539 # we are comparing working dir against non-parent
1539 # we are comparing working dir against non-parent
1540 # generate a pseudo-manifest for the working dir
1540 # generate a pseudo-manifest for the working dir
1541 mf2 = mfmatches(self['.'])
1541 mf2 = mfmatches(self['.'])
1542 for f in cmp + modified + added:
1542 for f in cmp + modified + added:
1543 mf2[f] = None
1543 mf2[f] = None
1544 mf2.set(f, ctx2.flags(f))
1544 mf2.set(f, ctx2.flags(f))
1545 for f in removed:
1545 for f in removed:
1546 if f in mf2:
1546 if f in mf2:
1547 del mf2[f]
1547 del mf2[f]
1548 else:
1548 else:
1549 # we are comparing two revisions
1549 # we are comparing two revisions
1550 deleted, unknown, ignored = [], [], []
1550 deleted, unknown, ignored = [], [], []
1551 mf2 = mfmatches(ctx2)
1551 mf2 = mfmatches(ctx2)
1552
1552
1553 modified, added, clean = [], [], []
1553 modified, added, clean = [], [], []
1554 withflags = mf1.withflags() | mf2.withflags()
1554 withflags = mf1.withflags() | mf2.withflags()
1555 for fn, mf2node in mf2.iteritems():
1555 for fn, mf2node in mf2.iteritems():
1556 if fn in mf1:
1556 if fn in mf1:
1557 if (fn not in deleted and
1557 if (fn not in deleted and
1558 ((fn in withflags and mf1.flags(fn) != mf2.flags(fn)) or
1558 ((fn in withflags and mf1.flags(fn) != mf2.flags(fn)) or
1559 (mf1[fn] != mf2node and
1559 (mf1[fn] != mf2node and
1560 (mf2node or ctx1[fn].cmp(ctx2[fn]))))):
1560 (mf2node or ctx1[fn].cmp(ctx2[fn]))))):
1561 modified.append(fn)
1561 modified.append(fn)
1562 elif listclean:
1562 elif listclean:
1563 clean.append(fn)
1563 clean.append(fn)
1564 del mf1[fn]
1564 del mf1[fn]
1565 elif fn not in deleted:
1565 elif fn not in deleted:
1566 added.append(fn)
1566 added.append(fn)
1567 removed = mf1.keys()
1567 removed = mf1.keys()
1568
1568
1569 if working and modified and not self.dirstate._checklink:
1569 if working and modified and not self.dirstate._checklink:
1570 # Symlink placeholders may get non-symlink-like contents
1570 # Symlink placeholders may get non-symlink-like contents
1571 # via user error or dereferencing by NFS or Samba servers,
1571 # via user error or dereferencing by NFS or Samba servers,
1572 # so we filter out any placeholders that don't look like a
1572 # so we filter out any placeholders that don't look like a
1573 # symlink
1573 # symlink
1574 sane = []
1574 sane = []
1575 for f in modified:
1575 for f in modified:
1576 if ctx2.flags(f) == 'l':
1576 if ctx2.flags(f) == 'l':
1577 d = ctx2[f].data()
1577 d = ctx2[f].data()
1578 if d == '' or len(d) >= 1024 or '\n' in d or util.binary(d):
1578 if d == '' or len(d) >= 1024 or '\n' in d or util.binary(d):
1579 self.ui.debug('ignoring suspect symlink placeholder'
1579 self.ui.debug('ignoring suspect symlink placeholder'
1580 ' "%s"\n' % f)
1580 ' "%s"\n' % f)
1581 continue
1581 continue
1582 sane.append(f)
1582 sane.append(f)
1583 modified = sane
1583 modified = sane
1584
1584
1585 r = modified, added, removed, deleted, unknown, ignored, clean
1585 r = modified, added, removed, deleted, unknown, ignored, clean
1586
1586
1587 if listsubrepos:
1587 if listsubrepos:
1588 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
1588 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
1589 if working:
1589 if working:
1590 rev2 = None
1590 rev2 = None
1591 else:
1591 else:
1592 rev2 = ctx2.substate[subpath][1]
1592 rev2 = ctx2.substate[subpath][1]
1593 try:
1593 try:
1594 submatch = matchmod.narrowmatcher(subpath, match)
1594 submatch = matchmod.narrowmatcher(subpath, match)
1595 s = sub.status(rev2, match=submatch, ignored=listignored,
1595 s = sub.status(rev2, match=submatch, ignored=listignored,
1596 clean=listclean, unknown=listunknown,
1596 clean=listclean, unknown=listunknown,
1597 listsubrepos=True)
1597 listsubrepos=True)
1598 for rfiles, sfiles in zip(r, s):
1598 for rfiles, sfiles in zip(r, s):
1599 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
1599 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
1600 except error.LookupError:
1600 except error.LookupError:
1601 self.ui.status(_("skipping missing subrepository: %s\n")
1601 self.ui.status(_("skipping missing subrepository: %s\n")
1602 % subpath)
1602 % subpath)
1603
1603
1604 for l in r:
1604 for l in r:
1605 l.sort()
1605 l.sort()
1606 return r
1606 return r
1607
1607
1608 def heads(self, start=None):
1608 def heads(self, start=None):
1609 heads = self.changelog.heads(start)
1609 heads = self.changelog.heads(start)
1610 # sort the output in rev descending order
1610 # sort the output in rev descending order
1611 return sorted(heads, key=self.changelog.rev, reverse=True)
1611 return sorted(heads, key=self.changelog.rev, reverse=True)
1612
1612
1613 def branchheads(self, branch=None, start=None, closed=False):
1613 def branchheads(self, branch=None, start=None, closed=False):
1614 '''return a (possibly filtered) list of heads for the given branch
1614 '''return a (possibly filtered) list of heads for the given branch
1615
1615
1616 Heads are returned in topological order, from newest to oldest.
1616 Heads are returned in topological order, from newest to oldest.
1617 If branch is None, use the dirstate branch.
1617 If branch is None, use the dirstate branch.
1618 If start is not None, return only heads reachable from start.
1618 If start is not None, return only heads reachable from start.
1619 If closed is True, return heads that are marked as closed as well.
1619 If closed is True, return heads that are marked as closed as well.
1620 '''
1620 '''
1621 if branch is None:
1621 if branch is None:
1622 branch = self[None].branch()
1622 branch = self[None].branch()
1623 branches = self.branchmap()
1623 branches = self.branchmap()
1624 if branch not in branches:
1624 if branch not in branches:
1625 return []
1625 return []
1626 # the cache returns heads ordered lowest to highest
1626 # the cache returns heads ordered lowest to highest
1627 bheads = list(reversed(branches[branch]))
1627 bheads = list(reversed(branches[branch]))
1628 if start is not None:
1628 if start is not None:
1629 # filter out the heads that cannot be reached from startrev
1629 # filter out the heads that cannot be reached from startrev
1630 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1630 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1631 bheads = [h for h in bheads if h in fbheads]
1631 bheads = [h for h in bheads if h in fbheads]
1632 if not closed:
1632 if not closed:
1633 bheads = [h for h in bheads if not self[h].closesbranch()]
1633 bheads = [h for h in bheads if not self[h].closesbranch()]
1634 return bheads
1634 return bheads
1635
1635
1636 def branches(self, nodes):
1636 def branches(self, nodes):
1637 if not nodes:
1637 if not nodes:
1638 nodes = [self.changelog.tip()]
1638 nodes = [self.changelog.tip()]
1639 b = []
1639 b = []
1640 for n in nodes:
1640 for n in nodes:
1641 t = n
1641 t = n
1642 while True:
1642 while True:
1643 p = self.changelog.parents(n)
1643 p = self.changelog.parents(n)
1644 if p[1] != nullid or p[0] == nullid:
1644 if p[1] != nullid or p[0] == nullid:
1645 b.append((t, n, p[0], p[1]))
1645 b.append((t, n, p[0], p[1]))
1646 break
1646 break
1647 n = p[0]
1647 n = p[0]
1648 return b
1648 return b
1649
1649
1650 def between(self, pairs):
1650 def between(self, pairs):
1651 r = []
1651 r = []
1652
1652
1653 for top, bottom in pairs:
1653 for top, bottom in pairs:
1654 n, l, i = top, [], 0
1654 n, l, i = top, [], 0
1655 f = 1
1655 f = 1
1656
1656
1657 while n != bottom and n != nullid:
1657 while n != bottom and n != nullid:
1658 p = self.changelog.parents(n)[0]
1658 p = self.changelog.parents(n)[0]
1659 if i == f:
1659 if i == f:
1660 l.append(n)
1660 l.append(n)
1661 f = f * 2
1661 f = f * 2
1662 n = p
1662 n = p
1663 i += 1
1663 i += 1
1664
1664
1665 r.append(l)
1665 r.append(l)
1666
1666
1667 return r
1667 return r
1668
1668
1669 def pull(self, remote, heads=None, force=False):
1669 def pull(self, remote, heads=None, force=False):
1670 if remote.local():
1670 if remote.local():
1671 missing = set(remote.requirements) - self.supported
1671 missing = set(remote.requirements) - self.supported
1672 if missing:
1672 if missing:
1673 msg = _("required features are not"
1673 msg = _("required features are not"
1674 " supported in the destination:"
1674 " supported in the destination:"
1675 " %s") % (', '.join(sorted(missing)))
1675 " %s") % (', '.join(sorted(missing)))
1676 raise util.Abort(msg)
1676 raise util.Abort(msg)
1677
1677
1678 # don't open transaction for nothing or you break future useful
1678 # don't open transaction for nothing or you break future useful
1679 # rollback call
1679 # rollback call
1680 tr = None
1680 tr = None
1681 trname = 'pull\n' + util.hidepassword(remote.url())
1681 trname = 'pull\n' + util.hidepassword(remote.url())
1682 lock = self.lock()
1682 lock = self.lock()
1683 try:
1683 try:
1684 tmp = discovery.findcommonincoming(self, remote, heads=heads,
1684 tmp = discovery.findcommonincoming(self, remote, heads=heads,
1685 force=force)
1685 force=force)
1686 common, fetch, rheads = tmp
1686 common, fetch, rheads = tmp
1687 if not fetch:
1687 if not fetch:
1688 self.ui.status(_("no changes found\n"))
1688 self.ui.status(_("no changes found\n"))
1689 added = []
1689 added = []
1690 result = 0
1690 result = 0
1691 else:
1691 else:
1692 tr = self.transaction(trname)
1692 tr = self.transaction(trname)
1693 if heads is None and list(common) == [nullid]:
1693 if heads is None and list(common) == [nullid]:
1694 self.ui.status(_("requesting all changes\n"))
1694 self.ui.status(_("requesting all changes\n"))
1695 elif heads is None and remote.capable('changegroupsubset'):
1695 elif heads is None and remote.capable('changegroupsubset'):
1696 # issue1320, avoid a race if remote changed after discovery
1696 # issue1320, avoid a race if remote changed after discovery
1697 heads = rheads
1697 heads = rheads
1698
1698
1699 if remote.capable('getbundle'):
1699 if remote.capable('getbundle'):
1700 # TODO: get bundlecaps from remote
1700 # TODO: get bundlecaps from remote
1701 cg = remote.getbundle('pull', common=common,
1701 cg = remote.getbundle('pull', common=common,
1702 heads=heads or rheads)
1702 heads=heads or rheads)
1703 elif heads is None:
1703 elif heads is None:
1704 cg = remote.changegroup(fetch, 'pull')
1704 cg = remote.changegroup(fetch, 'pull')
1705 elif not remote.capable('changegroupsubset'):
1705 elif not remote.capable('changegroupsubset'):
1706 raise util.Abort(_("partial pull cannot be done because "
1706 raise util.Abort(_("partial pull cannot be done because "
1707 "other repository doesn't support "
1707 "other repository doesn't support "
1708 "changegroupsubset."))
1708 "changegroupsubset."))
1709 else:
1709 else:
1710 cg = remote.changegroupsubset(fetch, heads, 'pull')
1710 cg = remote.changegroupsubset(fetch, heads, 'pull')
1711 # we use unfiltered changelog here because hidden revision must
1711 # we use unfiltered changelog here because hidden revision must
1712 # be taken in account for phase synchronization. They may
1712 # be taken in account for phase synchronization. They may
1713 # becomes public and becomes visible again.
1713 # becomes public and becomes visible again.
1714 cl = self.unfiltered().changelog
1714 cl = self.unfiltered().changelog
1715 clstart = len(cl)
1715 clstart = len(cl)
1716 result = self.addchangegroup(cg, 'pull', remote.url())
1716 result = self.addchangegroup(cg, 'pull', remote.url())
1717 clend = len(cl)
1717 clend = len(cl)
1718 added = [cl.node(r) for r in xrange(clstart, clend)]
1718 added = [cl.node(r) for r in xrange(clstart, clend)]
1719
1719
1720 # compute target subset
1720 # compute target subset
1721 if heads is None:
1721 if heads is None:
1722 # We pulled every thing possible
1722 # We pulled every thing possible
1723 # sync on everything common
1723 # sync on everything common
1724 subset = common + added
1724 subset = common + added
1725 else:
1725 else:
1726 # We pulled a specific subset
1726 # We pulled a specific subset
1727 # sync on this subset
1727 # sync on this subset
1728 subset = heads
1728 subset = heads
1729
1729
1730 # Get remote phases data from remote
1730 # Get remote phases data from remote
1731 remotephases = remote.listkeys('phases')
1731 remotephases = remote.listkeys('phases')
1732 publishing = bool(remotephases.get('publishing', False))
1732 publishing = bool(remotephases.get('publishing', False))
1733 if remotephases and not publishing:
1733 if remotephases and not publishing:
1734 # remote is new and unpublishing
1734 # remote is new and unpublishing
1735 pheads, _dr = phases.analyzeremotephases(self, subset,
1735 pheads, _dr = phases.analyzeremotephases(self, subset,
1736 remotephases)
1736 remotephases)
1737 phases.advanceboundary(self, phases.public, pheads)
1737 phases.advanceboundary(self, phases.public, pheads)
1738 phases.advanceboundary(self, phases.draft, subset)
1738 phases.advanceboundary(self, phases.draft, subset)
1739 else:
1739 else:
1740 # Remote is old or publishing all common changesets
1740 # Remote is old or publishing all common changesets
1741 # should be seen as public
1741 # should be seen as public
1742 phases.advanceboundary(self, phases.public, subset)
1742 phases.advanceboundary(self, phases.public, subset)
1743
1743
1744 def gettransaction():
1744 def gettransaction():
1745 if tr is None:
1745 if tr is None:
1746 return self.transaction(trname)
1746 return self.transaction(trname)
1747 return tr
1747 return tr
1748
1748
1749 obstr = obsolete.syncpull(self, remote, gettransaction)
1749 obstr = obsolete.syncpull(self, remote, gettransaction)
1750 if obstr is not None:
1750 if obstr is not None:
1751 tr = obstr
1751 tr = obstr
1752
1752
1753 if tr is not None:
1753 if tr is not None:
1754 tr.close()
1754 tr.close()
1755 finally:
1755 finally:
1756 if tr is not None:
1756 if tr is not None:
1757 tr.release()
1757 tr.release()
1758 lock.release()
1758 lock.release()
1759
1759
1760 return result
1760 return result
1761
1761
1762 def checkpush(self, force, revs):
1762 def checkpush(self, force, revs):
1763 """Extensions can override this function if additional checks have
1763 """Extensions can override this function if additional checks have
1764 to be performed before pushing, or call it if they override push
1764 to be performed before pushing, or call it if they override push
1765 command.
1765 command.
1766 """
1766 """
1767 pass
1767 pass
1768
1768
1769 def push(self, remote, force=False, revs=None, newbranch=False):
1769 def push(self, remote, force=False, revs=None, newbranch=False):
1770 '''Push outgoing changesets (limited by revs) from the current
1770 '''Push outgoing changesets (limited by revs) from the current
1771 repository to remote. Return an integer:
1771 repository to remote. Return an integer:
1772 - None means nothing to push
1772 - None means nothing to push
1773 - 0 means HTTP error
1773 - 0 means HTTP error
1774 - 1 means we pushed and remote head count is unchanged *or*
1774 - 1 means we pushed and remote head count is unchanged *or*
1775 we have outgoing changesets but refused to push
1775 we have outgoing changesets but refused to push
1776 - other values as described by addchangegroup()
1776 - other values as described by addchangegroup()
1777 '''
1777 '''
1778 if remote.local():
1778 if remote.local():
1779 missing = set(self.requirements) - remote.local().supported
1779 missing = set(self.requirements) - remote.local().supported
1780 if missing:
1780 if missing:
1781 msg = _("required features are not"
1781 msg = _("required features are not"
1782 " supported in the destination:"
1782 " supported in the destination:"
1783 " %s") % (', '.join(sorted(missing)))
1783 " %s") % (', '.join(sorted(missing)))
1784 raise util.Abort(msg)
1784 raise util.Abort(msg)
1785
1785
1786 # there are two ways to push to remote repo:
1786 # there are two ways to push to remote repo:
1787 #
1787 #
1788 # addchangegroup assumes local user can lock remote
1788 # addchangegroup assumes local user can lock remote
1789 # repo (local filesystem, old ssh servers).
1789 # repo (local filesystem, old ssh servers).
1790 #
1790 #
1791 # unbundle assumes local user cannot lock remote repo (new ssh
1791 # unbundle assumes local user cannot lock remote repo (new ssh
1792 # servers, http servers).
1792 # servers, http servers).
1793
1793
1794 if not remote.canpush():
1794 if not remote.canpush():
1795 raise util.Abort(_("destination does not support push"))
1795 raise util.Abort(_("destination does not support push"))
1796 unfi = self.unfiltered()
1796 unfi = self.unfiltered()
1797 def localphasemove(nodes, phase=phases.public):
1797 def localphasemove(nodes, phase=phases.public):
1798 """move <nodes> to <phase> in the local source repo"""
1798 """move <nodes> to <phase> in the local source repo"""
1799 if locallock is not None:
1799 if locallock is not None:
1800 phases.advanceboundary(self, phase, nodes)
1800 phases.advanceboundary(self, phase, nodes)
1801 else:
1801 else:
1802 # repo is not locked, do not change any phases!
1802 # repo is not locked, do not change any phases!
1803 # Informs the user that phases should have been moved when
1803 # Informs the user that phases should have been moved when
1804 # applicable.
1804 # applicable.
1805 actualmoves = [n for n in nodes if phase < self[n].phase()]
1805 actualmoves = [n for n in nodes if phase < self[n].phase()]
1806 phasestr = phases.phasenames[phase]
1806 phasestr = phases.phasenames[phase]
1807 if actualmoves:
1807 if actualmoves:
1808 self.ui.status(_('cannot lock source repo, skipping local'
1808 self.ui.status(_('cannot lock source repo, skipping local'
1809 ' %s phase update\n') % phasestr)
1809 ' %s phase update\n') % phasestr)
1810 # get local lock as we might write phase data
1810 # get local lock as we might write phase data
1811 locallock = None
1811 locallock = None
1812 try:
1812 try:
1813 locallock = self.lock()
1813 locallock = self.lock()
1814 except IOError, err:
1814 except IOError, err:
1815 if err.errno != errno.EACCES:
1815 if err.errno != errno.EACCES:
1816 raise
1816 raise
1817 # source repo cannot be locked.
1817 # source repo cannot be locked.
1818 # We do not abort the push, but just disable the local phase
1818 # We do not abort the push, but just disable the local phase
1819 # synchronisation.
1819 # synchronisation.
1820 msg = 'cannot lock source repository: %s\n' % err
1820 msg = 'cannot lock source repository: %s\n' % err
1821 self.ui.debug(msg)
1821 self.ui.debug(msg)
1822 try:
1822 try:
1823 self.checkpush(force, revs)
1823 self.checkpush(force, revs)
1824 lock = None
1824 lock = None
1825 unbundle = remote.capable('unbundle')
1825 unbundle = remote.capable('unbundle')
1826 if not unbundle:
1826 if not unbundle:
1827 lock = remote.lock()
1827 lock = remote.lock()
1828 try:
1828 try:
1829 # discovery
1829 # discovery
1830 fci = discovery.findcommonincoming
1830 fci = discovery.findcommonincoming
1831 commoninc = fci(unfi, remote, force=force)
1831 commoninc = fci(unfi, remote, force=force)
1832 common, inc, remoteheads = commoninc
1832 common, inc, remoteheads = commoninc
1833 fco = discovery.findcommonoutgoing
1833 fco = discovery.findcommonoutgoing
1834 outgoing = fco(unfi, remote, onlyheads=revs,
1834 outgoing = fco(unfi, remote, onlyheads=revs,
1835 commoninc=commoninc, force=force)
1835 commoninc=commoninc, force=force)
1836
1836
1837
1837
1838 if not outgoing.missing:
1838 if not outgoing.missing:
1839 # nothing to push
1839 # nothing to push
1840 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
1840 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
1841 ret = None
1841 ret = None
1842 else:
1842 else:
1843 # something to push
1843 # something to push
1844 if not force:
1844 if not force:
1845 # if self.obsstore == False --> no obsolete
1845 # if self.obsstore == False --> no obsolete
1846 # then, save the iteration
1846 # then, save the iteration
1847 if unfi.obsstore:
1847 if unfi.obsstore:
1848 # this message are here for 80 char limit reason
1848 # this message are here for 80 char limit reason
1849 mso = _("push includes obsolete changeset: %s!")
1849 mso = _("push includes obsolete changeset: %s!")
1850 mst = "push includes %s changeset: %s!"
1850 mst = "push includes %s changeset: %s!"
1851 # plain versions for i18n tool to detect them
1851 # plain versions for i18n tool to detect them
1852 _("push includes unstable changeset: %s!")
1852 _("push includes unstable changeset: %s!")
1853 _("push includes bumped changeset: %s!")
1853 _("push includes bumped changeset: %s!")
1854 _("push includes divergent changeset: %s!")
1854 _("push includes divergent changeset: %s!")
1855 # If we are to push if there is at least one
1855 # If we are to push if there is at least one
1856 # obsolete or unstable changeset in missing, at
1856 # obsolete or unstable changeset in missing, at
1857 # least one of the missinghead will be obsolete or
1857 # least one of the missinghead will be obsolete or
1858 # unstable. So checking heads only is ok
1858 # unstable. So checking heads only is ok
1859 for node in outgoing.missingheads:
1859 for node in outgoing.missingheads:
1860 ctx = unfi[node]
1860 ctx = unfi[node]
1861 if ctx.obsolete():
1861 if ctx.obsolete():
1862 raise util.Abort(mso % ctx)
1862 raise util.Abort(mso % ctx)
1863 elif ctx.troubled():
1863 elif ctx.troubled():
1864 raise util.Abort(_(mst)
1864 raise util.Abort(_(mst)
1865 % (ctx.troubles()[0],
1865 % (ctx.troubles()[0],
1866 ctx))
1866 ctx))
1867 discovery.checkheads(unfi, remote, outgoing,
1867 discovery.checkheads(unfi, remote, outgoing,
1868 remoteheads, newbranch,
1868 remoteheads, newbranch,
1869 bool(inc))
1869 bool(inc))
1870
1870
1871 # TODO: get bundlecaps from remote
1871 # TODO: get bundlecaps from remote
1872 bundlecaps = None
1872 bundlecaps = None
1873 # create a changegroup from local
1873 # create a changegroup from local
1874 if revs is None and not outgoing.excluded:
1874 if revs is None and not outgoing.excluded:
1875 # push everything,
1875 # push everything,
1876 # use the fast path, no race possible on push
1876 # use the fast path, no race possible on push
1877 bundler = changegroup.bundle10(self, bundlecaps)
1877 bundler = changegroup.bundle10(self, bundlecaps)
1878 cg = self._changegroupsubset(outgoing,
1878 cg = self._changegroupsubset(outgoing,
1879 bundler,
1879 bundler,
1880 'push',
1880 'push',
1881 fastpath=True)
1881 fastpath=True)
1882 else:
1882 else:
1883 cg = self.getlocalbundle('push', outgoing, bundlecaps)
1883 cg = self.getlocalbundle('push', outgoing, bundlecaps)
1884
1884
1885 # apply changegroup to remote
1885 # apply changegroup to remote
1886 if unbundle:
1886 if unbundle:
1887 # local repo finds heads on server, finds out what
1887 # local repo finds heads on server, finds out what
1888 # revs it must push. once revs transferred, if server
1888 # revs it must push. once revs transferred, if server
1889 # finds it has different heads (someone else won
1889 # finds it has different heads (someone else won
1890 # commit/push race), server aborts.
1890 # commit/push race), server aborts.
1891 if force:
1891 if force:
1892 remoteheads = ['force']
1892 remoteheads = ['force']
1893 # ssh: return remote's addchangegroup()
1893 # ssh: return remote's addchangegroup()
1894 # http: return remote's addchangegroup() or 0 for error
1894 # http: return remote's addchangegroup() or 0 for error
1895 ret = remote.unbundle(cg, remoteheads, 'push')
1895 ret = remote.unbundle(cg, remoteheads, 'push')
1896 else:
1896 else:
1897 # we return an integer indicating remote head count
1897 # we return an integer indicating remote head count
1898 # change
1898 # change
1899 ret = remote.addchangegroup(cg, 'push', self.url())
1899 ret = remote.addchangegroup(cg, 'push', self.url())
1900
1900
1901 if ret:
1901 if ret:
1902 # push succeed, synchronize target of the push
1902 # push succeed, synchronize target of the push
1903 cheads = outgoing.missingheads
1903 cheads = outgoing.missingheads
1904 elif revs is None:
1904 elif revs is None:
1905 # All out push fails. synchronize all common
1905 # All out push fails. synchronize all common
1906 cheads = outgoing.commonheads
1906 cheads = outgoing.commonheads
1907 else:
1907 else:
1908 # I want cheads = heads(::missingheads and ::commonheads)
1908 # I want cheads = heads(::missingheads and ::commonheads)
1909 # (missingheads is revs with secret changeset filtered out)
1909 # (missingheads is revs with secret changeset filtered out)
1910 #
1910 #
1911 # This can be expressed as:
1911 # This can be expressed as:
1912 # cheads = ( (missingheads and ::commonheads)
1912 # cheads = ( (missingheads and ::commonheads)
1913 # + (commonheads and ::missingheads))"
1913 # + (commonheads and ::missingheads))"
1914 # )
1914 # )
1915 #
1915 #
1916 # while trying to push we already computed the following:
1916 # while trying to push we already computed the following:
1917 # common = (::commonheads)
1917 # common = (::commonheads)
1918 # missing = ((commonheads::missingheads) - commonheads)
1918 # missing = ((commonheads::missingheads) - commonheads)
1919 #
1919 #
1920 # We can pick:
1920 # We can pick:
1921 # * missingheads part of common (::commonheads)
1921 # * missingheads part of common (::commonheads)
1922 common = set(outgoing.common)
1922 common = set(outgoing.common)
1923 cheads = [node for node in revs if node in common]
1923 cheads = [node for node in revs if node in common]
1924 # and
1924 # and
1925 # * commonheads parents on missing
1925 # * commonheads parents on missing
1926 revset = unfi.set('%ln and parents(roots(%ln))',
1926 revset = unfi.set('%ln and parents(roots(%ln))',
1927 outgoing.commonheads,
1927 outgoing.commonheads,
1928 outgoing.missing)
1928 outgoing.missing)
1929 cheads.extend(c.node() for c in revset)
1929 cheads.extend(c.node() for c in revset)
1930 # even when we don't push, exchanging phase data is useful
1930 # even when we don't push, exchanging phase data is useful
1931 remotephases = remote.listkeys('phases')
1931 remotephases = remote.listkeys('phases')
1932 if (self.ui.configbool('ui', '_usedassubrepo', False)
1932 if (self.ui.configbool('ui', '_usedassubrepo', False)
1933 and remotephases # server supports phases
1933 and remotephases # server supports phases
1934 and ret is None # nothing was pushed
1934 and ret is None # nothing was pushed
1935 and remotephases.get('publishing', False)):
1935 and remotephases.get('publishing', False)):
1936 # When:
1936 # When:
1937 # - this is a subrepo push
1937 # - this is a subrepo push
1938 # - and remote support phase
1938 # - and remote support phase
1939 # - and no changeset was pushed
1939 # - and no changeset was pushed
1940 # - and remote is publishing
1940 # - and remote is publishing
1941 # We may be in issue 3871 case!
1941 # We may be in issue 3871 case!
1942 # We drop the possible phase synchronisation done by
1942 # We drop the possible phase synchronisation done by
1943 # courtesy to publish changesets possibly locally draft
1943 # courtesy to publish changesets possibly locally draft
1944 # on the remote.
1944 # on the remote.
1945 remotephases = {'publishing': 'True'}
1945 remotephases = {'publishing': 'True'}
1946 if not remotephases: # old server or public only repo
1946 if not remotephases: # old server or public only repo
1947 localphasemove(cheads)
1947 localphasemove(cheads)
1948 # don't push any phase data as there is nothing to push
1948 # don't push any phase data as there is nothing to push
1949 else:
1949 else:
1950 ana = phases.analyzeremotephases(self, cheads, remotephases)
1950 ana = phases.analyzeremotephases(self, cheads, remotephases)
1951 pheads, droots = ana
1951 pheads, droots = ana
1952 ### Apply remote phase on local
1952 ### Apply remote phase on local
1953 if remotephases.get('publishing', False):
1953 if remotephases.get('publishing', False):
1954 localphasemove(cheads)
1954 localphasemove(cheads)
1955 else: # publish = False
1955 else: # publish = False
1956 localphasemove(pheads)
1956 localphasemove(pheads)
1957 localphasemove(cheads, phases.draft)
1957 localphasemove(cheads, phases.draft)
1958 ### Apply local phase on remote
1958 ### Apply local phase on remote
1959
1959
1960 # Get the list of all revs draft on remote by public here.
1960 # Get the list of all revs draft on remote by public here.
1961 # XXX Beware that revset break if droots is not strictly
1961 # XXX Beware that revset break if droots is not strictly
1962 # XXX root we may want to ensure it is but it is costly
1962 # XXX root we may want to ensure it is but it is costly
1963 outdated = unfi.set('heads((%ln::%ln) and public())',
1963 outdated = unfi.set('heads((%ln::%ln) and public())',
1964 droots, cheads)
1964 droots, cheads)
1965 for newremotehead in outdated:
1965 for newremotehead in outdated:
1966 r = remote.pushkey('phases',
1966 r = remote.pushkey('phases',
1967 newremotehead.hex(),
1967 newremotehead.hex(),
1968 str(phases.draft),
1968 str(phases.draft),
1969 str(phases.public))
1969 str(phases.public))
1970 if not r:
1970 if not r:
1971 self.ui.warn(_('updating %s to public failed!\n')
1971 self.ui.warn(_('updating %s to public failed!\n')
1972 % newremotehead)
1972 % newremotehead)
1973 self.ui.debug('try to push obsolete markers to remote\n')
1973 self.ui.debug('try to push obsolete markers to remote\n')
1974 obsolete.syncpush(self, remote)
1974 obsolete.syncpush(self, remote)
1975 finally:
1975 finally:
1976 if lock is not None:
1976 if lock is not None:
1977 lock.release()
1977 lock.release()
1978 finally:
1978 finally:
1979 if locallock is not None:
1979 if locallock is not None:
1980 locallock.release()
1980 locallock.release()
1981
1981
1982 bookmarks.updateremote(self.ui, unfi, remote, revs)
1982 bookmarks.updateremote(self.ui, unfi, remote, revs)
1983 return ret
1983 return ret
1984
1984
1985 def changegroupinfo(self, nodes, source):
1985 def changegroupinfo(self, nodes, source):
1986 if self.ui.verbose or source == 'bundle':
1986 if self.ui.verbose or source == 'bundle':
1987 self.ui.status(_("%d changesets found\n") % len(nodes))
1987 self.ui.status(_("%d changesets found\n") % len(nodes))
1988 if self.ui.debugflag:
1988 if self.ui.debugflag:
1989 self.ui.debug("list of changesets:\n")
1989 self.ui.debug("list of changesets:\n")
1990 for node in nodes:
1990 for node in nodes:
1991 self.ui.debug("%s\n" % hex(node))
1991 self.ui.debug("%s\n" % hex(node))
1992
1992
1993 def changegroupsubset(self, bases, heads, source):
1993 def changegroupsubset(self, bases, heads, source):
1994 """Compute a changegroup consisting of all the nodes that are
1994 """Compute a changegroup consisting of all the nodes that are
1995 descendants of any of the bases and ancestors of any of the heads.
1995 descendants of any of the bases and ancestors of any of the heads.
1996 Return a chunkbuffer object whose read() method will return
1996 Return a chunkbuffer object whose read() method will return
1997 successive changegroup chunks.
1997 successive changegroup chunks.
1998
1998
1999 It is fairly complex as determining which filenodes and which
1999 It is fairly complex as determining which filenodes and which
2000 manifest nodes need to be included for the changeset to be complete
2000 manifest nodes need to be included for the changeset to be complete
2001 is non-trivial.
2001 is non-trivial.
2002
2002
2003 Another wrinkle is doing the reverse, figuring out which changeset in
2003 Another wrinkle is doing the reverse, figuring out which changeset in
2004 the changegroup a particular filenode or manifestnode belongs to.
2004 the changegroup a particular filenode or manifestnode belongs to.
2005 """
2005 """
2006 cl = self.changelog
2006 cl = self.changelog
2007 if not bases:
2007 if not bases:
2008 bases = [nullid]
2008 bases = [nullid]
2009 # TODO: remove call to nodesbetween.
2009 # TODO: remove call to nodesbetween.
2010 csets, bases, heads = cl.nodesbetween(bases, heads)
2010 csets, bases, heads = cl.nodesbetween(bases, heads)
2011 bases = [p for n in bases for p in cl.parents(n) if p != nullid]
2011 bases = [p for n in bases for p in cl.parents(n) if p != nullid]
2012 outgoing = discovery.outgoing(cl, bases, heads)
2012 outgoing = discovery.outgoing(cl, bases, heads)
2013 bundler = changegroup.bundle10(self)
2013 bundler = changegroup.bundle10(self)
2014 return self._changegroupsubset(outgoing, bundler, source)
2014 return self._changegroupsubset(outgoing, bundler, source)
2015
2015
2016 def getlocalbundle(self, source, outgoing, bundlecaps=None):
2016 def getlocalbundle(self, source, outgoing, bundlecaps=None):
2017 """Like getbundle, but taking a discovery.outgoing as an argument.
2017 """Like getbundle, but taking a discovery.outgoing as an argument.
2018
2018
2019 This is only implemented for local repos and reuses potentially
2019 This is only implemented for local repos and reuses potentially
2020 precomputed sets in outgoing."""
2020 precomputed sets in outgoing."""
2021 if not outgoing.missing:
2021 if not outgoing.missing:
2022 return None
2022 return None
2023 bundler = changegroup.bundle10(self, bundlecaps)
2023 bundler = changegroup.bundle10(self, bundlecaps)
2024 return self._changegroupsubset(outgoing, bundler, source)
2024 return self._changegroupsubset(outgoing, bundler, source)
2025
2025
2026 def getbundle(self, source, heads=None, common=None, bundlecaps=None):
2026 def getbundle(self, source, heads=None, common=None, bundlecaps=None):
2027 """Like changegroupsubset, but returns the set difference between the
2027 """Like changegroupsubset, but returns the set difference between the
2028 ancestors of heads and the ancestors common.
2028 ancestors of heads and the ancestors common.
2029
2029
2030 If heads is None, use the local heads. If common is None, use [nullid].
2030 If heads is None, use the local heads. If common is None, use [nullid].
2031
2031
2032 The nodes in common might not all be known locally due to the way the
2032 The nodes in common might not all be known locally due to the way the
2033 current discovery protocol works.
2033 current discovery protocol works.
2034 """
2034 """
2035 cl = self.changelog
2035 cl = self.changelog
2036 if common:
2036 if common:
2037 hasnode = cl.hasnode
2037 hasnode = cl.hasnode
2038 common = [n for n in common if hasnode(n)]
2038 common = [n for n in common if hasnode(n)]
2039 else:
2039 else:
2040 common = [nullid]
2040 common = [nullid]
2041 if not heads:
2041 if not heads:
2042 heads = cl.heads()
2042 heads = cl.heads()
2043 return self.getlocalbundle(source,
2043 return self.getlocalbundle(source,
2044 discovery.outgoing(cl, common, heads),
2044 discovery.outgoing(cl, common, heads),
2045 bundlecaps=bundlecaps)
2045 bundlecaps=bundlecaps)
2046
2046
2047 @unfilteredmethod
2047 @unfilteredmethod
2048 def _changegroupsubset(self, outgoing, bundler, source,
2048 def _changegroupsubset(self, outgoing, bundler, source,
2049 fastpath=False):
2049 fastpath=False):
2050 commonrevs = outgoing.common
2050 commonrevs = outgoing.common
2051 csets = outgoing.missing
2051 csets = outgoing.missing
2052 heads = outgoing.missingheads
2052 heads = outgoing.missingheads
2053 # We go through the fast path if we get told to, or if all (unfiltered
2053 # We go through the fast path if we get told to, or if all (unfiltered
2054 # heads have been requested (since we then know there all linkrevs will
2054 # heads have been requested (since we then know there all linkrevs will
2055 # be pulled by the client).
2055 # be pulled by the client).
2056 heads.sort()
2056 heads.sort()
2057 fastpathlinkrev = fastpath or (
2057 fastpathlinkrev = fastpath or (
2058 self.filtername is None and heads == sorted(self.heads()))
2058 self.filtername is None and heads == sorted(self.heads()))
2059
2059
2060 self.hook('preoutgoing', throw=True, source=source)
2060 self.hook('preoutgoing', throw=True, source=source)
2061 self.changegroupinfo(csets, source)
2061 self.changegroupinfo(csets, source)
2062 gengroup = bundler.generate(commonrevs, csets, fastpathlinkrev, source)
2062 gengroup = bundler.generate(commonrevs, csets, fastpathlinkrev, source)
2063 return changegroup.unbundle10(util.chunkbuffer(gengroup), 'UN')
2063 return changegroup.unbundle10(util.chunkbuffer(gengroup), 'UN')
2064
2064
2065 def changegroup(self, basenodes, source):
2065 def changegroup(self, basenodes, source):
2066 # to avoid a race we use changegroupsubset() (issue1320)
2066 # to avoid a race we use changegroupsubset() (issue1320)
2067 return self.changegroupsubset(basenodes, self.heads(), source)
2067 return self.changegroupsubset(basenodes, self.heads(), source)
2068
2068
2069 @unfilteredmethod
2069 @unfilteredmethod
2070 def addchangegroup(self, source, srctype, url, emptyok=False):
2070 def addchangegroup(self, source, srctype, url, emptyok=False):
2071 """Add the changegroup returned by source.read() to this repo.
2071 """Add the changegroup returned by source.read() to this repo.
2072 srctype is a string like 'push', 'pull', or 'unbundle'. url is
2072 srctype is a string like 'push', 'pull', or 'unbundle'. url is
2073 the URL of the repo where this changegroup is coming from.
2073 the URL of the repo where this changegroup is coming from.
2074
2074
2075 Return an integer summarizing the change to this repo:
2075 Return an integer summarizing the change to this repo:
2076 - nothing changed or no source: 0
2076 - nothing changed or no source: 0
2077 - more heads than before: 1+added heads (2..n)
2077 - more heads than before: 1+added heads (2..n)
2078 - fewer heads than before: -1-removed heads (-2..-n)
2078 - fewer heads than before: -1-removed heads (-2..-n)
2079 - number of heads stays the same: 1
2079 - number of heads stays the same: 1
2080 """
2080 """
2081 def csmap(x):
2081 def csmap(x):
2082 self.ui.debug("add changeset %s\n" % short(x))
2082 self.ui.debug("add changeset %s\n" % short(x))
2083 return len(cl)
2083 return len(cl)
2084
2084
2085 def revmap(x):
2085 def revmap(x):
2086 return cl.rev(x)
2086 return cl.rev(x)
2087
2087
2088 if not source:
2088 if not source:
2089 return 0
2089 return 0
2090
2090
2091 self.hook('prechangegroup', throw=True, source=srctype, url=url)
2091 self.hook('prechangegroup', throw=True, source=srctype, url=url)
2092
2092
2093 changesets = files = revisions = 0
2093 changesets = files = revisions = 0
2094 efiles = set()
2094 efiles = set()
2095
2095
2096 # write changelog data to temp files so concurrent readers will not see
2096 # write changelog data to temp files so concurrent readers will not see
2097 # inconsistent view
2097 # inconsistent view
2098 cl = self.changelog
2098 cl = self.changelog
2099 cl.delayupdate()
2099 cl.delayupdate()
2100 oldheads = cl.heads()
2100 oldheads = cl.heads()
2101
2101
2102 tr = self.transaction("\n".join([srctype, util.hidepassword(url)]))
2102 tr = self.transaction("\n".join([srctype, util.hidepassword(url)]))
2103 try:
2103 try:
2104 trp = weakref.proxy(tr)
2104 trp = weakref.proxy(tr)
2105 # pull off the changeset group
2105 # pull off the changeset group
2106 self.ui.status(_("adding changesets\n"))
2106 self.ui.status(_("adding changesets\n"))
2107 clstart = len(cl)
2107 clstart = len(cl)
2108 class prog(object):
2108 class prog(object):
2109 step = _('changesets')
2109 step = _('changesets')
2110 count = 1
2110 count = 1
2111 ui = self.ui
2111 ui = self.ui
2112 total = None
2112 total = None
2113 def __call__(self):
2113 def __call__(self):
2114 self.ui.progress(self.step, self.count, unit=_('chunks'),
2114 self.ui.progress(self.step, self.count, unit=_('chunks'),
2115 total=self.total)
2115 total=self.total)
2116 self.count += 1
2116 self.count += 1
2117 pr = prog()
2117 pr = prog()
2118 source.callback = pr
2118 source.callback = pr
2119
2119
2120 source.changelogheader()
2120 source.changelogheader()
2121 srccontent = cl.addgroup(source, csmap, trp)
2121 srccontent = cl.addgroup(source, csmap, trp)
2122 if not (srccontent or emptyok):
2122 if not (srccontent or emptyok):
2123 raise util.Abort(_("received changelog group is empty"))
2123 raise util.Abort(_("received changelog group is empty"))
2124 clend = len(cl)
2124 clend = len(cl)
2125 changesets = clend - clstart
2125 changesets = clend - clstart
2126 for c in xrange(clstart, clend):
2126 for c in xrange(clstart, clend):
2127 efiles.update(self[c].files())
2127 efiles.update(self[c].files())
2128 efiles = len(efiles)
2128 efiles = len(efiles)
2129 self.ui.progress(_('changesets'), None)
2129 self.ui.progress(_('changesets'), None)
2130
2130
2131 # pull off the manifest group
2131 # pull off the manifest group
2132 self.ui.status(_("adding manifests\n"))
2132 self.ui.status(_("adding manifests\n"))
2133 pr.step = _('manifests')
2133 pr.step = _('manifests')
2134 pr.count = 1
2134 pr.count = 1
2135 pr.total = changesets # manifests <= changesets
2135 pr.total = changesets # manifests <= changesets
2136 # no need to check for empty manifest group here:
2136 # no need to check for empty manifest group here:
2137 # if the result of the merge of 1 and 2 is the same in 3 and 4,
2137 # if the result of the merge of 1 and 2 is the same in 3 and 4,
2138 # no new manifest will be created and the manifest group will
2138 # no new manifest will be created and the manifest group will
2139 # be empty during the pull
2139 # be empty during the pull
2140 source.manifestheader()
2140 source.manifestheader()
2141 self.manifest.addgroup(source, revmap, trp)
2141 self.manifest.addgroup(source, revmap, trp)
2142 self.ui.progress(_('manifests'), None)
2142 self.ui.progress(_('manifests'), None)
2143
2143
2144 needfiles = {}
2144 needfiles = {}
2145 if self.ui.configbool('server', 'validate', default=False):
2145 if self.ui.configbool('server', 'validate', default=False):
2146 # validate incoming csets have their manifests
2146 # validate incoming csets have their manifests
2147 for cset in xrange(clstart, clend):
2147 for cset in xrange(clstart, clend):
2148 mfest = self.changelog.read(self.changelog.node(cset))[0]
2148 mfest = self.changelog.read(self.changelog.node(cset))[0]
2149 mfest = self.manifest.readdelta(mfest)
2149 mfest = self.manifest.readdelta(mfest)
2150 # store file nodes we must see
2150 # store file nodes we must see
2151 for f, n in mfest.iteritems():
2151 for f, n in mfest.iteritems():
2152 needfiles.setdefault(f, set()).add(n)
2152 needfiles.setdefault(f, set()).add(n)
2153
2153
2154 # process the files
2154 # process the files
2155 self.ui.status(_("adding file changes\n"))
2155 self.ui.status(_("adding file changes\n"))
2156 pr.step = _('files')
2156 pr.step = _('files')
2157 pr.count = 1
2157 pr.count = 1
2158 pr.total = efiles
2158 pr.total = efiles
2159 source.callback = None
2159 source.callback = None
2160
2160
2161 newrevs, newfiles = self.addchangegroupfiles(source, revmap, trp,
2161 newrevs, newfiles = self.addchangegroupfiles(source, revmap, trp,
2162 pr, needfiles)
2162 pr, needfiles)
2163 revisions += newrevs
2163 revisions += newrevs
2164 files += newfiles
2164 files += newfiles
2165
2165
2166 dh = 0
2166 dh = 0
2167 if oldheads:
2167 if oldheads:
2168 heads = cl.heads()
2168 heads = cl.heads()
2169 dh = len(heads) - len(oldheads)
2169 dh = len(heads) - len(oldheads)
2170 for h in heads:
2170 for h in heads:
2171 if h not in oldheads and self[h].closesbranch():
2171 if h not in oldheads and self[h].closesbranch():
2172 dh -= 1
2172 dh -= 1
2173 htext = ""
2173 htext = ""
2174 if dh:
2174 if dh:
2175 htext = _(" (%+d heads)") % dh
2175 htext = _(" (%+d heads)") % dh
2176
2176
2177 self.ui.status(_("added %d changesets"
2177 self.ui.status(_("added %d changesets"
2178 " with %d changes to %d files%s\n")
2178 " with %d changes to %d files%s\n")
2179 % (changesets, revisions, files, htext))
2179 % (changesets, revisions, files, htext))
2180 self.invalidatevolatilesets()
2180 self.invalidatevolatilesets()
2181
2181
2182 if changesets > 0:
2182 if changesets > 0:
2183 p = lambda: cl.writepending() and self.root or ""
2183 p = lambda: cl.writepending() and self.root or ""
2184 self.hook('pretxnchangegroup', throw=True,
2184 self.hook('pretxnchangegroup', throw=True,
2185 node=hex(cl.node(clstart)), source=srctype,
2185 node=hex(cl.node(clstart)), source=srctype,
2186 url=url, pending=p)
2186 url=url, pending=p)
2187
2187
2188 added = [cl.node(r) for r in xrange(clstart, clend)]
2188 added = [cl.node(r) for r in xrange(clstart, clend)]
2189 publishing = self.ui.configbool('phases', 'publish', True)
2189 publishing = self.ui.configbool('phases', 'publish', True)
2190 if srctype == 'push':
2190 if srctype == 'push':
2191 # Old server can not push the boundary themself.
2191 # Old server can not push the boundary themself.
2192 # New server won't push the boundary if changeset already
2192 # New server won't push the boundary if changeset already
2193 # existed locally as secrete
2193 # existed locally as secrete
2194 #
2194 #
2195 # We should not use added here but the list of all change in
2195 # We should not use added here but the list of all change in
2196 # the bundle
2196 # the bundle
2197 if publishing:
2197 if publishing:
2198 phases.advanceboundary(self, phases.public, srccontent)
2198 phases.advanceboundary(self, phases.public, srccontent)
2199 else:
2199 else:
2200 phases.advanceboundary(self, phases.draft, srccontent)
2200 phases.advanceboundary(self, phases.draft, srccontent)
2201 phases.retractboundary(self, phases.draft, added)
2201 phases.retractboundary(self, phases.draft, added)
2202 elif srctype != 'strip':
2202 elif srctype != 'strip':
2203 # publishing only alter behavior during push
2203 # publishing only alter behavior during push
2204 #
2204 #
2205 # strip should not touch boundary at all
2205 # strip should not touch boundary at all
2206 phases.retractboundary(self, phases.draft, added)
2206 phases.retractboundary(self, phases.draft, added)
2207
2207
2208 # make changelog see real files again
2208 # make changelog see real files again
2209 cl.finalize(trp)
2209 cl.finalize(trp)
2210
2210
2211 tr.close()
2211 tr.close()
2212
2212
2213 if changesets > 0:
2213 if changesets > 0:
2214 if srctype != 'strip':
2214 if srctype != 'strip':
2215 # During strip, branchcache is invalid but coming call to
2215 # During strip, branchcache is invalid but coming call to
2216 # `destroyed` will repair it.
2216 # `destroyed` will repair it.
2217 # In other case we can safely update cache on disk.
2217 # In other case we can safely update cache on disk.
2218 branchmap.updatecache(self.filtered('served'))
2218 branchmap.updatecache(self.filtered('served'))
2219 def runhooks():
2219 def runhooks():
2220 # These hooks run when the lock releases, not when the
2220 # These hooks run when the lock releases, not when the
2221 # transaction closes. So it's possible for the changelog
2221 # transaction closes. So it's possible for the changelog
2222 # to have changed since we last saw it.
2222 # to have changed since we last saw it.
2223 if clstart >= len(self):
2223 if clstart >= len(self):
2224 return
2224 return
2225
2225
2226 # forcefully update the on-disk branch cache
2226 # forcefully update the on-disk branch cache
2227 self.ui.debug("updating the branch cache\n")
2227 self.ui.debug("updating the branch cache\n")
2228 self.hook("changegroup", node=hex(cl.node(clstart)),
2228 self.hook("changegroup", node=hex(cl.node(clstart)),
2229 source=srctype, url=url)
2229 source=srctype, url=url)
2230
2230
2231 for n in added:
2231 for n in added:
2232 self.hook("incoming", node=hex(n), source=srctype,
2232 self.hook("incoming", node=hex(n), source=srctype,
2233 url=url)
2233 url=url)
2234
2234
2235 newheads = [h for h in self.heads() if h not in oldheads]
2235 newheads = [h for h in self.heads() if h not in oldheads]
2236 self.ui.log("incoming",
2236 self.ui.log("incoming",
2237 "%s incoming changes - new heads: %s\n",
2237 "%s incoming changes - new heads: %s\n",
2238 len(added),
2238 len(added),
2239 ', '.join([hex(c[:6]) for c in newheads]))
2239 ', '.join([hex(c[:6]) for c in newheads]))
2240 self._afterlock(runhooks)
2240 self._afterlock(runhooks)
2241
2241
2242 finally:
2242 finally:
2243 tr.release()
2243 tr.release()
2244 # never return 0 here:
2244 # never return 0 here:
2245 if dh < 0:
2245 if dh < 0:
2246 return dh - 1
2246 return dh - 1
2247 else:
2247 else:
2248 return dh + 1
2248 return dh + 1
2249
2249
2250 def addchangegroupfiles(self, source, revmap, trp, pr, needfiles):
2250 def addchangegroupfiles(self, source, revmap, trp, pr, needfiles):
2251 revisions = 0
2251 revisions = 0
2252 files = 0
2252 files = 0
2253 while True:
2253 while True:
2254 chunkdata = source.filelogheader()
2254 chunkdata = source.filelogheader()
2255 if not chunkdata:
2255 if not chunkdata:
2256 break
2256 break
2257 f = chunkdata["filename"]
2257 f = chunkdata["filename"]
2258 self.ui.debug("adding %s revisions\n" % f)
2258 self.ui.debug("adding %s revisions\n" % f)
2259 pr()
2259 pr()
2260 fl = self.file(f)
2260 fl = self.file(f)
2261 o = len(fl)
2261 o = len(fl)
2262 if not fl.addgroup(source, revmap, trp):
2262 if not fl.addgroup(source, revmap, trp):
2263 raise util.Abort(_("received file revlog group is empty"))
2263 raise util.Abort(_("received file revlog group is empty"))
2264 revisions += len(fl) - o
2264 revisions += len(fl) - o
2265 files += 1
2265 files += 1
2266 if f in needfiles:
2266 if f in needfiles:
2267 needs = needfiles[f]
2267 needs = needfiles[f]
2268 for new in xrange(o, len(fl)):
2268 for new in xrange(o, len(fl)):
2269 n = fl.node(new)
2269 n = fl.node(new)
2270 if n in needs:
2270 if n in needs:
2271 needs.remove(n)
2271 needs.remove(n)
2272 else:
2272 else:
2273 raise util.Abort(
2273 raise util.Abort(
2274 _("received spurious file revlog entry"))
2274 _("received spurious file revlog entry"))
2275 if not needs:
2275 if not needs:
2276 del needfiles[f]
2276 del needfiles[f]
2277 self.ui.progress(_('files'), None)
2277 self.ui.progress(_('files'), None)
2278
2278
2279 for f, needs in needfiles.iteritems():
2279 for f, needs in needfiles.iteritems():
2280 fl = self.file(f)
2280 fl = self.file(f)
2281 for n in needs:
2281 for n in needs:
2282 try:
2282 try:
2283 fl.rev(n)
2283 fl.rev(n)
2284 except error.LookupError:
2284 except error.LookupError:
2285 raise util.Abort(
2285 raise util.Abort(
2286 _('missing file data for %s:%s - run hg verify') %
2286 _('missing file data for %s:%s - run hg verify') %
2287 (f, hex(n)))
2287 (f, hex(n)))
2288
2288
2289 return revisions, files
2289 return revisions, files
2290
2290
2291 def stream_in(self, remote, requirements):
2291 def stream_in(self, remote, requirements):
2292 lock = self.lock()
2292 lock = self.lock()
2293 try:
2293 try:
2294 # Save remote branchmap. We will use it later
2294 # Save remote branchmap. We will use it later
2295 # to speed up branchcache creation
2295 # to speed up branchcache creation
2296 rbranchmap = None
2296 rbranchmap = None
2297 if remote.capable("branchmap"):
2297 if remote.capable("branchmap"):
2298 rbranchmap = remote.branchmap()
2298 rbranchmap = remote.branchmap()
2299
2299
2300 fp = remote.stream_out()
2300 fp = remote.stream_out()
2301 l = fp.readline()
2301 l = fp.readline()
2302 try:
2302 try:
2303 resp = int(l)
2303 resp = int(l)
2304 except ValueError:
2304 except ValueError:
2305 raise error.ResponseError(
2305 raise error.ResponseError(
2306 _('unexpected response from remote server:'), l)
2306 _('unexpected response from remote server:'), l)
2307 if resp == 1:
2307 if resp == 1:
2308 raise util.Abort(_('operation forbidden by server'))
2308 raise util.Abort(_('operation forbidden by server'))
2309 elif resp == 2:
2309 elif resp == 2:
2310 raise util.Abort(_('locking the remote repository failed'))
2310 raise util.Abort(_('locking the remote repository failed'))
2311 elif resp != 0:
2311 elif resp != 0:
2312 raise util.Abort(_('the server sent an unknown error code'))
2312 raise util.Abort(_('the server sent an unknown error code'))
2313 self.ui.status(_('streaming all changes\n'))
2313 self.ui.status(_('streaming all changes\n'))
2314 l = fp.readline()
2314 l = fp.readline()
2315 try:
2315 try:
2316 total_files, total_bytes = map(int, l.split(' ', 1))
2316 total_files, total_bytes = map(int, l.split(' ', 1))
2317 except (ValueError, TypeError):
2317 except (ValueError, TypeError):
2318 raise error.ResponseError(
2318 raise error.ResponseError(
2319 _('unexpected response from remote server:'), l)
2319 _('unexpected response from remote server:'), l)
2320 self.ui.status(_('%d files to transfer, %s of data\n') %
2320 self.ui.status(_('%d files to transfer, %s of data\n') %
2321 (total_files, util.bytecount(total_bytes)))
2321 (total_files, util.bytecount(total_bytes)))
2322 handled_bytes = 0
2322 handled_bytes = 0
2323 self.ui.progress(_('clone'), 0, total=total_bytes)
2323 self.ui.progress(_('clone'), 0, total=total_bytes)
2324 start = time.time()
2324 start = time.time()
2325 for i in xrange(total_files):
2325 for i in xrange(total_files):
2326 # XXX doesn't support '\n' or '\r' in filenames
2326 # XXX doesn't support '\n' or '\r' in filenames
2327 l = fp.readline()
2327 l = fp.readline()
2328 try:
2328 try:
2329 name, size = l.split('\0', 1)
2329 name, size = l.split('\0', 1)
2330 size = int(size)
2330 size = int(size)
2331 except (ValueError, TypeError):
2331 except (ValueError, TypeError):
2332 raise error.ResponseError(
2332 raise error.ResponseError(
2333 _('unexpected response from remote server:'), l)
2333 _('unexpected response from remote server:'), l)
2334 if self.ui.debugflag:
2334 if self.ui.debugflag:
2335 self.ui.debug('adding %s (%s)\n' %
2335 self.ui.debug('adding %s (%s)\n' %
2336 (name, util.bytecount(size)))
2336 (name, util.bytecount(size)))
2337 # for backwards compat, name was partially encoded
2337 # for backwards compat, name was partially encoded
2338 ofp = self.sopener(store.decodedir(name), 'w')
2338 ofp = self.sopener(store.decodedir(name), 'w')
2339 for chunk in util.filechunkiter(fp, limit=size):
2339 for chunk in util.filechunkiter(fp, limit=size):
2340 handled_bytes += len(chunk)
2340 handled_bytes += len(chunk)
2341 self.ui.progress(_('clone'), handled_bytes,
2341 self.ui.progress(_('clone'), handled_bytes,
2342 total=total_bytes)
2342 total=total_bytes)
2343 ofp.write(chunk)
2343 ofp.write(chunk)
2344 ofp.close()
2344 ofp.close()
2345 elapsed = time.time() - start
2345 elapsed = time.time() - start
2346 if elapsed <= 0:
2346 if elapsed <= 0:
2347 elapsed = 0.001
2347 elapsed = 0.001
2348 self.ui.progress(_('clone'), None)
2348 self.ui.progress(_('clone'), None)
2349 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
2349 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
2350 (util.bytecount(total_bytes), elapsed,
2350 (util.bytecount(total_bytes), elapsed,
2351 util.bytecount(total_bytes / elapsed)))
2351 util.bytecount(total_bytes / elapsed)))
2352
2352
2353 # new requirements = old non-format requirements +
2353 # new requirements = old non-format requirements +
2354 # new format-related
2354 # new format-related
2355 # requirements from the streamed-in repository
2355 # requirements from the streamed-in repository
2356 requirements.update(set(self.requirements) - self.supportedformats)
2356 requirements.update(set(self.requirements) - self.supportedformats)
2357 self._applyrequirements(requirements)
2357 self._applyrequirements(requirements)
2358 self._writerequirements()
2358 self._writerequirements()
2359
2359
2360 if rbranchmap:
2360 if rbranchmap:
2361 rbheads = []
2361 rbheads = []
2362 for bheads in rbranchmap.itervalues():
2362 for bheads in rbranchmap.itervalues():
2363 rbheads.extend(bheads)
2363 rbheads.extend(bheads)
2364
2364
2365 if rbheads:
2365 if rbheads:
2366 rtiprev = max((int(self.changelog.rev(node))
2366 rtiprev = max((int(self.changelog.rev(node))
2367 for node in rbheads))
2367 for node in rbheads))
2368 cache = branchmap.branchcache(rbranchmap,
2368 cache = branchmap.branchcache(rbranchmap,
2369 self[rtiprev].node(),
2369 self[rtiprev].node(),
2370 rtiprev)
2370 rtiprev)
2371 # Try to stick it as low as possible
2371 # Try to stick it as low as possible
2372 # filter above served are unlikely to be fetch from a clone
2372 # filter above served are unlikely to be fetch from a clone
2373 for candidate in ('base', 'immutable', 'served'):
2373 for candidate in ('base', 'immutable', 'served'):
2374 rview = self.filtered(candidate)
2374 rview = self.filtered(candidate)
2375 if cache.validfor(rview):
2375 if cache.validfor(rview):
2376 self._branchcaches[candidate] = cache
2376 self._branchcaches[candidate] = cache
2377 cache.write(rview)
2377 cache.write(rview)
2378 break
2378 break
2379 self.invalidate()
2379 self.invalidate()
2380 return len(self.heads()) + 1
2380 return len(self.heads()) + 1
2381 finally:
2381 finally:
2382 lock.release()
2382 lock.release()
2383
2383
2384 def clone(self, remote, heads=[], stream=False):
2384 def clone(self, remote, heads=[], stream=False):
2385 '''clone remote repository.
2385 '''clone remote repository.
2386
2386
2387 keyword arguments:
2387 keyword arguments:
2388 heads: list of revs to clone (forces use of pull)
2388 heads: list of revs to clone (forces use of pull)
2389 stream: use streaming clone if possible'''
2389 stream: use streaming clone if possible'''
2390
2390
2391 # now, all clients that can request uncompressed clones can
2391 # now, all clients that can request uncompressed clones can
2392 # read repo formats supported by all servers that can serve
2392 # read repo formats supported by all servers that can serve
2393 # them.
2393 # them.
2394
2394
2395 # if revlog format changes, client will have to check version
2395 # if revlog format changes, client will have to check version
2396 # and format flags on "stream" capability, and use
2396 # and format flags on "stream" capability, and use
2397 # uncompressed only if compatible.
2397 # uncompressed only if compatible.
2398
2398
2399 if not stream:
2399 if not stream:
2400 # if the server explicitly prefers to stream (for fast LANs)
2400 # if the server explicitly prefers to stream (for fast LANs)
2401 stream = remote.capable('stream-preferred')
2401 stream = remote.capable('stream-preferred')
2402
2402
2403 if stream and not heads:
2403 if stream and not heads:
2404 # 'stream' means remote revlog format is revlogv1 only
2404 # 'stream' means remote revlog format is revlogv1 only
2405 if remote.capable('stream'):
2405 if remote.capable('stream'):
2406 return self.stream_in(remote, set(('revlogv1',)))
2406 return self.stream_in(remote, set(('revlogv1',)))
2407 # otherwise, 'streamreqs' contains the remote revlog format
2407 # otherwise, 'streamreqs' contains the remote revlog format
2408 streamreqs = remote.capable('streamreqs')
2408 streamreqs = remote.capable('streamreqs')
2409 if streamreqs:
2409 if streamreqs:
2410 streamreqs = set(streamreqs.split(','))
2410 streamreqs = set(streamreqs.split(','))
2411 # if we support it, stream in and adjust our requirements
2411 # if we support it, stream in and adjust our requirements
2412 if not streamreqs - self.supportedformats:
2412 if not streamreqs - self.supportedformats:
2413 return self.stream_in(remote, streamreqs)
2413 return self.stream_in(remote, streamreqs)
2414 return self.pull(remote, heads)
2414 return self.pull(remote, heads)
2415
2415
2416 def pushkey(self, namespace, key, old, new):
2416 def pushkey(self, namespace, key, old, new):
2417 self.hook('prepushkey', throw=True, namespace=namespace, key=key,
2417 self.hook('prepushkey', throw=True, namespace=namespace, key=key,
2418 old=old, new=new)
2418 old=old, new=new)
2419 self.ui.debug('pushing key for "%s:%s"\n' % (namespace, key))
2419 self.ui.debug('pushing key for "%s:%s"\n' % (namespace, key))
2420 ret = pushkey.push(self, namespace, key, old, new)
2420 ret = pushkey.push(self, namespace, key, old, new)
2421 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
2421 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
2422 ret=ret)
2422 ret=ret)
2423 return ret
2423 return ret
2424
2424
2425 def listkeys(self, namespace):
2425 def listkeys(self, namespace):
2426 self.hook('prelistkeys', throw=True, namespace=namespace)
2426 self.hook('prelistkeys', throw=True, namespace=namespace)
2427 self.ui.debug('listing keys for "%s"\n' % namespace)
2427 self.ui.debug('listing keys for "%s"\n' % namespace)
2428 values = pushkey.list(self, namespace)
2428 values = pushkey.list(self, namespace)
2429 self.hook('listkeys', namespace=namespace, values=values)
2429 self.hook('listkeys', namespace=namespace, values=values)
2430 return values
2430 return values
2431
2431
2432 def debugwireargs(self, one, two, three=None, four=None, five=None):
2432 def debugwireargs(self, one, two, three=None, four=None, five=None):
2433 '''used to test argument passing over the wire'''
2433 '''used to test argument passing over the wire'''
2434 return "%s %s %s %s %s" % (one, two, three, four, five)
2434 return "%s %s %s %s %s" % (one, two, three, four, five)
2435
2435
2436 def savecommitmessage(self, text):
2436 def savecommitmessage(self, text):
2437 fp = self.opener('last-message.txt', 'wb')
2437 fp = self.opener('last-message.txt', 'wb')
2438 try:
2438 try:
2439 fp.write(text)
2439 fp.write(text)
2440 finally:
2440 finally:
2441 fp.close()
2441 fp.close()
2442 return self.pathto(fp.name[len(self.root) + 1:])
2442 return self.pathto(fp.name[len(self.root) + 1:])
2443
2443
2444 # used to avoid circular references so destructors work
2444 # used to avoid circular references so destructors work
2445 def aftertrans(files):
2445 def aftertrans(files):
2446 renamefiles = [tuple(t) for t in files]
2446 renamefiles = [tuple(t) for t in files]
2447 def a():
2447 def a():
2448 for vfs, src, dest in renamefiles:
2448 for vfs, src, dest in renamefiles:
2449 try:
2449 try:
2450 vfs.rename(src, dest)
2450 vfs.rename(src, dest)
2451 except OSError: # journal file does not yet exist
2451 except OSError: # journal file does not yet exist
2452 pass
2452 pass
2453 return a
2453 return a
2454
2454
2455 def undoname(fn):
2455 def undoname(fn):
2456 base, name = os.path.split(fn)
2456 base, name = os.path.split(fn)
2457 assert name.startswith('journal')
2457 assert name.startswith('journal')
2458 return os.path.join(base, name.replace('journal', 'undo', 1))
2458 return os.path.join(base, name.replace('journal', 'undo', 1))
2459
2459
2460 def instance(ui, path, create):
2460 def instance(ui, path, create):
2461 return localrepository(ui, util.urllocalpath(path), create)
2461 return localrepository(ui, util.urllocalpath(path), create)
2462
2462
2463 def islocal(path):
2463 def islocal(path):
2464 return True
2464 return True
@@ -1,1485 +1,1526 b''
1 # subrepo.py - sub-repository handling for Mercurial
1 # subrepo.py - sub-repository handling for Mercurial
2 #
2 #
3 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2009-2010 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 import errno, os, re, shutil, posixpath, sys
8 import errno, os, re, shutil, posixpath, sys
9 import xml.dom.minidom
9 import xml.dom.minidom
10 import stat, subprocess, tarfile
10 import stat, subprocess, tarfile
11 from i18n import _
11 from i18n import _
12 import config, util, node, error, cmdutil, bookmarks, match as matchmod
12 import config, util, node, error, cmdutil, bookmarks, match as matchmod
13 import phases
13 import pathutil
14 import pathutil
14 hg = None
15 hg = None
15 propertycache = util.propertycache
16 propertycache = util.propertycache
16
17
17 nullstate = ('', '', 'empty')
18 nullstate = ('', '', 'empty')
18
19
19 def _expandedabspath(path):
20 def _expandedabspath(path):
20 '''
21 '''
21 get a path or url and if it is a path expand it and return an absolute path
22 get a path or url and if it is a path expand it and return an absolute path
22 '''
23 '''
23 expandedpath = util.urllocalpath(util.expandpath(path))
24 expandedpath = util.urllocalpath(util.expandpath(path))
24 u = util.url(expandedpath)
25 u = util.url(expandedpath)
25 if not u.scheme:
26 if not u.scheme:
26 path = util.normpath(os.path.abspath(u.path))
27 path = util.normpath(os.path.abspath(u.path))
27 return path
28 return path
28
29
29 def _getstorehashcachename(remotepath):
30 def _getstorehashcachename(remotepath):
30 '''get a unique filename for the store hash cache of a remote repository'''
31 '''get a unique filename for the store hash cache of a remote repository'''
31 return util.sha1(_expandedabspath(remotepath)).hexdigest()[0:12]
32 return util.sha1(_expandedabspath(remotepath)).hexdigest()[0:12]
32
33
33 def _calcfilehash(filename):
34 def _calcfilehash(filename):
34 data = ''
35 data = ''
35 if os.path.exists(filename):
36 if os.path.exists(filename):
36 fd = open(filename, 'rb')
37 fd = open(filename, 'rb')
37 data = fd.read()
38 data = fd.read()
38 fd.close()
39 fd.close()
39 return util.sha1(data).hexdigest()
40 return util.sha1(data).hexdigest()
40
41
41 class SubrepoAbort(error.Abort):
42 class SubrepoAbort(error.Abort):
42 """Exception class used to avoid handling a subrepo error more than once"""
43 """Exception class used to avoid handling a subrepo error more than once"""
43 def __init__(self, *args, **kw):
44 def __init__(self, *args, **kw):
44 error.Abort.__init__(self, *args, **kw)
45 error.Abort.__init__(self, *args, **kw)
45 self.subrepo = kw.get('subrepo')
46 self.subrepo = kw.get('subrepo')
46 self.cause = kw.get('cause')
47 self.cause = kw.get('cause')
47
48
48 def annotatesubrepoerror(func):
49 def annotatesubrepoerror(func):
49 def decoratedmethod(self, *args, **kargs):
50 def decoratedmethod(self, *args, **kargs):
50 try:
51 try:
51 res = func(self, *args, **kargs)
52 res = func(self, *args, **kargs)
52 except SubrepoAbort, ex:
53 except SubrepoAbort, ex:
53 # This exception has already been handled
54 # This exception has already been handled
54 raise ex
55 raise ex
55 except error.Abort, ex:
56 except error.Abort, ex:
56 subrepo = subrelpath(self)
57 subrepo = subrelpath(self)
57 errormsg = str(ex) + ' ' + _('(in subrepo %s)') % subrepo
58 errormsg = str(ex) + ' ' + _('(in subrepo %s)') % subrepo
58 # avoid handling this exception by raising a SubrepoAbort exception
59 # avoid handling this exception by raising a SubrepoAbort exception
59 raise SubrepoAbort(errormsg, hint=ex.hint, subrepo=subrepo,
60 raise SubrepoAbort(errormsg, hint=ex.hint, subrepo=subrepo,
60 cause=sys.exc_info())
61 cause=sys.exc_info())
61 return res
62 return res
62 return decoratedmethod
63 return decoratedmethod
63
64
64 def state(ctx, ui):
65 def state(ctx, ui):
65 """return a state dict, mapping subrepo paths configured in .hgsub
66 """return a state dict, mapping subrepo paths configured in .hgsub
66 to tuple: (source from .hgsub, revision from .hgsubstate, kind
67 to tuple: (source from .hgsub, revision from .hgsubstate, kind
67 (key in types dict))
68 (key in types dict))
68 """
69 """
69 p = config.config()
70 p = config.config()
70 def read(f, sections=None, remap=None):
71 def read(f, sections=None, remap=None):
71 if f in ctx:
72 if f in ctx:
72 try:
73 try:
73 data = ctx[f].data()
74 data = ctx[f].data()
74 except IOError, err:
75 except IOError, err:
75 if err.errno != errno.ENOENT:
76 if err.errno != errno.ENOENT:
76 raise
77 raise
77 # handle missing subrepo spec files as removed
78 # handle missing subrepo spec files as removed
78 ui.warn(_("warning: subrepo spec file %s not found\n") % f)
79 ui.warn(_("warning: subrepo spec file %s not found\n") % f)
79 return
80 return
80 p.parse(f, data, sections, remap, read)
81 p.parse(f, data, sections, remap, read)
81 else:
82 else:
82 raise util.Abort(_("subrepo spec file %s not found") % f)
83 raise util.Abort(_("subrepo spec file %s not found") % f)
83
84
84 if '.hgsub' in ctx:
85 if '.hgsub' in ctx:
85 read('.hgsub')
86 read('.hgsub')
86
87
87 for path, src in ui.configitems('subpaths'):
88 for path, src in ui.configitems('subpaths'):
88 p.set('subpaths', path, src, ui.configsource('subpaths', path))
89 p.set('subpaths', path, src, ui.configsource('subpaths', path))
89
90
90 rev = {}
91 rev = {}
91 if '.hgsubstate' in ctx:
92 if '.hgsubstate' in ctx:
92 try:
93 try:
93 for i, l in enumerate(ctx['.hgsubstate'].data().splitlines()):
94 for i, l in enumerate(ctx['.hgsubstate'].data().splitlines()):
94 l = l.lstrip()
95 l = l.lstrip()
95 if not l:
96 if not l:
96 continue
97 continue
97 try:
98 try:
98 revision, path = l.split(" ", 1)
99 revision, path = l.split(" ", 1)
99 except ValueError:
100 except ValueError:
100 raise util.Abort(_("invalid subrepository revision "
101 raise util.Abort(_("invalid subrepository revision "
101 "specifier in .hgsubstate line %d")
102 "specifier in .hgsubstate line %d")
102 % (i + 1))
103 % (i + 1))
103 rev[path] = revision
104 rev[path] = revision
104 except IOError, err:
105 except IOError, err:
105 if err.errno != errno.ENOENT:
106 if err.errno != errno.ENOENT:
106 raise
107 raise
107
108
108 def remap(src):
109 def remap(src):
109 for pattern, repl in p.items('subpaths'):
110 for pattern, repl in p.items('subpaths'):
110 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
111 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
111 # does a string decode.
112 # does a string decode.
112 repl = repl.encode('string-escape')
113 repl = repl.encode('string-escape')
113 # However, we still want to allow back references to go
114 # However, we still want to allow back references to go
114 # through unharmed, so we turn r'\\1' into r'\1'. Again,
115 # through unharmed, so we turn r'\\1' into r'\1'. Again,
115 # extra escapes are needed because re.sub string decodes.
116 # extra escapes are needed because re.sub string decodes.
116 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
117 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
117 try:
118 try:
118 src = re.sub(pattern, repl, src, 1)
119 src = re.sub(pattern, repl, src, 1)
119 except re.error, e:
120 except re.error, e:
120 raise util.Abort(_("bad subrepository pattern in %s: %s")
121 raise util.Abort(_("bad subrepository pattern in %s: %s")
121 % (p.source('subpaths', pattern), e))
122 % (p.source('subpaths', pattern), e))
122 return src
123 return src
123
124
124 state = {}
125 state = {}
125 for path, src in p[''].items():
126 for path, src in p[''].items():
126 kind = 'hg'
127 kind = 'hg'
127 if src.startswith('['):
128 if src.startswith('['):
128 if ']' not in src:
129 if ']' not in src:
129 raise util.Abort(_('missing ] in subrepo source'))
130 raise util.Abort(_('missing ] in subrepo source'))
130 kind, src = src.split(']', 1)
131 kind, src = src.split(']', 1)
131 kind = kind[1:]
132 kind = kind[1:]
132 src = src.lstrip() # strip any extra whitespace after ']'
133 src = src.lstrip() # strip any extra whitespace after ']'
133
134
134 if not util.url(src).isabs():
135 if not util.url(src).isabs():
135 parent = _abssource(ctx._repo, abort=False)
136 parent = _abssource(ctx._repo, abort=False)
136 if parent:
137 if parent:
137 parent = util.url(parent)
138 parent = util.url(parent)
138 parent.path = posixpath.join(parent.path or '', src)
139 parent.path = posixpath.join(parent.path or '', src)
139 parent.path = posixpath.normpath(parent.path)
140 parent.path = posixpath.normpath(parent.path)
140 joined = str(parent)
141 joined = str(parent)
141 # Remap the full joined path and use it if it changes,
142 # Remap the full joined path and use it if it changes,
142 # else remap the original source.
143 # else remap the original source.
143 remapped = remap(joined)
144 remapped = remap(joined)
144 if remapped == joined:
145 if remapped == joined:
145 src = remap(src)
146 src = remap(src)
146 else:
147 else:
147 src = remapped
148 src = remapped
148
149
149 src = remap(src)
150 src = remap(src)
150 state[util.pconvert(path)] = (src.strip(), rev.get(path, ''), kind)
151 state[util.pconvert(path)] = (src.strip(), rev.get(path, ''), kind)
151
152
152 return state
153 return state
153
154
154 def writestate(repo, state):
155 def writestate(repo, state):
155 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
156 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
156 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)]
157 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)]
157 repo.wwrite('.hgsubstate', ''.join(lines), '')
158 repo.wwrite('.hgsubstate', ''.join(lines), '')
158
159
159 def submerge(repo, wctx, mctx, actx, overwrite):
160 def submerge(repo, wctx, mctx, actx, overwrite):
160 """delegated from merge.applyupdates: merging of .hgsubstate file
161 """delegated from merge.applyupdates: merging of .hgsubstate file
161 in working context, merging context and ancestor context"""
162 in working context, merging context and ancestor context"""
162 if mctx == actx: # backwards?
163 if mctx == actx: # backwards?
163 actx = wctx.p1()
164 actx = wctx.p1()
164 s1 = wctx.substate
165 s1 = wctx.substate
165 s2 = mctx.substate
166 s2 = mctx.substate
166 sa = actx.substate
167 sa = actx.substate
167 sm = {}
168 sm = {}
168
169
169 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
170 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
170
171
171 def debug(s, msg, r=""):
172 def debug(s, msg, r=""):
172 if r:
173 if r:
173 r = "%s:%s:%s" % r
174 r = "%s:%s:%s" % r
174 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
175 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
175
176
176 for s, l in sorted(s1.iteritems()):
177 for s, l in sorted(s1.iteritems()):
177 a = sa.get(s, nullstate)
178 a = sa.get(s, nullstate)
178 ld = l # local state with possible dirty flag for compares
179 ld = l # local state with possible dirty flag for compares
179 if wctx.sub(s).dirty():
180 if wctx.sub(s).dirty():
180 ld = (l[0], l[1] + "+")
181 ld = (l[0], l[1] + "+")
181 if wctx == actx: # overwrite
182 if wctx == actx: # overwrite
182 a = ld
183 a = ld
183
184
184 if s in s2:
185 if s in s2:
185 r = s2[s]
186 r = s2[s]
186 if ld == r or r == a: # no change or local is newer
187 if ld == r or r == a: # no change or local is newer
187 sm[s] = l
188 sm[s] = l
188 continue
189 continue
189 elif ld == a: # other side changed
190 elif ld == a: # other side changed
190 debug(s, "other changed, get", r)
191 debug(s, "other changed, get", r)
191 wctx.sub(s).get(r, overwrite)
192 wctx.sub(s).get(r, overwrite)
192 sm[s] = r
193 sm[s] = r
193 elif ld[0] != r[0]: # sources differ
194 elif ld[0] != r[0]: # sources differ
194 if repo.ui.promptchoice(
195 if repo.ui.promptchoice(
195 _(' subrepository sources for %s differ\n'
196 _(' subrepository sources for %s differ\n'
196 'use (l)ocal source (%s) or (r)emote source (%s)?'
197 'use (l)ocal source (%s) or (r)emote source (%s)?'
197 '$$ &Local $$ &Remote') % (s, l[0], r[0]), 0):
198 '$$ &Local $$ &Remote') % (s, l[0], r[0]), 0):
198 debug(s, "prompt changed, get", r)
199 debug(s, "prompt changed, get", r)
199 wctx.sub(s).get(r, overwrite)
200 wctx.sub(s).get(r, overwrite)
200 sm[s] = r
201 sm[s] = r
201 elif ld[1] == a[1]: # local side is unchanged
202 elif ld[1] == a[1]: # local side is unchanged
202 debug(s, "other side changed, get", r)
203 debug(s, "other side changed, get", r)
203 wctx.sub(s).get(r, overwrite)
204 wctx.sub(s).get(r, overwrite)
204 sm[s] = r
205 sm[s] = r
205 else:
206 else:
206 debug(s, "both sides changed")
207 debug(s, "both sides changed")
207 option = repo.ui.promptchoice(
208 option = repo.ui.promptchoice(
208 _(' subrepository %s diverged (local revision: %s, '
209 _(' subrepository %s diverged (local revision: %s, '
209 'remote revision: %s)\n'
210 'remote revision: %s)\n'
210 '(M)erge, keep (l)ocal or keep (r)emote?'
211 '(M)erge, keep (l)ocal or keep (r)emote?'
211 '$$ &Merge $$ &Local $$ &Remote')
212 '$$ &Merge $$ &Local $$ &Remote')
212 % (s, l[1][:12], r[1][:12]), 0)
213 % (s, l[1][:12], r[1][:12]), 0)
213 if option == 0:
214 if option == 0:
214 wctx.sub(s).merge(r)
215 wctx.sub(s).merge(r)
215 sm[s] = l
216 sm[s] = l
216 debug(s, "merge with", r)
217 debug(s, "merge with", r)
217 elif option == 1:
218 elif option == 1:
218 sm[s] = l
219 sm[s] = l
219 debug(s, "keep local subrepo revision", l)
220 debug(s, "keep local subrepo revision", l)
220 else:
221 else:
221 wctx.sub(s).get(r, overwrite)
222 wctx.sub(s).get(r, overwrite)
222 sm[s] = r
223 sm[s] = r
223 debug(s, "get remote subrepo revision", r)
224 debug(s, "get remote subrepo revision", r)
224 elif ld == a: # remote removed, local unchanged
225 elif ld == a: # remote removed, local unchanged
225 debug(s, "remote removed, remove")
226 debug(s, "remote removed, remove")
226 wctx.sub(s).remove()
227 wctx.sub(s).remove()
227 elif a == nullstate: # not present in remote or ancestor
228 elif a == nullstate: # not present in remote or ancestor
228 debug(s, "local added, keep")
229 debug(s, "local added, keep")
229 sm[s] = l
230 sm[s] = l
230 continue
231 continue
231 else:
232 else:
232 if repo.ui.promptchoice(
233 if repo.ui.promptchoice(
233 _(' local changed subrepository %s which remote removed\n'
234 _(' local changed subrepository %s which remote removed\n'
234 'use (c)hanged version or (d)elete?'
235 'use (c)hanged version or (d)elete?'
235 '$$ &Changed $$ &Delete') % s, 0):
236 '$$ &Changed $$ &Delete') % s, 0):
236 debug(s, "prompt remove")
237 debug(s, "prompt remove")
237 wctx.sub(s).remove()
238 wctx.sub(s).remove()
238
239
239 for s, r in sorted(s2.items()):
240 for s, r in sorted(s2.items()):
240 if s in s1:
241 if s in s1:
241 continue
242 continue
242 elif s not in sa:
243 elif s not in sa:
243 debug(s, "remote added, get", r)
244 debug(s, "remote added, get", r)
244 mctx.sub(s).get(r)
245 mctx.sub(s).get(r)
245 sm[s] = r
246 sm[s] = r
246 elif r != sa[s]:
247 elif r != sa[s]:
247 if repo.ui.promptchoice(
248 if repo.ui.promptchoice(
248 _(' remote changed subrepository %s which local removed\n'
249 _(' remote changed subrepository %s which local removed\n'
249 'use (c)hanged version or (d)elete?'
250 'use (c)hanged version or (d)elete?'
250 '$$ &Changed $$ &Delete') % s, 0) == 0:
251 '$$ &Changed $$ &Delete') % s, 0) == 0:
251 debug(s, "prompt recreate", r)
252 debug(s, "prompt recreate", r)
252 wctx.sub(s).get(r)
253 wctx.sub(s).get(r)
253 sm[s] = r
254 sm[s] = r
254
255
255 # record merged .hgsubstate
256 # record merged .hgsubstate
256 writestate(repo, sm)
257 writestate(repo, sm)
257 return sm
258 return sm
258
259
259 def _updateprompt(ui, sub, dirty, local, remote):
260 def _updateprompt(ui, sub, dirty, local, remote):
260 if dirty:
261 if dirty:
261 msg = (_(' subrepository sources for %s differ\n'
262 msg = (_(' subrepository sources for %s differ\n'
262 'use (l)ocal source (%s) or (r)emote source (%s)?\n'
263 'use (l)ocal source (%s) or (r)emote source (%s)?\n'
263 '$$ &Local $$ &Remote')
264 '$$ &Local $$ &Remote')
264 % (subrelpath(sub), local, remote))
265 % (subrelpath(sub), local, remote))
265 else:
266 else:
266 msg = (_(' subrepository sources for %s differ (in checked out '
267 msg = (_(' subrepository sources for %s differ (in checked out '
267 'version)\n'
268 'version)\n'
268 'use (l)ocal source (%s) or (r)emote source (%s)?\n'
269 'use (l)ocal source (%s) or (r)emote source (%s)?\n'
269 '$$ &Local $$ &Remote')
270 '$$ &Local $$ &Remote')
270 % (subrelpath(sub), local, remote))
271 % (subrelpath(sub), local, remote))
271 return ui.promptchoice(msg, 0)
272 return ui.promptchoice(msg, 0)
272
273
273 def reporelpath(repo):
274 def reporelpath(repo):
274 """return path to this (sub)repo as seen from outermost repo"""
275 """return path to this (sub)repo as seen from outermost repo"""
275 parent = repo
276 parent = repo
276 while util.safehasattr(parent, '_subparent'):
277 while util.safehasattr(parent, '_subparent'):
277 parent = parent._subparent
278 parent = parent._subparent
278 p = parent.root.rstrip(os.sep)
279 p = parent.root.rstrip(os.sep)
279 return repo.root[len(p) + 1:]
280 return repo.root[len(p) + 1:]
280
281
281 def subrelpath(sub):
282 def subrelpath(sub):
282 """return path to this subrepo as seen from outermost repo"""
283 """return path to this subrepo as seen from outermost repo"""
283 if util.safehasattr(sub, '_relpath'):
284 if util.safehasattr(sub, '_relpath'):
284 return sub._relpath
285 return sub._relpath
285 if not util.safehasattr(sub, '_repo'):
286 if not util.safehasattr(sub, '_repo'):
286 return sub._path
287 return sub._path
287 return reporelpath(sub._repo)
288 return reporelpath(sub._repo)
288
289
289 def _abssource(repo, push=False, abort=True):
290 def _abssource(repo, push=False, abort=True):
290 """return pull/push path of repo - either based on parent repo .hgsub info
291 """return pull/push path of repo - either based on parent repo .hgsub info
291 or on the top repo config. Abort or return None if no source found."""
292 or on the top repo config. Abort or return None if no source found."""
292 if util.safehasattr(repo, '_subparent'):
293 if util.safehasattr(repo, '_subparent'):
293 source = util.url(repo._subsource)
294 source = util.url(repo._subsource)
294 if source.isabs():
295 if source.isabs():
295 return str(source)
296 return str(source)
296 source.path = posixpath.normpath(source.path)
297 source.path = posixpath.normpath(source.path)
297 parent = _abssource(repo._subparent, push, abort=False)
298 parent = _abssource(repo._subparent, push, abort=False)
298 if parent:
299 if parent:
299 parent = util.url(util.pconvert(parent))
300 parent = util.url(util.pconvert(parent))
300 parent.path = posixpath.join(parent.path or '', source.path)
301 parent.path = posixpath.join(parent.path or '', source.path)
301 parent.path = posixpath.normpath(parent.path)
302 parent.path = posixpath.normpath(parent.path)
302 return str(parent)
303 return str(parent)
303 else: # recursion reached top repo
304 else: # recursion reached top repo
304 if util.safehasattr(repo, '_subtoppath'):
305 if util.safehasattr(repo, '_subtoppath'):
305 return repo._subtoppath
306 return repo._subtoppath
306 if push and repo.ui.config('paths', 'default-push'):
307 if push and repo.ui.config('paths', 'default-push'):
307 return repo.ui.config('paths', 'default-push')
308 return repo.ui.config('paths', 'default-push')
308 if repo.ui.config('paths', 'default'):
309 if repo.ui.config('paths', 'default'):
309 return repo.ui.config('paths', 'default')
310 return repo.ui.config('paths', 'default')
310 if repo.sharedpath != repo.path:
311 if repo.sharedpath != repo.path:
311 # chop off the .hg component to get the default path form
312 # chop off the .hg component to get the default path form
312 return os.path.dirname(repo.sharedpath)
313 return os.path.dirname(repo.sharedpath)
313 if abort:
314 if abort:
314 raise util.Abort(_("default path for subrepository not found"))
315 raise util.Abort(_("default path for subrepository not found"))
315
316
316 def _sanitize(ui, path):
317 def _sanitize(ui, path):
317 def v(arg, dirname, names):
318 def v(arg, dirname, names):
318 if os.path.basename(dirname).lower() != '.hg':
319 if os.path.basename(dirname).lower() != '.hg':
319 return
320 return
320 for f in names:
321 for f in names:
321 if f.lower() == 'hgrc':
322 if f.lower() == 'hgrc':
322 ui.warn(
323 ui.warn(
323 _("warning: removing potentially hostile .hg/hgrc in '%s'"
324 _("warning: removing potentially hostile .hg/hgrc in '%s'"
324 % path))
325 % path))
325 os.unlink(os.path.join(dirname, f))
326 os.unlink(os.path.join(dirname, f))
326 os.walk(path, v, None)
327 os.walk(path, v, None)
327
328
328 def itersubrepos(ctx1, ctx2):
329 def itersubrepos(ctx1, ctx2):
329 """find subrepos in ctx1 or ctx2"""
330 """find subrepos in ctx1 or ctx2"""
330 # Create a (subpath, ctx) mapping where we prefer subpaths from
331 # Create a (subpath, ctx) mapping where we prefer subpaths from
331 # ctx1. The subpaths from ctx2 are important when the .hgsub file
332 # ctx1. The subpaths from ctx2 are important when the .hgsub file
332 # has been modified (in ctx2) but not yet committed (in ctx1).
333 # has been modified (in ctx2) but not yet committed (in ctx1).
333 subpaths = dict.fromkeys(ctx2.substate, ctx2)
334 subpaths = dict.fromkeys(ctx2.substate, ctx2)
334 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
335 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
335 for subpath, ctx in sorted(subpaths.iteritems()):
336 for subpath, ctx in sorted(subpaths.iteritems()):
336 yield subpath, ctx.sub(subpath)
337 yield subpath, ctx.sub(subpath)
337
338
338 def subrepo(ctx, path):
339 def subrepo(ctx, path):
339 """return instance of the right subrepo class for subrepo in path"""
340 """return instance of the right subrepo class for subrepo in path"""
340 # subrepo inherently violates our import layering rules
341 # subrepo inherently violates our import layering rules
341 # because it wants to make repo objects from deep inside the stack
342 # because it wants to make repo objects from deep inside the stack
342 # so we manually delay the circular imports to not break
343 # so we manually delay the circular imports to not break
343 # scripts that don't use our demand-loading
344 # scripts that don't use our demand-loading
344 global hg
345 global hg
345 import hg as h
346 import hg as h
346 hg = h
347 hg = h
347
348
348 pathutil.pathauditor(ctx._repo.root)(path)
349 pathutil.pathauditor(ctx._repo.root)(path)
349 state = ctx.substate[path]
350 state = ctx.substate[path]
350 if state[2] not in types:
351 if state[2] not in types:
351 raise util.Abort(_('unknown subrepo type %s') % state[2])
352 raise util.Abort(_('unknown subrepo type %s') % state[2])
352 return types[state[2]](ctx, path, state[:2])
353 return types[state[2]](ctx, path, state[:2])
353
354
355 def newcommitphase(ui, ctx):
356 commitphase = phases.newcommitphase(ui)
357 substate = getattr(ctx, "substate", None)
358 if not substate:
359 return commitphase
360 check = ui.config('phases', 'checksubrepos', 'follow')
361 if check not in ('ignore', 'follow', 'abort'):
362 raise util.Abort(_('invalid phases.checksubrepos configuration: %s')
363 % (check))
364 if check == 'ignore':
365 return commitphase
366 maxphase = phases.public
367 maxsub = None
368 for s in sorted(substate):
369 sub = ctx.sub(s)
370 subphase = sub.phase(substate[s][1])
371 if maxphase < subphase:
372 maxphase = subphase
373 maxsub = s
374 if commitphase < maxphase:
375 if check == 'abort':
376 raise util.Abort(_("can't commit in %s phase"
377 " conflicting %s from subrepository %s") %
378 (phases.phasenames[commitphase],
379 phases.phasenames[maxphase], maxsub))
380 ui.warn(_("warning: changes are committed in"
381 " %s phase from subrepository %s\n") %
382 (phases.phasenames[maxphase], maxsub))
383 return maxphase
384 return commitphase
385
354 # subrepo classes need to implement the following abstract class:
386 # subrepo classes need to implement the following abstract class:
355
387
356 class abstractsubrepo(object):
388 class abstractsubrepo(object):
357
389
358 def storeclean(self, path):
390 def storeclean(self, path):
359 """
391 """
360 returns true if the repository has not changed since it was last
392 returns true if the repository has not changed since it was last
361 cloned from or pushed to a given repository.
393 cloned from or pushed to a given repository.
362 """
394 """
363 return False
395 return False
364
396
365 def dirty(self, ignoreupdate=False):
397 def dirty(self, ignoreupdate=False):
366 """returns true if the dirstate of the subrepo is dirty or does not
398 """returns true if the dirstate of the subrepo is dirty or does not
367 match current stored state. If ignoreupdate is true, only check
399 match current stored state. If ignoreupdate is true, only check
368 whether the subrepo has uncommitted changes in its dirstate.
400 whether the subrepo has uncommitted changes in its dirstate.
369 """
401 """
370 raise NotImplementedError
402 raise NotImplementedError
371
403
372 def basestate(self):
404 def basestate(self):
373 """current working directory base state, disregarding .hgsubstate
405 """current working directory base state, disregarding .hgsubstate
374 state and working directory modifications"""
406 state and working directory modifications"""
375 raise NotImplementedError
407 raise NotImplementedError
376
408
377 def checknested(self, path):
409 def checknested(self, path):
378 """check if path is a subrepository within this repository"""
410 """check if path is a subrepository within this repository"""
379 return False
411 return False
380
412
381 def commit(self, text, user, date):
413 def commit(self, text, user, date):
382 """commit the current changes to the subrepo with the given
414 """commit the current changes to the subrepo with the given
383 log message. Use given user and date if possible. Return the
415 log message. Use given user and date if possible. Return the
384 new state of the subrepo.
416 new state of the subrepo.
385 """
417 """
386 raise NotImplementedError
418 raise NotImplementedError
387
419
420 def phase(self, state):
421 """returns phase of specified state in the subrepository.
422 """
423 return phases.public
424
388 def remove(self):
425 def remove(self):
389 """remove the subrepo
426 """remove the subrepo
390
427
391 (should verify the dirstate is not dirty first)
428 (should verify the dirstate is not dirty first)
392 """
429 """
393 raise NotImplementedError
430 raise NotImplementedError
394
431
395 def get(self, state, overwrite=False):
432 def get(self, state, overwrite=False):
396 """run whatever commands are needed to put the subrepo into
433 """run whatever commands are needed to put the subrepo into
397 this state
434 this state
398 """
435 """
399 raise NotImplementedError
436 raise NotImplementedError
400
437
401 def merge(self, state):
438 def merge(self, state):
402 """merge currently-saved state with the new state."""
439 """merge currently-saved state with the new state."""
403 raise NotImplementedError
440 raise NotImplementedError
404
441
405 def push(self, opts):
442 def push(self, opts):
406 """perform whatever action is analogous to 'hg push'
443 """perform whatever action is analogous to 'hg push'
407
444
408 This may be a no-op on some systems.
445 This may be a no-op on some systems.
409 """
446 """
410 raise NotImplementedError
447 raise NotImplementedError
411
448
412 def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
449 def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
413 return []
450 return []
414
451
415 def status(self, rev2, **opts):
452 def status(self, rev2, **opts):
416 return [], [], [], [], [], [], []
453 return [], [], [], [], [], [], []
417
454
418 def diff(self, ui, diffopts, node2, match, prefix, **opts):
455 def diff(self, ui, diffopts, node2, match, prefix, **opts):
419 pass
456 pass
420
457
421 def outgoing(self, ui, dest, opts):
458 def outgoing(self, ui, dest, opts):
422 return 1
459 return 1
423
460
424 def incoming(self, ui, source, opts):
461 def incoming(self, ui, source, opts):
425 return 1
462 return 1
426
463
427 def files(self):
464 def files(self):
428 """return filename iterator"""
465 """return filename iterator"""
429 raise NotImplementedError
466 raise NotImplementedError
430
467
431 def filedata(self, name):
468 def filedata(self, name):
432 """return file data"""
469 """return file data"""
433 raise NotImplementedError
470 raise NotImplementedError
434
471
435 def fileflags(self, name):
472 def fileflags(self, name):
436 """return file flags"""
473 """return file flags"""
437 return ''
474 return ''
438
475
439 def archive(self, ui, archiver, prefix, match=None):
476 def archive(self, ui, archiver, prefix, match=None):
440 if match is not None:
477 if match is not None:
441 files = [f for f in self.files() if match(f)]
478 files = [f for f in self.files() if match(f)]
442 else:
479 else:
443 files = self.files()
480 files = self.files()
444 total = len(files)
481 total = len(files)
445 relpath = subrelpath(self)
482 relpath = subrelpath(self)
446 ui.progress(_('archiving (%s)') % relpath, 0,
483 ui.progress(_('archiving (%s)') % relpath, 0,
447 unit=_('files'), total=total)
484 unit=_('files'), total=total)
448 for i, name in enumerate(files):
485 for i, name in enumerate(files):
449 flags = self.fileflags(name)
486 flags = self.fileflags(name)
450 mode = 'x' in flags and 0755 or 0644
487 mode = 'x' in flags and 0755 or 0644
451 symlink = 'l' in flags
488 symlink = 'l' in flags
452 archiver.addfile(os.path.join(prefix, self._path, name),
489 archiver.addfile(os.path.join(prefix, self._path, name),
453 mode, symlink, self.filedata(name))
490 mode, symlink, self.filedata(name))
454 ui.progress(_('archiving (%s)') % relpath, i + 1,
491 ui.progress(_('archiving (%s)') % relpath, i + 1,
455 unit=_('files'), total=total)
492 unit=_('files'), total=total)
456 ui.progress(_('archiving (%s)') % relpath, None)
493 ui.progress(_('archiving (%s)') % relpath, None)
457 return total
494 return total
458
495
459 def walk(self, match):
496 def walk(self, match):
460 '''
497 '''
461 walk recursively through the directory tree, finding all files
498 walk recursively through the directory tree, finding all files
462 matched by the match function
499 matched by the match function
463 '''
500 '''
464 pass
501 pass
465
502
466 def forget(self, ui, match, prefix):
503 def forget(self, ui, match, prefix):
467 return ([], [])
504 return ([], [])
468
505
469 def revert(self, ui, substate, *pats, **opts):
506 def revert(self, ui, substate, *pats, **opts):
470 ui.warn('%s: reverting %s subrepos is unsupported\n' \
507 ui.warn('%s: reverting %s subrepos is unsupported\n' \
471 % (substate[0], substate[2]))
508 % (substate[0], substate[2]))
472 return []
509 return []
473
510
474 class hgsubrepo(abstractsubrepo):
511 class hgsubrepo(abstractsubrepo):
475 def __init__(self, ctx, path, state):
512 def __init__(self, ctx, path, state):
476 self._path = path
513 self._path = path
477 self._state = state
514 self._state = state
478 r = ctx._repo
515 r = ctx._repo
479 root = r.wjoin(path)
516 root = r.wjoin(path)
480 create = False
517 create = False
481 if not os.path.exists(os.path.join(root, '.hg')):
518 if not os.path.exists(os.path.join(root, '.hg')):
482 create = True
519 create = True
483 util.makedirs(root)
520 util.makedirs(root)
484 self._repo = hg.repository(r.baseui, root, create=create)
521 self._repo = hg.repository(r.baseui, root, create=create)
485 for s, k in [('ui', 'commitsubrepos')]:
522 for s, k in [('ui', 'commitsubrepos')]:
486 v = r.ui.config(s, k)
523 v = r.ui.config(s, k)
487 if v:
524 if v:
488 self._repo.ui.setconfig(s, k, v)
525 self._repo.ui.setconfig(s, k, v)
489 self._repo.ui.setconfig('ui', '_usedassubrepo', 'True')
526 self._repo.ui.setconfig('ui', '_usedassubrepo', 'True')
490 self._initrepo(r, state[0], create)
527 self._initrepo(r, state[0], create)
491
528
492 def storeclean(self, path):
529 def storeclean(self, path):
493 clean = True
530 clean = True
494 lock = self._repo.lock()
531 lock = self._repo.lock()
495 itercache = self._calcstorehash(path)
532 itercache = self._calcstorehash(path)
496 try:
533 try:
497 for filehash in self._readstorehashcache(path):
534 for filehash in self._readstorehashcache(path):
498 if filehash != itercache.next():
535 if filehash != itercache.next():
499 clean = False
536 clean = False
500 break
537 break
501 except StopIteration:
538 except StopIteration:
502 # the cached and current pull states have a different size
539 # the cached and current pull states have a different size
503 clean = False
540 clean = False
504 if clean:
541 if clean:
505 try:
542 try:
506 itercache.next()
543 itercache.next()
507 # the cached and current pull states have a different size
544 # the cached and current pull states have a different size
508 clean = False
545 clean = False
509 except StopIteration:
546 except StopIteration:
510 pass
547 pass
511 lock.release()
548 lock.release()
512 return clean
549 return clean
513
550
514 def _calcstorehash(self, remotepath):
551 def _calcstorehash(self, remotepath):
515 '''calculate a unique "store hash"
552 '''calculate a unique "store hash"
516
553
517 This method is used to to detect when there are changes that may
554 This method is used to to detect when there are changes that may
518 require a push to a given remote path.'''
555 require a push to a given remote path.'''
519 # sort the files that will be hashed in increasing (likely) file size
556 # sort the files that will be hashed in increasing (likely) file size
520 filelist = ('bookmarks', 'store/phaseroots', 'store/00changelog.i')
557 filelist = ('bookmarks', 'store/phaseroots', 'store/00changelog.i')
521 yield '# %s\n' % _expandedabspath(remotepath)
558 yield '# %s\n' % _expandedabspath(remotepath)
522 for relname in filelist:
559 for relname in filelist:
523 absname = os.path.normpath(self._repo.join(relname))
560 absname = os.path.normpath(self._repo.join(relname))
524 yield '%s = %s\n' % (relname, _calcfilehash(absname))
561 yield '%s = %s\n' % (relname, _calcfilehash(absname))
525
562
526 def _getstorehashcachepath(self, remotepath):
563 def _getstorehashcachepath(self, remotepath):
527 '''get a unique path for the store hash cache'''
564 '''get a unique path for the store hash cache'''
528 return self._repo.join(os.path.join(
565 return self._repo.join(os.path.join(
529 'cache', 'storehash', _getstorehashcachename(remotepath)))
566 'cache', 'storehash', _getstorehashcachename(remotepath)))
530
567
531 def _readstorehashcache(self, remotepath):
568 def _readstorehashcache(self, remotepath):
532 '''read the store hash cache for a given remote repository'''
569 '''read the store hash cache for a given remote repository'''
533 cachefile = self._getstorehashcachepath(remotepath)
570 cachefile = self._getstorehashcachepath(remotepath)
534 if not os.path.exists(cachefile):
571 if not os.path.exists(cachefile):
535 return ''
572 return ''
536 fd = open(cachefile, 'r')
573 fd = open(cachefile, 'r')
537 pullstate = fd.readlines()
574 pullstate = fd.readlines()
538 fd.close()
575 fd.close()
539 return pullstate
576 return pullstate
540
577
541 def _cachestorehash(self, remotepath):
578 def _cachestorehash(self, remotepath):
542 '''cache the current store hash
579 '''cache the current store hash
543
580
544 Each remote repo requires its own store hash cache, because a subrepo
581 Each remote repo requires its own store hash cache, because a subrepo
545 store may be "clean" versus a given remote repo, but not versus another
582 store may be "clean" versus a given remote repo, but not versus another
546 '''
583 '''
547 cachefile = self._getstorehashcachepath(remotepath)
584 cachefile = self._getstorehashcachepath(remotepath)
548 lock = self._repo.lock()
585 lock = self._repo.lock()
549 storehash = list(self._calcstorehash(remotepath))
586 storehash = list(self._calcstorehash(remotepath))
550 cachedir = os.path.dirname(cachefile)
587 cachedir = os.path.dirname(cachefile)
551 if not os.path.exists(cachedir):
588 if not os.path.exists(cachedir):
552 util.makedirs(cachedir, notindexed=True)
589 util.makedirs(cachedir, notindexed=True)
553 fd = open(cachefile, 'w')
590 fd = open(cachefile, 'w')
554 fd.writelines(storehash)
591 fd.writelines(storehash)
555 fd.close()
592 fd.close()
556 lock.release()
593 lock.release()
557
594
558 @annotatesubrepoerror
595 @annotatesubrepoerror
559 def _initrepo(self, parentrepo, source, create):
596 def _initrepo(self, parentrepo, source, create):
560 self._repo._subparent = parentrepo
597 self._repo._subparent = parentrepo
561 self._repo._subsource = source
598 self._repo._subsource = source
562
599
563 if create:
600 if create:
564 fp = self._repo.opener("hgrc", "w", text=True)
601 fp = self._repo.opener("hgrc", "w", text=True)
565 fp.write('[paths]\n')
602 fp.write('[paths]\n')
566
603
567 def addpathconfig(key, value):
604 def addpathconfig(key, value):
568 if value:
605 if value:
569 fp.write('%s = %s\n' % (key, value))
606 fp.write('%s = %s\n' % (key, value))
570 self._repo.ui.setconfig('paths', key, value)
607 self._repo.ui.setconfig('paths', key, value)
571
608
572 defpath = _abssource(self._repo, abort=False)
609 defpath = _abssource(self._repo, abort=False)
573 defpushpath = _abssource(self._repo, True, abort=False)
610 defpushpath = _abssource(self._repo, True, abort=False)
574 addpathconfig('default', defpath)
611 addpathconfig('default', defpath)
575 if defpath != defpushpath:
612 if defpath != defpushpath:
576 addpathconfig('default-push', defpushpath)
613 addpathconfig('default-push', defpushpath)
577 fp.close()
614 fp.close()
578
615
579 @annotatesubrepoerror
616 @annotatesubrepoerror
580 def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
617 def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
581 return cmdutil.add(ui, self._repo, match, dryrun, listsubrepos,
618 return cmdutil.add(ui, self._repo, match, dryrun, listsubrepos,
582 os.path.join(prefix, self._path), explicitonly)
619 os.path.join(prefix, self._path), explicitonly)
583
620
584 @annotatesubrepoerror
621 @annotatesubrepoerror
585 def status(self, rev2, **opts):
622 def status(self, rev2, **opts):
586 try:
623 try:
587 rev1 = self._state[1]
624 rev1 = self._state[1]
588 ctx1 = self._repo[rev1]
625 ctx1 = self._repo[rev1]
589 ctx2 = self._repo[rev2]
626 ctx2 = self._repo[rev2]
590 return self._repo.status(ctx1, ctx2, **opts)
627 return self._repo.status(ctx1, ctx2, **opts)
591 except error.RepoLookupError, inst:
628 except error.RepoLookupError, inst:
592 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
629 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
593 % (inst, subrelpath(self)))
630 % (inst, subrelpath(self)))
594 return [], [], [], [], [], [], []
631 return [], [], [], [], [], [], []
595
632
596 @annotatesubrepoerror
633 @annotatesubrepoerror
597 def diff(self, ui, diffopts, node2, match, prefix, **opts):
634 def diff(self, ui, diffopts, node2, match, prefix, **opts):
598 try:
635 try:
599 node1 = node.bin(self._state[1])
636 node1 = node.bin(self._state[1])
600 # We currently expect node2 to come from substate and be
637 # We currently expect node2 to come from substate and be
601 # in hex format
638 # in hex format
602 if node2 is not None:
639 if node2 is not None:
603 node2 = node.bin(node2)
640 node2 = node.bin(node2)
604 cmdutil.diffordiffstat(ui, self._repo, diffopts,
641 cmdutil.diffordiffstat(ui, self._repo, diffopts,
605 node1, node2, match,
642 node1, node2, match,
606 prefix=posixpath.join(prefix, self._path),
643 prefix=posixpath.join(prefix, self._path),
607 listsubrepos=True, **opts)
644 listsubrepos=True, **opts)
608 except error.RepoLookupError, inst:
645 except error.RepoLookupError, inst:
609 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
646 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
610 % (inst, subrelpath(self)))
647 % (inst, subrelpath(self)))
611
648
612 @annotatesubrepoerror
649 @annotatesubrepoerror
613 def archive(self, ui, archiver, prefix, match=None):
650 def archive(self, ui, archiver, prefix, match=None):
614 self._get(self._state + ('hg',))
651 self._get(self._state + ('hg',))
615 total = abstractsubrepo.archive(self, ui, archiver, prefix, match)
652 total = abstractsubrepo.archive(self, ui, archiver, prefix, match)
616 rev = self._state[1]
653 rev = self._state[1]
617 ctx = self._repo[rev]
654 ctx = self._repo[rev]
618 for subpath in ctx.substate:
655 for subpath in ctx.substate:
619 s = subrepo(ctx, subpath)
656 s = subrepo(ctx, subpath)
620 submatch = matchmod.narrowmatcher(subpath, match)
657 submatch = matchmod.narrowmatcher(subpath, match)
621 total += s.archive(
658 total += s.archive(
622 ui, archiver, os.path.join(prefix, self._path), submatch)
659 ui, archiver, os.path.join(prefix, self._path), submatch)
623 return total
660 return total
624
661
625 @annotatesubrepoerror
662 @annotatesubrepoerror
626 def dirty(self, ignoreupdate=False):
663 def dirty(self, ignoreupdate=False):
627 r = self._state[1]
664 r = self._state[1]
628 if r == '' and not ignoreupdate: # no state recorded
665 if r == '' and not ignoreupdate: # no state recorded
629 return True
666 return True
630 w = self._repo[None]
667 w = self._repo[None]
631 if r != w.p1().hex() and not ignoreupdate:
668 if r != w.p1().hex() and not ignoreupdate:
632 # different version checked out
669 # different version checked out
633 return True
670 return True
634 return w.dirty() # working directory changed
671 return w.dirty() # working directory changed
635
672
636 def basestate(self):
673 def basestate(self):
637 return self._repo['.'].hex()
674 return self._repo['.'].hex()
638
675
639 def checknested(self, path):
676 def checknested(self, path):
640 return self._repo._checknested(self._repo.wjoin(path))
677 return self._repo._checknested(self._repo.wjoin(path))
641
678
642 @annotatesubrepoerror
679 @annotatesubrepoerror
643 def commit(self, text, user, date):
680 def commit(self, text, user, date):
644 # don't bother committing in the subrepo if it's only been
681 # don't bother committing in the subrepo if it's only been
645 # updated
682 # updated
646 if not self.dirty(True):
683 if not self.dirty(True):
647 return self._repo['.'].hex()
684 return self._repo['.'].hex()
648 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
685 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
649 n = self._repo.commit(text, user, date)
686 n = self._repo.commit(text, user, date)
650 if not n:
687 if not n:
651 return self._repo['.'].hex() # different version checked out
688 return self._repo['.'].hex() # different version checked out
652 return node.hex(n)
689 return node.hex(n)
653
690
654 @annotatesubrepoerror
691 @annotatesubrepoerror
692 def phase(self, state):
693 return self._repo[state].phase()
694
695 @annotatesubrepoerror
655 def remove(self):
696 def remove(self):
656 # we can't fully delete the repository as it may contain
697 # we can't fully delete the repository as it may contain
657 # local-only history
698 # local-only history
658 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
699 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
659 hg.clean(self._repo, node.nullid, False)
700 hg.clean(self._repo, node.nullid, False)
660
701
661 def _get(self, state):
702 def _get(self, state):
662 source, revision, kind = state
703 source, revision, kind = state
663 if revision not in self._repo:
704 if revision not in self._repo:
664 self._repo._subsource = source
705 self._repo._subsource = source
665 srcurl = _abssource(self._repo)
706 srcurl = _abssource(self._repo)
666 other = hg.peer(self._repo, {}, srcurl)
707 other = hg.peer(self._repo, {}, srcurl)
667 if len(self._repo) == 0:
708 if len(self._repo) == 0:
668 self._repo.ui.status(_('cloning subrepo %s from %s\n')
709 self._repo.ui.status(_('cloning subrepo %s from %s\n')
669 % (subrelpath(self), srcurl))
710 % (subrelpath(self), srcurl))
670 parentrepo = self._repo._subparent
711 parentrepo = self._repo._subparent
671 shutil.rmtree(self._repo.path)
712 shutil.rmtree(self._repo.path)
672 other, cloned = hg.clone(self._repo._subparent.baseui, {},
713 other, cloned = hg.clone(self._repo._subparent.baseui, {},
673 other, self._repo.root,
714 other, self._repo.root,
674 update=False)
715 update=False)
675 self._repo = cloned.local()
716 self._repo = cloned.local()
676 self._initrepo(parentrepo, source, create=True)
717 self._initrepo(parentrepo, source, create=True)
677 self._cachestorehash(srcurl)
718 self._cachestorehash(srcurl)
678 else:
719 else:
679 self._repo.ui.status(_('pulling subrepo %s from %s\n')
720 self._repo.ui.status(_('pulling subrepo %s from %s\n')
680 % (subrelpath(self), srcurl))
721 % (subrelpath(self), srcurl))
681 cleansub = self.storeclean(srcurl)
722 cleansub = self.storeclean(srcurl)
682 remotebookmarks = other.listkeys('bookmarks')
723 remotebookmarks = other.listkeys('bookmarks')
683 self._repo.pull(other)
724 self._repo.pull(other)
684 bookmarks.updatefromremote(self._repo.ui, self._repo,
725 bookmarks.updatefromremote(self._repo.ui, self._repo,
685 remotebookmarks, srcurl)
726 remotebookmarks, srcurl)
686 if cleansub:
727 if cleansub:
687 # keep the repo clean after pull
728 # keep the repo clean after pull
688 self._cachestorehash(srcurl)
729 self._cachestorehash(srcurl)
689
730
690 @annotatesubrepoerror
731 @annotatesubrepoerror
691 def get(self, state, overwrite=False):
732 def get(self, state, overwrite=False):
692 self._get(state)
733 self._get(state)
693 source, revision, kind = state
734 source, revision, kind = state
694 self._repo.ui.debug("getting subrepo %s\n" % self._path)
735 self._repo.ui.debug("getting subrepo %s\n" % self._path)
695 hg.updaterepo(self._repo, revision, overwrite)
736 hg.updaterepo(self._repo, revision, overwrite)
696
737
697 @annotatesubrepoerror
738 @annotatesubrepoerror
698 def merge(self, state):
739 def merge(self, state):
699 self._get(state)
740 self._get(state)
700 cur = self._repo['.']
741 cur = self._repo['.']
701 dst = self._repo[state[1]]
742 dst = self._repo[state[1]]
702 anc = dst.ancestor(cur)
743 anc = dst.ancestor(cur)
703
744
704 def mergefunc():
745 def mergefunc():
705 if anc == cur and dst.branch() == cur.branch():
746 if anc == cur and dst.branch() == cur.branch():
706 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
747 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
707 hg.update(self._repo, state[1])
748 hg.update(self._repo, state[1])
708 elif anc == dst:
749 elif anc == dst:
709 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
750 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
710 else:
751 else:
711 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
752 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
712 hg.merge(self._repo, state[1], remind=False)
753 hg.merge(self._repo, state[1], remind=False)
713
754
714 wctx = self._repo[None]
755 wctx = self._repo[None]
715 if self.dirty():
756 if self.dirty():
716 if anc != dst:
757 if anc != dst:
717 if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst):
758 if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst):
718 mergefunc()
759 mergefunc()
719 else:
760 else:
720 mergefunc()
761 mergefunc()
721 else:
762 else:
722 mergefunc()
763 mergefunc()
723
764
724 @annotatesubrepoerror
765 @annotatesubrepoerror
725 def push(self, opts):
766 def push(self, opts):
726 force = opts.get('force')
767 force = opts.get('force')
727 newbranch = opts.get('new_branch')
768 newbranch = opts.get('new_branch')
728 ssh = opts.get('ssh')
769 ssh = opts.get('ssh')
729
770
730 # push subrepos depth-first for coherent ordering
771 # push subrepos depth-first for coherent ordering
731 c = self._repo['']
772 c = self._repo['']
732 subs = c.substate # only repos that are committed
773 subs = c.substate # only repos that are committed
733 for s in sorted(subs):
774 for s in sorted(subs):
734 if c.sub(s).push(opts) == 0:
775 if c.sub(s).push(opts) == 0:
735 return False
776 return False
736
777
737 dsturl = _abssource(self._repo, True)
778 dsturl = _abssource(self._repo, True)
738 if not force:
779 if not force:
739 if self.storeclean(dsturl):
780 if self.storeclean(dsturl):
740 self._repo.ui.status(
781 self._repo.ui.status(
741 _('no changes made to subrepo %s since last push to %s\n')
782 _('no changes made to subrepo %s since last push to %s\n')
742 % (subrelpath(self), dsturl))
783 % (subrelpath(self), dsturl))
743 return None
784 return None
744 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
785 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
745 (subrelpath(self), dsturl))
786 (subrelpath(self), dsturl))
746 other = hg.peer(self._repo, {'ssh': ssh}, dsturl)
787 other = hg.peer(self._repo, {'ssh': ssh}, dsturl)
747 res = self._repo.push(other, force, newbranch=newbranch)
788 res = self._repo.push(other, force, newbranch=newbranch)
748
789
749 # the repo is now clean
790 # the repo is now clean
750 self._cachestorehash(dsturl)
791 self._cachestorehash(dsturl)
751 return res
792 return res
752
793
753 @annotatesubrepoerror
794 @annotatesubrepoerror
754 def outgoing(self, ui, dest, opts):
795 def outgoing(self, ui, dest, opts):
755 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
796 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
756
797
757 @annotatesubrepoerror
798 @annotatesubrepoerror
758 def incoming(self, ui, source, opts):
799 def incoming(self, ui, source, opts):
759 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
800 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
760
801
761 @annotatesubrepoerror
802 @annotatesubrepoerror
762 def files(self):
803 def files(self):
763 rev = self._state[1]
804 rev = self._state[1]
764 ctx = self._repo[rev]
805 ctx = self._repo[rev]
765 return ctx.manifest()
806 return ctx.manifest()
766
807
767 def filedata(self, name):
808 def filedata(self, name):
768 rev = self._state[1]
809 rev = self._state[1]
769 return self._repo[rev][name].data()
810 return self._repo[rev][name].data()
770
811
771 def fileflags(self, name):
812 def fileflags(self, name):
772 rev = self._state[1]
813 rev = self._state[1]
773 ctx = self._repo[rev]
814 ctx = self._repo[rev]
774 return ctx.flags(name)
815 return ctx.flags(name)
775
816
776 def walk(self, match):
817 def walk(self, match):
777 ctx = self._repo[None]
818 ctx = self._repo[None]
778 return ctx.walk(match)
819 return ctx.walk(match)
779
820
780 @annotatesubrepoerror
821 @annotatesubrepoerror
781 def forget(self, ui, match, prefix):
822 def forget(self, ui, match, prefix):
782 return cmdutil.forget(ui, self._repo, match,
823 return cmdutil.forget(ui, self._repo, match,
783 os.path.join(prefix, self._path), True)
824 os.path.join(prefix, self._path), True)
784
825
785 @annotatesubrepoerror
826 @annotatesubrepoerror
786 def revert(self, ui, substate, *pats, **opts):
827 def revert(self, ui, substate, *pats, **opts):
787 # reverting a subrepo is a 2 step process:
828 # reverting a subrepo is a 2 step process:
788 # 1. if the no_backup is not set, revert all modified
829 # 1. if the no_backup is not set, revert all modified
789 # files inside the subrepo
830 # files inside the subrepo
790 # 2. update the subrepo to the revision specified in
831 # 2. update the subrepo to the revision specified in
791 # the corresponding substate dictionary
832 # the corresponding substate dictionary
792 ui.status(_('reverting subrepo %s\n') % substate[0])
833 ui.status(_('reverting subrepo %s\n') % substate[0])
793 if not opts.get('no_backup'):
834 if not opts.get('no_backup'):
794 # Revert all files on the subrepo, creating backups
835 # Revert all files on the subrepo, creating backups
795 # Note that this will not recursively revert subrepos
836 # Note that this will not recursively revert subrepos
796 # We could do it if there was a set:subrepos() predicate
837 # We could do it if there was a set:subrepos() predicate
797 opts = opts.copy()
838 opts = opts.copy()
798 opts['date'] = None
839 opts['date'] = None
799 opts['rev'] = substate[1]
840 opts['rev'] = substate[1]
800
841
801 pats = []
842 pats = []
802 if not opts.get('all'):
843 if not opts.get('all'):
803 pats = ['set:modified()']
844 pats = ['set:modified()']
804 self.filerevert(ui, *pats, **opts)
845 self.filerevert(ui, *pats, **opts)
805
846
806 # Update the repo to the revision specified in the given substate
847 # Update the repo to the revision specified in the given substate
807 self.get(substate, overwrite=True)
848 self.get(substate, overwrite=True)
808
849
809 def filerevert(self, ui, *pats, **opts):
850 def filerevert(self, ui, *pats, **opts):
810 ctx = self._repo[opts['rev']]
851 ctx = self._repo[opts['rev']]
811 parents = self._repo.dirstate.parents()
852 parents = self._repo.dirstate.parents()
812 if opts.get('all'):
853 if opts.get('all'):
813 pats = ['set:modified()']
854 pats = ['set:modified()']
814 else:
855 else:
815 pats = []
856 pats = []
816 cmdutil.revert(ui, self._repo, ctx, parents, *pats, **opts)
857 cmdutil.revert(ui, self._repo, ctx, parents, *pats, **opts)
817
858
818 class svnsubrepo(abstractsubrepo):
859 class svnsubrepo(abstractsubrepo):
819 def __init__(self, ctx, path, state):
860 def __init__(self, ctx, path, state):
820 self._path = path
861 self._path = path
821 self._state = state
862 self._state = state
822 self._ctx = ctx
863 self._ctx = ctx
823 self._ui = ctx._repo.ui
864 self._ui = ctx._repo.ui
824 self._exe = util.findexe('svn')
865 self._exe = util.findexe('svn')
825 if not self._exe:
866 if not self._exe:
826 raise util.Abort(_("'svn' executable not found for subrepo '%s'")
867 raise util.Abort(_("'svn' executable not found for subrepo '%s'")
827 % self._path)
868 % self._path)
828
869
829 def _svncommand(self, commands, filename='', failok=False):
870 def _svncommand(self, commands, filename='', failok=False):
830 cmd = [self._exe]
871 cmd = [self._exe]
831 extrakw = {}
872 extrakw = {}
832 if not self._ui.interactive():
873 if not self._ui.interactive():
833 # Making stdin be a pipe should prevent svn from behaving
874 # Making stdin be a pipe should prevent svn from behaving
834 # interactively even if we can't pass --non-interactive.
875 # interactively even if we can't pass --non-interactive.
835 extrakw['stdin'] = subprocess.PIPE
876 extrakw['stdin'] = subprocess.PIPE
836 # Starting in svn 1.5 --non-interactive is a global flag
877 # Starting in svn 1.5 --non-interactive is a global flag
837 # instead of being per-command, but we need to support 1.4 so
878 # instead of being per-command, but we need to support 1.4 so
838 # we have to be intelligent about what commands take
879 # we have to be intelligent about what commands take
839 # --non-interactive.
880 # --non-interactive.
840 if commands[0] in ('update', 'checkout', 'commit'):
881 if commands[0] in ('update', 'checkout', 'commit'):
841 cmd.append('--non-interactive')
882 cmd.append('--non-interactive')
842 cmd.extend(commands)
883 cmd.extend(commands)
843 if filename is not None:
884 if filename is not None:
844 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
885 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
845 cmd.append(path)
886 cmd.append(path)
846 env = dict(os.environ)
887 env = dict(os.environ)
847 # Avoid localized output, preserve current locale for everything else.
888 # Avoid localized output, preserve current locale for everything else.
848 lc_all = env.get('LC_ALL')
889 lc_all = env.get('LC_ALL')
849 if lc_all:
890 if lc_all:
850 env['LANG'] = lc_all
891 env['LANG'] = lc_all
851 del env['LC_ALL']
892 del env['LC_ALL']
852 env['LC_MESSAGES'] = 'C'
893 env['LC_MESSAGES'] = 'C'
853 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
894 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
854 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
895 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
855 universal_newlines=True, env=env, **extrakw)
896 universal_newlines=True, env=env, **extrakw)
856 stdout, stderr = p.communicate()
897 stdout, stderr = p.communicate()
857 stderr = stderr.strip()
898 stderr = stderr.strip()
858 if not failok:
899 if not failok:
859 if p.returncode:
900 if p.returncode:
860 raise util.Abort(stderr or 'exited with code %d' % p.returncode)
901 raise util.Abort(stderr or 'exited with code %d' % p.returncode)
861 if stderr:
902 if stderr:
862 self._ui.warn(stderr + '\n')
903 self._ui.warn(stderr + '\n')
863 return stdout, stderr
904 return stdout, stderr
864
905
865 @propertycache
906 @propertycache
866 def _svnversion(self):
907 def _svnversion(self):
867 output, err = self._svncommand(['--version', '--quiet'], filename=None)
908 output, err = self._svncommand(['--version', '--quiet'], filename=None)
868 m = re.search(r'^(\d+)\.(\d+)', output)
909 m = re.search(r'^(\d+)\.(\d+)', output)
869 if not m:
910 if not m:
870 raise util.Abort(_('cannot retrieve svn tool version'))
911 raise util.Abort(_('cannot retrieve svn tool version'))
871 return (int(m.group(1)), int(m.group(2)))
912 return (int(m.group(1)), int(m.group(2)))
872
913
873 def _wcrevs(self):
914 def _wcrevs(self):
874 # Get the working directory revision as well as the last
915 # Get the working directory revision as well as the last
875 # commit revision so we can compare the subrepo state with
916 # commit revision so we can compare the subrepo state with
876 # both. We used to store the working directory one.
917 # both. We used to store the working directory one.
877 output, err = self._svncommand(['info', '--xml'])
918 output, err = self._svncommand(['info', '--xml'])
878 doc = xml.dom.minidom.parseString(output)
919 doc = xml.dom.minidom.parseString(output)
879 entries = doc.getElementsByTagName('entry')
920 entries = doc.getElementsByTagName('entry')
880 lastrev, rev = '0', '0'
921 lastrev, rev = '0', '0'
881 if entries:
922 if entries:
882 rev = str(entries[0].getAttribute('revision')) or '0'
923 rev = str(entries[0].getAttribute('revision')) or '0'
883 commits = entries[0].getElementsByTagName('commit')
924 commits = entries[0].getElementsByTagName('commit')
884 if commits:
925 if commits:
885 lastrev = str(commits[0].getAttribute('revision')) or '0'
926 lastrev = str(commits[0].getAttribute('revision')) or '0'
886 return (lastrev, rev)
927 return (lastrev, rev)
887
928
888 def _wcrev(self):
929 def _wcrev(self):
889 return self._wcrevs()[0]
930 return self._wcrevs()[0]
890
931
891 def _wcchanged(self):
932 def _wcchanged(self):
892 """Return (changes, extchanges, missing) where changes is True
933 """Return (changes, extchanges, missing) where changes is True
893 if the working directory was changed, extchanges is
934 if the working directory was changed, extchanges is
894 True if any of these changes concern an external entry and missing
935 True if any of these changes concern an external entry and missing
895 is True if any change is a missing entry.
936 is True if any change is a missing entry.
896 """
937 """
897 output, err = self._svncommand(['status', '--xml'])
938 output, err = self._svncommand(['status', '--xml'])
898 externals, changes, missing = [], [], []
939 externals, changes, missing = [], [], []
899 doc = xml.dom.minidom.parseString(output)
940 doc = xml.dom.minidom.parseString(output)
900 for e in doc.getElementsByTagName('entry'):
941 for e in doc.getElementsByTagName('entry'):
901 s = e.getElementsByTagName('wc-status')
942 s = e.getElementsByTagName('wc-status')
902 if not s:
943 if not s:
903 continue
944 continue
904 item = s[0].getAttribute('item')
945 item = s[0].getAttribute('item')
905 props = s[0].getAttribute('props')
946 props = s[0].getAttribute('props')
906 path = e.getAttribute('path')
947 path = e.getAttribute('path')
907 if item == 'external':
948 if item == 'external':
908 externals.append(path)
949 externals.append(path)
909 elif item == 'missing':
950 elif item == 'missing':
910 missing.append(path)
951 missing.append(path)
911 if (item not in ('', 'normal', 'unversioned', 'external')
952 if (item not in ('', 'normal', 'unversioned', 'external')
912 or props not in ('', 'none', 'normal')):
953 or props not in ('', 'none', 'normal')):
913 changes.append(path)
954 changes.append(path)
914 for path in changes:
955 for path in changes:
915 for ext in externals:
956 for ext in externals:
916 if path == ext or path.startswith(ext + os.sep):
957 if path == ext or path.startswith(ext + os.sep):
917 return True, True, bool(missing)
958 return True, True, bool(missing)
918 return bool(changes), False, bool(missing)
959 return bool(changes), False, bool(missing)
919
960
920 def dirty(self, ignoreupdate=False):
961 def dirty(self, ignoreupdate=False):
921 if not self._wcchanged()[0]:
962 if not self._wcchanged()[0]:
922 if self._state[1] in self._wcrevs() or ignoreupdate:
963 if self._state[1] in self._wcrevs() or ignoreupdate:
923 return False
964 return False
924 return True
965 return True
925
966
926 def basestate(self):
967 def basestate(self):
927 lastrev, rev = self._wcrevs()
968 lastrev, rev = self._wcrevs()
928 if lastrev != rev:
969 if lastrev != rev:
929 # Last committed rev is not the same than rev. We would
970 # Last committed rev is not the same than rev. We would
930 # like to take lastrev but we do not know if the subrepo
971 # like to take lastrev but we do not know if the subrepo
931 # URL exists at lastrev. Test it and fallback to rev it
972 # URL exists at lastrev. Test it and fallback to rev it
932 # is not there.
973 # is not there.
933 try:
974 try:
934 self._svncommand(['list', '%s@%s' % (self._state[0], lastrev)])
975 self._svncommand(['list', '%s@%s' % (self._state[0], lastrev)])
935 return lastrev
976 return lastrev
936 except error.Abort:
977 except error.Abort:
937 pass
978 pass
938 return rev
979 return rev
939
980
940 @annotatesubrepoerror
981 @annotatesubrepoerror
941 def commit(self, text, user, date):
982 def commit(self, text, user, date):
942 # user and date are out of our hands since svn is centralized
983 # user and date are out of our hands since svn is centralized
943 changed, extchanged, missing = self._wcchanged()
984 changed, extchanged, missing = self._wcchanged()
944 if not changed:
985 if not changed:
945 return self.basestate()
986 return self.basestate()
946 if extchanged:
987 if extchanged:
947 # Do not try to commit externals
988 # Do not try to commit externals
948 raise util.Abort(_('cannot commit svn externals'))
989 raise util.Abort(_('cannot commit svn externals'))
949 if missing:
990 if missing:
950 # svn can commit with missing entries but aborting like hg
991 # svn can commit with missing entries but aborting like hg
951 # seems a better approach.
992 # seems a better approach.
952 raise util.Abort(_('cannot commit missing svn entries'))
993 raise util.Abort(_('cannot commit missing svn entries'))
953 commitinfo, err = self._svncommand(['commit', '-m', text])
994 commitinfo, err = self._svncommand(['commit', '-m', text])
954 self._ui.status(commitinfo)
995 self._ui.status(commitinfo)
955 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
996 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
956 if not newrev:
997 if not newrev:
957 if not commitinfo.strip():
998 if not commitinfo.strip():
958 # Sometimes, our definition of "changed" differs from
999 # Sometimes, our definition of "changed" differs from
959 # svn one. For instance, svn ignores missing files
1000 # svn one. For instance, svn ignores missing files
960 # when committing. If there are only missing files, no
1001 # when committing. If there are only missing files, no
961 # commit is made, no output and no error code.
1002 # commit is made, no output and no error code.
962 raise util.Abort(_('failed to commit svn changes'))
1003 raise util.Abort(_('failed to commit svn changes'))
963 raise util.Abort(commitinfo.splitlines()[-1])
1004 raise util.Abort(commitinfo.splitlines()[-1])
964 newrev = newrev.groups()[0]
1005 newrev = newrev.groups()[0]
965 self._ui.status(self._svncommand(['update', '-r', newrev])[0])
1006 self._ui.status(self._svncommand(['update', '-r', newrev])[0])
966 return newrev
1007 return newrev
967
1008
968 @annotatesubrepoerror
1009 @annotatesubrepoerror
969 def remove(self):
1010 def remove(self):
970 if self.dirty():
1011 if self.dirty():
971 self._ui.warn(_('not removing repo %s because '
1012 self._ui.warn(_('not removing repo %s because '
972 'it has changes.\n' % self._path))
1013 'it has changes.\n' % self._path))
973 return
1014 return
974 self._ui.note(_('removing subrepo %s\n') % self._path)
1015 self._ui.note(_('removing subrepo %s\n') % self._path)
975
1016
976 def onerror(function, path, excinfo):
1017 def onerror(function, path, excinfo):
977 if function is not os.remove:
1018 if function is not os.remove:
978 raise
1019 raise
979 # read-only files cannot be unlinked under Windows
1020 # read-only files cannot be unlinked under Windows
980 s = os.stat(path)
1021 s = os.stat(path)
981 if (s.st_mode & stat.S_IWRITE) != 0:
1022 if (s.st_mode & stat.S_IWRITE) != 0:
982 raise
1023 raise
983 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
1024 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
984 os.remove(path)
1025 os.remove(path)
985
1026
986 path = self._ctx._repo.wjoin(self._path)
1027 path = self._ctx._repo.wjoin(self._path)
987 shutil.rmtree(path, onerror=onerror)
1028 shutil.rmtree(path, onerror=onerror)
988 try:
1029 try:
989 os.removedirs(os.path.dirname(path))
1030 os.removedirs(os.path.dirname(path))
990 except OSError:
1031 except OSError:
991 pass
1032 pass
992
1033
993 @annotatesubrepoerror
1034 @annotatesubrepoerror
994 def get(self, state, overwrite=False):
1035 def get(self, state, overwrite=False):
995 if overwrite:
1036 if overwrite:
996 self._svncommand(['revert', '--recursive'])
1037 self._svncommand(['revert', '--recursive'])
997 args = ['checkout']
1038 args = ['checkout']
998 if self._svnversion >= (1, 5):
1039 if self._svnversion >= (1, 5):
999 args.append('--force')
1040 args.append('--force')
1000 # The revision must be specified at the end of the URL to properly
1041 # The revision must be specified at the end of the URL to properly
1001 # update to a directory which has since been deleted and recreated.
1042 # update to a directory which has since been deleted and recreated.
1002 args.append('%s@%s' % (state[0], state[1]))
1043 args.append('%s@%s' % (state[0], state[1]))
1003 status, err = self._svncommand(args, failok=True)
1044 status, err = self._svncommand(args, failok=True)
1004 _sanitize(self._ui, self._path)
1045 _sanitize(self._ui, self._path)
1005 if not re.search('Checked out revision [0-9]+.', status):
1046 if not re.search('Checked out revision [0-9]+.', status):
1006 if ('is already a working copy for a different URL' in err
1047 if ('is already a working copy for a different URL' in err
1007 and (self._wcchanged()[:2] == (False, False))):
1048 and (self._wcchanged()[:2] == (False, False))):
1008 # obstructed but clean working copy, so just blow it away.
1049 # obstructed but clean working copy, so just blow it away.
1009 self.remove()
1050 self.remove()
1010 self.get(state, overwrite=False)
1051 self.get(state, overwrite=False)
1011 return
1052 return
1012 raise util.Abort((status or err).splitlines()[-1])
1053 raise util.Abort((status or err).splitlines()[-1])
1013 self._ui.status(status)
1054 self._ui.status(status)
1014
1055
1015 @annotatesubrepoerror
1056 @annotatesubrepoerror
1016 def merge(self, state):
1057 def merge(self, state):
1017 old = self._state[1]
1058 old = self._state[1]
1018 new = state[1]
1059 new = state[1]
1019 wcrev = self._wcrev()
1060 wcrev = self._wcrev()
1020 if new != wcrev:
1061 if new != wcrev:
1021 dirty = old == wcrev or self._wcchanged()[0]
1062 dirty = old == wcrev or self._wcchanged()[0]
1022 if _updateprompt(self._ui, self, dirty, wcrev, new):
1063 if _updateprompt(self._ui, self, dirty, wcrev, new):
1023 self.get(state, False)
1064 self.get(state, False)
1024
1065
1025 def push(self, opts):
1066 def push(self, opts):
1026 # push is a no-op for SVN
1067 # push is a no-op for SVN
1027 return True
1068 return True
1028
1069
1029 @annotatesubrepoerror
1070 @annotatesubrepoerror
1030 def files(self):
1071 def files(self):
1031 output = self._svncommand(['list', '--recursive', '--xml'])[0]
1072 output = self._svncommand(['list', '--recursive', '--xml'])[0]
1032 doc = xml.dom.minidom.parseString(output)
1073 doc = xml.dom.minidom.parseString(output)
1033 paths = []
1074 paths = []
1034 for e in doc.getElementsByTagName('entry'):
1075 for e in doc.getElementsByTagName('entry'):
1035 kind = str(e.getAttribute('kind'))
1076 kind = str(e.getAttribute('kind'))
1036 if kind != 'file':
1077 if kind != 'file':
1037 continue
1078 continue
1038 name = ''.join(c.data for c
1079 name = ''.join(c.data for c
1039 in e.getElementsByTagName('name')[0].childNodes
1080 in e.getElementsByTagName('name')[0].childNodes
1040 if c.nodeType == c.TEXT_NODE)
1081 if c.nodeType == c.TEXT_NODE)
1041 paths.append(name.encode('utf-8'))
1082 paths.append(name.encode('utf-8'))
1042 return paths
1083 return paths
1043
1084
1044 def filedata(self, name):
1085 def filedata(self, name):
1045 return self._svncommand(['cat'], name)[0]
1086 return self._svncommand(['cat'], name)[0]
1046
1087
1047
1088
1048 class gitsubrepo(abstractsubrepo):
1089 class gitsubrepo(abstractsubrepo):
1049 def __init__(self, ctx, path, state):
1090 def __init__(self, ctx, path, state):
1050 self._state = state
1091 self._state = state
1051 self._ctx = ctx
1092 self._ctx = ctx
1052 self._path = path
1093 self._path = path
1053 self._relpath = os.path.join(reporelpath(ctx._repo), path)
1094 self._relpath = os.path.join(reporelpath(ctx._repo), path)
1054 self._abspath = ctx._repo.wjoin(path)
1095 self._abspath = ctx._repo.wjoin(path)
1055 self._subparent = ctx._repo
1096 self._subparent = ctx._repo
1056 self._ui = ctx._repo.ui
1097 self._ui = ctx._repo.ui
1057 self._ensuregit()
1098 self._ensuregit()
1058
1099
1059 def _ensuregit(self):
1100 def _ensuregit(self):
1060 try:
1101 try:
1061 self._gitexecutable = 'git'
1102 self._gitexecutable = 'git'
1062 out, err = self._gitnodir(['--version'])
1103 out, err = self._gitnodir(['--version'])
1063 except OSError, e:
1104 except OSError, e:
1064 if e.errno != 2 or os.name != 'nt':
1105 if e.errno != 2 or os.name != 'nt':
1065 raise
1106 raise
1066 self._gitexecutable = 'git.cmd'
1107 self._gitexecutable = 'git.cmd'
1067 out, err = self._gitnodir(['--version'])
1108 out, err = self._gitnodir(['--version'])
1068 m = re.search(r'^git version (\d+)\.(\d+)\.(\d+)', out)
1109 m = re.search(r'^git version (\d+)\.(\d+)\.(\d+)', out)
1069 if not m:
1110 if not m:
1070 self._ui.warn(_('cannot retrieve git version'))
1111 self._ui.warn(_('cannot retrieve git version'))
1071 return
1112 return
1072 version = (int(m.group(1)), m.group(2), m.group(3))
1113 version = (int(m.group(1)), m.group(2), m.group(3))
1073 # git 1.4.0 can't work at all, but 1.5.X can in at least some cases,
1114 # git 1.4.0 can't work at all, but 1.5.X can in at least some cases,
1074 # despite the docstring comment. For now, error on 1.4.0, warn on
1115 # despite the docstring comment. For now, error on 1.4.0, warn on
1075 # 1.5.0 but attempt to continue.
1116 # 1.5.0 but attempt to continue.
1076 if version < (1, 5, 0):
1117 if version < (1, 5, 0):
1077 raise util.Abort(_('git subrepo requires at least 1.6.0 or later'))
1118 raise util.Abort(_('git subrepo requires at least 1.6.0 or later'))
1078 elif version < (1, 6, 0):
1119 elif version < (1, 6, 0):
1079 self._ui.warn(_('git subrepo requires at least 1.6.0 or later'))
1120 self._ui.warn(_('git subrepo requires at least 1.6.0 or later'))
1080
1121
1081 def _gitcommand(self, commands, env=None, stream=False):
1122 def _gitcommand(self, commands, env=None, stream=False):
1082 return self._gitdir(commands, env=env, stream=stream)[0]
1123 return self._gitdir(commands, env=env, stream=stream)[0]
1083
1124
1084 def _gitdir(self, commands, env=None, stream=False):
1125 def _gitdir(self, commands, env=None, stream=False):
1085 return self._gitnodir(commands, env=env, stream=stream,
1126 return self._gitnodir(commands, env=env, stream=stream,
1086 cwd=self._abspath)
1127 cwd=self._abspath)
1087
1128
1088 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
1129 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
1089 """Calls the git command
1130 """Calls the git command
1090
1131
1091 The methods tries to call the git command. versions prior to 1.6.0
1132 The methods tries to call the git command. versions prior to 1.6.0
1092 are not supported and very probably fail.
1133 are not supported and very probably fail.
1093 """
1134 """
1094 self._ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
1135 self._ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
1095 # unless ui.quiet is set, print git's stderr,
1136 # unless ui.quiet is set, print git's stderr,
1096 # which is mostly progress and useful info
1137 # which is mostly progress and useful info
1097 errpipe = None
1138 errpipe = None
1098 if self._ui.quiet:
1139 if self._ui.quiet:
1099 errpipe = open(os.devnull, 'w')
1140 errpipe = open(os.devnull, 'w')
1100 p = subprocess.Popen([self._gitexecutable] + commands, bufsize=-1,
1141 p = subprocess.Popen([self._gitexecutable] + commands, bufsize=-1,
1101 cwd=cwd, env=env, close_fds=util.closefds,
1142 cwd=cwd, env=env, close_fds=util.closefds,
1102 stdout=subprocess.PIPE, stderr=errpipe)
1143 stdout=subprocess.PIPE, stderr=errpipe)
1103 if stream:
1144 if stream:
1104 return p.stdout, None
1145 return p.stdout, None
1105
1146
1106 retdata = p.stdout.read().strip()
1147 retdata = p.stdout.read().strip()
1107 # wait for the child to exit to avoid race condition.
1148 # wait for the child to exit to avoid race condition.
1108 p.wait()
1149 p.wait()
1109
1150
1110 if p.returncode != 0 and p.returncode != 1:
1151 if p.returncode != 0 and p.returncode != 1:
1111 # there are certain error codes that are ok
1152 # there are certain error codes that are ok
1112 command = commands[0]
1153 command = commands[0]
1113 if command in ('cat-file', 'symbolic-ref'):
1154 if command in ('cat-file', 'symbolic-ref'):
1114 return retdata, p.returncode
1155 return retdata, p.returncode
1115 # for all others, abort
1156 # for all others, abort
1116 raise util.Abort('git %s error %d in %s' %
1157 raise util.Abort('git %s error %d in %s' %
1117 (command, p.returncode, self._relpath))
1158 (command, p.returncode, self._relpath))
1118
1159
1119 return retdata, p.returncode
1160 return retdata, p.returncode
1120
1161
1121 def _gitmissing(self):
1162 def _gitmissing(self):
1122 return not os.path.exists(os.path.join(self._abspath, '.git'))
1163 return not os.path.exists(os.path.join(self._abspath, '.git'))
1123
1164
1124 def _gitstate(self):
1165 def _gitstate(self):
1125 return self._gitcommand(['rev-parse', 'HEAD'])
1166 return self._gitcommand(['rev-parse', 'HEAD'])
1126
1167
1127 def _gitcurrentbranch(self):
1168 def _gitcurrentbranch(self):
1128 current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
1169 current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
1129 if err:
1170 if err:
1130 current = None
1171 current = None
1131 return current
1172 return current
1132
1173
1133 def _gitremote(self, remote):
1174 def _gitremote(self, remote):
1134 out = self._gitcommand(['remote', 'show', '-n', remote])
1175 out = self._gitcommand(['remote', 'show', '-n', remote])
1135 line = out.split('\n')[1]
1176 line = out.split('\n')[1]
1136 i = line.index('URL: ') + len('URL: ')
1177 i = line.index('URL: ') + len('URL: ')
1137 return line[i:]
1178 return line[i:]
1138
1179
1139 def _githavelocally(self, revision):
1180 def _githavelocally(self, revision):
1140 out, code = self._gitdir(['cat-file', '-e', revision])
1181 out, code = self._gitdir(['cat-file', '-e', revision])
1141 return code == 0
1182 return code == 0
1142
1183
1143 def _gitisancestor(self, r1, r2):
1184 def _gitisancestor(self, r1, r2):
1144 base = self._gitcommand(['merge-base', r1, r2])
1185 base = self._gitcommand(['merge-base', r1, r2])
1145 return base == r1
1186 return base == r1
1146
1187
1147 def _gitisbare(self):
1188 def _gitisbare(self):
1148 return self._gitcommand(['config', '--bool', 'core.bare']) == 'true'
1189 return self._gitcommand(['config', '--bool', 'core.bare']) == 'true'
1149
1190
1150 def _gitupdatestat(self):
1191 def _gitupdatestat(self):
1151 """This must be run before git diff-index.
1192 """This must be run before git diff-index.
1152 diff-index only looks at changes to file stat;
1193 diff-index only looks at changes to file stat;
1153 this command looks at file contents and updates the stat."""
1194 this command looks at file contents and updates the stat."""
1154 self._gitcommand(['update-index', '-q', '--refresh'])
1195 self._gitcommand(['update-index', '-q', '--refresh'])
1155
1196
1156 def _gitbranchmap(self):
1197 def _gitbranchmap(self):
1157 '''returns 2 things:
1198 '''returns 2 things:
1158 a map from git branch to revision
1199 a map from git branch to revision
1159 a map from revision to branches'''
1200 a map from revision to branches'''
1160 branch2rev = {}
1201 branch2rev = {}
1161 rev2branch = {}
1202 rev2branch = {}
1162
1203
1163 out = self._gitcommand(['for-each-ref', '--format',
1204 out = self._gitcommand(['for-each-ref', '--format',
1164 '%(objectname) %(refname)'])
1205 '%(objectname) %(refname)'])
1165 for line in out.split('\n'):
1206 for line in out.split('\n'):
1166 revision, ref = line.split(' ')
1207 revision, ref = line.split(' ')
1167 if (not ref.startswith('refs/heads/') and
1208 if (not ref.startswith('refs/heads/') and
1168 not ref.startswith('refs/remotes/')):
1209 not ref.startswith('refs/remotes/')):
1169 continue
1210 continue
1170 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
1211 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
1171 continue # ignore remote/HEAD redirects
1212 continue # ignore remote/HEAD redirects
1172 branch2rev[ref] = revision
1213 branch2rev[ref] = revision
1173 rev2branch.setdefault(revision, []).append(ref)
1214 rev2branch.setdefault(revision, []).append(ref)
1174 return branch2rev, rev2branch
1215 return branch2rev, rev2branch
1175
1216
1176 def _gittracking(self, branches):
1217 def _gittracking(self, branches):
1177 'return map of remote branch to local tracking branch'
1218 'return map of remote branch to local tracking branch'
1178 # assumes no more than one local tracking branch for each remote
1219 # assumes no more than one local tracking branch for each remote
1179 tracking = {}
1220 tracking = {}
1180 for b in branches:
1221 for b in branches:
1181 if b.startswith('refs/remotes/'):
1222 if b.startswith('refs/remotes/'):
1182 continue
1223 continue
1183 bname = b.split('/', 2)[2]
1224 bname = b.split('/', 2)[2]
1184 remote = self._gitcommand(['config', 'branch.%s.remote' % bname])
1225 remote = self._gitcommand(['config', 'branch.%s.remote' % bname])
1185 if remote:
1226 if remote:
1186 ref = self._gitcommand(['config', 'branch.%s.merge' % bname])
1227 ref = self._gitcommand(['config', 'branch.%s.merge' % bname])
1187 tracking['refs/remotes/%s/%s' %
1228 tracking['refs/remotes/%s/%s' %
1188 (remote, ref.split('/', 2)[2])] = b
1229 (remote, ref.split('/', 2)[2])] = b
1189 return tracking
1230 return tracking
1190
1231
1191 def _abssource(self, source):
1232 def _abssource(self, source):
1192 if '://' not in source:
1233 if '://' not in source:
1193 # recognize the scp syntax as an absolute source
1234 # recognize the scp syntax as an absolute source
1194 colon = source.find(':')
1235 colon = source.find(':')
1195 if colon != -1 and '/' not in source[:colon]:
1236 if colon != -1 and '/' not in source[:colon]:
1196 return source
1237 return source
1197 self._subsource = source
1238 self._subsource = source
1198 return _abssource(self)
1239 return _abssource(self)
1199
1240
1200 def _fetch(self, source, revision):
1241 def _fetch(self, source, revision):
1201 if self._gitmissing():
1242 if self._gitmissing():
1202 source = self._abssource(source)
1243 source = self._abssource(source)
1203 self._ui.status(_('cloning subrepo %s from %s\n') %
1244 self._ui.status(_('cloning subrepo %s from %s\n') %
1204 (self._relpath, source))
1245 (self._relpath, source))
1205 self._gitnodir(['clone', source, self._abspath])
1246 self._gitnodir(['clone', source, self._abspath])
1206 if self._githavelocally(revision):
1247 if self._githavelocally(revision):
1207 return
1248 return
1208 self._ui.status(_('pulling subrepo %s from %s\n') %
1249 self._ui.status(_('pulling subrepo %s from %s\n') %
1209 (self._relpath, self._gitremote('origin')))
1250 (self._relpath, self._gitremote('origin')))
1210 # try only origin: the originally cloned repo
1251 # try only origin: the originally cloned repo
1211 self._gitcommand(['fetch'])
1252 self._gitcommand(['fetch'])
1212 if not self._githavelocally(revision):
1253 if not self._githavelocally(revision):
1213 raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
1254 raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
1214 (revision, self._relpath))
1255 (revision, self._relpath))
1215
1256
1216 @annotatesubrepoerror
1257 @annotatesubrepoerror
1217 def dirty(self, ignoreupdate=False):
1258 def dirty(self, ignoreupdate=False):
1218 if self._gitmissing():
1259 if self._gitmissing():
1219 return self._state[1] != ''
1260 return self._state[1] != ''
1220 if self._gitisbare():
1261 if self._gitisbare():
1221 return True
1262 return True
1222 if not ignoreupdate and self._state[1] != self._gitstate():
1263 if not ignoreupdate and self._state[1] != self._gitstate():
1223 # different version checked out
1264 # different version checked out
1224 return True
1265 return True
1225 # check for staged changes or modified files; ignore untracked files
1266 # check for staged changes or modified files; ignore untracked files
1226 self._gitupdatestat()
1267 self._gitupdatestat()
1227 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1268 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1228 return code == 1
1269 return code == 1
1229
1270
1230 def basestate(self):
1271 def basestate(self):
1231 return self._gitstate()
1272 return self._gitstate()
1232
1273
1233 @annotatesubrepoerror
1274 @annotatesubrepoerror
1234 def get(self, state, overwrite=False):
1275 def get(self, state, overwrite=False):
1235 source, revision, kind = state
1276 source, revision, kind = state
1236 if not revision:
1277 if not revision:
1237 self.remove()
1278 self.remove()
1238 return
1279 return
1239 self._fetch(source, revision)
1280 self._fetch(source, revision)
1240 # if the repo was set to be bare, unbare it
1281 # if the repo was set to be bare, unbare it
1241 if self._gitisbare():
1282 if self._gitisbare():
1242 self._gitcommand(['config', 'core.bare', 'false'])
1283 self._gitcommand(['config', 'core.bare', 'false'])
1243 if self._gitstate() == revision:
1284 if self._gitstate() == revision:
1244 self._gitcommand(['reset', '--hard', 'HEAD'])
1285 self._gitcommand(['reset', '--hard', 'HEAD'])
1245 return
1286 return
1246 elif self._gitstate() == revision:
1287 elif self._gitstate() == revision:
1247 if overwrite:
1288 if overwrite:
1248 # first reset the index to unmark new files for commit, because
1289 # first reset the index to unmark new files for commit, because
1249 # reset --hard will otherwise throw away files added for commit,
1290 # reset --hard will otherwise throw away files added for commit,
1250 # not just unmark them.
1291 # not just unmark them.
1251 self._gitcommand(['reset', 'HEAD'])
1292 self._gitcommand(['reset', 'HEAD'])
1252 self._gitcommand(['reset', '--hard', 'HEAD'])
1293 self._gitcommand(['reset', '--hard', 'HEAD'])
1253 return
1294 return
1254 branch2rev, rev2branch = self._gitbranchmap()
1295 branch2rev, rev2branch = self._gitbranchmap()
1255
1296
1256 def checkout(args):
1297 def checkout(args):
1257 cmd = ['checkout']
1298 cmd = ['checkout']
1258 if overwrite:
1299 if overwrite:
1259 # first reset the index to unmark new files for commit, because
1300 # first reset the index to unmark new files for commit, because
1260 # the -f option will otherwise throw away files added for
1301 # the -f option will otherwise throw away files added for
1261 # commit, not just unmark them.
1302 # commit, not just unmark them.
1262 self._gitcommand(['reset', 'HEAD'])
1303 self._gitcommand(['reset', 'HEAD'])
1263 cmd.append('-f')
1304 cmd.append('-f')
1264 self._gitcommand(cmd + args)
1305 self._gitcommand(cmd + args)
1265 _sanitize(self._ui, self._path)
1306 _sanitize(self._ui, self._path)
1266
1307
1267 def rawcheckout():
1308 def rawcheckout():
1268 # no branch to checkout, check it out with no branch
1309 # no branch to checkout, check it out with no branch
1269 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
1310 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
1270 self._relpath)
1311 self._relpath)
1271 self._ui.warn(_('check out a git branch if you intend '
1312 self._ui.warn(_('check out a git branch if you intend '
1272 'to make changes\n'))
1313 'to make changes\n'))
1273 checkout(['-q', revision])
1314 checkout(['-q', revision])
1274
1315
1275 if revision not in rev2branch:
1316 if revision not in rev2branch:
1276 rawcheckout()
1317 rawcheckout()
1277 return
1318 return
1278 branches = rev2branch[revision]
1319 branches = rev2branch[revision]
1279 firstlocalbranch = None
1320 firstlocalbranch = None
1280 for b in branches:
1321 for b in branches:
1281 if b == 'refs/heads/master':
1322 if b == 'refs/heads/master':
1282 # master trumps all other branches
1323 # master trumps all other branches
1283 checkout(['refs/heads/master'])
1324 checkout(['refs/heads/master'])
1284 return
1325 return
1285 if not firstlocalbranch and not b.startswith('refs/remotes/'):
1326 if not firstlocalbranch and not b.startswith('refs/remotes/'):
1286 firstlocalbranch = b
1327 firstlocalbranch = b
1287 if firstlocalbranch:
1328 if firstlocalbranch:
1288 checkout([firstlocalbranch])
1329 checkout([firstlocalbranch])
1289 return
1330 return
1290
1331
1291 tracking = self._gittracking(branch2rev.keys())
1332 tracking = self._gittracking(branch2rev.keys())
1292 # choose a remote branch already tracked if possible
1333 # choose a remote branch already tracked if possible
1293 remote = branches[0]
1334 remote = branches[0]
1294 if remote not in tracking:
1335 if remote not in tracking:
1295 for b in branches:
1336 for b in branches:
1296 if b in tracking:
1337 if b in tracking:
1297 remote = b
1338 remote = b
1298 break
1339 break
1299
1340
1300 if remote not in tracking:
1341 if remote not in tracking:
1301 # create a new local tracking branch
1342 # create a new local tracking branch
1302 local = remote.split('/', 3)[3]
1343 local = remote.split('/', 3)[3]
1303 checkout(['-b', local, remote])
1344 checkout(['-b', local, remote])
1304 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
1345 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
1305 # When updating to a tracked remote branch,
1346 # When updating to a tracked remote branch,
1306 # if the local tracking branch is downstream of it,
1347 # if the local tracking branch is downstream of it,
1307 # a normal `git pull` would have performed a "fast-forward merge"
1348 # a normal `git pull` would have performed a "fast-forward merge"
1308 # which is equivalent to updating the local branch to the remote.
1349 # which is equivalent to updating the local branch to the remote.
1309 # Since we are only looking at branching at update, we need to
1350 # Since we are only looking at branching at update, we need to
1310 # detect this situation and perform this action lazily.
1351 # detect this situation and perform this action lazily.
1311 if tracking[remote] != self._gitcurrentbranch():
1352 if tracking[remote] != self._gitcurrentbranch():
1312 checkout([tracking[remote]])
1353 checkout([tracking[remote]])
1313 self._gitcommand(['merge', '--ff', remote])
1354 self._gitcommand(['merge', '--ff', remote])
1314 else:
1355 else:
1315 # a real merge would be required, just checkout the revision
1356 # a real merge would be required, just checkout the revision
1316 rawcheckout()
1357 rawcheckout()
1317
1358
1318 @annotatesubrepoerror
1359 @annotatesubrepoerror
1319 def commit(self, text, user, date):
1360 def commit(self, text, user, date):
1320 if self._gitmissing():
1361 if self._gitmissing():
1321 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1362 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1322 cmd = ['commit', '-a', '-m', text]
1363 cmd = ['commit', '-a', '-m', text]
1323 env = os.environ.copy()
1364 env = os.environ.copy()
1324 if user:
1365 if user:
1325 cmd += ['--author', user]
1366 cmd += ['--author', user]
1326 if date:
1367 if date:
1327 # git's date parser silently ignores when seconds < 1e9
1368 # git's date parser silently ignores when seconds < 1e9
1328 # convert to ISO8601
1369 # convert to ISO8601
1329 env['GIT_AUTHOR_DATE'] = util.datestr(date,
1370 env['GIT_AUTHOR_DATE'] = util.datestr(date,
1330 '%Y-%m-%dT%H:%M:%S %1%2')
1371 '%Y-%m-%dT%H:%M:%S %1%2')
1331 self._gitcommand(cmd, env=env)
1372 self._gitcommand(cmd, env=env)
1332 # make sure commit works otherwise HEAD might not exist under certain
1373 # make sure commit works otherwise HEAD might not exist under certain
1333 # circumstances
1374 # circumstances
1334 return self._gitstate()
1375 return self._gitstate()
1335
1376
1336 @annotatesubrepoerror
1377 @annotatesubrepoerror
1337 def merge(self, state):
1378 def merge(self, state):
1338 source, revision, kind = state
1379 source, revision, kind = state
1339 self._fetch(source, revision)
1380 self._fetch(source, revision)
1340 base = self._gitcommand(['merge-base', revision, self._state[1]])
1381 base = self._gitcommand(['merge-base', revision, self._state[1]])
1341 self._gitupdatestat()
1382 self._gitupdatestat()
1342 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1383 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1343
1384
1344 def mergefunc():
1385 def mergefunc():
1345 if base == revision:
1386 if base == revision:
1346 self.get(state) # fast forward merge
1387 self.get(state) # fast forward merge
1347 elif base != self._state[1]:
1388 elif base != self._state[1]:
1348 self._gitcommand(['merge', '--no-commit', revision])
1389 self._gitcommand(['merge', '--no-commit', revision])
1349 _sanitize(self._ui, self._path)
1390 _sanitize(self._ui, self._path)
1350
1391
1351 if self.dirty():
1392 if self.dirty():
1352 if self._gitstate() != revision:
1393 if self._gitstate() != revision:
1353 dirty = self._gitstate() == self._state[1] or code != 0
1394 dirty = self._gitstate() == self._state[1] or code != 0
1354 if _updateprompt(self._ui, self, dirty,
1395 if _updateprompt(self._ui, self, dirty,
1355 self._state[1][:7], revision[:7]):
1396 self._state[1][:7], revision[:7]):
1356 mergefunc()
1397 mergefunc()
1357 else:
1398 else:
1358 mergefunc()
1399 mergefunc()
1359
1400
1360 @annotatesubrepoerror
1401 @annotatesubrepoerror
1361 def push(self, opts):
1402 def push(self, opts):
1362 force = opts.get('force')
1403 force = opts.get('force')
1363
1404
1364 if not self._state[1]:
1405 if not self._state[1]:
1365 return True
1406 return True
1366 if self._gitmissing():
1407 if self._gitmissing():
1367 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1408 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1368 # if a branch in origin contains the revision, nothing to do
1409 # if a branch in origin contains the revision, nothing to do
1369 branch2rev, rev2branch = self._gitbranchmap()
1410 branch2rev, rev2branch = self._gitbranchmap()
1370 if self._state[1] in rev2branch:
1411 if self._state[1] in rev2branch:
1371 for b in rev2branch[self._state[1]]:
1412 for b in rev2branch[self._state[1]]:
1372 if b.startswith('refs/remotes/origin/'):
1413 if b.startswith('refs/remotes/origin/'):
1373 return True
1414 return True
1374 for b, revision in branch2rev.iteritems():
1415 for b, revision in branch2rev.iteritems():
1375 if b.startswith('refs/remotes/origin/'):
1416 if b.startswith('refs/remotes/origin/'):
1376 if self._gitisancestor(self._state[1], revision):
1417 if self._gitisancestor(self._state[1], revision):
1377 return True
1418 return True
1378 # otherwise, try to push the currently checked out branch
1419 # otherwise, try to push the currently checked out branch
1379 cmd = ['push']
1420 cmd = ['push']
1380 if force:
1421 if force:
1381 cmd.append('--force')
1422 cmd.append('--force')
1382
1423
1383 current = self._gitcurrentbranch()
1424 current = self._gitcurrentbranch()
1384 if current:
1425 if current:
1385 # determine if the current branch is even useful
1426 # determine if the current branch is even useful
1386 if not self._gitisancestor(self._state[1], current):
1427 if not self._gitisancestor(self._state[1], current):
1387 self._ui.warn(_('unrelated git branch checked out '
1428 self._ui.warn(_('unrelated git branch checked out '
1388 'in subrepo %s\n') % self._relpath)
1429 'in subrepo %s\n') % self._relpath)
1389 return False
1430 return False
1390 self._ui.status(_('pushing branch %s of subrepo %s\n') %
1431 self._ui.status(_('pushing branch %s of subrepo %s\n') %
1391 (current.split('/', 2)[2], self._relpath))
1432 (current.split('/', 2)[2], self._relpath))
1392 self._gitcommand(cmd + ['origin', current])
1433 self._gitcommand(cmd + ['origin', current])
1393 return True
1434 return True
1394 else:
1435 else:
1395 self._ui.warn(_('no branch checked out in subrepo %s\n'
1436 self._ui.warn(_('no branch checked out in subrepo %s\n'
1396 'cannot push revision %s\n') %
1437 'cannot push revision %s\n') %
1397 (self._relpath, self._state[1]))
1438 (self._relpath, self._state[1]))
1398 return False
1439 return False
1399
1440
1400 @annotatesubrepoerror
1441 @annotatesubrepoerror
1401 def remove(self):
1442 def remove(self):
1402 if self._gitmissing():
1443 if self._gitmissing():
1403 return
1444 return
1404 if self.dirty():
1445 if self.dirty():
1405 self._ui.warn(_('not removing repo %s because '
1446 self._ui.warn(_('not removing repo %s because '
1406 'it has changes.\n') % self._relpath)
1447 'it has changes.\n') % self._relpath)
1407 return
1448 return
1408 # we can't fully delete the repository as it may contain
1449 # we can't fully delete the repository as it may contain
1409 # local-only history
1450 # local-only history
1410 self._ui.note(_('removing subrepo %s\n') % self._relpath)
1451 self._ui.note(_('removing subrepo %s\n') % self._relpath)
1411 self._gitcommand(['config', 'core.bare', 'true'])
1452 self._gitcommand(['config', 'core.bare', 'true'])
1412 for f in os.listdir(self._abspath):
1453 for f in os.listdir(self._abspath):
1413 if f == '.git':
1454 if f == '.git':
1414 continue
1455 continue
1415 path = os.path.join(self._abspath, f)
1456 path = os.path.join(self._abspath, f)
1416 if os.path.isdir(path) and not os.path.islink(path):
1457 if os.path.isdir(path) and not os.path.islink(path):
1417 shutil.rmtree(path)
1458 shutil.rmtree(path)
1418 else:
1459 else:
1419 os.remove(path)
1460 os.remove(path)
1420
1461
1421 def archive(self, ui, archiver, prefix, match=None):
1462 def archive(self, ui, archiver, prefix, match=None):
1422 total = 0
1463 total = 0
1423 source, revision = self._state
1464 source, revision = self._state
1424 if not revision:
1465 if not revision:
1425 return total
1466 return total
1426 self._fetch(source, revision)
1467 self._fetch(source, revision)
1427
1468
1428 # Parse git's native archive command.
1469 # Parse git's native archive command.
1429 # This should be much faster than manually traversing the trees
1470 # This should be much faster than manually traversing the trees
1430 # and objects with many subprocess calls.
1471 # and objects with many subprocess calls.
1431 tarstream = self._gitcommand(['archive', revision], stream=True)
1472 tarstream = self._gitcommand(['archive', revision], stream=True)
1432 tar = tarfile.open(fileobj=tarstream, mode='r|')
1473 tar = tarfile.open(fileobj=tarstream, mode='r|')
1433 relpath = subrelpath(self)
1474 relpath = subrelpath(self)
1434 ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
1475 ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
1435 for i, info in enumerate(tar):
1476 for i, info in enumerate(tar):
1436 if info.isdir():
1477 if info.isdir():
1437 continue
1478 continue
1438 if match and not match(info.name):
1479 if match and not match(info.name):
1439 continue
1480 continue
1440 if info.issym():
1481 if info.issym():
1441 data = info.linkname
1482 data = info.linkname
1442 else:
1483 else:
1443 data = tar.extractfile(info).read()
1484 data = tar.extractfile(info).read()
1444 archiver.addfile(os.path.join(prefix, self._path, info.name),
1485 archiver.addfile(os.path.join(prefix, self._path, info.name),
1445 info.mode, info.issym(), data)
1486 info.mode, info.issym(), data)
1446 total += 1
1487 total += 1
1447 ui.progress(_('archiving (%s)') % relpath, i + 1,
1488 ui.progress(_('archiving (%s)') % relpath, i + 1,
1448 unit=_('files'))
1489 unit=_('files'))
1449 ui.progress(_('archiving (%s)') % relpath, None)
1490 ui.progress(_('archiving (%s)') % relpath, None)
1450 return total
1491 return total
1451
1492
1452
1493
1453 @annotatesubrepoerror
1494 @annotatesubrepoerror
1454 def status(self, rev2, **opts):
1495 def status(self, rev2, **opts):
1455 rev1 = self._state[1]
1496 rev1 = self._state[1]
1456 if self._gitmissing() or not rev1:
1497 if self._gitmissing() or not rev1:
1457 # if the repo is missing, return no results
1498 # if the repo is missing, return no results
1458 return [], [], [], [], [], [], []
1499 return [], [], [], [], [], [], []
1459 modified, added, removed = [], [], []
1500 modified, added, removed = [], [], []
1460 self._gitupdatestat()
1501 self._gitupdatestat()
1461 if rev2:
1502 if rev2:
1462 command = ['diff-tree', rev1, rev2]
1503 command = ['diff-tree', rev1, rev2]
1463 else:
1504 else:
1464 command = ['diff-index', rev1]
1505 command = ['diff-index', rev1]
1465 out = self._gitcommand(command)
1506 out = self._gitcommand(command)
1466 for line in out.split('\n'):
1507 for line in out.split('\n'):
1467 tab = line.find('\t')
1508 tab = line.find('\t')
1468 if tab == -1:
1509 if tab == -1:
1469 continue
1510 continue
1470 status, f = line[tab - 1], line[tab + 1:]
1511 status, f = line[tab - 1], line[tab + 1:]
1471 if status == 'M':
1512 if status == 'M':
1472 modified.append(f)
1513 modified.append(f)
1473 elif status == 'A':
1514 elif status == 'A':
1474 added.append(f)
1515 added.append(f)
1475 elif status == 'D':
1516 elif status == 'D':
1476 removed.append(f)
1517 removed.append(f)
1477
1518
1478 deleted = unknown = ignored = clean = []
1519 deleted = unknown = ignored = clean = []
1479 return modified, added, removed, deleted, unknown, ignored, clean
1520 return modified, added, removed, deleted, unknown, ignored, clean
1480
1521
1481 types = {
1522 types = {
1482 'hg': hgsubrepo,
1523 'hg': hgsubrepo,
1483 'svn': svnsubrepo,
1524 'svn': svnsubrepo,
1484 'git': gitsubrepo,
1525 'git': gitsubrepo,
1485 }
1526 }
@@ -1,1235 +1,1300 b''
1 Let commit recurse into subrepos by default to match pre-2.0 behavior:
1 Let commit recurse into subrepos by default to match pre-2.0 behavior:
2
2
3 $ echo "[ui]" >> $HGRCPATH
3 $ echo "[ui]" >> $HGRCPATH
4 $ echo "commitsubrepos = Yes" >> $HGRCPATH
4 $ echo "commitsubrepos = Yes" >> $HGRCPATH
5
5
6 $ hg init t
6 $ hg init t
7 $ cd t
7 $ cd t
8
8
9 first revision, no sub
9 first revision, no sub
10
10
11 $ echo a > a
11 $ echo a > a
12 $ hg ci -Am0
12 $ hg ci -Am0
13 adding a
13 adding a
14
14
15 add first sub
15 add first sub
16
16
17 $ echo s = s > .hgsub
17 $ echo s = s > .hgsub
18 $ hg add .hgsub
18 $ hg add .hgsub
19 $ hg init s
19 $ hg init s
20 $ echo a > s/a
20 $ echo a > s/a
21
21
22 Issue2232: committing a subrepo without .hgsub
22 Issue2232: committing a subrepo without .hgsub
23
23
24 $ hg ci -mbad s
24 $ hg ci -mbad s
25 abort: can't commit subrepos without .hgsub
25 abort: can't commit subrepos without .hgsub
26 [255]
26 [255]
27
27
28 $ hg -R s ci -Ams0
28 $ hg -R s ci -Ams0
29 adding a
29 adding a
30 $ hg sum
30 $ hg sum
31 parent: 0:f7b1eb17ad24 tip
31 parent: 0:f7b1eb17ad24 tip
32 0
32 0
33 branch: default
33 branch: default
34 commit: 1 added, 1 subrepos
34 commit: 1 added, 1 subrepos
35 update: (current)
35 update: (current)
36 $ hg ci -m1
36 $ hg ci -m1
37
37
38 Revert subrepo and test subrepo fileset keyword:
38 Revert subrepo and test subrepo fileset keyword:
39
39
40 $ echo b > s/a
40 $ echo b > s/a
41 $ hg revert "set:subrepo('glob:s*')"
41 $ hg revert "set:subrepo('glob:s*')"
42 reverting subrepo s
42 reverting subrepo s
43 reverting s/a (glob)
43 reverting s/a (glob)
44 $ rm s/a.orig
44 $ rm s/a.orig
45
45
46 Revert subrepo with no backup. The "reverting s/a" line is gone since
46 Revert subrepo with no backup. The "reverting s/a" line is gone since
47 we're really running 'hg update' in the subrepo:
47 we're really running 'hg update' in the subrepo:
48
48
49 $ echo b > s/a
49 $ echo b > s/a
50 $ hg revert --no-backup s
50 $ hg revert --no-backup s
51 reverting subrepo s
51 reverting subrepo s
52
52
53 Issue2022: update -C
53 Issue2022: update -C
54
54
55 $ echo b > s/a
55 $ echo b > s/a
56 $ hg sum
56 $ hg sum
57 parent: 1:7cf8cfea66e4 tip
57 parent: 1:7cf8cfea66e4 tip
58 1
58 1
59 branch: default
59 branch: default
60 commit: 1 subrepos
60 commit: 1 subrepos
61 update: (current)
61 update: (current)
62 $ hg co -C 1
62 $ hg co -C 1
63 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
63 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 $ hg sum
64 $ hg sum
65 parent: 1:7cf8cfea66e4 tip
65 parent: 1:7cf8cfea66e4 tip
66 1
66 1
67 branch: default
67 branch: default
68 commit: (clean)
68 commit: (clean)
69 update: (current)
69 update: (current)
70
70
71 commands that require a clean repo should respect subrepos
71 commands that require a clean repo should respect subrepos
72
72
73 $ echo b >> s/a
73 $ echo b >> s/a
74 $ hg backout tip
74 $ hg backout tip
75 abort: uncommitted changes in subrepo s
75 abort: uncommitted changes in subrepo s
76 [255]
76 [255]
77 $ hg revert -C -R s s/a
77 $ hg revert -C -R s s/a
78
78
79 add sub sub
79 add sub sub
80
80
81 $ echo ss = ss > s/.hgsub
81 $ echo ss = ss > s/.hgsub
82 $ hg init s/ss
82 $ hg init s/ss
83 $ echo a > s/ss/a
83 $ echo a > s/ss/a
84 $ hg -R s add s/.hgsub
84 $ hg -R s add s/.hgsub
85 $ hg -R s/ss add s/ss/a
85 $ hg -R s/ss add s/ss/a
86 $ hg sum
86 $ hg sum
87 parent: 1:7cf8cfea66e4 tip
87 parent: 1:7cf8cfea66e4 tip
88 1
88 1
89 branch: default
89 branch: default
90 commit: 1 subrepos
90 commit: 1 subrepos
91 update: (current)
91 update: (current)
92 $ hg ci -m2
92 $ hg ci -m2
93 committing subrepository s
93 committing subrepository s
94 committing subrepository s/ss (glob)
94 committing subrepository s/ss (glob)
95 $ hg sum
95 $ hg sum
96 parent: 2:df30734270ae tip
96 parent: 2:df30734270ae tip
97 2
97 2
98 branch: default
98 branch: default
99 commit: (clean)
99 commit: (clean)
100 update: (current)
100 update: (current)
101
101
102 bump sub rev (and check it is ignored by ui.commitsubrepos)
102 bump sub rev (and check it is ignored by ui.commitsubrepos)
103
103
104 $ echo b > s/a
104 $ echo b > s/a
105 $ hg -R s ci -ms1
105 $ hg -R s ci -ms1
106 $ hg --config ui.commitsubrepos=no ci -m3
106 $ hg --config ui.commitsubrepos=no ci -m3
107
107
108 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
108 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
109
109
110 $ echo c > s/a
110 $ echo c > s/a
111 $ hg --config ui.commitsubrepos=no ci -m4
111 $ hg --config ui.commitsubrepos=no ci -m4
112 abort: uncommitted changes in subrepo s
112 abort: uncommitted changes in subrepo s
113 (use --subrepos for recursive commit)
113 (use --subrepos for recursive commit)
114 [255]
114 [255]
115 $ hg id
115 $ hg id
116 f6affe3fbfaa+ tip
116 f6affe3fbfaa+ tip
117 $ hg -R s ci -mc
117 $ hg -R s ci -mc
118 $ hg id
118 $ hg id
119 f6affe3fbfaa+ tip
119 f6affe3fbfaa+ tip
120 $ echo d > s/a
120 $ echo d > s/a
121 $ hg ci -m4
121 $ hg ci -m4
122 committing subrepository s
122 committing subrepository s
123 $ hg tip -R s
123 $ hg tip -R s
124 changeset: 4:02dcf1d70411
124 changeset: 4:02dcf1d70411
125 tag: tip
125 tag: tip
126 user: test
126 user: test
127 date: Thu Jan 01 00:00:00 1970 +0000
127 date: Thu Jan 01 00:00:00 1970 +0000
128 summary: 4
128 summary: 4
129
129
130
130
131 check caching
131 check caching
132
132
133 $ hg co 0
133 $ hg co 0
134 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
134 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
135 $ hg debugsub
135 $ hg debugsub
136
136
137 restore
137 restore
138
138
139 $ hg co
139 $ hg co
140 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 $ hg debugsub
141 $ hg debugsub
142 path s
142 path s
143 source s
143 source s
144 revision 02dcf1d704118aee3ee306ccfa1910850d5b05ef
144 revision 02dcf1d704118aee3ee306ccfa1910850d5b05ef
145
145
146 new branch for merge tests
146 new branch for merge tests
147
147
148 $ hg co 1
148 $ hg co 1
149 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
149 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 $ echo t = t >> .hgsub
150 $ echo t = t >> .hgsub
151 $ hg init t
151 $ hg init t
152 $ echo t > t/t
152 $ echo t > t/t
153 $ hg -R t add t
153 $ hg -R t add t
154 adding t/t (glob)
154 adding t/t (glob)
155
155
156 5
156 5
157
157
158 $ hg ci -m5 # add sub
158 $ hg ci -m5 # add sub
159 committing subrepository t
159 committing subrepository t
160 created new head
160 created new head
161 $ echo t2 > t/t
161 $ echo t2 > t/t
162
162
163 6
163 6
164
164
165 $ hg st -R s
165 $ hg st -R s
166 $ hg ci -m6 # change sub
166 $ hg ci -m6 # change sub
167 committing subrepository t
167 committing subrepository t
168 $ hg debugsub
168 $ hg debugsub
169 path s
169 path s
170 source s
170 source s
171 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
171 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
172 path t
172 path t
173 source t
173 source t
174 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
174 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
175 $ echo t3 > t/t
175 $ echo t3 > t/t
176
176
177 7
177 7
178
178
179 $ hg ci -m7 # change sub again for conflict test
179 $ hg ci -m7 # change sub again for conflict test
180 committing subrepository t
180 committing subrepository t
181 $ hg rm .hgsub
181 $ hg rm .hgsub
182
182
183 8
183 8
184
184
185 $ hg ci -m8 # remove sub
185 $ hg ci -m8 # remove sub
186
186
187 merge tests
187 merge tests
188
188
189 $ hg co -C 3
189 $ hg co -C 3
190 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 $ hg merge 5 # test adding
191 $ hg merge 5 # test adding
192 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
192 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
193 (branch merge, don't forget to commit)
193 (branch merge, don't forget to commit)
194 $ hg debugsub
194 $ hg debugsub
195 path s
195 path s
196 source s
196 source s
197 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
197 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
198 path t
198 path t
199 source t
199 source t
200 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
200 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
201 $ hg ci -m9
201 $ hg ci -m9
202 created new head
202 created new head
203 $ hg merge 6 --debug # test change
203 $ hg merge 6 --debug # test change
204 searching for copies back to rev 2
204 searching for copies back to rev 2
205 resolving manifests
205 resolving manifests
206 branchmerge: True, force: False, partial: False
206 branchmerge: True, force: False, partial: False
207 ancestor: 1f14a2e2d3ec, local: f0d2028bf86d+, remote: 1831e14459c4
207 ancestor: 1f14a2e2d3ec, local: f0d2028bf86d+, remote: 1831e14459c4
208 .hgsubstate: versions differ -> m
208 .hgsubstate: versions differ -> m
209 updating: .hgsubstate 1/1 files (100.00%)
209 updating: .hgsubstate 1/1 files (100.00%)
210 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
210 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
211 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
211 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
212 getting subrepo t
212 getting subrepo t
213 resolving manifests
213 resolving manifests
214 branchmerge: False, force: False, partial: False
214 branchmerge: False, force: False, partial: False
215 ancestor: 60ca1237c194, local: 60ca1237c194+, remote: 6747d179aa9a
215 ancestor: 60ca1237c194, local: 60ca1237c194+, remote: 6747d179aa9a
216 t: remote is newer -> g
216 t: remote is newer -> g
217 getting t
217 getting t
218 updating: t 1/1 files (100.00%)
218 updating: t 1/1 files (100.00%)
219 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
219 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
220 (branch merge, don't forget to commit)
220 (branch merge, don't forget to commit)
221 $ hg debugsub
221 $ hg debugsub
222 path s
222 path s
223 source s
223 source s
224 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
224 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
225 path t
225 path t
226 source t
226 source t
227 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
227 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
228 $ echo conflict > t/t
228 $ echo conflict > t/t
229 $ hg ci -m10
229 $ hg ci -m10
230 committing subrepository t
230 committing subrepository t
231 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
231 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
232 searching for copies back to rev 2
232 searching for copies back to rev 2
233 resolving manifests
233 resolving manifests
234 branchmerge: True, force: False, partial: False
234 branchmerge: True, force: False, partial: False
235 ancestor: 1831e14459c4, local: e45c8b14af55+, remote: f94576341bcf
235 ancestor: 1831e14459c4, local: e45c8b14af55+, remote: f94576341bcf
236 .hgsubstate: versions differ -> m
236 .hgsubstate: versions differ -> m
237 updating: .hgsubstate 1/1 files (100.00%)
237 updating: .hgsubstate 1/1 files (100.00%)
238 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
238 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
239 subrepo t: both sides changed
239 subrepo t: both sides changed
240 subrepository t diverged (local revision: 20a0db6fbf6c, remote revision: 7af322bc1198)
240 subrepository t diverged (local revision: 20a0db6fbf6c, remote revision: 7af322bc1198)
241 (M)erge, keep (l)ocal or keep (r)emote? m
241 (M)erge, keep (l)ocal or keep (r)emote? m
242 merging subrepo t
242 merging subrepo t
243 searching for copies back to rev 2
243 searching for copies back to rev 2
244 resolving manifests
244 resolving manifests
245 branchmerge: True, force: False, partial: False
245 branchmerge: True, force: False, partial: False
246 ancestor: 6747d179aa9a, local: 20a0db6fbf6c+, remote: 7af322bc1198
246 ancestor: 6747d179aa9a, local: 20a0db6fbf6c+, remote: 7af322bc1198
247 t: versions differ -> m
247 t: versions differ -> m
248 preserving t for resolve of t
248 preserving t for resolve of t
249 updating: t 1/1 files (100.00%)
249 updating: t 1/1 files (100.00%)
250 picked tool 'internal:merge' for t (binary False symlink False)
250 picked tool 'internal:merge' for t (binary False symlink False)
251 merging t
251 merging t
252 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
252 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
253 warning: conflicts during merge.
253 warning: conflicts during merge.
254 merging t incomplete! (edit conflicts, then use 'hg resolve --mark')
254 merging t incomplete! (edit conflicts, then use 'hg resolve --mark')
255 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
255 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
256 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
256 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
257 subrepo t: merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
257 subrepo t: merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
258 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
258 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
259 (branch merge, don't forget to commit)
259 (branch merge, don't forget to commit)
260
260
261 should conflict
261 should conflict
262
262
263 $ cat t/t
263 $ cat t/t
264 <<<<<<< local
264 <<<<<<< local
265 conflict
265 conflict
266 =======
266 =======
267 t3
267 t3
268 >>>>>>> other
268 >>>>>>> other
269
269
270 clone
270 clone
271
271
272 $ cd ..
272 $ cd ..
273 $ hg clone t tc
273 $ hg clone t tc
274 updating to branch default
274 updating to branch default
275 cloning subrepo s from $TESTTMP/t/s
275 cloning subrepo s from $TESTTMP/t/s
276 cloning subrepo s/ss from $TESTTMP/t/s/ss (glob)
276 cloning subrepo s/ss from $TESTTMP/t/s/ss (glob)
277 cloning subrepo t from $TESTTMP/t/t
277 cloning subrepo t from $TESTTMP/t/t
278 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
278 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
279 $ cd tc
279 $ cd tc
280 $ hg debugsub
280 $ hg debugsub
281 path s
281 path s
282 source s
282 source s
283 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
283 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
284 path t
284 path t
285 source t
285 source t
286 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
286 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
287
287
288 push
288 push
289
289
290 $ echo bah > t/t
290 $ echo bah > t/t
291 $ hg ci -m11
291 $ hg ci -m11
292 committing subrepository t
292 committing subrepository t
293 $ hg push
293 $ hg push
294 pushing to $TESTTMP/t (glob)
294 pushing to $TESTTMP/t (glob)
295 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
295 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
296 no changes made to subrepo s since last push to $TESTTMP/t/s
296 no changes made to subrepo s since last push to $TESTTMP/t/s
297 pushing subrepo t to $TESTTMP/t/t
297 pushing subrepo t to $TESTTMP/t/t
298 searching for changes
298 searching for changes
299 adding changesets
299 adding changesets
300 adding manifests
300 adding manifests
301 adding file changes
301 adding file changes
302 added 1 changesets with 1 changes to 1 files
302 added 1 changesets with 1 changes to 1 files
303 searching for changes
303 searching for changes
304 adding changesets
304 adding changesets
305 adding manifests
305 adding manifests
306 adding file changes
306 adding file changes
307 added 1 changesets with 1 changes to 1 files
307 added 1 changesets with 1 changes to 1 files
308
308
309 push -f
309 push -f
310
310
311 $ echo bah > s/a
311 $ echo bah > s/a
312 $ hg ci -m12
312 $ hg ci -m12
313 committing subrepository s
313 committing subrepository s
314 $ hg push
314 $ hg push
315 pushing to $TESTTMP/t (glob)
315 pushing to $TESTTMP/t (glob)
316 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
316 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
317 pushing subrepo s to $TESTTMP/t/s
317 pushing subrepo s to $TESTTMP/t/s
318 searching for changes
318 searching for changes
319 abort: push creates new remote head 12a213df6fa9! (in subrepo s)
319 abort: push creates new remote head 12a213df6fa9! (in subrepo s)
320 (merge or see "hg help push" for details about pushing new heads)
320 (merge or see "hg help push" for details about pushing new heads)
321 [255]
321 [255]
322 $ hg push -f
322 $ hg push -f
323 pushing to $TESTTMP/t (glob)
323 pushing to $TESTTMP/t (glob)
324 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
324 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
325 searching for changes
325 searching for changes
326 no changes found
326 no changes found
327 pushing subrepo s to $TESTTMP/t/s
327 pushing subrepo s to $TESTTMP/t/s
328 searching for changes
328 searching for changes
329 adding changesets
329 adding changesets
330 adding manifests
330 adding manifests
331 adding file changes
331 adding file changes
332 added 1 changesets with 1 changes to 1 files (+1 heads)
332 added 1 changesets with 1 changes to 1 files (+1 heads)
333 pushing subrepo t to $TESTTMP/t/t
333 pushing subrepo t to $TESTTMP/t/t
334 searching for changes
334 searching for changes
335 no changes found
335 no changes found
336 searching for changes
336 searching for changes
337 adding changesets
337 adding changesets
338 adding manifests
338 adding manifests
339 adding file changes
339 adding file changes
340 added 1 changesets with 1 changes to 1 files
340 added 1 changesets with 1 changes to 1 files
341
341
342 check that unmodified subrepos are not pushed
342 check that unmodified subrepos are not pushed
343
343
344 $ hg clone . ../tcc
344 $ hg clone . ../tcc
345 updating to branch default
345 updating to branch default
346 cloning subrepo s from $TESTTMP/tc/s
346 cloning subrepo s from $TESTTMP/tc/s
347 cloning subrepo s/ss from $TESTTMP/tc/s/ss (glob)
347 cloning subrepo s/ss from $TESTTMP/tc/s/ss (glob)
348 cloning subrepo t from $TESTTMP/tc/t
348 cloning subrepo t from $TESTTMP/tc/t
349 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
349 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
350
350
351 the subrepos on the new clone have nothing to push to its source
351 the subrepos on the new clone have nothing to push to its source
352
352
353 $ hg push -R ../tcc .
353 $ hg push -R ../tcc .
354 pushing to .
354 pushing to .
355 no changes made to subrepo s/ss since last push to s/ss (glob)
355 no changes made to subrepo s/ss since last push to s/ss (glob)
356 no changes made to subrepo s since last push to s
356 no changes made to subrepo s since last push to s
357 no changes made to subrepo t since last push to t
357 no changes made to subrepo t since last push to t
358 searching for changes
358 searching for changes
359 no changes found
359 no changes found
360 [1]
360 [1]
361
361
362 the subrepos on the source do not have a clean store versus the clone target
362 the subrepos on the source do not have a clean store versus the clone target
363 because they were never explicitly pushed to the source
363 because they were never explicitly pushed to the source
364
364
365 $ hg push ../tcc
365 $ hg push ../tcc
366 pushing to ../tcc
366 pushing to ../tcc
367 pushing subrepo s/ss to ../tcc/s/ss (glob)
367 pushing subrepo s/ss to ../tcc/s/ss (glob)
368 searching for changes
368 searching for changes
369 no changes found
369 no changes found
370 pushing subrepo s to ../tcc/s
370 pushing subrepo s to ../tcc/s
371 searching for changes
371 searching for changes
372 no changes found
372 no changes found
373 pushing subrepo t to ../tcc/t
373 pushing subrepo t to ../tcc/t
374 searching for changes
374 searching for changes
375 no changes found
375 no changes found
376 searching for changes
376 searching for changes
377 no changes found
377 no changes found
378 [1]
378 [1]
379
379
380 after push their stores become clean
380 after push their stores become clean
381
381
382 $ hg push ../tcc
382 $ hg push ../tcc
383 pushing to ../tcc
383 pushing to ../tcc
384 no changes made to subrepo s/ss since last push to ../tcc/s/ss (glob)
384 no changes made to subrepo s/ss since last push to ../tcc/s/ss (glob)
385 no changes made to subrepo s since last push to ../tcc/s
385 no changes made to subrepo s since last push to ../tcc/s
386 no changes made to subrepo t since last push to ../tcc/t
386 no changes made to subrepo t since last push to ../tcc/t
387 searching for changes
387 searching for changes
388 no changes found
388 no changes found
389 [1]
389 [1]
390
390
391 updating a subrepo to a different revision or changing
391 updating a subrepo to a different revision or changing
392 its working directory does not make its store dirty
392 its working directory does not make its store dirty
393
393
394 $ hg -R s update '.^'
394 $ hg -R s update '.^'
395 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
395 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
396 $ hg push
396 $ hg push
397 pushing to $TESTTMP/t (glob)
397 pushing to $TESTTMP/t (glob)
398 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
398 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
399 no changes made to subrepo s since last push to $TESTTMP/t/s
399 no changes made to subrepo s since last push to $TESTTMP/t/s
400 no changes made to subrepo t since last push to $TESTTMP/t/t
400 no changes made to subrepo t since last push to $TESTTMP/t/t
401 searching for changes
401 searching for changes
402 no changes found
402 no changes found
403 [1]
403 [1]
404 $ echo foo >> s/a
404 $ echo foo >> s/a
405 $ hg push
405 $ hg push
406 pushing to $TESTTMP/t (glob)
406 pushing to $TESTTMP/t (glob)
407 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
407 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
408 no changes made to subrepo s since last push to $TESTTMP/t/s
408 no changes made to subrepo s since last push to $TESTTMP/t/s
409 no changes made to subrepo t since last push to $TESTTMP/t/t
409 no changes made to subrepo t since last push to $TESTTMP/t/t
410 searching for changes
410 searching for changes
411 no changes found
411 no changes found
412 [1]
412 [1]
413 $ hg -R s update -C tip
413 $ hg -R s update -C tip
414 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
414 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
415
415
416 committing into a subrepo makes its store (but not its parent's store) dirty
416 committing into a subrepo makes its store (but not its parent's store) dirty
417
417
418 $ echo foo >> s/ss/a
418 $ echo foo >> s/ss/a
419 $ hg -R s/ss commit -m 'test dirty store detection'
419 $ hg -R s/ss commit -m 'test dirty store detection'
420 $ hg push
420 $ hg push
421 pushing to $TESTTMP/t (glob)
421 pushing to $TESTTMP/t (glob)
422 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
422 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
423 searching for changes
423 searching for changes
424 adding changesets
424 adding changesets
425 adding manifests
425 adding manifests
426 adding file changes
426 adding file changes
427 added 1 changesets with 1 changes to 1 files
427 added 1 changesets with 1 changes to 1 files
428 no changes made to subrepo s since last push to $TESTTMP/t/s
428 no changes made to subrepo s since last push to $TESTTMP/t/s
429 no changes made to subrepo t since last push to $TESTTMP/t/t
429 no changes made to subrepo t since last push to $TESTTMP/t/t
430 searching for changes
430 searching for changes
431 no changes found
431 no changes found
432 [1]
432 [1]
433
433
434 a subrepo store may be clean versus one repo but not versus another
434 a subrepo store may be clean versus one repo but not versus another
435
435
436 $ hg push
436 $ hg push
437 pushing to $TESTTMP/t (glob)
437 pushing to $TESTTMP/t (glob)
438 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
438 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
439 no changes made to subrepo s since last push to $TESTTMP/t/s
439 no changes made to subrepo s since last push to $TESTTMP/t/s
440 no changes made to subrepo t since last push to $TESTTMP/t/t
440 no changes made to subrepo t since last push to $TESTTMP/t/t
441 searching for changes
441 searching for changes
442 no changes found
442 no changes found
443 [1]
443 [1]
444 $ hg push ../tcc
444 $ hg push ../tcc
445 pushing to ../tcc
445 pushing to ../tcc
446 pushing subrepo s/ss to ../tcc/s/ss (glob)
446 pushing subrepo s/ss to ../tcc/s/ss (glob)
447 searching for changes
447 searching for changes
448 adding changesets
448 adding changesets
449 adding manifests
449 adding manifests
450 adding file changes
450 adding file changes
451 added 1 changesets with 1 changes to 1 files
451 added 1 changesets with 1 changes to 1 files
452 no changes made to subrepo s since last push to ../tcc/s
452 no changes made to subrepo s since last push to ../tcc/s
453 no changes made to subrepo t since last push to ../tcc/t
453 no changes made to subrepo t since last push to ../tcc/t
454 searching for changes
454 searching for changes
455 no changes found
455 no changes found
456 [1]
456 [1]
457
457
458 update
458 update
459
459
460 $ cd ../t
460 $ cd ../t
461 $ hg up -C # discard our earlier merge
461 $ hg up -C # discard our earlier merge
462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
463 $ echo blah > t/t
463 $ echo blah > t/t
464 $ hg ci -m13
464 $ hg ci -m13
465 committing subrepository t
465 committing subrepository t
466
466
467 backout calls revert internally with minimal opts, which should not raise
467 backout calls revert internally with minimal opts, which should not raise
468 KeyError
468 KeyError
469
469
470 $ hg backout ".^"
470 $ hg backout ".^"
471 reverting .hgsubstate
471 reverting .hgsubstate
472 reverting subrepo s
472 reverting subrepo s
473 reverting s/a (glob)
473 reverting s/a (glob)
474 reverting subrepo ss
474 reverting subrepo ss
475 reverting subrepo t
475 reverting subrepo t
476 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
476 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
477
477
478 $ hg up -C # discard changes
478 $ hg up -C # discard changes
479 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
479 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
480
480
481 pull
481 pull
482
482
483 $ cd ../tc
483 $ cd ../tc
484 $ hg pull
484 $ hg pull
485 pulling from $TESTTMP/t (glob)
485 pulling from $TESTTMP/t (glob)
486 searching for changes
486 searching for changes
487 adding changesets
487 adding changesets
488 adding manifests
488 adding manifests
489 adding file changes
489 adding file changes
490 added 1 changesets with 1 changes to 1 files
490 added 1 changesets with 1 changes to 1 files
491 (run 'hg update' to get a working copy)
491 (run 'hg update' to get a working copy)
492
492
493 should pull t
493 should pull t
494
494
495 $ hg up
495 $ hg up
496 pulling subrepo t from $TESTTMP/t/t
496 pulling subrepo t from $TESTTMP/t/t
497 searching for changes
497 searching for changes
498 adding changesets
498 adding changesets
499 adding manifests
499 adding manifests
500 adding file changes
500 adding file changes
501 added 1 changesets with 1 changes to 1 files
501 added 1 changesets with 1 changes to 1 files
502 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
502 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
503 $ cat t/t
503 $ cat t/t
504 blah
504 blah
505
505
506 bogus subrepo path aborts
506 bogus subrepo path aborts
507
507
508 $ echo 'bogus=[boguspath' >> .hgsub
508 $ echo 'bogus=[boguspath' >> .hgsub
509 $ hg ci -m 'bogus subrepo path'
509 $ hg ci -m 'bogus subrepo path'
510 abort: missing ] in subrepo source
510 abort: missing ] in subrepo source
511 [255]
511 [255]
512
512
513 Issue1986: merge aborts when trying to merge a subrepo that
513 Issue1986: merge aborts when trying to merge a subrepo that
514 shouldn't need merging
514 shouldn't need merging
515
515
516 # subrepo layout
516 # subrepo layout
517 #
517 #
518 # o 5 br
518 # o 5 br
519 # /|
519 # /|
520 # o | 4 default
520 # o | 4 default
521 # | |
521 # | |
522 # | o 3 br
522 # | o 3 br
523 # |/|
523 # |/|
524 # o | 2 default
524 # o | 2 default
525 # | |
525 # | |
526 # | o 1 br
526 # | o 1 br
527 # |/
527 # |/
528 # o 0 default
528 # o 0 default
529
529
530 $ cd ..
530 $ cd ..
531 $ rm -rf sub
531 $ rm -rf sub
532 $ hg init main
532 $ hg init main
533 $ cd main
533 $ cd main
534 $ hg init s
534 $ hg init s
535 $ cd s
535 $ cd s
536 $ echo a > a
536 $ echo a > a
537 $ hg ci -Am1
537 $ hg ci -Am1
538 adding a
538 adding a
539 $ hg branch br
539 $ hg branch br
540 marked working directory as branch br
540 marked working directory as branch br
541 (branches are permanent and global, did you want a bookmark?)
541 (branches are permanent and global, did you want a bookmark?)
542 $ echo a >> a
542 $ echo a >> a
543 $ hg ci -m1
543 $ hg ci -m1
544 $ hg up default
544 $ hg up default
545 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
545 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
546 $ echo b > b
546 $ echo b > b
547 $ hg ci -Am1
547 $ hg ci -Am1
548 adding b
548 adding b
549 $ hg up br
549 $ hg up br
550 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
550 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
551 $ hg merge tip
551 $ hg merge tip
552 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
552 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
553 (branch merge, don't forget to commit)
553 (branch merge, don't forget to commit)
554 $ hg ci -m1
554 $ hg ci -m1
555 $ hg up 2
555 $ hg up 2
556 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
556 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
557 $ echo c > c
557 $ echo c > c
558 $ hg ci -Am1
558 $ hg ci -Am1
559 adding c
559 adding c
560 $ hg up 3
560 $ hg up 3
561 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
561 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
562 $ hg merge 4
562 $ hg merge 4
563 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
563 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
564 (branch merge, don't forget to commit)
564 (branch merge, don't forget to commit)
565 $ hg ci -m1
565 $ hg ci -m1
566
566
567 # main repo layout:
567 # main repo layout:
568 #
568 #
569 # * <-- try to merge default into br again
569 # * <-- try to merge default into br again
570 # .`|
570 # .`|
571 # . o 5 br --> substate = 5
571 # . o 5 br --> substate = 5
572 # . |
572 # . |
573 # o | 4 default --> substate = 4
573 # o | 4 default --> substate = 4
574 # | |
574 # | |
575 # | o 3 br --> substate = 2
575 # | o 3 br --> substate = 2
576 # |/|
576 # |/|
577 # o | 2 default --> substate = 2
577 # o | 2 default --> substate = 2
578 # | |
578 # | |
579 # | o 1 br --> substate = 3
579 # | o 1 br --> substate = 3
580 # |/
580 # |/
581 # o 0 default --> substate = 2
581 # o 0 default --> substate = 2
582
582
583 $ cd ..
583 $ cd ..
584 $ echo 's = s' > .hgsub
584 $ echo 's = s' > .hgsub
585 $ hg -R s up 2
585 $ hg -R s up 2
586 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
586 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
587 $ hg ci -Am1
587 $ hg ci -Am1
588 adding .hgsub
588 adding .hgsub
589 $ hg branch br
589 $ hg branch br
590 marked working directory as branch br
590 marked working directory as branch br
591 (branches are permanent and global, did you want a bookmark?)
591 (branches are permanent and global, did you want a bookmark?)
592 $ echo b > b
592 $ echo b > b
593 $ hg -R s up 3
593 $ hg -R s up 3
594 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
594 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
595 $ hg ci -Am1
595 $ hg ci -Am1
596 adding b
596 adding b
597 $ hg up default
597 $ hg up default
598 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
598 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
599 $ echo c > c
599 $ echo c > c
600 $ hg ci -Am1
600 $ hg ci -Am1
601 adding c
601 adding c
602 $ hg up 1
602 $ hg up 1
603 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
603 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
604 $ hg merge 2
604 $ hg merge 2
605 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
605 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
606 (branch merge, don't forget to commit)
606 (branch merge, don't forget to commit)
607 $ hg ci -m1
607 $ hg ci -m1
608 $ hg up 2
608 $ hg up 2
609 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
609 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
610 $ hg -R s up 4
610 $ hg -R s up 4
611 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
611 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
612 $ echo d > d
612 $ echo d > d
613 $ hg ci -Am1
613 $ hg ci -Am1
614 adding d
614 adding d
615 $ hg up 3
615 $ hg up 3
616 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
616 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
617 $ hg -R s up 5
617 $ hg -R s up 5
618 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
618 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
619 $ echo e > e
619 $ echo e > e
620 $ hg ci -Am1
620 $ hg ci -Am1
621 adding e
621 adding e
622
622
623 $ hg up 5
623 $ hg up 5
624 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
624 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
625 $ hg merge 4 # try to merge default into br again
625 $ hg merge 4 # try to merge default into br again
626 subrepository s diverged (local revision: f8f13b33206e, remote revision: a3f9062a4f88)
626 subrepository s diverged (local revision: f8f13b33206e, remote revision: a3f9062a4f88)
627 (M)erge, keep (l)ocal or keep (r)emote? m
627 (M)erge, keep (l)ocal or keep (r)emote? m
628 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
628 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
629 (branch merge, don't forget to commit)
629 (branch merge, don't forget to commit)
630 $ cd ..
630 $ cd ..
631
631
632 test subrepo delete from .hgsubstate
632 test subrepo delete from .hgsubstate
633
633
634 $ hg init testdelete
634 $ hg init testdelete
635 $ mkdir testdelete/nested testdelete/nested2
635 $ mkdir testdelete/nested testdelete/nested2
636 $ hg init testdelete/nested
636 $ hg init testdelete/nested
637 $ hg init testdelete/nested2
637 $ hg init testdelete/nested2
638 $ echo test > testdelete/nested/foo
638 $ echo test > testdelete/nested/foo
639 $ echo test > testdelete/nested2/foo
639 $ echo test > testdelete/nested2/foo
640 $ hg -R testdelete/nested add
640 $ hg -R testdelete/nested add
641 adding testdelete/nested/foo (glob)
641 adding testdelete/nested/foo (glob)
642 $ hg -R testdelete/nested2 add
642 $ hg -R testdelete/nested2 add
643 adding testdelete/nested2/foo (glob)
643 adding testdelete/nested2/foo (glob)
644 $ hg -R testdelete/nested ci -m test
644 $ hg -R testdelete/nested ci -m test
645 $ hg -R testdelete/nested2 ci -m test
645 $ hg -R testdelete/nested2 ci -m test
646 $ echo nested = nested > testdelete/.hgsub
646 $ echo nested = nested > testdelete/.hgsub
647 $ echo nested2 = nested2 >> testdelete/.hgsub
647 $ echo nested2 = nested2 >> testdelete/.hgsub
648 $ hg -R testdelete add
648 $ hg -R testdelete add
649 adding testdelete/.hgsub (glob)
649 adding testdelete/.hgsub (glob)
650 $ hg -R testdelete ci -m "nested 1 & 2 added"
650 $ hg -R testdelete ci -m "nested 1 & 2 added"
651 $ echo nested = nested > testdelete/.hgsub
651 $ echo nested = nested > testdelete/.hgsub
652 $ hg -R testdelete ci -m "nested 2 deleted"
652 $ hg -R testdelete ci -m "nested 2 deleted"
653 $ cat testdelete/.hgsubstate
653 $ cat testdelete/.hgsubstate
654 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
654 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
655 $ hg -R testdelete remove testdelete/.hgsub
655 $ hg -R testdelete remove testdelete/.hgsub
656 $ hg -R testdelete ci -m ".hgsub deleted"
656 $ hg -R testdelete ci -m ".hgsub deleted"
657 $ cat testdelete/.hgsubstate
657 $ cat testdelete/.hgsubstate
658 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
658 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
659
659
660 test repository cloning
660 test repository cloning
661
661
662 $ mkdir mercurial mercurial2
662 $ mkdir mercurial mercurial2
663 $ hg init nested_absolute
663 $ hg init nested_absolute
664 $ echo test > nested_absolute/foo
664 $ echo test > nested_absolute/foo
665 $ hg -R nested_absolute add
665 $ hg -R nested_absolute add
666 adding nested_absolute/foo (glob)
666 adding nested_absolute/foo (glob)
667 $ hg -R nested_absolute ci -mtest
667 $ hg -R nested_absolute ci -mtest
668 $ cd mercurial
668 $ cd mercurial
669 $ hg init nested_relative
669 $ hg init nested_relative
670 $ echo test2 > nested_relative/foo2
670 $ echo test2 > nested_relative/foo2
671 $ hg -R nested_relative add
671 $ hg -R nested_relative add
672 adding nested_relative/foo2 (glob)
672 adding nested_relative/foo2 (glob)
673 $ hg -R nested_relative ci -mtest2
673 $ hg -R nested_relative ci -mtest2
674 $ hg init main
674 $ hg init main
675 $ echo "nested_relative = ../nested_relative" > main/.hgsub
675 $ echo "nested_relative = ../nested_relative" > main/.hgsub
676 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
676 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
677 $ hg -R main add
677 $ hg -R main add
678 adding main/.hgsub (glob)
678 adding main/.hgsub (glob)
679 $ hg -R main ci -m "add subrepos"
679 $ hg -R main ci -m "add subrepos"
680 $ cd ..
680 $ cd ..
681 $ hg clone mercurial/main mercurial2/main
681 $ hg clone mercurial/main mercurial2/main
682 updating to branch default
682 updating to branch default
683 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
683 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
684 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
684 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
685 > mercurial2/main/nested_relative/.hg/hgrc
685 > mercurial2/main/nested_relative/.hg/hgrc
686 [paths]
686 [paths]
687 default = $TESTTMP/mercurial/nested_absolute
687 default = $TESTTMP/mercurial/nested_absolute
688 [paths]
688 [paths]
689 default = $TESTTMP/mercurial/nested_relative
689 default = $TESTTMP/mercurial/nested_relative
690 $ rm -rf mercurial mercurial2
690 $ rm -rf mercurial mercurial2
691
691
692 Issue1977: multirepo push should fail if subrepo push fails
692 Issue1977: multirepo push should fail if subrepo push fails
693
693
694 $ hg init repo
694 $ hg init repo
695 $ hg init repo/s
695 $ hg init repo/s
696 $ echo a > repo/s/a
696 $ echo a > repo/s/a
697 $ hg -R repo/s ci -Am0
697 $ hg -R repo/s ci -Am0
698 adding a
698 adding a
699 $ echo s = s > repo/.hgsub
699 $ echo s = s > repo/.hgsub
700 $ hg -R repo ci -Am1
700 $ hg -R repo ci -Am1
701 adding .hgsub
701 adding .hgsub
702 $ hg clone repo repo2
702 $ hg clone repo repo2
703 updating to branch default
703 updating to branch default
704 cloning subrepo s from $TESTTMP/repo/s
704 cloning subrepo s from $TESTTMP/repo/s
705 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
705 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
706 $ hg -q -R repo2 pull -u
706 $ hg -q -R repo2 pull -u
707 $ echo 1 > repo2/s/a
707 $ echo 1 > repo2/s/a
708 $ hg -R repo2/s ci -m2
708 $ hg -R repo2/s ci -m2
709 $ hg -q -R repo2/s push
709 $ hg -q -R repo2/s push
710 $ hg -R repo2/s up -C 0
710 $ hg -R repo2/s up -C 0
711 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
711 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
712 $ echo 2 > repo2/s/b
712 $ echo 2 > repo2/s/b
713 $ hg -R repo2/s ci -m3 -A
713 $ hg -R repo2/s ci -m3 -A
714 adding b
714 adding b
715 created new head
715 created new head
716 $ hg -R repo2 ci -m3
716 $ hg -R repo2 ci -m3
717 $ hg -q -R repo2 push
717 $ hg -q -R repo2 push
718 abort: push creates new remote head cc505f09a8b2! (in subrepo s)
718 abort: push creates new remote head cc505f09a8b2! (in subrepo s)
719 (merge or see "hg help push" for details about pushing new heads)
719 (merge or see "hg help push" for details about pushing new heads)
720 [255]
720 [255]
721 $ hg -R repo update
721 $ hg -R repo update
722 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
722 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
723
723
724 test if untracked file is not overwritten
724 test if untracked file is not overwritten
725
725
726 $ echo issue3276_ok > repo/s/b
726 $ echo issue3276_ok > repo/s/b
727 $ hg -R repo2 push -f -q
727 $ hg -R repo2 push -f -q
728 $ hg -R repo update
728 $ hg -R repo update
729 b: untracked file differs
729 b: untracked file differs
730 abort: untracked files in working directory differ from files in requested revision (in subrepo s)
730 abort: untracked files in working directory differ from files in requested revision (in subrepo s)
731 [255]
731 [255]
732
732
733 $ cat repo/s/b
733 $ cat repo/s/b
734 issue3276_ok
734 issue3276_ok
735 $ rm repo/s/b
735 $ rm repo/s/b
736 $ hg -R repo revert --all
736 $ hg -R repo revert --all
737 reverting repo/.hgsubstate (glob)
737 reverting repo/.hgsubstate (glob)
738 reverting subrepo s
738 reverting subrepo s
739 $ hg -R repo update
739 $ hg -R repo update
740 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
740 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
741 $ cat repo/s/b
741 $ cat repo/s/b
742 2
742 2
743 $ rm -rf repo2 repo
743 $ rm -rf repo2 repo
744
744
745
745
746 Issue1852 subrepos with relative paths always push/pull relative to default
746 Issue1852 subrepos with relative paths always push/pull relative to default
747
747
748 Prepare a repo with subrepo
748 Prepare a repo with subrepo
749
749
750 $ hg init issue1852a
750 $ hg init issue1852a
751 $ cd issue1852a
751 $ cd issue1852a
752 $ hg init sub/repo
752 $ hg init sub/repo
753 $ echo test > sub/repo/foo
753 $ echo test > sub/repo/foo
754 $ hg -R sub/repo add sub/repo/foo
754 $ hg -R sub/repo add sub/repo/foo
755 $ echo sub/repo = sub/repo > .hgsub
755 $ echo sub/repo = sub/repo > .hgsub
756 $ hg add .hgsub
756 $ hg add .hgsub
757 $ hg ci -mtest
757 $ hg ci -mtest
758 committing subrepository sub/repo (glob)
758 committing subrepository sub/repo (glob)
759 $ echo test >> sub/repo/foo
759 $ echo test >> sub/repo/foo
760 $ hg ci -mtest
760 $ hg ci -mtest
761 committing subrepository sub/repo (glob)
761 committing subrepository sub/repo (glob)
762 $ cd ..
762 $ cd ..
763
763
764 Create repo without default path, pull top repo, and see what happens on update
764 Create repo without default path, pull top repo, and see what happens on update
765
765
766 $ hg init issue1852b
766 $ hg init issue1852b
767 $ hg -R issue1852b pull issue1852a
767 $ hg -R issue1852b pull issue1852a
768 pulling from issue1852a
768 pulling from issue1852a
769 requesting all changes
769 requesting all changes
770 adding changesets
770 adding changesets
771 adding manifests
771 adding manifests
772 adding file changes
772 adding file changes
773 added 2 changesets with 3 changes to 2 files
773 added 2 changesets with 3 changes to 2 files
774 (run 'hg update' to get a working copy)
774 (run 'hg update' to get a working copy)
775 $ hg -R issue1852b update
775 $ hg -R issue1852b update
776 abort: default path for subrepository not found (in subrepo sub/repo) (glob)
776 abort: default path for subrepository not found (in subrepo sub/repo) (glob)
777 [255]
777 [255]
778
778
779 Ensure a full traceback, not just the SubrepoAbort part
779 Ensure a full traceback, not just the SubrepoAbort part
780
780
781 $ hg -R issue1852b update --traceback 2>&1 | grep 'raise util\.Abort'
781 $ hg -R issue1852b update --traceback 2>&1 | grep 'raise util\.Abort'
782 raise util.Abort(_("default path for subrepository not found"))
782 raise util.Abort(_("default path for subrepository not found"))
783
783
784 Pull -u now doesn't help
784 Pull -u now doesn't help
785
785
786 $ hg -R issue1852b pull -u issue1852a
786 $ hg -R issue1852b pull -u issue1852a
787 pulling from issue1852a
787 pulling from issue1852a
788 searching for changes
788 searching for changes
789 no changes found
789 no changes found
790
790
791 Try the same, but with pull -u
791 Try the same, but with pull -u
792
792
793 $ hg init issue1852c
793 $ hg init issue1852c
794 $ hg -R issue1852c pull -r0 -u issue1852a
794 $ hg -R issue1852c pull -r0 -u issue1852a
795 pulling from issue1852a
795 pulling from issue1852a
796 adding changesets
796 adding changesets
797 adding manifests
797 adding manifests
798 adding file changes
798 adding file changes
799 added 1 changesets with 2 changes to 2 files
799 added 1 changesets with 2 changes to 2 files
800 cloning subrepo sub/repo from issue1852a/sub/repo (glob)
800 cloning subrepo sub/repo from issue1852a/sub/repo (glob)
801 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
801 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
802
802
803 Try to push from the other side
803 Try to push from the other side
804
804
805 $ hg -R issue1852a push `pwd`/issue1852c
805 $ hg -R issue1852a push `pwd`/issue1852c
806 pushing to $TESTTMP/issue1852c (glob)
806 pushing to $TESTTMP/issue1852c (glob)
807 pushing subrepo sub/repo to $TESTTMP/issue1852c/sub/repo (glob)
807 pushing subrepo sub/repo to $TESTTMP/issue1852c/sub/repo (glob)
808 searching for changes
808 searching for changes
809 no changes found
809 no changes found
810 searching for changes
810 searching for changes
811 adding changesets
811 adding changesets
812 adding manifests
812 adding manifests
813 adding file changes
813 adding file changes
814 added 1 changesets with 1 changes to 1 files
814 added 1 changesets with 1 changes to 1 files
815
815
816 Incoming and outgoing should not use the default path:
816 Incoming and outgoing should not use the default path:
817
817
818 $ hg clone -q issue1852a issue1852d
818 $ hg clone -q issue1852a issue1852d
819 $ hg -R issue1852d outgoing --subrepos issue1852c
819 $ hg -R issue1852d outgoing --subrepos issue1852c
820 comparing with issue1852c
820 comparing with issue1852c
821 searching for changes
821 searching for changes
822 no changes found
822 no changes found
823 comparing with issue1852c/sub/repo
823 comparing with issue1852c/sub/repo
824 searching for changes
824 searching for changes
825 no changes found
825 no changes found
826 [1]
826 [1]
827 $ hg -R issue1852d incoming --subrepos issue1852c
827 $ hg -R issue1852d incoming --subrepos issue1852c
828 comparing with issue1852c
828 comparing with issue1852c
829 searching for changes
829 searching for changes
830 no changes found
830 no changes found
831 comparing with issue1852c/sub/repo
831 comparing with issue1852c/sub/repo
832 searching for changes
832 searching for changes
833 no changes found
833 no changes found
834 [1]
834 [1]
835
835
836 Check status of files when none of them belong to the first
836 Check status of files when none of them belong to the first
837 subrepository:
837 subrepository:
838
838
839 $ hg init subrepo-status
839 $ hg init subrepo-status
840 $ cd subrepo-status
840 $ cd subrepo-status
841 $ hg init subrepo-1
841 $ hg init subrepo-1
842 $ hg init subrepo-2
842 $ hg init subrepo-2
843 $ cd subrepo-2
843 $ cd subrepo-2
844 $ touch file
844 $ touch file
845 $ hg add file
845 $ hg add file
846 $ cd ..
846 $ cd ..
847 $ echo subrepo-1 = subrepo-1 > .hgsub
847 $ echo subrepo-1 = subrepo-1 > .hgsub
848 $ echo subrepo-2 = subrepo-2 >> .hgsub
848 $ echo subrepo-2 = subrepo-2 >> .hgsub
849 $ hg add .hgsub
849 $ hg add .hgsub
850 $ hg ci -m 'Added subrepos'
850 $ hg ci -m 'Added subrepos'
851 committing subrepository subrepo-2
851 committing subrepository subrepo-2
852 $ hg st subrepo-2/file
852 $ hg st subrepo-2/file
853
853
854 Check that share works with subrepo
854 Check that share works with subrepo
855 $ hg --config extensions.share= share . ../shared
855 $ hg --config extensions.share= share . ../shared
856 updating working directory
856 updating working directory
857 cloning subrepo subrepo-2 from $TESTTMP/subrepo-status/subrepo-2
857 cloning subrepo subrepo-2 from $TESTTMP/subrepo-status/subrepo-2
858 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
858 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
859 $ test -f ../shared/subrepo-1/.hg/sharedpath
859 $ test -f ../shared/subrepo-1/.hg/sharedpath
860 [1]
860 [1]
861 $ hg -R ../shared in
861 $ hg -R ../shared in
862 abort: repository default not found!
862 abort: repository default not found!
863 [255]
863 [255]
864 $ hg -R ../shared/subrepo-2 showconfig paths
864 $ hg -R ../shared/subrepo-2 showconfig paths
865 paths.default=$TESTTMP/subrepo-status/subrepo-2
865 paths.default=$TESTTMP/subrepo-status/subrepo-2
866 $ hg -R ../shared/subrepo-1 sum --remote
866 $ hg -R ../shared/subrepo-1 sum --remote
867 parent: -1:000000000000 tip (empty repository)
867 parent: -1:000000000000 tip (empty repository)
868 branch: default
868 branch: default
869 commit: (clean)
869 commit: (clean)
870 update: (current)
870 update: (current)
871 remote: (synced)
871 remote: (synced)
872
872
873 Check hg update --clean
873 Check hg update --clean
874 $ cd $TESTTMP/t
874 $ cd $TESTTMP/t
875 $ rm -r t/t.orig
875 $ rm -r t/t.orig
876 $ hg status -S --all
876 $ hg status -S --all
877 C .hgsub
877 C .hgsub
878 C .hgsubstate
878 C .hgsubstate
879 C a
879 C a
880 C s/.hgsub
880 C s/.hgsub
881 C s/.hgsubstate
881 C s/.hgsubstate
882 C s/a
882 C s/a
883 C s/ss/a
883 C s/ss/a
884 C t/t
884 C t/t
885 $ echo c1 > s/a
885 $ echo c1 > s/a
886 $ cd s
886 $ cd s
887 $ echo c1 > b
887 $ echo c1 > b
888 $ echo c1 > c
888 $ echo c1 > c
889 $ hg add b
889 $ hg add b
890 $ cd ..
890 $ cd ..
891 $ hg status -S
891 $ hg status -S
892 M s/a
892 M s/a
893 A s/b
893 A s/b
894 ? s/c
894 ? s/c
895 $ hg update -C
895 $ hg update -C
896 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
896 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
897 $ hg status -S
897 $ hg status -S
898 ? s/b
898 ? s/b
899 ? s/c
899 ? s/c
900
900
901 Sticky subrepositories, no changes
901 Sticky subrepositories, no changes
902 $ cd $TESTTMP/t
902 $ cd $TESTTMP/t
903 $ hg id
903 $ hg id
904 925c17564ef8 tip
904 925c17564ef8 tip
905 $ hg -R s id
905 $ hg -R s id
906 12a213df6fa9 tip
906 12a213df6fa9 tip
907 $ hg -R t id
907 $ hg -R t id
908 52c0adc0515a tip
908 52c0adc0515a tip
909 $ hg update 11
909 $ hg update 11
910 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
910 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
911 $ hg id
911 $ hg id
912 365661e5936a
912 365661e5936a
913 $ hg -R s id
913 $ hg -R s id
914 fc627a69481f
914 fc627a69481f
915 $ hg -R t id
915 $ hg -R t id
916 e95bcfa18a35
916 e95bcfa18a35
917
917
918 Sticky subrepositorys, file changes
918 Sticky subrepositorys, file changes
919 $ touch s/f1
919 $ touch s/f1
920 $ touch t/f1
920 $ touch t/f1
921 $ hg add -S s/f1
921 $ hg add -S s/f1
922 $ hg add -S t/f1
922 $ hg add -S t/f1
923 $ hg id
923 $ hg id
924 365661e5936a+
924 365661e5936a+
925 $ hg -R s id
925 $ hg -R s id
926 fc627a69481f+
926 fc627a69481f+
927 $ hg -R t id
927 $ hg -R t id
928 e95bcfa18a35+
928 e95bcfa18a35+
929 $ hg update tip
929 $ hg update tip
930 subrepository s diverged (local revision: fc627a69481f, remote revision: 12a213df6fa9)
930 subrepository s diverged (local revision: fc627a69481f, remote revision: 12a213df6fa9)
931 (M)erge, keep (l)ocal or keep (r)emote? m
931 (M)erge, keep (l)ocal or keep (r)emote? m
932 subrepository sources for s differ
932 subrepository sources for s differ
933 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
933 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
934 l
934 l
935 subrepository t diverged (local revision: e95bcfa18a35, remote revision: 52c0adc0515a)
935 subrepository t diverged (local revision: e95bcfa18a35, remote revision: 52c0adc0515a)
936 (M)erge, keep (l)ocal or keep (r)emote? m
936 (M)erge, keep (l)ocal or keep (r)emote? m
937 subrepository sources for t differ
937 subrepository sources for t differ
938 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
938 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
939 l
939 l
940 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
940 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
941 $ hg id
941 $ hg id
942 925c17564ef8+ tip
942 925c17564ef8+ tip
943 $ hg -R s id
943 $ hg -R s id
944 fc627a69481f+
944 fc627a69481f+
945 $ hg -R t id
945 $ hg -R t id
946 e95bcfa18a35+
946 e95bcfa18a35+
947 $ hg update --clean tip
947 $ hg update --clean tip
948 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
948 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
949
949
950 Sticky subrepository, revision updates
950 Sticky subrepository, revision updates
951 $ hg id
951 $ hg id
952 925c17564ef8 tip
952 925c17564ef8 tip
953 $ hg -R s id
953 $ hg -R s id
954 12a213df6fa9 tip
954 12a213df6fa9 tip
955 $ hg -R t id
955 $ hg -R t id
956 52c0adc0515a tip
956 52c0adc0515a tip
957 $ cd s
957 $ cd s
958 $ hg update -r -2
958 $ hg update -r -2
959 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
959 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
960 $ cd ../t
960 $ cd ../t
961 $ hg update -r 2
961 $ hg update -r 2
962 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
962 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
963 $ cd ..
963 $ cd ..
964 $ hg update 10
964 $ hg update 10
965 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
965 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
966 (M)erge, keep (l)ocal or keep (r)emote? m
966 (M)erge, keep (l)ocal or keep (r)emote? m
967 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 20a0db6fbf6c)
967 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 20a0db6fbf6c)
968 (M)erge, keep (l)ocal or keep (r)emote? m
968 (M)erge, keep (l)ocal or keep (r)emote? m
969 subrepository sources for t differ (in checked out version)
969 subrepository sources for t differ (in checked out version)
970 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
970 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
971 l
971 l
972 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
972 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
973 $ hg id
973 $ hg id
974 e45c8b14af55+
974 e45c8b14af55+
975 $ hg -R s id
975 $ hg -R s id
976 02dcf1d70411
976 02dcf1d70411
977 $ hg -R t id
977 $ hg -R t id
978 7af322bc1198
978 7af322bc1198
979
979
980 Sticky subrepository, file changes and revision updates
980 Sticky subrepository, file changes and revision updates
981 $ touch s/f1
981 $ touch s/f1
982 $ touch t/f1
982 $ touch t/f1
983 $ hg add -S s/f1
983 $ hg add -S s/f1
984 $ hg add -S t/f1
984 $ hg add -S t/f1
985 $ hg id
985 $ hg id
986 e45c8b14af55+
986 e45c8b14af55+
987 $ hg -R s id
987 $ hg -R s id
988 02dcf1d70411+
988 02dcf1d70411+
989 $ hg -R t id
989 $ hg -R t id
990 7af322bc1198+
990 7af322bc1198+
991 $ hg update tip
991 $ hg update tip
992 subrepository s diverged (local revision: 12a213df6fa9, remote revision: 12a213df6fa9)
992 subrepository s diverged (local revision: 12a213df6fa9, remote revision: 12a213df6fa9)
993 (M)erge, keep (l)ocal or keep (r)emote? m
993 (M)erge, keep (l)ocal or keep (r)emote? m
994 subrepository sources for s differ
994 subrepository sources for s differ
995 use (l)ocal source (02dcf1d70411) or (r)emote source (12a213df6fa9)?
995 use (l)ocal source (02dcf1d70411) or (r)emote source (12a213df6fa9)?
996 l
996 l
997 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 52c0adc0515a)
997 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 52c0adc0515a)
998 (M)erge, keep (l)ocal or keep (r)emote? m
998 (M)erge, keep (l)ocal or keep (r)emote? m
999 subrepository sources for t differ
999 subrepository sources for t differ
1000 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
1000 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
1001 l
1001 l
1002 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1002 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1003 $ hg id
1003 $ hg id
1004 925c17564ef8+ tip
1004 925c17564ef8+ tip
1005 $ hg -R s id
1005 $ hg -R s id
1006 02dcf1d70411+
1006 02dcf1d70411+
1007 $ hg -R t id
1007 $ hg -R t id
1008 7af322bc1198+
1008 7af322bc1198+
1009
1009
1010 Sticky repository, update --clean
1010 Sticky repository, update --clean
1011 $ hg update --clean tip
1011 $ hg update --clean tip
1012 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1012 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1013 $ hg id
1013 $ hg id
1014 925c17564ef8 tip
1014 925c17564ef8 tip
1015 $ hg -R s id
1015 $ hg -R s id
1016 12a213df6fa9 tip
1016 12a213df6fa9 tip
1017 $ hg -R t id
1017 $ hg -R t id
1018 52c0adc0515a tip
1018 52c0adc0515a tip
1019
1019
1020 Test subrepo already at intended revision:
1020 Test subrepo already at intended revision:
1021 $ cd s
1021 $ cd s
1022 $ hg update fc627a69481f
1022 $ hg update fc627a69481f
1023 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1023 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1024 $ cd ..
1024 $ cd ..
1025 $ hg update 11
1025 $ hg update 11
1026 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1026 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1027 (M)erge, keep (l)ocal or keep (r)emote? m
1027 (M)erge, keep (l)ocal or keep (r)emote? m
1028 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1028 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1029 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1029 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1030 $ hg id -n
1030 $ hg id -n
1031 11+
1031 11+
1032 $ hg -R s id
1032 $ hg -R s id
1033 fc627a69481f
1033 fc627a69481f
1034 $ hg -R t id
1034 $ hg -R t id
1035 e95bcfa18a35
1035 e95bcfa18a35
1036
1036
1037 Test that removing .hgsubstate doesn't break anything:
1037 Test that removing .hgsubstate doesn't break anything:
1038
1038
1039 $ hg rm -f .hgsubstate
1039 $ hg rm -f .hgsubstate
1040 $ hg ci -mrm
1040 $ hg ci -mrm
1041 nothing changed
1041 nothing changed
1042 [1]
1042 [1]
1043 $ hg log -vr tip
1043 $ hg log -vr tip
1044 changeset: 13:925c17564ef8
1044 changeset: 13:925c17564ef8
1045 tag: tip
1045 tag: tip
1046 user: test
1046 user: test
1047 date: Thu Jan 01 00:00:00 1970 +0000
1047 date: Thu Jan 01 00:00:00 1970 +0000
1048 files: .hgsubstate
1048 files: .hgsubstate
1049 description:
1049 description:
1050 13
1050 13
1051
1051
1052
1052
1053
1053
1054 Test that removing .hgsub removes .hgsubstate:
1054 Test that removing .hgsub removes .hgsubstate:
1055
1055
1056 $ hg rm .hgsub
1056 $ hg rm .hgsub
1057 $ hg ci -mrm2
1057 $ hg ci -mrm2
1058 created new head
1058 created new head
1059 $ hg log -vr tip
1059 $ hg log -vr tip
1060 changeset: 14:2400bccd50af
1060 changeset: 14:2400bccd50af
1061 tag: tip
1061 tag: tip
1062 parent: 11:365661e5936a
1062 parent: 11:365661e5936a
1063 user: test
1063 user: test
1064 date: Thu Jan 01 00:00:00 1970 +0000
1064 date: Thu Jan 01 00:00:00 1970 +0000
1065 files: .hgsub .hgsubstate
1065 files: .hgsub .hgsubstate
1066 description:
1066 description:
1067 rm2
1067 rm2
1068
1068
1069
1069
1070 Test issue3153: diff -S with deleted subrepos
1070 Test issue3153: diff -S with deleted subrepos
1071
1071
1072 $ hg diff --nodates -S -c .
1072 $ hg diff --nodates -S -c .
1073 diff -r 365661e5936a -r 2400bccd50af .hgsub
1073 diff -r 365661e5936a -r 2400bccd50af .hgsub
1074 --- a/.hgsub
1074 --- a/.hgsub
1075 +++ /dev/null
1075 +++ /dev/null
1076 @@ -1,2 +0,0 @@
1076 @@ -1,2 +0,0 @@
1077 -s = s
1077 -s = s
1078 -t = t
1078 -t = t
1079 diff -r 365661e5936a -r 2400bccd50af .hgsubstate
1079 diff -r 365661e5936a -r 2400bccd50af .hgsubstate
1080 --- a/.hgsubstate
1080 --- a/.hgsubstate
1081 +++ /dev/null
1081 +++ /dev/null
1082 @@ -1,2 +0,0 @@
1082 @@ -1,2 +0,0 @@
1083 -fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1083 -fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1084 -e95bcfa18a358dc4936da981ebf4147b4cad1362 t
1084 -e95bcfa18a358dc4936da981ebf4147b4cad1362 t
1085
1085
1086 Test behavior of add for explicit path in subrepo:
1086 Test behavior of add for explicit path in subrepo:
1087 $ cd ..
1087 $ cd ..
1088 $ hg init explicit
1088 $ hg init explicit
1089 $ cd explicit
1089 $ cd explicit
1090 $ echo s = s > .hgsub
1090 $ echo s = s > .hgsub
1091 $ hg add .hgsub
1091 $ hg add .hgsub
1092 $ hg init s
1092 $ hg init s
1093 $ hg ci -m0
1093 $ hg ci -m0
1094 Adding with an explicit path in a subrepo adds the file
1094 Adding with an explicit path in a subrepo adds the file
1095 $ echo c1 > f1
1095 $ echo c1 > f1
1096 $ echo c2 > s/f2
1096 $ echo c2 > s/f2
1097 $ hg st -S
1097 $ hg st -S
1098 ? f1
1098 ? f1
1099 ? s/f2
1099 ? s/f2
1100 $ hg add s/f2
1100 $ hg add s/f2
1101 $ hg st -S
1101 $ hg st -S
1102 A s/f2
1102 A s/f2
1103 ? f1
1103 ? f1
1104 $ hg ci -R s -m0
1104 $ hg ci -R s -m0
1105 $ hg ci -Am1
1105 $ hg ci -Am1
1106 adding f1
1106 adding f1
1107 Adding with an explicit path in a subrepo with -S has the same behavior
1107 Adding with an explicit path in a subrepo with -S has the same behavior
1108 $ echo c3 > f3
1108 $ echo c3 > f3
1109 $ echo c4 > s/f4
1109 $ echo c4 > s/f4
1110 $ hg st -S
1110 $ hg st -S
1111 ? f3
1111 ? f3
1112 ? s/f4
1112 ? s/f4
1113 $ hg add -S s/f4
1113 $ hg add -S s/f4
1114 $ hg st -S
1114 $ hg st -S
1115 A s/f4
1115 A s/f4
1116 ? f3
1116 ? f3
1117 $ hg ci -R s -m1
1117 $ hg ci -R s -m1
1118 $ hg ci -Ama2
1118 $ hg ci -Ama2
1119 adding f3
1119 adding f3
1120 Adding without a path or pattern silently ignores subrepos
1120 Adding without a path or pattern silently ignores subrepos
1121 $ echo c5 > f5
1121 $ echo c5 > f5
1122 $ echo c6 > s/f6
1122 $ echo c6 > s/f6
1123 $ echo c7 > s/f7
1123 $ echo c7 > s/f7
1124 $ hg st -S
1124 $ hg st -S
1125 ? f5
1125 ? f5
1126 ? s/f6
1126 ? s/f6
1127 ? s/f7
1127 ? s/f7
1128 $ hg add
1128 $ hg add
1129 adding f5
1129 adding f5
1130 $ hg st -S
1130 $ hg st -S
1131 A f5
1131 A f5
1132 ? s/f6
1132 ? s/f6
1133 ? s/f7
1133 ? s/f7
1134 $ hg ci -R s -Am2
1134 $ hg ci -R s -Am2
1135 adding f6
1135 adding f6
1136 adding f7
1136 adding f7
1137 $ hg ci -m3
1137 $ hg ci -m3
1138 Adding without a path or pattern with -S also adds files in subrepos
1138 Adding without a path or pattern with -S also adds files in subrepos
1139 $ echo c8 > f8
1139 $ echo c8 > f8
1140 $ echo c9 > s/f9
1140 $ echo c9 > s/f9
1141 $ echo c10 > s/f10
1141 $ echo c10 > s/f10
1142 $ hg st -S
1142 $ hg st -S
1143 ? f8
1143 ? f8
1144 ? s/f10
1144 ? s/f10
1145 ? s/f9
1145 ? s/f9
1146 $ hg add -S
1146 $ hg add -S
1147 adding f8
1147 adding f8
1148 adding s/f10 (glob)
1148 adding s/f10 (glob)
1149 adding s/f9 (glob)
1149 adding s/f9 (glob)
1150 $ hg st -S
1150 $ hg st -S
1151 A f8
1151 A f8
1152 A s/f10
1152 A s/f10
1153 A s/f9
1153 A s/f9
1154 $ hg ci -R s -m3
1154 $ hg ci -R s -m3
1155 $ hg ci -m4
1155 $ hg ci -m4
1156 Adding with a pattern silently ignores subrepos
1156 Adding with a pattern silently ignores subrepos
1157 $ echo c11 > fm11
1157 $ echo c11 > fm11
1158 $ echo c12 > fn12
1158 $ echo c12 > fn12
1159 $ echo c13 > s/fm13
1159 $ echo c13 > s/fm13
1160 $ echo c14 > s/fn14
1160 $ echo c14 > s/fn14
1161 $ hg st -S
1161 $ hg st -S
1162 ? fm11
1162 ? fm11
1163 ? fn12
1163 ? fn12
1164 ? s/fm13
1164 ? s/fm13
1165 ? s/fn14
1165 ? s/fn14
1166 $ hg add 'glob:**fm*'
1166 $ hg add 'glob:**fm*'
1167 adding fm11
1167 adding fm11
1168 $ hg st -S
1168 $ hg st -S
1169 A fm11
1169 A fm11
1170 ? fn12
1170 ? fn12
1171 ? s/fm13
1171 ? s/fm13
1172 ? s/fn14
1172 ? s/fn14
1173 $ hg ci -R s -Am4
1173 $ hg ci -R s -Am4
1174 adding fm13
1174 adding fm13
1175 adding fn14
1175 adding fn14
1176 $ hg ci -Am5
1176 $ hg ci -Am5
1177 adding fn12
1177 adding fn12
1178 Adding with a pattern with -S also adds matches in subrepos
1178 Adding with a pattern with -S also adds matches in subrepos
1179 $ echo c15 > fm15
1179 $ echo c15 > fm15
1180 $ echo c16 > fn16
1180 $ echo c16 > fn16
1181 $ echo c17 > s/fm17
1181 $ echo c17 > s/fm17
1182 $ echo c18 > s/fn18
1182 $ echo c18 > s/fn18
1183 $ hg st -S
1183 $ hg st -S
1184 ? fm15
1184 ? fm15
1185 ? fn16
1185 ? fn16
1186 ? s/fm17
1186 ? s/fm17
1187 ? s/fn18
1187 ? s/fn18
1188 $ hg add -S 'glob:**fm*'
1188 $ hg add -S 'glob:**fm*'
1189 adding fm15
1189 adding fm15
1190 adding s/fm17 (glob)
1190 adding s/fm17 (glob)
1191 $ hg st -S
1191 $ hg st -S
1192 A fm15
1192 A fm15
1193 A s/fm17
1193 A s/fm17
1194 ? fn16
1194 ? fn16
1195 ? s/fn18
1195 ? s/fn18
1196 $ hg ci -R s -Am5
1196 $ hg ci -R s -Am5
1197 adding fn18
1197 adding fn18
1198 $ hg ci -Am6
1198 $ hg ci -Am6
1199 adding fn16
1199 adding fn16
1200
1200
1201 Test behavior of forget for explicit path in subrepo:
1201 Test behavior of forget for explicit path in subrepo:
1202 Forgetting an explicit path in a subrepo untracks the file
1202 Forgetting an explicit path in a subrepo untracks the file
1203 $ echo c19 > s/f19
1203 $ echo c19 > s/f19
1204 $ hg add s/f19
1204 $ hg add s/f19
1205 $ hg st -S
1205 $ hg st -S
1206 A s/f19
1206 A s/f19
1207 $ hg forget s/f19
1207 $ hg forget s/f19
1208 $ hg st -S
1208 $ hg st -S
1209 ? s/f19
1209 ? s/f19
1210 $ rm s/f19
1210 $ rm s/f19
1211 $ cd ..
1211 $ cd ..
1212
1212
1213 Courtesy phases synchronisation to publishing server does not block the push
1213 Courtesy phases synchronisation to publishing server does not block the push
1214 (issue3781)
1214 (issue3781)
1215
1215
1216 $ cp -r main issue3781
1216 $ cp -r main issue3781
1217 $ cp -r main issue3781-dest
1217 $ cp -r main issue3781-dest
1218 $ cd issue3781-dest/s
1218 $ cd issue3781-dest/s
1219 $ hg phase tip # show we have draft changeset
1219 $ hg phase tip # show we have draft changeset
1220 5: draft
1220 5: draft
1221 $ chmod a-w .hg/store/phaseroots # prevent phase push
1221 $ chmod a-w .hg/store/phaseroots # prevent phase push
1222 $ cd ../../issue3781
1222 $ cd ../../issue3781
1223 $ cat >> .hg/hgrc << EOF
1223 $ cat >> .hg/hgrc << EOF
1224 > [paths]
1224 > [paths]
1225 > default=../issue3781-dest/
1225 > default=../issue3781-dest/
1226 > EOF
1226 > EOF
1227 $ hg push
1227 $ hg push
1228 pushing to $TESTTMP/issue3781-dest (glob)
1228 pushing to $TESTTMP/issue3781-dest (glob)
1229 pushing subrepo s to $TESTTMP/issue3781-dest/s
1229 pushing subrepo s to $TESTTMP/issue3781-dest/s
1230 searching for changes
1230 searching for changes
1231 no changes found
1231 no changes found
1232 searching for changes
1232 searching for changes
1233 no changes found
1233 no changes found
1234 [1]
1234 [1]
1235 $ cd ..
1235
1236
1237 Test phase choice for newly created commit with "phases.subrepochecks"
1238 configuration
1239
1240 $ cd t
1241 $ hg update -q -r 12
1242
1243 $ cat >> s/ss/.hg/hgrc <<EOF
1244 > [phases]
1245 > new-commit = secret
1246 > EOF
1247 $ cat >> s/.hg/hgrc <<EOF
1248 > [phases]
1249 > new-commit = draft
1250 > EOF
1251 $ echo phasecheck1 >> s/ss/a
1252 $ hg -R s commit -S --config phases.checksubrepos=abort -m phasecheck1
1253 committing subrepository ss
1254 transaction abort!
1255 rollback completed
1256 abort: can't commit in draft phase conflicting secret from subrepository ss
1257 [255]
1258 $ echo phasecheck2 >> s/ss/a
1259 $ hg -R s commit -S --config phases.checksubrepos=ignore -m phasecheck2
1260 committing subrepository ss
1261 $ hg -R s/ss phase tip
1262 3: secret
1263 $ hg -R s phase tip
1264 6: draft
1265 $ echo phasecheck3 >> s/ss/a
1266 $ hg -R s commit -S -m phasecheck3
1267 committing subrepository ss
1268 warning: changes are committed in secret phase from subrepository ss
1269 $ hg -R s/ss phase tip
1270 4: secret
1271 $ hg -R s phase tip
1272 7: secret
1273
1274 $ cat >> t/.hg/hgrc <<EOF
1275 > [phases]
1276 > new-commit = draft
1277 > EOF
1278 $ cat >> .hg/hgrc <<EOF
1279 > [phases]
1280 > new-commit = public
1281 > EOF
1282 $ echo phasecheck4 >> s/ss/a
1283 $ echo phasecheck4 >> t/t
1284 $ hg commit -S -m phasecheck4
1285 committing subrepository s
1286 committing subrepository s/ss
1287 warning: changes are committed in secret phase from subrepository ss
1288 committing subrepository t
1289 warning: changes are committed in secret phase from subrepository s
1290 created new head
1291 $ hg -R s/ss phase tip
1292 5: secret
1293 $ hg -R s phase tip
1294 8: secret
1295 $ hg -R t phase tip
1296 6: draft
1297 $ hg phase tip
1298 15: secret
1299
1300 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now